From 49434ae0728b449bfe7ff928e6d4ce04d334d4c7 Mon Sep 17 00:00:00 2001 From: renzhiyuan <465386466@qq.com> Date: Fri, 28 Aug 2026 09:34:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E4=BB=B6:=20sdk=5FL?= =?UTF-8?q?inkedMall/valid.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sdk_LinkedMall/valid.md | 1329 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1329 insertions(+) create mode 100644 sdk_LinkedMall/valid.md diff --git a/sdk_LinkedMall/valid.md b/sdk_LinkedMall/valid.md new file mode 100644 index 0000000..4ae66cc --- /dev/null +++ b/sdk_LinkedMall/valid.md @@ -0,0 +1,1329 @@ +// File: sdk_LinkedMall/go.mod +``` +module sdk_LinkedMall + +go 1.21 + +require ( + github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 + github.com/alibabacloud-go/tea/v2 v2.2.0 +) + +// Run `go mod tidy` to generate go.sum and resolve all transitive dependencies. +// If you encounter network timeout, set GOPROXY=https://goproxy.cn,direct +``` + +// File: sdk_LinkedMall/types.go +```go +package sdk_LinkedMall + +import "encoding/json" + +// ============================================================ +// 公共响应结构体 +// ============================================================ + +// CommonResponse 是所有接口返回的统一外层包装 +type CommonResponse struct { + RequestId string `json:"RequestId"` + Success bool `json:"Success"` + Code string `json:"Code"` + Message string `json:"Message"` + SubCode string `json:"SubCode"` + SubMessage string `json:"SubMessage"` + Data json.RawMessage `json:"Data"` +} + +// ============================================================ +// 采购方店铺 (Purchaser Shop) +// ============================================================ + +// ListPurchaserShopsReq 分页获取采购方店铺列表的请求参数(Query) +type ListPurchaserShopsReq struct { + PageNum int `json:"PageNum,omitempty"` // 页码,默认1 + PageSize int `json:"PageSize,omitempty"` // 每页条数,最大100 +} + +// ListPurchaserShopsRespData 分页获取采购方店铺列表的响应Data +type ListPurchaserShopsRespData struct { + Total int64 `json:"Total"` + PageNum int `json:"PageNum"` + PageSize int `json:"PageSize"` + ShopList []PurchaserShopItem `json:"ShopList"` +} + +// PurchaserShopItem 采购方店铺信息 +type PurchaserShopItem struct { + ShopId string `json:"ShopId"` + PurchaserId string `json:"PurchaserId"` + ShopName string `json:"ShopName"` + ShopStatus string `json:"ShopStatus"` +} + +// GetPurchaserShopRespData 获取单个采购店铺详情的响应Data +type GetPurchaserShopRespData struct { + ShopId string `json:"ShopId"` + PurchaserId string `json:"PurchaserId"` + ShopName string `json:"ShopName"` + ShopStatus string `json:"ShopStatus"` + ContactInfo string `json:"ContactInfo"` +} + +// ============================================================ +// 选品池商品 (Selection Product) +// ============================================================ + +// ListSelectionProductsReq 分页查询选品池商品列表的请求参数(Query) +type ListSelectionProductsReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID,必填 + PageNum int `json:"PageNum,omitempty"` // 页码 + PageSize int `json:"PageSize,omitempty"` // 每页条数,最大100 +} + +// ListSelectionProductsRespData 分页查询选品池商品列表的响应Data +type ListSelectionProductsRespData struct { + Total int64 `json:"Total"` + PageNum int `json:"PageNum"` + PageSize int `json:"PageSize"` + ProductList []SelectionProductItem `json:"ProductList"` +} + +// SelectionProductItem 选品池商品摘要信息 +type SelectionProductItem struct { + ProductId string `json:"ProductId"` + Title string `json:"Title"` + MainImage string `json:"MainImage"` + BrandName string `json:"BrandName"` + CategoryId string `json:"CategoryId"` +} + +// GetSelectionProductRespData 查询选品池商品详情的响应Data +type GetSelectionProductRespData struct { + ProductId string `json:"ProductId"` + Title string `json:"Title"` + MainImage string `json:"MainImage"` + Images []string `json:"Images"` + BrandName string `json:"BrandName"` + CategoryId string `json:"CategoryId"` + Desc string `json:"Desc"` + SkuList []SelectionSkuItem `json:"SkuList"` + CanSale bool `json:"CanSale"` // 传入divisionCode才有效,该区域是否可售 + StockQuantity int64 `json:"StockQuantity"` // 总库存数量 +} + +// SelectionSkuItem SKU信息 +type SelectionSkuItem struct { + SkuId string `json:"SkuId"` + SkuSpec string `json:"SkuSpec"` + SalePrice int64 `json:"SalePrice"` // 单位分 + MarketPrice int64 `json:"MarketPrice"` // 单位分 + StockQuantity int64 `json:"StockQuantity"` // 库存数量 +} + +// GetSelectionProductSaleInfoRespData 查询选品池商品销售信息的响应Data +type GetSelectionProductSaleInfoRespData struct { + CanSale bool `json:"CanSale"` + StockQuantity int64 `json:"StockQuantity"` + SkuList []SelectionSkuItem `json:"SkuList"` +} + +// ListSelectionProductSaleInfosReq 批量查询商品销售信息的请求Body +type ListSelectionProductSaleInfosReq struct { + PurchaserId string `json:"PurchaserId"` + ProductIdList []string `json:"ProductIdList"` + DivisionCode string `json:"DivisionCode,omitempty"` +} + +// ProductSaleInfo 商品销售信息 +type ProductSaleInfo struct { + ProductId string `json:"ProductId"` + CanSale bool `json:"CanSale"` + StockQuantity int64 `json:"StockQuantity"` + SkuList []SelectionSkuItem `json:"SkuList"` +} + +// ListSelectionProductSaleInfosRespData 批量查询商品销售信息的响应Data +type ListSelectionProductSaleInfosRespData struct { + ProductSaleInfoList []ProductSaleInfo `json:"ProductSaleInfoList"` +} + +// ListSelectionSkuSaleInfosReq 批量查询SKU销售信息的请求Body +type ListSelectionSkuSaleInfosReq struct { + PurchaserId string `json:"PurchaserId"` + SkuIdList []string `json:"SkuIdList"` + DivisionCode string `json:"DivisionCode,omitempty"` +} + +// SkuSaleInfo SKU销售信息 +type SkuSaleInfo struct { + SkuId string `json:"SkuId"` + SalePrice int64 `json:"SalePrice"` + MarketPrice int64 `json:"MarketPrice"` + StockQuantity int64 `json:"StockQuantity"` + CanSale bool `json:"CanSale"` +} + +// ListSelectionSkuSaleInfosRespData 批量查询SKU销售信息的响应Data +type ListSelectionSkuSaleInfosRespData struct { + SkuSaleInfoList []SkuSaleInfo `json:"SkuSaleInfoList"` +} + +// SearchProductsReq 搜索选品池商品的请求Body +type SearchProductsReq struct { + Keyword string `json:"Keyword,omitempty"` // 关键词 + CategoryId string `json:"CategoryId,omitempty"` // 类目ID + PageNum int `json:"PageNum,omitempty"` // 页码 + PageSize int `json:"PageSize,omitempty"` // 每页条数 + PurchaserId string `json:"PurchaserId"` // 采购方ID,必填 +} + +// SearchProductsRespData 搜索选品池商品的响应Data +type SearchProductsRespData struct { + Total int64 `json:"Total"` + PageNum int `json:"PageNum"` + PageSize int `json:"PageSize"` + ProductList []SelectionProductItem `json:"ProductList"` +} + +// ============================================================ +// 类目 (Category) +// ============================================================ + +// ListCategoriesReq 查询类目列表的请求参数(Query) +type ListCategoriesReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID,必填 + ParentCategoryId string `json:"ParentCategoryId,omitempty"` // 父类目ID,不传查一级类目 +} + +// CategoryItem 类目信息 +type CategoryItem struct { + CategoryId string `json:"CategoryId"` + CategoryName string `json:"CategoryName"` + ParentId string `json:"ParentId"` + Level int `json:"Level"` +} + +// ListCategoriesRespData 查询类目列表的响应Data +type ListCategoriesRespData struct { + CategoryList []CategoryItem `json:"CategoryList"` +} + +// ============================================================ +// 选品池入库/出库 (Selection Group) +// ============================================================ + +// SelectionGroupAddProductReq 选品池商品入库请求Body +type SelectionGroupAddProductReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID,必填 + ShopId string `json:"ShopId"` // 店铺ID,必填 + ProductIdList []string `json:"ProductIdList"` // 商品ID列表,必填 +} + +// SelectionGroupRemoveProductReq 选品池商品出库请求Body +type SelectionGroupRemoveProductReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID,必填 + ShopId string `json:"ShopId"` // 店铺ID,必填 + ProductIdList []string `json:"ProductIdList"` // 商品ID列表,必填 +} + +// ============================================================ +// 采购单 (Purchase Order) +// ============================================================ + +// RenderPurchaseOrderReq 采购单渲染请求Body +type RenderPurchaseOrderReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID + ShopId string `json:"ShopId"` // 店铺ID + DivisionCode string `json:"DivisionCode"` // 五级乡镇编码 + ItemList []RenderOrderItem `json:"ItemList"` // 商品列表 + ReceiverInfo ReceiverInfo `json:"ReceiverInfo"` // 收货人信息 +} + +// RenderOrderItem 渲染采购单的商品条目 +type RenderOrderItem struct { + SkuId string `json:"SkuId"` // SKU ID + Quantity int64 `json:"Quantity"` // 数量 +} + +// ReceiverInfo 收货人信息 +type ReceiverInfo struct { + ReceiverName string `json:"ReceiverName"` // 收货人姓名 + ReceiverPhone string `json:"ReceiverPhone"` // 收货人电话 + ProvinceCode string `json:"ProvinceCode"` // 省份编码 + CityCode string `json:"CityCode"` // 城市编码 + DistrictCode string `json:"DistrictCode"` // 区县编码 + TownCode string `json:"TownCode"` // 乡镇编码 + DetailAddress string `json:"DetailAddress"` // 详细地址 +} + +// RenderPurchaseOrderRespData 采购单渲染的响应Data +type RenderPurchaseOrderRespData struct { + TotalAmount int64 `json:"TotalAmount"` // 总金额,单位分 + TotalFreight int64 `json:"TotalFreight"` // 总运费,单位分 + ItemValidResult []ItemValidResultItem `json:"ItemValidResult"` // 商品校验结果 + RenderItemList []RenderOrderItemResult `json:"RenderItemList"` // 渲染后的商品列表 +} + +// ItemValidResultItem 商品校验结果 +type ItemValidResultItem struct { + SkuId string `json:"SkuId"` + Valid bool `json:"Valid"` // 是否有效 + Reason string `json:"Reason"` // 不可售原因 +} + +// RenderOrderItemResult 渲染后的商品条目 +type RenderOrderItemResult struct { + SkuId string `json:"SkuId"` + SalePrice int64 `json:"SalePrice"` // 实时售价,单位分 + Quantity int64 `json:"Quantity"` + SubTotal int64 `json:"SubTotal"` // 小计,单位分 +} + +// SplitPurchaseOrderReq 采购单渲染并拆单的请求Body(与RenderPurchaseOrderReq结构一致) +type SplitPurchaseOrderReq = RenderPurchaseOrderReq + +// SplitOrderItem 拆单后的子单 +type SplitOrderItem struct { + SubOrderId string `json:"SubOrderId"` // 子单ID + SkuId string `json:"SkuId"` + Quantity int64 `json:"Quantity"` + SalePrice int64 `json:"SalePrice"` // 单位分 + SubTotal int64 `json:"SubTotal"` // 单位分 + Freight int64 `json:"Freight"` // 运费,单位分 +} + +// SplitPurchaseOrderRespData 采购单渲染并拆单的响应Data +type SplitPurchaseOrderRespData struct { + TotalAmount int64 `json:"TotalAmount"` // 总金额,单位分 + TotalFreight int64 `json:"TotalFreight"` // 总运费,单位分 + SubOrderList []SplitOrderItem `json:"SubOrderList"` // 子单列表 +} + +// CreatePurchaseOrderReq 创建采购单请求Body +type CreatePurchaseOrderReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID + ShopId string `json:"ShopId"` // 店铺ID + OuterPurchaseOrderId string `json:"OuterPurchaseOrderId"` // 外部业务唯一单号,幂等 + DivisionCode string `json:"DivisionCode"` // 五级乡镇编码 + ReceiverInfo ReceiverInfo `json:"ReceiverInfo"` // 收货人信息 + SubOrderList []CreateSubOrderItem `json:"SubOrderList"` // 子单列表 +} + +// CreateSubOrderItem 创建采购单的子单条目 +type CreateSubOrderItem struct { + SkuId string `json:"SkuId"` + Quantity int64 `json:"Quantity"` +} + +// CreatePurchaseOrderRespData 创建采购单的响应Data +type CreatePurchaseOrderRespData struct { + PurchaseOrderId string `json:"PurchaseOrderId"` // 阿里云采购单号 +} + +// GetPurchaseOrderStatusReq 获取采购单状态的请求参数(Query + Path) +type GetPurchaseOrderStatusReq struct { + PurchaseOrderId string `json:"-"` // 采购单ID,Path参数 + PurchaserId string `json:"PurchaserId"` // 采购方ID,Query参数 +} + +// GetPurchaseOrderStatusRespData 获取采购单状态的响应Data +type GetPurchaseOrderStatusRespData struct { + PurchaseOrderId string `json:"PurchaseOrderId"` + Status string `json:"Status"` // INIT / PROCESS / SUCCESS / FAIL / CLOSED +} + +// ============================================================ +// 订单 (Order) +// ============================================================ + +// GetOrderReq 获取订单详情的请求参数 +type GetOrderReq struct { + OrderId string `json:"-"` // 订单ID,Path参数 + PurchaserId string `json:"PurchaserId"` // 采购方ID,Query参数 +} + +// GetOrderRespData 获取订单详情的响应Data +type GetOrderRespData struct { + OrderId string `json:"OrderId"` + PurchaseOrderId string `json:"PurchaseOrderId"` + PurchaserId string `json:"PurchaserId"` + ShopId string `json:"ShopId"` + OrderStatus string `json:"OrderStatus"` + TotalAmount int64 `json:"TotalAmount"` // 实付金额,单位分 + TotalFreight int64 `json:"TotalFreight"` // 运费,单位分 + ReceiverInfo ReceiverInfo `json:"ReceiverInfo"` + OrderItemList []OrderItemDetail `json:"OrderItemList"` + CreateTime string `json:"CreateTime"` + PayTime string `json:"PayTime"` +} + +// OrderItemDetail 订单商品明细 +type OrderItemDetail struct { + OrderItemId string `json:"OrderItemId"` + SkuId string `json:"SkuId"` + ProductId string `json:"ProductId"` + ProductName string `json:"ProductName"` + Quantity int64 `json:"Quantity"` + SalePrice int64 `json:"SalePrice"` // 单位分 + SubTotal int64 `json:"SubTotal"` // 单位分 + ItemStatus string `json:"ItemStatus"` + RefundQuantity int64 `json:"RefundQuantity"` +} + +// QueryOrdersReq 查询订单列表的请求参数(Query) +type QueryOrdersReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID,必填 + PurchaseOrderId string `json:"PurchaseOrderId,omitempty"` // 采购单ID + PageNum int `json:"PageNum,omitempty"` // 页码 + PageSize int `json:"PageSize,omitempty"` // 每页条数 + StartTime string `json:"StartTime,omitempty"` // 开始时间 + EndTime string `json:"EndTime,omitempty"` // 结束时间 +} + +// QueryOrdersRespData 查询订单列表的响应Data +type QueryOrdersRespData struct { + Total int64 `json:"Total"` + PageNum int `json:"PageNum"` + PageSize int `json:"PageSize"` + OrderList []OrderSummaryItem `json:"OrderList"` +} + +// OrderSummaryItem 订单摘要信息 +type OrderSummaryItem struct { + OrderId string `json:"OrderId"` + PurchaseOrderId string `json:"PurchaseOrderId"` + OrderStatus string `json:"OrderStatus"` + TotalAmount int64 `json:"TotalAmount"` // 单位分 + CreateTime string `json:"CreateTime"` + PayTime string `json:"PayTime"` +} + +// ============================================================ +// 物流 (Logistics) +// ============================================================ + +// ListLogisticsOrdersReq 查询订单物流信息的请求参数 +type ListLogisticsOrdersReq struct { + OrderId string `json:"-"` // 订单ID,Path参数 + PurchaserId string `json:"PurchaserId"` // 采购方ID,Query参数 +} + +// ListLogisticsOrdersRespData 查询订单物流信息的响应Data +type ListLogisticsOrdersRespData struct { + LogisticsList []LogisticsInfo `json:"LogisticsList"` +} + +// LogisticsInfo 物流信息 +type LogisticsInfo struct { + LogisticsCompany string `json:"LogisticsCompany"` // 物流公司 + TrackingNumber string `json:"TrackingNumber"` // 运单号 + Traces []LogisticsTrace `json:"Traces"` // 物流轨迹 +} + +// LogisticsTrace 物流轨迹 +type LogisticsTrace struct { + Time string `json:"Time"` // 轨迹时间 + Location string `json:"Location"` // 轨迹地点 + Action string `json:"Action"` // 轨迹描述 +} + +// ============================================================ +// 确认收货 (Confirm Disburse) +// ============================================================ + +// ConfirmDisburseReq 确认收货的请求Body +type ConfirmDisburseReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID +} + +// ============================================================ +// 售后单 (Refund Order) +// ============================================================ + +// RenderRefundOrderReq 售后渲染预校验的请求Body +type RenderRefundOrderReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID + OrderId string `json:"OrderId"` // 订单ID + OrderItemId string `json:"OrderItemId"` // 订单商品明细ID + RefundQuantity int64 `json:"RefundQuantity"` // 退款数量 + RefundType string `json:"RefundType"` // 退款类型(仅退款/退货退款) +} + +// RenderRefundOrderRespData 售后渲染预校验的响应Data +type RenderRefundOrderRespData struct { + Valid bool `json:"Valid"` // 是否可售后 + MaxRefundQuantity int64 `json:"MaxRefundQuantity"` // 最大可退数量 + MaxRefundAmount int64 `json:"MaxRefundAmount"` // 最大可退金额,单位分 + RefundReason string `json:"RefundReason"` // 不可售原因 +} + +// CreateRefundOrderReq 创建售后单的请求Body +type CreateRefundOrderReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID + OrderId string `json:"OrderId"` // 订单ID + OrderItemId string `json:"OrderItemId"` // 订单商品明细ID + RefundQuantity int64 `json:"RefundQuantity"` // 退款数量 + RefundAmount int64 `json:"RefundAmount"` // 退款金额,单位分 + RefundType string `json:"RefundType"` // 退款类型 + RefundReason string `json:"RefundReason"` // 退款原因 + OuterRefundNo string `json:"OuterRefundNo"` // 外部售后单号 +} + +// CreateRefundOrderRespData 创建售后单的响应Data +type CreateRefundOrderRespData struct { + RefundOrderId string `json:"RefundOrderId"` // 售后单ID +} + +// CancelRefundOrderReq 取消售后单的请求Body +type CancelRefundOrderReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID +} + +// CancelRefundOrderRespData 取消售后单的响应Data +type CancelRefundOrderRespData struct { + RefundOrderId string `json:"RefundOrderId"` + Status string `json:"Status"` +} + +// GetRefundOrderReq 获取售后单详情的请求参数 +type GetRefundOrderReq struct { + RefundOrderId string `json:"-"` // 售后单ID,Path参数 + PurchaserId string `json:"PurchaserId"` // 采购方ID,Query参数 +} + +// GetRefundOrderRespData 获取售后单详情的响应Data +type GetRefundOrderRespData struct { + RefundOrderId string `json:"RefundOrderId"` + OrderId string `json:"OrderId"` + OrderItemId string `json:"OrderItemId"` + PurchaserId string `json:"PurchaserId"` + RefundType string `json:"RefundType"` + RefundStatus string `json:"RefundStatus"` + RefundQuantity int64 `json:"RefundQuantity"` + RefundAmount int64 `json:"RefundAmount"` // 单位分 + RefundReason string `json:"RefundReason"` + OuterRefundNo string `json:"OuterRefundNo"` + CreateTime string `json:"CreateTime"` +} + +// CreateGoodsShippingNoticeReq 回填退货物流运单的请求Body +type CreateGoodsShippingNoticeReq struct { + PurchaserId string `json:"PurchaserId"` // 采购方ID + LogisticsCompany string `json:"LogisticsCompany"` // 物流公司 + TrackingNumber string `json:"TrackingNumber"` // 运单号 +} + +// CreateGoodsShippingNoticeRespData 回填退货物流运单的响应Data +type CreateGoodsShippingNoticeRespData struct { + Result bool `json:"Result"` +} + +// ============================================================ +// 区域编码 (Division Code) +// ============================================================ + +// QueryChildDivisionCodeReq 查询子区域编码的请求参数(Query) +type QueryChildDivisionCodeReq struct { + ParentDivisionCode string `json:"ParentDivisionCode,omitempty"` // 父区域编码,不传返回省级 +} + +// DivisionInfo 区域编码信息 +type DivisionInfo struct { + DivisionCode string `json:"DivisionCode"` // 区域编码 + DivisionName string `json:"DivisionName"` // 区域名称 + Level int `json:"Level"` // 层级:1-省,2-市,3-区,4-乡镇 + ParentCode string `json:"ParentCode"` // 父区域编码 +} + +// QueryChildDivisionCodeRespData 查询子区域编码的响应Data +type QueryChildDivisionCodeRespData struct { + DivisionList []DivisionInfo `json:"DivisionList"` +} + +// ============================================================ +// 通用操作响应 +// ============================================================ + +// OperationRespData 通用操作响应Data(入库/出库/确认收货等) +type OperationRespData struct { + Result bool `json:"Result"` +} +``` + +// File: sdk_LinkedMall/errors.go +```go +package sdk_LinkedMall + +import "fmt" + +// APIError 表示API返回的业务错误 +type APIError struct { + Code string `json:"Code"` // 错误码 + Message string `json:"Message"` // 错误信息 + SubCode string `json:"SubCode"` // 子错误码 + SubMessage string `json:"SubMessage"` // 子错误信息 + RequestId string `json:"RequestId"` // 请求ID +} + +func (e *APIError) Error() string { + return fmt.Sprintf("linkedmall API error: code=%s, message=%s, subCode=%s, subMessage=%s, requestId=%s", + e.Code, e.Message, e.SubCode, e.SubMessage, e.RequestId) +} + +// IsSuccess 判断是否业务成功 +func (e *APIError) IsSuccess() bool { + return e.Code == "SUCCESS" +} + +// 预定义错误码常量 +const ( + ErrCodeShopTypeInvalid = "ShopTypeInvalid" + ErrCodeSkuPriceNotLatest = "SkuPriceUnique" + ErrCodePurchaseOrderNotFound = "PurchaseOrderNotFound" + ErrCodeRefundNumberExceed = "RefundNumberMustLessThanOrder" + ErrCodeRefundAmountExceed = "RefundAmountMustLessThanOrder" + ErrCodeNoPrivilege = "HasNoPrivilege" + ErrCodeOrderNotFound = "OrderNotFound" + ErrCodeShopNotFound = "ShopNotFind" + ErrCodeSavePurchaseOrderError = "SavePurchaseOrderError" + ErrCodeOuterPurchaseOrderIdExist = "OuterPurchaseOrderIdExist" +) + +// ErrResp 用于解析错误响应 +type ErrResp struct { + Code string `json:"Code"` + Message string `json:"Message"` + SubCode string `json:"SubCode"` + SubMessage string `json:"SubMessage"` + RequestId string `json:"RequestId"` +} +``` + +// File: sdk_LinkedMall/crypto.go +```go +package sdk_LinkedMall + +// 本文件预留用于加密相关功能。 +// +// 当前SDK使用阿里云 darabonba-openapi 客户端发起ROA签名调用, +// 签名过程由底层客户端自动处理,业务层无需实现签名算法。 +// +// 如需使用国密(SM2/SM3/SM4)或其他加密算法,可在此文件中添加实现。 +// 建议使用 github.com/tjfoc/gmsm 库进行国密算法实现。 +// +// 示例: +// import "github.com/tjfoc/gmsm/sm3" +// func SM3Hash(data []byte) []byte { +// h := sm3.New() +// h.Write(data) +// return h.Sum(nil) +// } +``` + +// File: sdk_LinkedMall/client.go +```go +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, "&") +} +``` + +// File: sdk_LinkedMall/example_test.go +```go +package sdk_LinkedMall + +import ( + "fmt" + "log" + "os" +) + +// ExampleNewClient 演示如何创建客户端 +func ExampleNewClient() { + // 从环境变量获取AK,禁止硬编码 + accessKeyId := os.Getenv("LINKEDMALL_AK_ID") + accessKeySecret := os.Getenv("LINKEDMALL_AK_SECRET") + + cli, err := NewClient(accessKeyId, accessKeySecret) + if err != nil { + log.Fatalf("failed to create client: %v", err) + } + _ = cli + fmt.Println("client created successfully") + // Output: client created successfully +} +``` \ No newline at end of file