package main /* #include */ import "C" import ( "bytes" "crypto/md5" "encoding/hex" "encoding/json" "fmt" "github.com/parnurzeal/gorequest" "io" "mime/multipart" "os" "path/filepath" "sort" "strings" "time" "unsafe" ) // ErrorResponse 错误响应结构 type ErrorResponse struct { ErrorMsg string `json:"error_msg"` // 错误信息 SubMsg string `json:"sub_msg"` // 子错误信息 SubCode interface{} `json:"sub_code"` // 使用json.RawMessage处理null和不同类型 ErrorCode int `json:"error_code"` // 错误代码 RequestID string `json:"request_id"` // 请求ID } // ErrorWrapper 最外层错误响应包装 type ErrorWrapper struct { ErrorResponse ErrorResponse `json:"error_response"` // 错误响应 } /* * 生成签名 * param params[map[string]interface{}] 生成签名需要的map * param clientSecret[string] 客户端密钥 * return 签名 */ func generateSign(params map[string]interface{}, clientSecret string) string { // 获取所有键并排序 keys := make([]string, 0, len(params)) for k := range params { keys = append(keys, k) } // 按键名升序排序 sort.Strings(keys) // 拼接签名字符串 var signStr strings.Builder for _, k := range keys { // 跳过 sign 参数(签名本身不参与签名) if strings.ToLower(k) == "sign" { continue } value := "" if params[k] != nil { value = fmt.Sprintf("%v", params[k]) // 将任意值转为字符串 } // 按照文档格式:参数名+参数值 signStr.WriteString(k + value) } signString := signStr.String() // 拼接client_secret: client_secret + 参数串 + client_secret data := clientSecret + signString + clientSecret // MD5加密并转大写 hasher := md5.New() hasher.Write([]byte(data)) return strings.ToUpper(hex.EncodeToString(hasher.Sum(nil))) } /* * 类目预测 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param outerCatId[string] 外部类目ID * param outerCatName[string] 外部类目名称 * param outerGoodsName[string] 外部商品名称 * return 类目预测响应结构体,错误信息 */ func pddGoodsOuterCatMappingGet(clientId, clientSecret, accessToken, outerCatId, outerCatName, outerGoodsName string) (string, error) { // API地址 url := fmt.Sprint("https://gw-api.pinduoduo.com/api/router") // 当前时间戳 timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名参数 params := map[string]interface{}{ "type": "pdd.goods.outer.cat.mapping.get", // API类型 "data_type": "JSON", // 数据类型 "client_id": clientId, // 客户端ID "access_token": accessToken, // 访问令牌 "outer_cat_id": outerCatId, // 外部类目ID "outer_cat_name": outerCatName, // 外部类目名称 "outer_goods_name": outerGoodsName, // 外部商品名称 "timestamp": timestamp, // 时间戳 } // 生成签名 sign := generateSign(params, clientSecret) // 请求体 formData := map[string]interface{}{ "type": "pdd.goods.outer.cat.mapping.get", "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "outer_cat_id": outerCatId, "outer_cat_name": outerCatName, "outer_goods_name": outerGoodsName, "timestamp": timestamp, "sign": sign, // 签名 } request := gorequest.New() resp, body, errs := request.Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"). Set("Accept", "application/json, text/plain, */*"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(30 * time.Second). // 30秒超时 Send(formData). // 发送表单数据 End() // 结束请求 if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 快递公司查看 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * return 快递公司查看响应结构体,错误信息 */ func pddLogisticsCompaniesGet(clientId, clientSecret string) (string, error) { url := fmt.Sprint("https://gw-api.pinduoduo.com/api/router") timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名参数 params := map[string]interface{}{ "type": "pdd.logistics.companies.get", // API类型:获取物流公司 "data_type": "JSON", "client_id": clientId, "timestamp": timestamp, } sign := generateSign(params, clientSecret) // 请求体 formData := map[string]interface{}{ "type": "pdd.logistics.companies.get", "data_type": "JSON", "client_id": clientId, "timestamp": timestamp, "sign": sign, } request := gorequest.New() resp, body, errs := request.Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"). Set("Accept", "application/json, text/plain, */*"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(30 * time.Second). Send(formData). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理:检查是否有错误响应 if response["error_response"] != nil { var errorWrapper ErrorWrapper // 解析响应 if err := json.Unmarshal([]byte(body), &errorWrapper); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", errorWrapper.ErrorResponse.ErrorMsg, errorWrapper.ErrorResponse.ErrorCode) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * erp打单信息同步 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param logisticsId[string] 物流公司编码 * param orderSn[string] 订单号 * param orderState[string] 订单状态:1-已打单 * param waybillNo[string] 运单号 * return 快递公司查看响应结构体,错误信息 */ func pddErpOrderSync(clientId, clientSecret, accessToken, logisticsId, orderSn, orderState, waybillNo string) (string, error) { url := fmt.Sprint("https://gw-api.pinduoduo.com/api/router") timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名 params := map[string]interface{}{ "type": "pdd.erp.order.sync", // API类型:ERP订单同步 "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "logistics_id": logisticsId, // 物流公司ID "order_sn": orderSn, // 订单号 "order_state": orderState, // 订单状态 "waybill_no": waybillNo, // 运单号 "timestamp": timestamp, } sign := generateSign(params, clientSecret) // 请求体 formData := map[string]interface{}{ "type": "pdd.erp.order.sync", "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "logistics_id": logisticsId, "order_sn": orderSn, "order_state": orderState, "waybill_no": waybillNo, "timestamp": timestamp, "sign": sign, } request := gorequest.New() resp, body, errs := request.Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"). Set("Accept", "application/json, text/plain, */*"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(30 * time.Second). Send(formData). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["error_response"] != nil { var errorWrapper ErrorWrapper // 解析响应 if err := json.Unmarshal([]byte(body), &errorWrapper); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", errorWrapper.ErrorResponse.ErrorMsg, errorWrapper.ErrorResponse.ErrorCode) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 订单发货通知接口 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param logisticsOnlineSendJson[string] 订单发货通知json字符串 * return 订单发货通知接口响应结构体,错误信息 */ func pddLogisticsOnlineSend(clientId, clientSecret, accessToken string, logisticsOnlineSendJson string) (string, error) { url := fmt.Sprint("https://gw-api.pinduoduo.com/api/router") timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名 params := map[string]interface{}{ "type": "pdd.logistics.online.send", "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "timestamp": timestamp, } // 将JSON参数合并到params中 toParams, err := addStructToParams(logisticsOnlineSendJson, params) if err != nil { return "", err } sign := generateSign(toParams, clientSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"). Set("Accept", "application/json, text/plain, */*"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["error_response"] != nil { var errorWrapper ErrorWrapper // 解析响应 if err := json.Unmarshal([]byte(body), &errorWrapper); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", errorWrapper.ErrorResponse.ErrorMsg, errorWrapper.ErrorResponse.ErrorCode) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // LogisticsCompany 物流公司信息结构体 type LogisticsCompany struct { Available int `json:"available"` // 是否可用 Code string `json:"code"` // 物流公司代码 ID int `json:"id"` // 物流公司ID LogisticsCompany string `json:"logistics_company"` // 物流公司名称 } // LogisticsCompaniesGetResponse 物流公司列表响应结构体 type LogisticsCompaniesGetResponse struct { LogisticsCompanies []LogisticsCompany `json:"logistics_companies"` // 物流公司列表 } // LogisticsResponse 最外层响应结构体 type LogisticsResponse struct { LogisticsCompaniesGetResponse LogisticsCompaniesGetResponse `json:"logistics_companies_get_response"` // 物流公司响应 } /* * 拼多多订单同步(组合接口:先查物流公司,再同步订单) * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param logisticsCompany[string] 外部类目ID * param logisticsOnlineSendJson[string] 拼多多订单同步json字符串 * return 类目预测响应结构体,错误信息 */ func pddOrderSynchronization(clientId, clientSecret, accessToken, logisticsCompany, logisticsOnlineSendJson string) (string, error) { var logisticsOnlineSendData map[string]interface{} err := json.Unmarshal([]byte(logisticsOnlineSendJson), &logisticsOnlineSendData) if err != nil { return "", fmt.Errorf("logisticsOnlineSendJson JSON解析失败: %v", err) } // 1. 获取物流公司列表 logisticsCompaniesGet, err := pddLogisticsCompaniesGet(clientId, clientSecret) if err != nil { return "", err } // 2. 解析物流公司响应 var response LogisticsResponse if err := json.Unmarshal([]byte(logisticsCompaniesGet), &response); err != nil { return "", fmt.Errorf("解析JSON失败: %v", err) } // 3. 根据物流公司名称查找对应的物流公司ID for _, lc := range response.LogisticsCompaniesGetResponse.LogisticsCompanies { if lc.LogisticsCompany == logisticsCompany { logisticsOnlineSendData["logistics_id"] = fmt.Sprintf("%d", lc.ID) break } } fmt.Println(logisticsOnlineSendData["logistics_id"]) logisticsOnlineSendStr, err := json.Marshal(logisticsOnlineSendData) if err != nil { return "", fmt.Errorf("logisticsOnlineSendData 序列化失败: %v", err) } logisticsOnlineSend, err := pddLogisticsOnlineSend(clientId, clientSecret, accessToken, string(logisticsOnlineSendStr)) if err != nil { return "", err } return logisticsOnlineSend, nil } /* * 商品图片上传接口 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param filePath[string] 商品图片文件流 * return 商品图片上传响应结构体,错误信息 */ func pddGoodsImgUpload(clientId, clientSecret, accessToken string, filePath string) (string, error) { url := fmt.Sprint("https://gw-upload.pinduoduo.com/api/upload") // 上传专用地址 // 1. 打开文件 file, err := os.Open(filePath) if err != nil { return "", fmt.Errorf("打开文件失败: %v", err) } defer file.Close() // 确保文件关闭 // 当前时间戳 timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名参数 params := map[string]interface{}{ "type": "pdd.goods.img.upload", // API类型:商品图片上传 "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "timestamp": timestamp, } sign := generateSign(params, clientSecret) // 创建multipart/form-data请求体 body := &bytes.Buffer{} writer := multipart.NewWriter(body) // 读取文件内容 fileData, err := os.ReadFile(filePath) if err != nil { return "", fmt.Errorf("读取文件失败: %v", err) } // 添加文件字段 part, err := writer.CreateFormFile("file", filepath.Base(filePath)) if err != nil { return "", fmt.Errorf("创建表单文件失败: %v", err) } _, err = io.Copy(part, bytes.NewReader(fileData)) if err != nil { return "", fmt.Errorf("复制文件内容失败: %v", err) } // 添加其他参数到multipart表单 for key, value := range params { writer.WriteField(key, fmt.Sprintf("%v", value)) } writer.WriteField("sign", sign) // 添加签名 writer.Close() // 关闭writer,完成表单构建 // 发送POST请求 request := gorequest.New() resp, respBody, errs := request.Post(url). Timeout(30*time.Second). Set("Content-Type", writer.FormDataContentType()). // 设置Content-Type Send(body.String()). // 发送请求体 End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(respBody), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["error_response"] != nil { var errorWrapper ErrorWrapper // 解析响应 if err := json.Unmarshal([]byte(respBody), &errorWrapper); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", errorWrapper.ErrorResponse.ErrorMsg, errorWrapper.ErrorResponse.ErrorCode) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // GoodsAddRequest 商品添加/编辑请求结构体 type GoodsAddRequest struct { AutoFillSpuProperty bool `json:"auto_fill_spu_property,omitempty"` // 是否自动补充标品属性 BadFruitClaim int `json:"bad_fruit_claim,omitempty"` // 坏果包赔 BuyLimit int64 `json:"buy_limit,omitempty"` // 限购次数 CarouselGallery []string `json:"carousel_gallery"` // 商品轮播图 CarouselVideo []CarouselVideo `json:"carousel_video,omitempty"` // 商品视频 CarouselVideoURL string `json:"carousel_video_url,omitempty"` // 轮播视频 CatID int64 `json:"cat_id"` // 叶子类目ID CostTemplateID int64 `json:"cost_template_id"` // 物流运费模板ID CountryID int `json:"country_id"` // 地区/国家ID CustomerNum int64 `json:"customer_num,omitempty"` // 团购人数 Customs string `json:"customs,omitempty"` // 海关名称 DeliveryOneDay int `json:"delivery_one_day,omitempty"` // 是否当日发货 DeliveryType int `json:"delivery_type,omitempty"` // 发货方式 DetailGallery []string `json:"detail_gallery"` // 商品详情图 ElecGoodsAttributes ElecGoodsAttributes `json:"elec_goods_attributes,omitempty"` // 卡券类商品属性 GoodsDesc string `json:"goods_desc,omitempty"` // 商品描述 GoodsName string `json:"goods_name"` // 商品标题 GoodsProperties []GoodsProperty `json:"goods_properties,omitempty"` // 商品属性列表 GoodsTradeAttr GoodsTradeAttr `json:"goods_trade_attr,omitempty"` // 日历商品交易相关信息 GoodsTravelAttr GoodsTravelAttr `json:"goods_travel_attr,omitempty"` // 商品出行信息 GoodsType int `json:"goods_type"` // 商品类型 IgnoreEditWarn bool `json:"ignore_edit_warn,omitempty"` // 是否获取商品发布警告信息 ImageURL string `json:"image_url,omitempty"` // 商品主图 InvoiceStatus bool `json:"invoice_status,omitempty"` // 是否支持开票 IsCustoms bool `json:"is_customs,omitempty"` // 是否需要上报海关 IsFolt bool `json:"is_folt"` // 是否支持假一赔十 IsGroupPreSale int `json:"is_group_pre_sale,omitempty"` // 是否成团预售 IsPreSale bool `json:"is_pre_sale"` // 是否预售 IsRefundable bool `json:"is_refundable"` // 是否7天无理由退换货 IsSkuPreSale int `json:"is_sku_pre_sale,omitempty"` // 是否sku预售 LackOfWeightClaim int `json:"lack_of_weight_claim,omitempty"` // 缺重包退 LocalServiceIDList []int `json:"local_service_id_list,omitempty"` // 本地服务id MaiJiaZiTi string `json:"mai_jia_zi_ti,omitempty"` // 买家自提模版id MarketPrice int64 `json:"market_price"` // 参考价格(分) OrderLimit int `json:"order_limit,omitempty"` // 单次限量 OriginCountryID int `json:"origin_country_id,omitempty"` // 原产地id OutGoodsID string `json:"out_goods_id,omitempty"` // 商品外部编码 OutSourceGoodsID string `json:"out_source_goods_id,omitempty"` // 第三方商品Id OutSourceType int `json:"out_source_type,omitempty"` // 第三方商品来源 OverseaGoods OverseaGoods `json:"oversea_goods,omitempty"` // 海淘商品信息 OverseaType int `json:"oversea_type,omitempty"` // oversea_type PreSaleTime int64 `json:"pre_sale_time,omitempty"` // 预售时间 PrivacyDelivery int `json:"privacy_delivery,omitempty"` // 保密发货 QuanGuoLianBao int `json:"quan_guo_lian_bao,omitempty"` // 是否支持全国联保 SecondHand bool `json:"second_hand"` // 是否二手商品 ShangMenAnZhuang string `json:"shang_men_an_zhuang,omitempty"` // 上门安装模版id ShipmentLimitSecond int64 `json:"shipment_limit_second"` // 承诺发货时间(秒) ShopGroupID int64 `json:"shop_group_id,omitempty"` // 门店组id SizeSpecID int64 `json:"size_spec_id,omitempty"` // 尺码表id SkuList []Sku `json:"sku_list"` // sku对象列表 SkuType int `json:"sku_type,omitempty"` // 库存方式 SongHuoAnZhuang string `json:"song_huo_an_zhuang,omitempty"` // 送货入户并安装模版id SongHuoRuHu string `json:"song_huo_ru_hu,omitempty"` // 送货入户模版id TinyName string `json:"tiny_name,omitempty"` // 短标题 TwoPiecesDiscount int `json:"two_pieces_discount,omitempty"` // 满2件折扣 Warehouse string `json:"warehouse,omitempty"` // 保税仓 WarmTips string `json:"warm_tips,omitempty"` // 水果类目温馨提示 ZhiHuanBuXiu int `json:"zhi_huan_bu_xiu,omitempty"` // 只换不修的天数 } // CarouselVideo 轮播视频 type CarouselVideo struct { FileID int64 `json:"file_id,omitempty"` // 商品视频id VideoURL string `json:"video_url,omitempty"` // 商品视频url } // ElecGoodsAttributes 卡券类商品属性 type ElecGoodsAttributes struct { BeginTime int64 `json:"begin_time,omitempty"` // 开始时间 DaysTime int `json:"days_time,omitempty"` // 天数内有效 EndTime int64 `json:"end_time,omitempty"` // 截止时间 TimeType int `json:"time_type,omitempty"` // 卡券核销类型 } // GoodsProperty 商品属性 type GoodsProperty struct { GroupID int `json:"group_id,omitempty"` // 属性值分组ID ImgURL string `json:"img_url,omitempty"` // 图片url Note string `json:"note,omitempty"` // 备注 ParentSpecID int64 `json:"parent_spec_id,omitempty"` // 父规格ID RefPid int64 `json:"ref_pid,omitempty"` // 引用属性id SpecID int64 `json:"spec_id,omitempty"` // 规格ID TemplatePid int64 `json:"template_pid,omitempty"` // 模板属性id Value string `json:"value,omitempty"` // 属性值 ValueUnit string `json:"value_unit,omitempty"` // 属性单位 Vid int64 `json:"vid,omitempty"` // 属性值id //TableInfo []TableValueList `json:"table_info,omitempty"` // 成分表表单信息 } //// TableValueList 表单内容列表 //type TableValueList struct { // ColumnType int `json:"column_type,omitempty"` // 列类型 1-材质成分百分比 // Unit string `json:"unit,omitempty"` // 表单单位,材质成分表时为:% // Value string `json:"value,omitempty"` // 表单值,材质成分表时为:占比百分值 //} // GoodsTradeAttr 日历商品交易相关信息 type GoodsTradeAttr struct { AdvancesDays int `json:"advances_days,omitempty"` // 提前预定天数 BookingNotes BookingNotes `json:"booking_notes,omitempty"` // 预订须知 LifeSpan int `json:"life_span,omitempty"` // 卡券有效期 } // BookingNotes 预订须知 type BookingNotes struct { URL *string `json:"url,omitempty"` // 预定须知图片地址 } // GoodsTravelAttr 商品出行信息 type GoodsTravelAttr struct { NeedTourist bool `json:"need_tourist,omitempty"` // 出行人是否必填 Type int `json:"type,omitempty"` // 日历商品类型 } // OverseaGoods 海淘商品信息 type OverseaGoods struct { BondedWarehouseKey string `json:"bonded_warehouse_key"` // 保税仓唯一标识 ConsumptionTaxRate int `json:"consumption_tax_rate,omitempty"` // 消费税率 CustomsBroker string `json:"customs_broker,omitempty"` // 清关服务商 HsCode string `json:"hs_code,omitempty"` // 海关编号 ValueAddedTaxRate int `json:"value_added_tax_rate,omitempty"` // 增值税率 } // Sku SKU信息 type Sku struct { IsOnsale int `json:"is_onsale"` // sku上架状态 Length int64 `json:"length,omitempty"` // sku送装参数:长度 LimitQuantity int64 `json:"limit_quantity"` // sku购买限制 MultiPrice int64 `json:"multi_price"` // 商品团购价格 OutSkuSn string `json:"out_sku_sn,omitempty"` // 商品sku外部编码 OutSourceSkuID string `json:"out_source_sku_id,omitempty"` // 第三方sku Id OverseaSku OverseaSku `json:"oversea_sku,omitempty"` // 海淘sku信息 Price int64 `json:"price"` // 商品单买价格 Quantity int64 `json:"quantity"` // 商品sku库存数量 SkuPreSaleTime int `json:"sku_pre_sale_time,omitempty"` // sku预售时间戳 SkuProperties []SkuProperty `json:"sku_properties"` // sku属性 SpecIDList string `json:"spec_id_list"` // 商品规格列表 ThumbURL string `json:"thumb_url"` // sku缩略图 Weight int64 `json:"weight"` // 重量(g) } // OverseaSku 海淘SKU信息 type OverseaSku struct { MeasurementCode string `json:"measurement_code"` // 计量单位编码 Specifications string `json:"specifications"` // 规格 Taxation int `json:"taxation"` // 税费 } // SkuProperty SKU属性 type SkuProperty struct { Punit string `json:"punit"` // 属性单位 RefPid int64 `json:"ref_pid"` // 属性id Value string `json:"value"` // 属性值 Vid int64 `json:"vid"` // 属性值id } /* * 商品新增接口 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param goodsAddJson[string] 新增商品信息json字符串 * return 商品新增接口响应结构体,错误信息 */ func pddGoodsAdd(clientId, clientSecret, accessToken string, goodsAddJson string) (string, error) { url := fmt.Sprint("http://gw-api.pinduoduo.com/api/router") // 当前时间戳 timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名参数 params := map[string]interface{}{ "type": "pdd.goods.add", // API类型:商品新增接口 "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "timestamp": timestamp, } if goodsAddJson == "" { return "", fmt.Errorf("goodsAddJson 参数为空!") } // 将JSON参数合并到params中 toParams, err := addStructToParams(goodsAddJson, params) if err != nil { return "", err } sign := generateSign(toParams, clientSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"). Set("Accept", "application/json, text/plain, */*"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["error_response"] != nil { var errorWrapper ErrorWrapper // 解析响应 if err := json.Unmarshal([]byte(body), &errorWrapper); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", errorWrapper.ErrorResponse.ErrorMsg, errorWrapper.ErrorResponse.ErrorCode) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } /* * 联合拼多多图片上传的商品新增(组合接口) * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param goodsAddJson[string] 新增商品信息json字符串 * return 商品新增接口响应结构体,错误信息 */ func selfPddGoodsAdd(clientId, clientSecret, accessToken string, filePath string, goodsAddJson string) (string, error) { // 1. 上传商品图片 upload, err := pddGoodsImgUpload(clientId, clientSecret, accessToken, filePath) if err != nil { return "", err } // 2. 解析商品添加请求JSON var goodsAddRequest GoodsAddRequest if err := json.Unmarshal([]byte(goodsAddJson), &goodsAddRequest); err != nil { return "", fmt.Errorf("解析 goodsAddJson 失败: %v", err) } // 3. 设置图片URL goodsAddRequest.ImageURL = upload // 4. 重新序列化为JSON goodsAddRequestStr, err := json.Marshal(goodsAddRequest) if err != nil { return "", fmt.Errorf("序列化 goodsAddRequest 失败:%v", err) } // 5. 调用商品添加接口 add, err := pddGoodsAdd(clientId, clientSecret, accessToken, string(goodsAddRequestStr)) if err != nil { return "", err } return add, nil } /* * 批量数据解密脱敏接口 * param clientId[string] 客户端ID * param clientSecret[string] 客户端密钥 * param accessToken[string] 访问Token * param reqJson[string] 批量数据解密脱敏接口json字符串 * return 批量数据解密脱敏接口响应结构体,错误信息 */ func pddOpenDecryptMaskBatch(clientId, clientSecret, accessToken string, reqJson string) (string, error) { url := fmt.Sprint("http://gw-api.pinduoduo.com/api/router") // 当前时间戳 timestamp := fmt.Sprintf("%d", time.Now().Unix()) // 生成签名参数 params := map[string]interface{}{ "type": "pdd.open.decrypt.mask.batch", // API类型:批量解密脱敏 "data_type": "JSON", "client_id": clientId, "access_token": accessToken, "timestamp": timestamp, } params["data_list"] = reqJson // 添加数据列表 sign := generateSign(params, clientSecret) if sign == "" { return "", fmt.Errorf("生成 sign 签名错误!") } params["sign"] = sign request := gorequest.New() resp, body, errs := request.Get(url). Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"). Set("Accept", "application/json, text/plain, */*"). Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8"). Timeout(30 * time.Second). Send(params). End() if len(errs) > 0 { return "", fmt.Errorf("请求失败: %v", errs) } if resp.StatusCode != 200 { return "", fmt.Errorf("HTTP状态码异常: %d, 响应: %s", resp.StatusCode, body) } // 解析响应 var response map[string]interface{} if err := json.Unmarshal([]byte(body), &response); err != nil { return "", fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, body) } // 异常处理 if response["error_response"] != nil { var errorWrapper ErrorWrapper // 解析响应 if err := json.Unmarshal([]byte(body), &errorWrapper); err != nil { return "", fmt.Errorf("解析 errorWrapper 失败: %v, 响应内容: %s", err, body) } return "", fmt.Errorf("请求失败: %v, 错误码: %d", errorWrapper.ErrorResponse.ErrorMsg, errorWrapper.ErrorResponse.ErrorCode) } // 转换成json字符串 responseJSON, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("JSON序列化失败: %v", err) } return string(responseJSON), nil } // =========================== 辅助函数 ============================ // 将结构体的字段添加到 params 映射中 func addStructToParams(req string, params map[string]interface{}) (map[string]interface{}, error) { // 将JSON字符串解析为map var tempMap map[string]interface{} if err := json.Unmarshal([]byte(req), &tempMap); err != nil { return nil, fmt.Errorf("解析 req json失败:%v ", err) } // 合并到params for k, v := range tempMap { // 只添加非nil的值 if v != nil { params[k] = v } } return params, nil } // ========================== C 导入函数 =================== // PddGoodsOuterCatMappingGet 类目预测 // //export PddGoodsOuterCatMappingGet func PddGoodsOuterCatMappingGet(clientId, clientSecret, accessToken, outerCatId, outerCatName, outerGoodsName *C.char) *C.char { // 将C字符串转换为Go字符串 goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goOuterCatId := C.GoString(outerCatId) goOuterCatName := C.GoString(outerCatName) goOuterGoodsName := C.GoString(outerGoodsName) // 调用Go函数 info, err := pddGoodsOuterCatMappingGet(goClientId, goClientSecret, goAccessToken, goOuterCatId, goOuterCatName, goOuterGoodsName) if err != nil { return C.CString(err.Error()) // 返回错误信息 } return C.CString(info) // 返回成功信息 } // PddLogisticsCompaniesGet 快递公司查看 // //export PddLogisticsCompaniesGet func PddLogisticsCompaniesGet(clientId, clientSecret *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) info, err := pddLogisticsCompaniesGet(goClientId, goClientSecret) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // PddErpOrderSync erp打单信息同步 // //export PddErpOrderSync func PddErpOrderSync(clientId, clientSecret, accessToken, logisticsId, orderSn, orderState, waybillNo *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goLogisticsId := C.GoString(logisticsId) goOrderSn := C.GoString(orderSn) goOrderState := C.GoString(orderState) goWaybillNo := C.GoString(waybillNo) info, err := pddErpOrderSync(goClientId, goClientSecret, goAccessToken, goLogisticsId, goOrderSn, goOrderState, goWaybillNo) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // PddOrderSynchronization 拼多多订单同步 // //export PddOrderSynchronization func PddOrderSynchronization(clientId, clientSecret, accessToken, logisticsCompany, logisticsOnlineSendJson *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goLogisticsCompany := C.GoString(logisticsCompany) goLogisticsOnlineSendJson := C.GoString(logisticsOnlineSendJson) info, err := pddOrderSynchronization(goClientId, goClientSecret, goAccessToken, goLogisticsCompany, goLogisticsOnlineSendJson) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // PddGoodsImgUpload 商品图片上传接口 // //export PddGoodsImgUpload func PddGoodsImgUpload(clientId, clientSecret, accessToken, filePath *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goFilePath := C.GoString(filePath) info, err := pddGoodsImgUpload(goClientId, goClientSecret, goAccessToken, goFilePath) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // PddGoodsAdd 商品新增接口 // //export PddGoodsAdd func PddGoodsAdd(clientId, clientSecret, accessToken, goodsAddJson *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goGoodsAddJson := C.GoString(goodsAddJson) info, err := pddGoodsAdd(goClientId, goClientSecret, goAccessToken, goGoodsAddJson) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // SelfPddGoodsAdd 联合拼多多图片上传的商品新增 // //export SelfPddGoodsAdd func SelfPddGoodsAdd(clientId, clientSecret, accessToken, filePath, goodsAddJson *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goFilePath := C.GoString(filePath) goGoodsAddJson := C.GoString(goodsAddJson) info, err := selfPddGoodsAdd(goClientId, goClientSecret, goAccessToken, goFilePath, goGoodsAddJson) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // PddOpenDecryptMaskBatch 批量数据解密脱敏接口 // //export PddOpenDecryptMaskBatch func PddOpenDecryptMaskBatch(clientId, clientSecret, accessToken, reqJson *C.char) *C.char { goClientId := C.GoString(clientId) goClientSecret := C.GoString(clientSecret) goAccessToken := C.GoString(accessToken) goReqJson := C.GoString(reqJson) info, err := pddOpenDecryptMaskBatch(goClientId, goClientSecret, goAccessToken, goReqJson) if err != nil { return C.CString(err.Error()) } return C.CString(info) } // FreeCString 释放C字符串内存 // //export FreeCString func FreeCString(str *C.char) { C.free(unsafe.Pointer(str)) } // main函数 //func main() { //}