Files
cmroubao/backend-api/internal/platform/shunyunbao/protocol.go
T

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
}