You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

379 lines
9.0 KiB

package jcook
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/url"
"recook/configs"
"reflect"
"sort"
"strconv"
"strings"
"sync"
"time"
"github.com/shopspring/decimal"
)
type client struct {
}
var c *client
var once sync.Once
func GetClient() *client {
once.Do(func() {
c = &client{}
})
return c
}
var httpClient = &http.Client{
Timeout: time.Second * 5,
}
func Md5OrderlyWithSecret(secret string, data map[string]string) string {
h := md5.New()
var order []string
for key, _ := range data {
order = append(order, key)
}
sort.Strings(order)
h.Write([]byte(secret))
for _, value := range order {
h.Write([]byte(fmt.Sprintf("%s%s", value, data[value])))
}
h.Write([]byte(secret))
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
type Requester interface {
GetApiName() string
}
type Response struct {
Code uint `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
ErrMsg string `json:"err_msg"`
}
type SkuListReq struct {
Page uint `json:"page"`
PageSize uint `json:"page_size"`
Brand string `json:"brand"`
}
func (o SkuListReq) GetApiName() string {
return "sku/list"
}
type SkuInfo struct {
SkuID uint `json:"sku_id"`
SkuName string `json:"sku_name"`
BrandName string `json:"brand_name"`
CategoryFirstName string `json:"category_first_name"`
CategorySecondName string `json:"category_second_name"`
CategoryThirdName string `json:"category_third_name"`
MainPhoto string `json:"main_photo"`
Status bool `json:"status"`
SupplyPrice decimal.Decimal `json:"supply_price"`
GuidePrice decimal.Decimal `json:"guide_price"`
Unit string `json:"unit"`
UpdatedAt string `json:"updated_at"`
Kind uint `json:"kind"`
UpcCode string `json:"upc_code"`
Yn bool `json:"yn"`
}
type SkuListResp struct {
Total uint `json:"total"`
Entries []SkuInfo `json:"entries"`
}
func (o *client) get(r Requester) (*http.Response, error) {
p := url.Values{}
ur, _ := url.Parse(configs.ConfigJCookUrl + r.GetApiName())
params, _ := json.Marshal(r)
data := map[string]string{
"timestamp": time.Now().Format("2006-01-02 15:04:05"),
"app_key": configs.ConfigJCookAppKey,
"channel_id": strconv.Itoa(configs.ConfigJCookAppChannelID),
"params": string(params),
}
sign := Md5OrderlyWithSecret(configs.ConfigJCookAppSecret, data)
data["sign"] = sign
for k, v := range data {
p.Set(k, v)
}
ur.RawQuery = p.Encode()
req, _ := http.NewRequest("GET", ur.String(), nil)
return httpClient.Do(req)
}
func (o *client) parse(resp *http.Response) (res Response, err error) {
data, err := io.ReadAll(resp.Body)
if err != nil {
return
}
d := json.NewDecoder(bytes.NewReader(data))
d.UseNumber()
err = d.Decode(&res)
return
}
func (o *client) mapToStruct(input interface{}, output interface{}) (err error) {
if reflect.TypeOf(output).Kind() != reflect.Ptr {
err = errors.New("output must a ptr")
return
}
t, err := json.Marshal(input)
err = json.Unmarshal(t, output)
return
}
func (o *client) exec(req Requester) (data Response, err error) {
resp, err := o.get(req)
if err != nil {
log.Println(err.Error())
return
}
defer resp.Body.Close()
data, err = o.parse(resp)
if err != nil {
return
}
return data, err
}
func (o *client) Exec(req Requester, obj interface{}) error {
data, err := o.exec(req)
if err != nil {
return err
}
if data.Code != 0 {
return errors.New(data.ErrMsg)
}
err = o.mapToStruct(data.Data, obj)
return err
}
type SkuDetailReq struct {
SkuIDSet []uint `json:"sku_id_set"`
}
type SkuImage struct {
Url string `json:"url"`
IsPrimer bool `json:"is_primer"`
OrderSort uint `json:"order_sort"`
}
type SkuDetailBase struct {
SkuID uint `json:"sku_id"`
SkuName string `json:"sku_name"`
ShopName string `json:"shop_name"`
VendorName string `json:"vendor_name"`
BrandName string `json:"brand_name"`
CategoryFirstName string `json:"category_first_name"`
CategorySecondName string `json:"category_second_name"`
CategoryThirdName string `json:"category_third_name"`
MainPhoto string `json:"main_photo"`
Status bool `json:"status"`
SupplyPrice decimal.Decimal `json:"supply_price"`
GuidePrice decimal.Decimal `json:"guide_price"`
Model string `json:"model"`
Tax string `json:"tax"`
Unit string `json:"unit"`
Size string `json:"size"`
Color string `json:"color"`
Warranty string `json:"warranty"`
ShelfLife string `json:"shelf_life"`
Delivery string `json:"delivery"`
PlaceOfProduction string `json:"place_of_production"`
UpcCode string `json:"upc_code"`
Length float64 `json:"length"`
Width float64 `json:"width"`
Height float64 `json:"height"`
Weight float64 `json:"weight"`
Yn bool `json:"yn"`
Kind uint `json:"kind"`
UpdatedAt string `json:"updated_at"`
}
type Spec struct {
GroupName string `json:"group_name"`
Attribute []SkuAttribute `json:"attribute"`
}
type SkuAttribute struct {
Name string `json:"name"`
Value string `json:"value"`
}
type SkuDetailResp struct {
Images []SkuImage `json:"images"`
SkuDetailBase SkuDetailBase `json:"sku_detail_base"`
BigInfo BigInfo `json:"big_info"`
Specification []Spec `json:"specification"`
ExtAttr []SkuAttribute `json:"ext_attr"`
}
type BigInfo struct {
PcWDis string `json:"pc_wdis"`
PcJsContent string `json:"pc_js_content"`
PcCssContent string `json:"pc_css_content"`
PcHtmlContent string `json:"pc_html_content"`
}
func (o SkuDetailReq) GetApiName() string {
return "sku/detail"
}
type SkuBrotherReq struct {
SkuIDSet []uint `json:"sku_id_set"`
}
type SkuBrotherResp struct {
BrotherSkuIDs []uint `json:"brother_sku_ids"`
}
func (o SkuBrotherReq) GetApiName() string {
return "sku/brother"
}
type SkuPriceReq struct {
SkuIDSet []uint `json:"sku_id_set"`
}
type SkuPriceResp struct {
SupplyPrice decimal.Decimal `json:"supply_price"`
GuidePrice decimal.Decimal `json:"guide_price"`
SkuID uint `json:"sku_id"`
}
func (o SkuPriceReq) GetApiName() string {
return "sku/price"
}
type SkuStockReq struct {
Address string `json:"address"`
SkuList []SkuQuantity `json:"sku_list"`
}
type SkuQuantity struct {
SkuID uint `json:"sku_id"`
Quantity uint `json:"quantity"`
}
type SkuStockResp struct {
SkuID uint `json:"sku_id"`
Quantity uint `json:"quantity"`
StockState uint `json:"stock_state"`
}
func (o SkuStockReq) GetApiName() string {
return "stock/detail"
}
type LogisticsFeeReq struct {
Address string `json:"address"`
SkuList []LogisticsInfo `json:"sku_list"`
OrderFee decimal.Decimal `json:"order_fee"`
}
type LogisticsInfo struct {
SkuID uint `json:"sku_id"`
Quantity uint `json:"quantity"`
SkuPrice decimal.Decimal `json:"sku_price"`
}
type LogisticsFeeResp struct {
Fee decimal.Decimal
}
func (o LogisticsFeeReq) GetApiName() string {
return "logistics/fee"
}
type OrderSubmitReq struct {
Address string `json:"address"`
SkuList []LogisticsInfo `json:"sku_list"`
OrderFee decimal.Decimal `json:"order_fee"`
Receiver OrderReceiver `json:"receiver"`
FreightFee decimal.Decimal `json:"freight_fee"`
UserIp string `json:"user_ip"`
ChannelOrderID string `json:"channel_order_id"`
}
type OrderReceiver struct {
Name string `json:"name"`
Mobile string `json:"mobile"`
}
type OrderSubmitResp struct {
OrderID uint `json:"order_id"`
ChannelOrderID string `json:"channel_order_id"`
ChannelID uint `json:"channel_id"`
}
func (o OrderSubmitReq) GetApiName() string {
return "order/submit"
}
type OrderCancelReq struct {
OrderID uint `json:"order_id"`
CancelReasonCode uint `json:"cancel_reason_code"`
}
type OrderCancelResp struct {
CancelStatus uint `json:"cancel_status"`
}
func (o OrderCancelReq) GetApiName() string {
return "order/cancel"
}
type OrderPushReq struct {
OrderID uint `json:"order_id"`
}
type OrderPushResp struct {
}
func (o OrderPushReq) GetApiName() string {
return "order/push"
}
type OrderFinishReq struct {
OrderID uint `json:"order_id"`
ClientIp string `json:"client_ip"`
ClientPort string `json:"client_port"`
}
type OrderFinishResp struct {
}
func (o OrderFinishReq) GetApiName() string {
return "order/confirm"
}