238 lines
7.9 KiB
Go
238 lines
7.9 KiB
Go
package shunyunbao
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
const (
|
|
CaptchaPath = "/api/p/code1"
|
|
LoginPath = "/am/auth/login"
|
|
UserPath = "/am/user/get"
|
|
StockListTotalPath = "/am/stock/listTotal"
|
|
StockListPath = "/am/stock/list"
|
|
StockDetailPath = "/am/stock/detail/listByStock"
|
|
|
|
maxPageSize = 500
|
|
maxDetailIDs = 100
|
|
maxOrderNumber = 128
|
|
maximumDateSpan = 6
|
|
)
|
|
|
|
var errInvalidProtocolInput = errors.New("invalid shunyunbao protocol input")
|
|
|
|
type Column struct {
|
|
TableName string `json:"tableName"`
|
|
ColumnName string `json:"colName"`
|
|
FieldName string `json:"fieldName"`
|
|
HasAlias int `json:"hasAlias"`
|
|
TableAlias string `json:"tableAlias"`
|
|
}
|
|
|
|
type QueryCondition struct {
|
|
Value string `json:"dvalue"`
|
|
TableName string `json:"tableName"`
|
|
ColumnName string `json:"colName"`
|
|
Operator int `json:"op"`
|
|
Type int `json:"type"`
|
|
TableAlias string `json:"tableAlias"`
|
|
OptionType int `json:"optType"`
|
|
}
|
|
|
|
var stockColumns = []Column{
|
|
{"t_stock", "created", "created", 0, "t"},
|
|
{"t_stock", "order_code", "orderCode", 0, "t"},
|
|
{"t_stock", "printer", "printer", 0, "t"},
|
|
{"t_stock", "weight_time", "weightTime", 0, "t"},
|
|
{"t_stock", "weight_inputer", "weightInputer", 0, "t"},
|
|
{"t_stock", "pkg_time", "pkgTime", 0, "t"},
|
|
{"t_stock", "code", "code", 0, "t"},
|
|
{"t_stock", "status", "status", 0, "t"},
|
|
{"t_stock", "order_status", "orderStatus", 0, "t"},
|
|
{"t_stock", "purchase_status", "purchaseStatus", 0, "t"},
|
|
{"t_stock", "exp_code", "expCode", 0, "t"},
|
|
{"t_stock", "exp_page_code", "expPageCode", 0, "t"},
|
|
{"t_stock", "exp_allow_print", "expAllowPrint", 0, "t"},
|
|
{"t_stock", "exp_page_status", "expPageStatus", 0, "t"},
|
|
{"t_stock", "page_id", "pageId", 0, "t"},
|
|
{"t_stock", "upload_time", "uploadTime", 0, "t"},
|
|
{"t_stock", "pay_time", "payTime", 0, "t"},
|
|
{"t_stock", "shop_day_to_ship", "shopDayToShip", 0, "t"},
|
|
{"t_stock", "remark9", "tsremark9", 1, "t"},
|
|
{"t_stock", "remark9", "remark9", 0, "t"},
|
|
{"t_stock", "detail_qty", "detailQty", 0, "t"},
|
|
{"t_stock", "order_qty", "orderQty", 0, "t"},
|
|
{"t_stock_detail", "inner_exp_code", "innerExpCode", 0, "t7"},
|
|
{"t_stock_detail", "shelf_code", "shelfCode", 0, "t7"},
|
|
{"t_stock", "shelf_code", "tsshelfCode", 1, "t"},
|
|
{"t_stock", "store_type", "storeType", 0, "t"},
|
|
{"t_stock", "order_bag_code", "orderBagCode", 0, "t"},
|
|
{"t_stock", "weight_cust_pkg", "weightCustPkg", 0, "t"},
|
|
{"t_stock", "weight_consign", "weightConsign", 0, "t"},
|
|
{"t_stock", "amt_order", "amtOrder", 0, "t"},
|
|
{"t_stock_append", "offline_amount", "offlineAmount", 0, "t8"},
|
|
{"t_stock_append", "escrow_amount", "escrowAmount", 0, "t8"},
|
|
{"t_stock", "exp_cod", "expCod", 0, "t"},
|
|
{"t_stock", "exp_company", "expCompany", 0, "t"},
|
|
{"t_stock", "transport", "transport", 0, "t"},
|
|
{"t_stock", "order_origin", "orderOrigin", 0, "t"},
|
|
{"t_stock", "exp_out_type", "expOutType", 0, "t"},
|
|
{"t_stock", "order_platform", "orderPlatform", 0, "t"},
|
|
{"t_stock", "exp_pkg_type", "expPkgType", 0, "t"},
|
|
{"t_stock", "exp_pkg_code", "expPkgCode", 0, "t"},
|
|
{"t_stock", "exp_batch", "expBatch", 0, "t"},
|
|
{"t_stock", "exp_ti_huo", "expTiHuo", 0, "t"},
|
|
{"t_stock", "print_time", "printTime", 0, "t"},
|
|
{"t_stock", "receiver", "receiver", 0, "t"},
|
|
{"t_stock", "receiver_tel", "receiverTel", 0, "t"},
|
|
{"t_stock", "receiver_addr", "receiverAddr", 0, "t"},
|
|
{"t_stock", "receiver_shop_name", "receiverShopName", 0, "t"},
|
|
{"t_stock", "receiver_shop_code", "receiverShopCode", 0, "t"},
|
|
{"t_stock", "product_name", "productName", 0, "t"},
|
|
{"t_stock", "is_cancel", "isCancel", 0, "t"},
|
|
{"t_stock", "err_msg", "errMsg", 0, "t"},
|
|
{"t_stock", "remark2", "remark2", 0, "t"},
|
|
{"t_stock", "remark1", "remark1", 0, "t"},
|
|
{"t_stock", "note", "note", 0, "t"},
|
|
{"t_store", "name", "name", 0, "t1"},
|
|
{"sys_user", "fullname", "sufullname", 1, "t3"},
|
|
{"sys_user", "dept_label_path", "deptLabelPath", 0, "t3"},
|
|
{"t_stock", "shop_name", "shopName", 0, "t"},
|
|
{"t_shop", "shop_id", "shopId", 0, "t6"},
|
|
{"t_stock", "remark4", "remark4", 0, "t"},
|
|
{"t_stock", "remark7", "remark7", 0, "t"},
|
|
{"t_stock", "package_time", "packageTime", 0, "t"},
|
|
{"t_stock", "packer", "packer", 0, "t"},
|
|
{"t_stock", "pack_type", "packType", 0, "t"},
|
|
{"t_stock", "track_status", "trackStatus", 0, "t"},
|
|
{"t_stock", "track_desc", "trackDesc", 0, "t"},
|
|
{"t_stock", "err_status", "errStatus", 0, "t"},
|
|
{"t_stock", "err_time", "errTime", 0, "t"},
|
|
{"t_stock", "err_msg", "tserrMsg", 1, "t"},
|
|
{"t_stock", "remark2", "tsremark2", 1, "t"},
|
|
{"t_stock", "remark1", "tsremark1", 1, "t"},
|
|
{"t_stock", "product_volume_str", "productVolumeStr", 0, "t"},
|
|
}
|
|
|
|
func RequestHeaders(baseURL string) (http.Header, error) {
|
|
origin, err := originFor(baseURL)
|
|
if err != nil {
|
|
return nil, errInvalidProtocolInput
|
|
}
|
|
return http.Header{
|
|
"Accept": {"application/json, text/plain, */*"},
|
|
"Origin": {origin},
|
|
"Referer": {origin + "/sys/login"},
|
|
"User-Agent": {"shunyunbaoerp-client/0.1"},
|
|
"X-Requested-With": {"XMLHttpRequest"},
|
|
}, nil
|
|
}
|
|
|
|
func StockColumns() []Column {
|
|
return append([]Column(nil), stockColumns...)
|
|
}
|
|
|
|
func OrderNumberQuery(orderNumber string) (QueryCondition, error) {
|
|
orderNumber = strings.TrimSpace(orderNumber)
|
|
if orderNumber == "" || len([]byte(orderNumber)) > maxOrderNumber ||
|
|
!utf8.ValidString(orderNumber) || hasControl(orderNumber) {
|
|
return QueryCondition{}, errInvalidProtocolInput
|
|
}
|
|
return QueryCondition{
|
|
Value: orderNumber,
|
|
TableName: "t_stock",
|
|
ColumnName: "allcode",
|
|
Operator: 6,
|
|
Type: 0,
|
|
TableAlias: "t",
|
|
OptionType: 1,
|
|
}, nil
|
|
}
|
|
|
|
func CreatedRangeQuery(createdFrom, createdTo string) (QueryCondition, error) {
|
|
from, err := time.Parse(time.DateOnly, createdFrom)
|
|
if err != nil || from.Format(time.DateOnly) != createdFrom {
|
|
return QueryCondition{}, errInvalidProtocolInput
|
|
}
|
|
to, err := time.Parse(time.DateOnly, createdTo)
|
|
if err != nil || to.Format(time.DateOnly) != createdTo || to.Before(from) ||
|
|
int(to.Sub(from)/(24*time.Hour)) > maximumDateSpan {
|
|
return QueryCondition{}, errInvalidProtocolInput
|
|
}
|
|
return QueryCondition{
|
|
Value: createdFrom + "," + createdTo,
|
|
TableName: "t_stock",
|
|
ColumnName: "created",
|
|
Operator: 0,
|
|
Type: 3,
|
|
TableAlias: "t",
|
|
OptionType: 0,
|
|
}, nil
|
|
}
|
|
|
|
func StockListPayload(
|
|
query QueryCondition,
|
|
start, pageIndex, pageSize int,
|
|
) (map[string]any, error) {
|
|
if start < 0 || pageIndex < 1 || pageSize < 1 || pageSize > maxPageSize {
|
|
return nil, errInvalidProtocolInput
|
|
}
|
|
return map[string]any{
|
|
"history": 0,
|
|
"length": pageSize,
|
|
"start": start,
|
|
"pageTotal": 0,
|
|
"pageIndex": pageIndex,
|
|
"store": false,
|
|
"columns": StockColumns(),
|
|
"queries": []QueryCondition{query},
|
|
}, nil
|
|
}
|
|
|
|
func StockDetailPayload(externalStockIDs []string) (map[string]any, error) {
|
|
if len(externalStockIDs) == 0 || len(externalStockIDs) > maxDetailIDs {
|
|
return nil, errInvalidProtocolInput
|
|
}
|
|
ids := make([]uint64, 0, len(externalStockIDs))
|
|
seen := make(map[uint64]struct{}, len(externalStockIDs))
|
|
for _, value := range externalStockIDs {
|
|
parsed, err := strconv.ParseUint(strings.TrimSpace(value), 10, 64)
|
|
if err != nil || parsed == 0 {
|
|
return nil, errInvalidProtocolInput
|
|
}
|
|
if _, exists := seen[parsed]; exists {
|
|
continue
|
|
}
|
|
seen[parsed] = struct{}{}
|
|
ids = append(ids, parsed)
|
|
}
|
|
if len(ids) == 0 {
|
|
return nil, errInvalidProtocolInput
|
|
}
|
|
return map[string]any{"ids": ids}, nil
|
|
}
|
|
|
|
func originFor(baseURL string) (string, error) {
|
|
parsed, err := url.Parse(strings.TrimSpace(baseURL))
|
|
if err != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") ||
|
|
parsed.Host == "" || parsed.User != nil || parsed.RawQuery != "" ||
|
|
parsed.Fragment != "" || (parsed.Path != "" && parsed.Path != "/") {
|
|
return "", errInvalidProtocolInput
|
|
}
|
|
return parsed.Scheme + "://" + parsed.Host, nil
|
|
}
|
|
|
|
func hasControl(value string) bool {
|
|
for _, character := range value {
|
|
if character < 32 || character == 127 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|