添加文件: sdk_LinkedMall/client.go
This commit is contained in:
parent
d53ae4a6c5
commit
4cfca2640c
|
|
@ -0,0 +1,678 @@
|
||||||
|
package sdk_LinkedMall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
|
"github.com/alibabacloud-go/tea/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultRegionId = "cn-zhangjiakou"
|
||||||
|
defaultEndpoint = "linkedmall.cn-zhangjiakou.aliyuncs.com"
|
||||||
|
basePath = "/opensaas-s2b/opensaas-s2b-biz-trade/v2"
|
||||||
|
readTimeout = 30000
|
||||||
|
connectTimeout = 10000
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client LinkedMall SDK 客户端
|
||||||
|
type Client struct {
|
||||||
|
inner *openapi.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient 创建一个新的LinkedMall SDK客户端
|
||||||
|
//
|
||||||
|
// 使用RAM子账号的AccessKey初始化,禁止使用主账号AK。
|
||||||
|
// 示例:
|
||||||
|
//
|
||||||
|
// cli, err := NewClient("your-access-key-id", "your-access-key-secret")
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
func NewClient(accessKeyId, accessKeySecret string) (*Client, error) {
|
||||||
|
config := &openapi.Config{
|
||||||
|
AccessKeyId: tea.String(accessKeyId),
|
||||||
|
AccessKeySecret: tea.String(accessKeySecret),
|
||||||
|
RegionId: tea.String(defaultRegionId),
|
||||||
|
Endpoint: tea.String(defaultEndpoint),
|
||||||
|
ReadTimeout: tea.Int(readTimeout),
|
||||||
|
ConnectTimeout: tea.Int(connectTimeout),
|
||||||
|
}
|
||||||
|
c, err := openapi.NewClient(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create openapi client: %w", err)
|
||||||
|
}
|
||||||
|
return &Client{inner: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildPath 构建完整的请求路径
|
||||||
|
func buildPath(suffix string) string {
|
||||||
|
return basePath + suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
// toQueryMap 将结构体转为查询参数map
|
||||||
|
func toQueryMap(params interface{}) map[string]*string {
|
||||||
|
result := make(map[string]*string)
|
||||||
|
if params == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用json标签序列化后转为map
|
||||||
|
data, _ := json.Marshal(params)
|
||||||
|
var rawMap map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &rawMap); err != nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range rawMap {
|
||||||
|
switch val := v.(type) {
|
||||||
|
case string:
|
||||||
|
if val != "" {
|
||||||
|
result[k] = tea.String(val)
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
if val != 0 {
|
||||||
|
result[k] = tea.String(strconv.FormatInt(int64(val), 10))
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
result[k] = tea.String(strconv.FormatBool(val))
|
||||||
|
default:
|
||||||
|
// 忽略复杂类型
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// doRequest 执行HTTP请求并返回响应体字节
|
||||||
|
func (c *Client) doRequest(method, path string, query map[string]*string, body interface{}) ([]byte, error) {
|
||||||
|
resp, err := c.inner.RoaRequest(
|
||||||
|
tea.String(method),
|
||||||
|
tea.String(path),
|
||||||
|
query,
|
||||||
|
body,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("roa request failed: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("unexpected http status %d, body: %s", resp.StatusCode, string(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.ReadAll(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseResponse 解析通用响应,如果业务失败返回 *APIError
|
||||||
|
func (c *Client) parseResponse(data []byte, target interface{}) error {
|
||||||
|
var commonResp CommonResponse
|
||||||
|
if err := json.Unmarshal(data, &commonResp); err != nil {
|
||||||
|
return fmt.Errorf("failed to parse common response: %w, body: %s", err, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !commonResp.Success {
|
||||||
|
return &APIError{
|
||||||
|
Code: commonResp.Code,
|
||||||
|
Message: commonResp.Message,
|
||||||
|
SubCode: commonResp.SubCode,
|
||||||
|
SubMessage: commonResp.SubMessage,
|
||||||
|
RequestId: commonResp.RequestId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if target != nil && len(commonResp.Data) > 0 {
|
||||||
|
if err := json.Unmarshal(commonResp.Data, target); err != nil {
|
||||||
|
return fmt.Errorf("failed to parse data field: %w, data: %s", err, string(commonResp.Data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 采购方店铺 (Purchaser Shop)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// ListPurchaserShops 分页获取采购方店铺列表
|
||||||
|
func (c *Client) ListPurchaserShops(req *ListPurchaserShopsReq) (*ListPurchaserShopsRespData, error) {
|
||||||
|
path := buildPath("/purchaser-shops")
|
||||||
|
query := toQueryMap(req)
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListPurchaserShopsRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPurchaserShop 获取单个采购店铺详情
|
||||||
|
func (c *Client) GetPurchaserShop(shopId string) (*GetPurchaserShopRespData, error) {
|
||||||
|
path := buildPath("/purchaser-shops/" + shopId)
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GetPurchaserShopRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 选品池商品 (Selection Product)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// ListSelectionProducts 分页查询选品池商品列表
|
||||||
|
func (c *Client) ListSelectionProducts(req *ListSelectionProductsReq) (*ListSelectionProductsRespData, error) {
|
||||||
|
path := buildPath("/selection-products")
|
||||||
|
query := toQueryMap(req)
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListSelectionProductsRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSelectionProduct 查询选品池商品详情
|
||||||
|
//
|
||||||
|
// divisionCode 为可选参数,传入五级乡镇区域编码后可返回该区域可售状态和库存。
|
||||||
|
func (c *Client) GetSelectionProduct(productId, purchaserId, divisionCode string) (*GetSelectionProductRespData, error) {
|
||||||
|
path := buildPath("/selection-products/" + productId)
|
||||||
|
query := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
if divisionCode != "" {
|
||||||
|
query["DivisionCode"] = tea.String(divisionCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GetSelectionProductRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSelectionProductSaleInfo 查询选品池商品销售信息
|
||||||
|
func (c *Client) GetSelectionProductSaleInfo(productId, purchaserId, divisionCode string) (*GetSelectionProductSaleInfoRespData, error) {
|
||||||
|
path := buildPath("/selection-products/" + productId + "/sale-info")
|
||||||
|
query := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
if divisionCode != "" {
|
||||||
|
query["DivisionCode"] = tea.String(divisionCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GetSelectionProductSaleInfoRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSelectionProductSaleInfos 批量查询商品销售信息
|
||||||
|
func (c *Client) ListSelectionProductSaleInfos(req *ListSelectionProductSaleInfosReq) (*ListSelectionProductSaleInfosRespData, error) {
|
||||||
|
path := buildPath("/selection-products:batch-sale-info")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListSelectionProductSaleInfosRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSelectionSkuSaleInfos 批量查询SKU销售信息
|
||||||
|
func (c *Client) ListSelectionSkuSaleInfos(req *ListSelectionSkuSaleInfosReq) (*ListSelectionSkuSaleInfosRespData, error) {
|
||||||
|
path := buildPath("/selection-skus:batch-sale-info")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListSelectionSkuSaleInfosRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListCategories 查询类目列表
|
||||||
|
func (c *Client) ListCategories(req *ListCategoriesReq) (*ListCategoriesRespData, error) {
|
||||||
|
path := buildPath("/categories")
|
||||||
|
query := toQueryMap(req)
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListCategoriesRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchProducts 搜索选品池商品
|
||||||
|
func (c *Client) SearchProducts(req *SearchProductsReq) (*SearchProductsRespData, error) {
|
||||||
|
path := buildPath("/selection-products:search")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SearchProductsRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 选品池入库/出库
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// SelectionGroupAddProduct 选品池商品入库
|
||||||
|
func (c *Client) SelectionGroupAddProduct(req *SelectionGroupAddProductReq) (*OperationRespData, error) {
|
||||||
|
path := buildPath("/selection-group/products:add")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OperationRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectionGroupRemoveProduct 选品池商品出库
|
||||||
|
func (c *Client) SelectionGroupRemoveProduct(req *SelectionGroupRemoveProductReq) (*OperationRespData, error) {
|
||||||
|
path := buildPath("/selection-group/products:remove")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OperationRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 采购单 (Purchase Order)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// RenderPurchaseOrder 采购单渲染(下单预校验)
|
||||||
|
//
|
||||||
|
// 下单前必须调用,获取实时价格、校验商品是否可售。
|
||||||
|
func (c *Client) RenderPurchaseOrder(req *RenderPurchaseOrderReq) (*RenderPurchaseOrderRespData, error) {
|
||||||
|
path := buildPath("/purchase-orders:render")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result RenderPurchaseOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitPurchaseOrder 采购单渲染并拆单
|
||||||
|
//
|
||||||
|
// 返回拆成多份子单结构,用于前端展示,拆单结果用于创建采购单入参。
|
||||||
|
func (c *Client) SplitPurchaseOrder(req *SplitPurchaseOrderReq) (*SplitPurchaseOrderRespData, error) {
|
||||||
|
path := buildPath("/purchase-orders:split-render")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SplitPurchaseOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatePurchaseOrder 创建采购单【异步】
|
||||||
|
//
|
||||||
|
// 重要:接口只返回采购单号,不代表下单成功,必须等待回调通知,再查询订单接口。
|
||||||
|
// 禁止在同步返回后直接标记本地订单成功。
|
||||||
|
func (c *Client) CreatePurchaseOrder(req *CreatePurchaseOrderReq) (*CreatePurchaseOrderRespData, error) {
|
||||||
|
path := buildPath("/purchase-orders")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CreatePurchaseOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPurchaseOrderStatus 获取采购单状态
|
||||||
|
//
|
||||||
|
// 状态枚举:INIT(初始化)、PROCESS(处理中)、SUCCESS(成功)、FAIL(失败)、CLOSED(已关闭)
|
||||||
|
func (c *Client) GetPurchaseOrderStatus(purchaseOrderId, purchaserId string) (*GetPurchaseOrderStatusRespData, error) {
|
||||||
|
path := buildPath("/purchase-orders/" + purchaseOrderId + "/status")
|
||||||
|
query := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GetPurchaseOrderStatusRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 订单 (Order)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// GetOrder 获取订单详情
|
||||||
|
func (c *Client) GetOrder(orderId, purchaserId string) (*GetOrderRespData, error) {
|
||||||
|
path := buildPath("/orders/" + orderId)
|
||||||
|
query := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GetOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryOrders 查询订单列表
|
||||||
|
func (c *Client) QueryOrders(req *QueryOrdersReq) (*QueryOrdersRespData, error) {
|
||||||
|
path := buildPath("/orders")
|
||||||
|
query := toQueryMap(req)
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result QueryOrdersRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListLogisticsOrders 查询订单物流信息
|
||||||
|
func (c *Client) ListLogisticsOrders(orderId, purchaserId string) (*ListLogisticsOrdersRespData, error) {
|
||||||
|
path := buildPath("/orders/" + orderId + "/logistics")
|
||||||
|
query := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListLogisticsOrdersRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfirmDisburse 确认收货
|
||||||
|
func (c *Client) ConfirmDisburse(orderId, purchaserId string) (*OperationRespData, error) {
|
||||||
|
path := buildPath("/orders/" + orderId + ":confirm-disburse")
|
||||||
|
body := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OperationRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 售后单 (Refund Order)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// RenderRefundOrder 售后渲染预校验
|
||||||
|
func (c *Client) RenderRefundOrder(req *RenderRefundOrderReq) (*RenderRefundOrderRespData, error) {
|
||||||
|
path := buildPath("/refund-orders:render")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result RenderRefundOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRefundOrder 创建售后单
|
||||||
|
func (c *Client) CreateRefundOrder(req *CreateRefundOrderReq) (*CreateRefundOrderRespData, error) {
|
||||||
|
path := buildPath("/refund-orders")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CreateRefundOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelRefundOrder 取消售后单
|
||||||
|
func (c *Client) CancelRefundOrder(refundOrderId, purchaserId string) (*CancelRefundOrderRespData, error) {
|
||||||
|
path := buildPath("/refund-orders/" + refundOrderId + ":cancel")
|
||||||
|
body := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CancelRefundOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRefundOrder 获取售后单详情
|
||||||
|
func (c *Client) GetRefundOrder(refundOrderId, purchaserId string) (*GetRefundOrderRespData, error) {
|
||||||
|
path := buildPath("/refund-orders/" + refundOrderId)
|
||||||
|
query := map[string]*string{
|
||||||
|
"PurchaserId": tea.String(purchaserId),
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GetRefundOrderRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGoodsShippingNotice 回填退货物流运单
|
||||||
|
func (c *Client) CreateGoodsShippingNotice(refundOrderId string, req *CreateGoodsShippingNoticeReq) (*CreateGoodsShippingNoticeRespData, error) {
|
||||||
|
path := buildPath("/refund-orders/" + refundOrderId + ":fill-logistics")
|
||||||
|
|
||||||
|
data, err := c.doRequest("POST", path, nil, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CreateGoodsShippingNoticeRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 区域编码 (Division Code)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// QueryChildDivisionCode 查询子区域编码
|
||||||
|
//
|
||||||
|
// 不传ParentDivisionCode返回省级编码;
|
||||||
|
// 传入省返回市,传入市返回区,传入区返回乡镇(五级)。
|
||||||
|
// 下单、商品可售校验必须拿到乡镇级DivisionCode。
|
||||||
|
func (c *Client) QueryChildDivisionCode(parentDivisionCode string) (*QueryChildDivisionCodeRespData, error) {
|
||||||
|
path := buildPath("/divisions:children")
|
||||||
|
var query map[string]*string
|
||||||
|
if parentDivisionCode != "" {
|
||||||
|
query = map[string]*string{
|
||||||
|
"ParentDivisionCode": tea.String(parentDivisionCode),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := c.doRequest("GET", path, query, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result QueryChildDivisionCodeRespData
|
||||||
|
if err := c.parseResponse(data, &result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 回调解析工具
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// CallbackEvent 回调通知事件结构体
|
||||||
|
type CallbackEvent struct {
|
||||||
|
EventCode string `json:"EventCode"` // 事件类型
|
||||||
|
PurchaseOrderId string `json:"PurchaseOrderId"` // 采购单ID
|
||||||
|
OrderIdList []string `json:"OrderIdList"` // 附属真实订单ID数组
|
||||||
|
Status string `json:"Status"` // 状态
|
||||||
|
RequestId string `json:"RequestId"` // 请求ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCallbackEvent 解析回调通知的JSON Body
|
||||||
|
//
|
||||||
|
// 业务侧在回调接口中接收阿里云POST请求,解析事件后做本地状态同步。
|
||||||
|
// 处理完成后需返回 {"success":true} 告知阿里云消费成功。
|
||||||
|
func ParseCallbackEvent(body []byte) (*CallbackEvent, error) {
|
||||||
|
var event CallbackEvent
|
||||||
|
if err := json.Unmarshal(body, &event); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse callback event: %w", err)
|
||||||
|
}
|
||||||
|
return &event, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallbackSuccessResponse 回调成功响应
|
||||||
|
//
|
||||||
|
// 业务处理完回调事件后,返回此结构告知阿里云消费成功。
|
||||||
|
func CallbackSuccessResponse() string {
|
||||||
|
return `{"success":true}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAPIError 判断错误是否为指定错误码
|
||||||
|
func IsAPIError(err error, code string) bool {
|
||||||
|
if apiErr, ok := err.(*APIError); ok {
|
||||||
|
return apiErr.Code == code
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 辅助函数
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
// ToQueryString 将结构体转为URL查询字符串(仅用于调试)
|
||||||
|
func ToQueryString(params interface{}) string {
|
||||||
|
query := toQueryMap(params)
|
||||||
|
if len(query) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var parts []string
|
||||||
|
for k, v := range query {
|
||||||
|
if v != nil {
|
||||||
|
parts = append(parts, k+"="+*v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(parts, "&")
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue