From 3a0be1d73ca367e96a38a7f9234acd19a9a0e239 Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Sat, 22 Aug 2026 12:24:52 +0800
Subject: [PATCH 1/5] =?UTF-8?q?=E5=BF=BD=E7=95=A5=E6=9C=AC=E5=9C=B0=20Supe?=
=?UTF-8?q?rpowers=20=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.gitignore b/.gitignore
index 6b8802547..11bf71865 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,9 @@ sonar-project.properties
!/.mvn/wrapper/maven-wrapper.jar
*.versionsBackup
+# Local Superpowers planning artifacts
+docs/superpowers/
+
# STS
.factorypath
*.zip
From f34db91356633a2059efa4a3a8c2b84147e1ff59 Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Sat, 22 Aug 2026 12:39:27 +0800
Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=B0=8F?=
=?UTF-8?q?=E5=BA=97=E5=95=86=E5=93=81=E7=AE=A1=E7=90=86=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../channel/api/WxChannelProductService.java | 61 +++++
.../api/impl/WxChannelProductServiceImpl.java | 113 ++++++++
.../AddProductThirdPartySourceParam.java | 22 ++
.../AddProductThirdPartySourceResponse.java | 16 ++
.../ExternalProductMappingNewParam.java | 31 +++
.../ExternalProductMappingNewResponse.java | 17 ++
.../product/ExternalProductMappingParam.java | 20 ++
.../ExternalProductMappingResponse.java | 23 ++
.../product/ProductAuditQuotaResponse.java | 36 +++
.../product/ProductAuditStrategyInfo.java | 18 ++
.../product/ProductAuditStrategyResponse.java | 16 ++
.../product/ProductAuditStrategySetParam.java | 14 +
.../product/ProductBrandRecommendParam.java | 20 ++
.../ProductBrandRecommendResponse.java | 20 ++
.../product/ProductCategoryClassifyParam.java | 20 ++
.../ProductCategoryClassifyResponse.java | 41 +++
.../product/ProductCategoryPreCheckParam.java | 14 +
.../ProductCategoryPreCheckResponse.java | 19 ++
.../bean/product/ProductSchemeParam.java | 19 ++
.../bean/product/ProductSchemeResponse.java | 14 +
.../bean/product/ProductStockFlowParam.java | 33 +++
.../product/ProductStockFlowResponse.java | 25 ++
.../bean/product/ProductTimingSaleParam.java | 16 ++
.../constant/WxChannelApiUrlConstants.java | 26 ++
...annelProductManagementServiceImplTest.java | 257 ++++++++++++++++++
.../src/test/resources/testng.xml | 1 +
26 files changed, 912 insertions(+)
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyInfo.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategySetParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowParam.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java
create mode 100644 weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductTimingSaleParam.java
create mode 100644 weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
index ce85e9f0a..4fdf9cee4 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
@@ -13,6 +13,26 @@
import me.chanjar.weixin.channel.bean.product.GiftProductInfo;
import me.chanjar.weixin.channel.bean.product.GiftProductListParam;
import me.chanjar.weixin.channel.bean.product.GiftProductListResponse;
+import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceParam;
+import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceResponse;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingNewParam;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingNewResponse;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingParam;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditQuotaResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategyResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategySetParam;
+import me.chanjar.weixin.channel.bean.product.ProductBrandRecommendParam;
+import me.chanjar.weixin.channel.bean.product.ProductBrandRecommendResponse;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryClassifyParam;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryClassifyResponse;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryPreCheckParam;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryPreCheckResponse;
+import me.chanjar.weixin.channel.bean.product.ProductSchemeParam;
+import me.chanjar.weixin.channel.bean.product.ProductSchemeResponse;
+import me.chanjar.weixin.channel.bean.product.ProductStockFlowParam;
+import me.chanjar.weixin.channel.bean.product.ProductStockFlowResponse;
+import me.chanjar.weixin.channel.bean.product.ProductTimingSaleParam;
import me.chanjar.weixin.channel.bean.product.SkuStockBatchResponse;
import me.chanjar.weixin.channel.bean.product.SkuStockResponse;
import me.chanjar.weixin.channel.bean.product.SpuFastInfo;
@@ -213,6 +233,47 @@ WxChannelBaseResponse updateStock(String productId, String skuId, Integer diffTy
*/
ProductTagLinkResponse getProductTagLink(String productId) throws WxErrorException;
+ /** 获取商品的移动应用跳转 scheme 码. */
+ ProductSchemeResponse getProductScheme(ProductSchemeParam param) throws WxErrorException;
+
+ /** 商品类目推荐. */
+ ProductCategoryClassifyResponse classifyProductCategory(ProductCategoryClassifyParam param) throws WxErrorException;
+
+ /** 商品立即开售. */
+ WxChannelBaseResponse beginTimingSale(ProductTimingSaleParam param) throws WxErrorException;
+
+ /** 取消商品开售. */
+ WxChannelBaseResponse cancelTimingSale(String productId) throws WxErrorException;
+
+ /** 站内外商品属性映射. */
+ ExternalProductMappingResponse externalProductMapping(ExternalProductMappingParam param) throws WxErrorException;
+
+ /** 发品前校验. */
+ ProductCategoryPreCheckResponse categoryPreCheck(ProductCategoryPreCheckParam param) throws WxErrorException;
+
+ /** 获取商品上架策略. */
+ ProductAuditStrategyResponse getProductAuditStrategy() throws WxErrorException;
+
+ /** 设置商品上架策略. */
+ WxChannelBaseResponse setProductAuditStrategy(ProductAuditStrategySetParam param) throws WxErrorException;
+
+ /** 获取商品提审限额. */
+ ProductAuditQuotaResponse getProductAuditQuota() throws WxErrorException;
+
+ /** 商品属性映射及推荐. */
+ ExternalProductMappingNewResponse externalProductMappingNew(ExternalProductMappingNewParam param)
+ throws WxErrorException;
+
+ /** 商品品牌推荐. */
+ ProductBrandRecommendResponse productBrandRecommend(ProductBrandRecommendParam param) throws WxErrorException;
+
+ /** 新增第三方货源信息. */
+ AddProductThirdPartySourceResponse addProductThirdPartySource(AddProductThirdPartySourceParam param)
+ throws WxErrorException;
+
+ /** 获取库存流水. */
+ ProductStockFlowResponse getStockFlow(ProductStockFlowParam param) throws WxErrorException;
+
/**
* 添加非卖商品
*
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java
index b3974e0aa..a7956d318 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java
@@ -14,22 +14,36 @@
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_PRODUCT_STOCK_UPDATE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_PRODUCT_UPDATE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.LIST_LIMIT_TASK_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_ADD_PRODUCT_THIRD_PARTY_SOURCE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_ADD_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_AUDIT_FREE_UPDATE_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_AUDIT_STRATEGY_GET_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_AUDIT_STRATEGY_SET_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_BEGIN_TIMING_SALE_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_CANCEL_TIMING_SALE_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_CATEGORY_CLASSIFY_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_CATEGORY_PRE_CHECK_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_DELISTING_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_DEL_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_EXTERNAL_PRODUCT_MAPPING_NEW_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_EXTERNAL_PRODUCT_MAPPING_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_AUDIT_QUOTA_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_STOCK_BATCH_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_STOCK_FLOW_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_STOCK_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_H5URL_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_LISTING_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_PRODUCT_BRAND_RECOMMEND_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_QRCODE_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_SCHEME_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_TAGLINK_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_UPDATE_STOCK_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_UPDATE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.STOP_LIMIT_TASK_URL;
+import java.util.Collections;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxChannelProductService;
@@ -38,6 +52,12 @@
import me.chanjar.weixin.channel.bean.limit.LimitTaskListParam;
import me.chanjar.weixin.channel.bean.limit.LimitTaskListResponse;
import me.chanjar.weixin.channel.bean.limit.LimitTaskParam;
+import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceParam;
+import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceResponse;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingNewParam;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingNewResponse;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingParam;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingResponse;
import me.chanjar.weixin.channel.bean.product.GiftActivityAddParam;
import me.chanjar.weixin.channel.bean.product.GiftActivityAddResponse;
import me.chanjar.weixin.channel.bean.product.GiftActivityInfo;
@@ -46,6 +66,20 @@
import me.chanjar.weixin.channel.bean.product.GiftProductInfo;
import me.chanjar.weixin.channel.bean.product.GiftProductListParam;
import me.chanjar.weixin.channel.bean.product.GiftProductListResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditQuotaResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategyResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategySetParam;
+import me.chanjar.weixin.channel.bean.product.ProductBrandRecommendParam;
+import me.chanjar.weixin.channel.bean.product.ProductBrandRecommendResponse;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryClassifyParam;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryClassifyResponse;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryPreCheckParam;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryPreCheckResponse;
+import me.chanjar.weixin.channel.bean.product.ProductSchemeParam;
+import me.chanjar.weixin.channel.bean.product.ProductSchemeResponse;
+import me.chanjar.weixin.channel.bean.product.ProductStockFlowParam;
+import me.chanjar.weixin.channel.bean.product.ProductStockFlowResponse;
+import me.chanjar.weixin.channel.bean.product.ProductTimingSaleParam;
import me.chanjar.weixin.channel.bean.product.SkuStockBatchParam;
import me.chanjar.weixin.channel.bean.product.SkuStockBatchResponse;
import me.chanjar.weixin.channel.bean.product.SkuStockParam;
@@ -228,6 +262,85 @@ public ProductTagLinkResponse getProductTagLink(String productId) throws WxError
return ResponseUtils.decode(resJson, ProductTagLinkResponse.class);
}
+ @Override
+ public ProductSchemeResponse getProductScheme(ProductSchemeParam param) throws WxErrorException {
+ return postAndDecode(SPU_SCHEME_URL, param, ProductSchemeResponse.class);
+ }
+
+ @Override
+ public ProductCategoryClassifyResponse classifyProductCategory(ProductCategoryClassifyParam param)
+ throws WxErrorException {
+ return postAndDecode(SPU_CATEGORY_CLASSIFY_URL, param, ProductCategoryClassifyResponse.class);
+ }
+
+ @Override
+ public WxChannelBaseResponse beginTimingSale(ProductTimingSaleParam param) throws WxErrorException {
+ return postAndDecode(SPU_BEGIN_TIMING_SALE_URL, param, WxChannelBaseResponse.class);
+ }
+
+ @Override
+ public WxChannelBaseResponse cancelTimingSale(String productId) throws WxErrorException {
+ return postAndDecode(SPU_CANCEL_TIMING_SALE_URL, Collections.singletonMap("product_id", productId),
+ WxChannelBaseResponse.class);
+ }
+
+ @Override
+ public ExternalProductMappingResponse externalProductMapping(ExternalProductMappingParam param)
+ throws WxErrorException {
+ return postAndDecode(SPU_EXTERNAL_PRODUCT_MAPPING_URL, param, ExternalProductMappingResponse.class);
+ }
+
+ @Override
+ public ProductCategoryPreCheckResponse categoryPreCheck(ProductCategoryPreCheckParam param)
+ throws WxErrorException {
+ return postAndDecode(SPU_CATEGORY_PRE_CHECK_URL, param, ProductCategoryPreCheckResponse.class);
+ }
+
+ @Override
+ public ProductAuditStrategyResponse getProductAuditStrategy() throws WxErrorException {
+ return postAndDecode(SPU_AUDIT_STRATEGY_GET_URL, "{}", ProductAuditStrategyResponse.class);
+ }
+
+ @Override
+ public WxChannelBaseResponse setProductAuditStrategy(ProductAuditStrategySetParam param) throws WxErrorException {
+ return postAndDecode(SPU_AUDIT_STRATEGY_SET_URL, param, WxChannelBaseResponse.class);
+ }
+
+ @Override
+ public ProductAuditQuotaResponse getProductAuditQuota() throws WxErrorException {
+ return postAndDecode(SPU_GET_AUDIT_QUOTA_URL, "{}", ProductAuditQuotaResponse.class);
+ }
+
+ @Override
+ public ExternalProductMappingNewResponse externalProductMappingNew(ExternalProductMappingNewParam param)
+ throws WxErrorException {
+ return postAndDecode(SPU_EXTERNAL_PRODUCT_MAPPING_NEW_URL, param, ExternalProductMappingNewResponse.class);
+ }
+
+ @Override
+ public ProductBrandRecommendResponse productBrandRecommend(ProductBrandRecommendParam param)
+ throws WxErrorException {
+ return postAndDecode(SPU_PRODUCT_BRAND_RECOMMEND_URL, param, ProductBrandRecommendResponse.class);
+ }
+
+ @Override
+ public AddProductThirdPartySourceResponse addProductThirdPartySource(AddProductThirdPartySourceParam param)
+ throws WxErrorException {
+ return postAndDecode(SPU_ADD_PRODUCT_THIRD_PARTY_SOURCE_URL, param, AddProductThirdPartySourceResponse.class);
+ }
+
+ @Override
+ public ProductStockFlowResponse getStockFlow(ProductStockFlowParam param) throws WxErrorException {
+ return postAndDecode(SPU_GET_STOCK_FLOW_URL, param, ProductStockFlowResponse.class);
+ }
+
+ private T postAndDecode(String url, Object param, Class responseType)
+ throws WxErrorException {
+ String reqJson = param instanceof String ? (String) param : JsonUtils.encode(param);
+ String resJson = shopService.post(url, reqJson);
+ return ResponseUtils.decode(resJson, responseType);
+ }
+
@Override
public GiftProductAddResponse addGiftProduct(GiftProductInfo info) throws WxErrorException {
String reqJson = JsonUtils.encode(info);
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceParam.java
new file mode 100644
index 000000000..6f258358b
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceParam.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 新增第三方货源信息请求参数. */
+@Data
+public class AddProductThirdPartySourceParam implements Serializable {
+ private static final long serialVersionUID = -5784320217481497742L;
+
+ @JsonProperty("scene_value")
+ private Integer sceneValue;
+ @JsonProperty("publish_method")
+ private Integer publishMethod;
+ private JsonNode supplier;
+ @JsonProperty("supplier_shop_performance")
+ private JsonNode supplierShopPerformance;
+ @JsonProperty("product_source_info")
+ private JsonNode productSourceInfo;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceResponse.java
new file mode 100644
index 000000000..aec4cef99
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/AddProductThirdPartySourceResponse.java
@@ -0,0 +1,16 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 新增第三方货源信息响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class AddProductThirdPartySourceResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = -7528226120383065861L;
+
+ @JsonProperty("third_party_source_id")
+ private Long thirdPartySourceId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewParam.java
new file mode 100644
index 000000000..d78ac8d31
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewParam.java
@@ -0,0 +1,31 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+
+/** 商品属性映射及推荐请求参数. */
+@Data
+public class ExternalProductMappingNewParam implements Serializable {
+ private static final long serialVersionUID = -7982070319116550518L;
+
+ @JsonProperty("cat_id")
+ private Long catId;
+ @JsonProperty("external_category_name")
+ private String externalCategoryName;
+ @JsonProperty("head_imgs")
+ private List headImgs;
+ @JsonProperty("detail_imgs")
+ private List detailImgs;
+ private String title;
+ @JsonProperty("external_attributes")
+ private List externalAttributes;
+
+ @Data
+ public static class ExternalAttribute implements Serializable {
+ private static final long serialVersionUID = 300805187240781417L;
+ private String key;
+ private String value;
+ }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java
new file mode 100644
index 000000000..29897d961
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 商品属性映射及推荐响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ExternalProductMappingNewResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = 4536547956225312823L;
+
+ @JsonProperty("attributes")
+ private List attributes;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingParam.java
new file mode 100644
index 000000000..849ec64ae
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingParam.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 站内外商品属性映射请求参数. */
+@Data
+public class ExternalProductMappingParam implements Serializable {
+ private static final long serialVersionUID = 3288069294712374035L;
+
+ @JsonProperty("cat_id")
+ private Long catId;
+ @JsonProperty("external_attribute_name")
+ private String externalAttributeName;
+ @JsonProperty("external_attribute_value")
+ private String externalAttributeValue;
+ @JsonProperty("external_category_name")
+ private String externalCategoryName;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingResponse.java
new file mode 100644
index 000000000..8899edcfd
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingResponse.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 站内外商品属性映射响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ExternalProductMappingResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = -8356596972896906087L;
+
+ @JsonProperty("external_attribute_name")
+ private String externalAttributeName;
+ @JsonProperty("external_attribute_value")
+ private String externalAttributeValue;
+ @JsonProperty("internal_attribute_name")
+ private String internalAttributeName;
+ @JsonProperty("internal_attribute_value")
+ private List internalAttributeValue;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java
new file mode 100644
index 000000000..3626dfe93
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java
@@ -0,0 +1,36 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 商品提审限额响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductAuditQuotaResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = -6242837308752181147L;
+
+ @JsonProperty("audit_quota")
+ private AuditQuota auditQuota;
+
+ @Data
+ public static class AuditQuota {
+ @JsonProperty("block_status")
+ private Integer blockStatus;
+ @JsonProperty("avail_quota")
+ private Integer availQuota;
+ @JsonProperty("total_quota")
+ private Integer totalQuota;
+ @JsonProperty("unlimited_type")
+ private Integer unlimitedType;
+ @JsonProperty("audit_total_quota")
+ private Integer auditTotalQuota;
+ @JsonProperty("audit_total_remaining")
+ private Integer auditTotalRemaining;
+ @JsonProperty("new_product_total_quota")
+ private Integer newProductTotalQuota;
+ @JsonProperty("new_product_remaining")
+ private Integer newProductRemaining;
+ }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyInfo.java
new file mode 100644
index 000000000..5bcdcacb8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyInfo.java
@@ -0,0 +1,18 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 商品上架策略信息. */
+@Data
+public class ProductAuditStrategyInfo implements Serializable {
+ private static final long serialVersionUID = -2747596416115475981L;
+
+ @JsonProperty("hide_err_field_flag")
+ private Integer hideErrFieldFlag;
+ @JsonProperty("hit_duplicated_flag")
+ private Integer hitDuplicatedFlag;
+ @JsonProperty("hit_low_risk_rule_flag")
+ private Integer hitLowRiskRuleFlag;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyResponse.java
new file mode 100644
index 000000000..92684bcba
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategyResponse.java
@@ -0,0 +1,16 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 商品上架策略响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductAuditStrategyResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = -1074784511408331849L;
+
+ @JsonProperty("audit_strategy")
+ private ProductAuditStrategyInfo auditStrategy;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategySetParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategySetParam.java
new file mode 100644
index 000000000..b07ff314e
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditStrategySetParam.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 设置商品上架策略请求参数. */
+@Data
+public class ProductAuditStrategySetParam implements Serializable {
+ private static final long serialVersionUID = 7542738744842032508L;
+
+ @JsonProperty("audit_strategy")
+ private ProductAuditStrategyInfo auditStrategy;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendParam.java
new file mode 100644
index 000000000..1fbdc0bb0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendParam.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+
+/** 商品品牌推荐请求参数. */
+@Data
+public class ProductBrandRecommendParam implements Serializable {
+ private static final long serialVersionUID = 6462717198206491138L;
+
+ @JsonProperty("cat_id")
+ private Long catId;
+ @JsonProperty("head_imgs")
+ private List headImgs;
+ @JsonProperty("detail_imgs")
+ private List detailImgs;
+ private String title;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendResponse.java
new file mode 100644
index 000000000..59344058f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductBrandRecommendResponse.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 商品品牌推荐响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductBrandRecommendResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = 4350605866373432810L;
+
+ @JsonProperty("brand_id")
+ private Long brandId;
+ @JsonProperty("brand_name_chinese")
+ private String brandNameChinese;
+ @JsonProperty("brand_name_english")
+ private String brandNameEnglish;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyParam.java
new file mode 100644
index 000000000..2e0a45243
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyParam.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+
+/** 商品类目推荐请求参数. */
+@Data
+public class ProductCategoryClassifyParam implements Serializable {
+ private static final long serialVersionUID = 4665563979720739777L;
+
+ @JsonProperty("req_type")
+ private Integer reqType;
+ private String title;
+ @JsonProperty("head_imgs")
+ private List headImgs;
+ @JsonProperty("cat_id")
+ private String catId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java
new file mode 100644
index 000000000..1e3410cbc
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java
@@ -0,0 +1,41 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 商品类目推荐响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductCategoryClassifyResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = 8258747142248203374L;
+
+ private List categories;
+ @JsonProperty("wrong_cat")
+ private Boolean wrongCat;
+
+ @Data
+ public static class CategoryInfo {
+ private List cats;
+ }
+
+ @Data
+ public static class CategoryLevel {
+ @JsonProperty("cat_info")
+ private Category catInfo;
+ @JsonProperty("has_permission")
+ private Boolean hasPermission;
+ }
+
+ @Data
+ public static class Category {
+ @JsonProperty("cat_id")
+ private String catId;
+ @JsonProperty("cat_name")
+ private String catName;
+ @JsonProperty("is_shop_no_audit")
+ private Boolean shopNoAudit;
+ }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckParam.java
new file mode 100644
index 000000000..aab647472
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckParam.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 发品前校验请求参数. */
+@Data
+public class ProductCategoryPreCheckParam implements Serializable {
+ private static final long serialVersionUID = 5155253060483296766L;
+
+ @JsonProperty("cat_id")
+ private Long catId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckResponse.java
new file mode 100644
index 000000000..42a8221a7
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryPreCheckResponse.java
@@ -0,0 +1,19 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 发品前校验响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductCategoryPreCheckResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = 7136603000806024499L;
+
+ @JsonProperty("all_pass")
+ private Boolean allPass;
+ @JsonProperty("fail_reasons")
+ private List failReasons;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeParam.java
new file mode 100644
index 000000000..f63774c32
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeParam.java
@@ -0,0 +1,19 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 获取商品移动应用跳转 scheme 码请求参数. */
+@Data
+public class ProductSchemeParam implements Serializable {
+ private static final long serialVersionUID = 613832623081127830L;
+
+ @JsonProperty("product_id")
+ private String productId;
+ @JsonProperty("from_appid")
+ private String fromAppid;
+ private Integer expire;
+ @JsonProperty("ext_info")
+ private String extInfo;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeResponse.java
new file mode 100644
index 000000000..d44c6b4a1
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSchemeResponse.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 获取商品移动应用跳转 scheme 码响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductSchemeResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = 7310433919100539990L;
+
+ private String openlink;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowParam.java
new file mode 100644
index 000000000..1354705bd
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowParam.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+
+/** 获取库存流水请求参数. */
+@Data
+public class ProductStockFlowParam implements Serializable {
+ private static final long serialVersionUID = -407227347279113050L;
+
+ @JsonProperty("product_id")
+ private String productId;
+ @JsonProperty("sku_id")
+ private String skuId;
+ @JsonProperty("stock_type")
+ private Integer stockType;
+ @JsonProperty("finder_id")
+ private String finderId;
+ @JsonProperty("begin_time")
+ private Long beginTime;
+ @JsonProperty("end_time")
+ private Long endTime;
+ @JsonProperty("op_type_list")
+ private List opTypeList;
+ @JsonProperty("page_size")
+ private Integer pageSize;
+ @JsonProperty("next_key")
+ private String nextKey;
+ @JsonProperty("stock_type_id")
+ private String stockTypeId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java
new file mode 100644
index 000000000..69388d762
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/** 获取库存流水响应. */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ProductStockFlowResponse extends WxChannelBaseResponse {
+ private static final long serialVersionUID = 7600529379926896515L;
+
+ private StockFlowData data;
+
+ @Data
+ public static class StockFlowData {
+ @JsonProperty("stock_flow_info_list")
+ private List stockFlowInfoList;
+ @JsonProperty("next_key")
+ private String nextKey;
+ }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductTimingSaleParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductTimingSaleParam.java
new file mode 100644
index 000000000..bb0e17396
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductTimingSaleParam.java
@@ -0,0 +1,16 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+
+/** 商品立即开售请求参数. */
+@Data
+public class ProductTimingSaleParam implements Serializable {
+ private static final long serialVersionUID = -7185451543781817487L;
+
+ @JsonProperty("product_id")
+ private String productId;
+ @JsonProperty("task_id")
+ private Long taskId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
index 0b62bf59d..462c67ee4 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
@@ -158,10 +158,36 @@ public interface Spu {
String SPU_H5URL_URL = "https://api.weixin.qq.com/channels/ec/product/h5url/get";
/** 获取商品二维码 */
String SPU_QRCODE_URL = "https://api.weixin.qq.com/channels/ec/product/qrcode/get";
+ /** 获取商品移动应用跳转 scheme 码 */
+ String SPU_SCHEME_URL = "https://api.weixin.qq.com/channels/ec/product/scheme/get";
/** 获取商品口令 */
String SPU_TAGLINK_URL = "https://api.weixin.qq.com/channels/ec/product/taglink/get";
+ /** 商品类目推荐 */
+ String SPU_CATEGORY_CLASSIFY_URL = "https://api.weixin.qq.com/channels/ec/product/category/classify";
+ /** 商品立即开售 */
+ String SPU_BEGIN_TIMING_SALE_URL = "https://api.weixin.qq.com/channels/ec/product/begintimingsale";
+ /** 取消商品开售 */
+ String SPU_CANCEL_TIMING_SALE_URL = "https://api.weixin.qq.com/channels/ec/product/canceltimingsale";
+ /** 站内外商品属性映射 */
+ String SPU_EXTERNAL_PRODUCT_MAPPING_URL = "https://api.weixin.qq.com/channels/ec/product/externalproductmapping";
+ /** 发品前校验 */
+ String SPU_CATEGORY_PRE_CHECK_URL = "https://api.weixin.qq.com/channels/ec/product/categoryprecheck";
+ /** 获取商品上架策略 */
+ String SPU_AUDIT_STRATEGY_GET_URL = "https://api.weixin.qq.com/channels/ec/product/auditstrategy/get";
+ /** 设置商品上架策略 */
+ String SPU_AUDIT_STRATEGY_SET_URL = "https://api.weixin.qq.com/channels/ec/product/auditstrategy/set";
+ /** 获取商品提审限额 */
+ String SPU_GET_AUDIT_QUOTA_URL = "https://api.weixin.qq.com/channels/ec/product/getauditquota";
+ /** 商品属性映射及推荐 */
+ String SPU_EXTERNAL_PRODUCT_MAPPING_NEW_URL = "https://api.weixin.qq.com/channels/ec/product/externalproductmappingnew";
+ /** 商品品牌推荐 */
+ String SPU_PRODUCT_BRAND_RECOMMEND_URL = "https://api.weixin.qq.com/channels/ec/product/productbrandrecommend";
+ /** 新增第三方货源信息 */
+ String SPU_ADD_PRODUCT_THIRD_PARTY_SOURCE_URL = "https://api.weixin.qq.com/channels/ec/product/addproductthirdpartysource";
/** 获取实时库存 */
String SPU_GET_STOCK_URL = "https://api.weixin.qq.com/channels/ec/product/stock/get";
+ /** 获取库存流水 */
+ String SPU_GET_STOCK_FLOW_URL = "https://api.weixin.qq.com/channels/ec/product/stock/getflow";
/** 获取实时库存 */
String SPU_GET_STOCK_BATCH_URL = "https://api.weixin.qq.com/channels/ec/product/stock/batchget";
/** 更新商品库存 */
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
new file mode 100644
index 000000000..a5cdafc65
--- /dev/null
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
@@ -0,0 +1,257 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceParam;
+import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceResponse;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingNewParam;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingNewResponse;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingParam;
+import me.chanjar.weixin.channel.bean.product.ExternalProductMappingResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditQuotaResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategyInfo;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategyResponse;
+import me.chanjar.weixin.channel.bean.product.ProductAuditStrategySetParam;
+import me.chanjar.weixin.channel.bean.product.ProductBrandRecommendParam;
+import me.chanjar.weixin.channel.bean.product.ProductBrandRecommendResponse;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryClassifyParam;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryClassifyResponse;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryPreCheckParam;
+import me.chanjar.weixin.channel.bean.product.ProductCategoryPreCheckResponse;
+import me.chanjar.weixin.channel.bean.product.ProductSchemeParam;
+import me.chanjar.weixin.channel.bean.product.ProductSchemeResponse;
+import me.chanjar.weixin.channel.bean.product.ProductStockFlowParam;
+import me.chanjar.weixin.channel.bean.product.ProductStockFlowResponse;
+import me.chanjar.weixin.channel.bean.product.ProductTimingSaleParam;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.testng.annotations.Test;
+
+/** Tests the product-management endpoint contracts without making network calls. */
+public class WxChannelProductManagementServiceImplTest {
+
+ @Test
+ public void shouldGetProductScheme() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"openlink\":\"weixin://dl/business/?t=abc\"}");
+ ProductSchemeParam param = new ProductSchemeParam();
+ param.setProductId("10001");
+ param.setFromAppid("wx-app");
+ param.setExpire(3600);
+ param.setExtInfo("source");
+
+ ProductSchemeResponse result = productService(channelService).getProductScheme(param);
+
+ assertRequest(channelService, "/channels/ec/product/scheme/get", "{\"product_id\":\"10001\",\"from_appid\":\"wx-app\",\"expire\":3600,\"ext_info\":\"source\"}");
+ assertEquals(result.getOpenlink(), "weixin://dl/business/?t=abc");
+ }
+
+ @Test
+ public void shouldClassifyProductCategoryAndDecodePermission() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"categories\":[{\"cats\":[{\"cat_info\":{\"cat_id\":\"6000\",\"cat_name\":\"童鞋\"},\"has_permission\":true}]}],\"wrong_cat\":false}");
+ ProductCategoryClassifyParam param = new ProductCategoryClassifyParam();
+ param.setReqType(2);
+ param.setTitle("儿童雨鞋");
+ param.setHeadImgs(Arrays.asList("https://example.com/image"));
+ param.setCatId("6000");
+
+ ProductCategoryClassifyResponse result = productService(channelService).classifyProductCategory(param);
+
+ assertRequest(channelService, "/channels/ec/product/category/classify", "{\"req_type\":2,\"title\":\"儿童雨鞋\",\"head_imgs\":[\"https://example.com/image\"],\"cat_id\":\"6000\"}");
+ assertEquals(result.getCategories().get(0).getCats().get(0).getCatInfo().getCatId(), "6000");
+ assertTrue(result.getCategories().get(0).getCats().get(0).getHasPermission());
+ }
+
+ @Test
+ public void shouldBeginTimingSale() throws WxErrorException {
+ RecordingChannelService channelService = response(okResponse());
+ ProductTimingSaleParam param = new ProductTimingSaleParam();
+ param.setProductId("10001");
+ param.setTaskId(123L);
+
+ WxChannelBaseResponse result = productService(channelService).beginTimingSale(param);
+
+ assertRequest(channelService, "/channels/ec/product/begintimingsale", "{\"product_id\":\"10001\",\"task_id\":123}");
+ assertTrue(result.isSuccess());
+ }
+
+ @Test
+ public void shouldCancelTimingSale() throws WxErrorException {
+ RecordingChannelService channelService = response(okResponse());
+
+ WxChannelBaseResponse result = productService(channelService).cancelTimingSale("10001");
+
+ assertRequest(channelService, "/channels/ec/product/canceltimingsale", "{\"product_id\":\"10001\"}");
+ assertTrue(result.isSuccess());
+ }
+
+ @Test
+ public void shouldMapExternalProductAttribute() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"external_attribute_name\":\"材质\",\"external_attribute_value\":\"塑胶\",\"internal_attribute_name\":\"鞋面材质\",\"internal_attribute_value\":[\"塑胶\"]}");
+ ExternalProductMappingParam param = new ExternalProductMappingParam();
+ param.setCatId(6000L);
+ param.setExternalAttributeName("材质");
+ param.setExternalAttributeValue("塑胶");
+ param.setExternalCategoryName("母婴:童鞋");
+
+ ExternalProductMappingResponse result = productService(channelService).externalProductMapping(param);
+
+ assertRequest(channelService, "/channels/ec/product/externalproductmapping", "{\"cat_id\":6000,\"external_attribute_name\":\"材质\",\"external_attribute_value\":\"塑胶\",\"external_category_name\":\"母婴:童鞋\"}");
+ assertEquals(result.getInternalAttributeValue(), Arrays.asList("塑胶"));
+ }
+
+ @Test
+ public void shouldPreCheckCategory() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"all_pass\":false,\"fail_reasons\":[\"缺少资质\"]}");
+ ProductCategoryPreCheckParam param = new ProductCategoryPreCheckParam();
+ param.setCatId(6000L);
+
+ ProductCategoryPreCheckResponse result = productService(channelService).categoryPreCheck(param);
+
+ assertRequest(channelService, "/channels/ec/product/categoryprecheck", "{\"cat_id\":6000}");
+ assertEquals(result.getFailReasons(), Arrays.asList("缺少资质"));
+ }
+
+ @Test
+ public void shouldGetProductAuditStrategy() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"audit_strategy\":{\"hide_err_field_flag\":1,\"hit_duplicated_flag\":0,\"hit_low_risk_rule_flag\":1}}");
+
+ ProductAuditStrategyResponse result = productService(channelService).getProductAuditStrategy();
+
+ assertRequest(channelService, "/channels/ec/product/auditstrategy/get", "{}");
+ assertEquals(result.getAuditStrategy().getHideErrFieldFlag(), Integer.valueOf(1));
+ }
+
+ @Test
+ public void shouldSetProductAuditStrategy() throws WxErrorException {
+ RecordingChannelService channelService = response(okResponse());
+ ProductAuditStrategyInfo strategy = new ProductAuditStrategyInfo();
+ strategy.setHideErrFieldFlag(1);
+ ProductAuditStrategySetParam param = new ProductAuditStrategySetParam();
+ param.setAuditStrategy(strategy);
+
+ WxChannelBaseResponse result = productService(channelService).setProductAuditStrategy(param);
+
+ assertRequest(channelService, "/channels/ec/product/auditstrategy/set", "{\"audit_strategy\":{\"hide_err_field_flag\":1}}");
+ assertTrue(result.isSuccess());
+ }
+
+ @Test
+ public void shouldGetProductAuditQuota() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"audit_quota\":{\"block_status\":0,\"avail_quota\":20,\"total_quota\":100,\"unlimited_type\":0,\"audit_total_quota\":100,\"audit_total_remaining\":80,\"new_product_total_quota\":50,\"new_product_remaining\":40}}");
+
+ ProductAuditQuotaResponse result = productService(channelService).getProductAuditQuota();
+
+ assertRequest(channelService, "/channels/ec/product/getauditquota", "{}");
+ assertEquals(result.getAuditQuota().getNewProductRemaining(), Integer.valueOf(40));
+ }
+
+ @Test
+ public void shouldMapAndRecommendExternalProductAttributes() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"attributes\":[{\"key\":\"鞋面材质\",\"value\":\"塑胶\"}]}");
+ ExternalProductMappingNewParam.ExternalAttribute attribute = new ExternalProductMappingNewParam.ExternalAttribute();
+ attribute.setKey("材质");
+ attribute.setValue("塑胶");
+ ExternalProductMappingNewParam param = new ExternalProductMappingNewParam();
+ param.setCatId(6000L);
+ param.setExternalCategoryName("母婴:童鞋");
+ param.setHeadImgs(Arrays.asList("https://example.com/head"));
+ param.setTitle("儿童雨鞋");
+ param.setExternalAttributes(Arrays.asList(attribute));
+
+ ExternalProductMappingNewResponse result = productService(channelService).externalProductMappingNew(param);
+
+ assertRequest(channelService, "/channels/ec/product/externalproductmappingnew", "{\"cat_id\":6000,\"external_category_name\":\"母婴:童鞋\",\"head_imgs\":[\"https://example.com/head\"],\"title\":\"儿童雨鞋\",\"external_attributes\":[{\"key\":\"材质\",\"value\":\"塑胶\"}]}");
+ assertEquals(result.getAttributes().get(0).getKey(), "鞋面材质");
+ }
+
+ @Test
+ public void shouldRecommendProductBrand() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"brand_id\":123,\"brand_name_chinese\":\"品牌\",\"brand_name_english\":\"Brand\"}");
+ ProductBrandRecommendParam param = new ProductBrandRecommendParam();
+ param.setCatId(6000L);
+ param.setHeadImgs(Arrays.asList("https://example.com/head"));
+ param.setTitle("商品");
+
+ ProductBrandRecommendResponse result = productService(channelService).productBrandRecommend(param);
+
+ assertRequest(channelService, "/channels/ec/product/productbrandrecommend", "{\"cat_id\":6000,\"head_imgs\":[\"https://example.com/head\"],\"title\":\"商品\"}");
+ assertEquals(result.getBrandId(), Long.valueOf(123));
+ }
+
+ @Test
+ public void shouldAddThirdPartyProductSource() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"third_party_source_id\":12345}");
+ AddProductThirdPartySourceParam param = new AddProductThirdPartySourceParam();
+ param.setSceneValue(1);
+ param.setPublishMethod(2);
+
+ AddProductThirdPartySourceResponse result = productService(channelService).addProductThirdPartySource(param);
+
+ assertRequest(channelService, "/channels/ec/product/addproductthirdpartysource", "{\"scene_value\":1,\"publish_method\":2}");
+ assertEquals(result.getThirdPartySourceId(), Long.valueOf(12345));
+ }
+
+ @Test
+ public void shouldGetStockFlowWithRequiredPaginationAndStockTypeId() throws WxErrorException {
+ RecordingChannelService channelService = response("{\"errcode\":0,\"errmsg\":\"ok\",\"data\":{\"stock_flow_info_list\":[{\"amount\":2}],\"next_key\":\"next\"}}");
+ ProductStockFlowParam param = new ProductStockFlowParam();
+ param.setProductId("10001");
+ param.setSkuId("10002");
+ param.setStockType(2);
+ param.setStockTypeId("activity-1");
+ param.setBeginTime(100L);
+ param.setEndTime(200L);
+ param.setPageSize(10);
+
+ ProductStockFlowResponse result = productService(channelService).getStockFlow(param);
+
+ assertRequest(channelService, "/channels/ec/product/stock/getflow", "{\"product_id\":\"10001\",\"sku_id\":\"10002\",\"stock_type\":2,\"begin_time\":100,\"end_time\":200,\"page_size\":10,\"stock_type_id\":\"activity-1\"}");
+ assertEquals(result.getData().getStockFlowInfoList().size(), 1);
+ assertEquals(result.getData().getNextKey(), "next");
+ }
+
+ private static WxChannelProductServiceImpl productService(RecordingChannelService channelService) {
+ return new WxChannelProductServiceImpl(channelService);
+ }
+
+ private static RecordingChannelService response(String response) {
+ return new RecordingChannelService(response);
+ }
+
+ private static String okResponse() {
+ return "{\"errcode\":0,\"errmsg\":\"ok\"}";
+ }
+
+ private static void assertRequest(RecordingChannelService channelService, String path, String expectedJson) {
+ assertTrue(channelService.getUrl().endsWith(path));
+ assertEquals(JsonUtils.decode(channelService.getRequestJson(), Object.class), JsonUtils.decode(expectedJson, Object.class));
+ }
+
+ private static class RecordingChannelService extends WxChannelServiceHttpClientImpl {
+ private final String response;
+ private String url;
+ private String requestJson;
+
+ RecordingChannelService(String response) {
+ this.response = response;
+ }
+
+ @Override
+ public String post(String url, String postData) {
+ this.url = url;
+ this.requestJson = postData;
+ return response;
+ }
+
+ String getUrl() {
+ return url;
+ }
+
+ String getRequestJson() {
+ return requestJson;
+ }
+ }
+}
diff --git a/weixin-java-channel/src/test/resources/testng.xml b/weixin-java-channel/src/test/resources/testng.xml
index 819ebcf5f..af6c9dc8c 100644
--- a/weixin-java-channel/src/test/resources/testng.xml
+++ b/weixin-java-channel/src/test/resources/testng.xml
@@ -3,6 +3,7 @@
+
From a0c2daa1114b5c41bc84c8b6ec1c8c234ac15c7b Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Sat, 22 Aug 2026 12:45:19 +0800
Subject: [PATCH 3/5] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=E5=95=86?=
=?UTF-8?q?=E5=93=81=E7=AE=A1=E7=90=86=E6=8E=A5=E5=8F=A3=E8=AF=B4=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../channel/api/WxChannelProductService.java | 102 +++++++++++++++---
.../product/ProductAuditQuotaResponse.java | 5 +-
.../ProductCategoryClassifyResponse.java | 13 ++-
.../product/ProductStockFlowResponse.java | 5 +-
...annelProductManagementServiceImplTest.java | 25 +++++
5 files changed, 132 insertions(+), 18 deletions(-)
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
index 4fdf9cee4..85a3ec7c5 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
@@ -233,45 +233,121 @@ WxChannelBaseResponse updateStock(String productId, String skuId, Integer diffTy
*/
ProductTagLinkResponse getProductTagLink(String productId) throws WxErrorException;
- /** 获取商品的移动应用跳转 scheme 码. */
+ /**
+ * 获取商品的移动应用跳转 scheme 码.
+ *
+ * @param param 商品 ID、来源 appid、过期时间和附加信息
+ * @return 商品跳转 scheme 码
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductSchemeResponse getProductScheme(ProductSchemeParam param) throws WxErrorException;
- /** 商品类目推荐. */
+ /**
+ * 商品类目推荐.
+ *
+ * @param param 请求类型、商品标题、主图和可选类目 ID;当请求类型为 2 时必须提供类目 ID
+ * @return 推荐类目及店铺经营权限
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductCategoryClassifyResponse classifyProductCategory(ProductCategoryClassifyParam param) throws WxErrorException;
- /** 商品立即开售. */
+ /**
+ * 将定时开售商品改为立即开售.
+ *
+ * @param param 商品 ID 和定时开售任务 ID
+ * @return 操作结果
+ * @throws WxErrorException 调用微信接口失败
+ */
WxChannelBaseResponse beginTimingSale(ProductTimingSaleParam param) throws WxErrorException;
- /** 取消商品开售. */
+ /**
+ * 取消商品开售.
+ *
+ * @param productId 商品 ID
+ * @return 操作结果
+ * @throws WxErrorException 调用微信接口失败
+ */
WxChannelBaseResponse cancelTimingSale(String productId) throws WxErrorException;
- /** 站内外商品属性映射. */
+ /**
+ * 查询站内外商品属性映射.
+ *
+ * @param param 叶子类目 ID、外部类目和外部属性
+ * @return 对应的站内属性及可选属性值
+ * @throws WxErrorException 调用微信接口失败
+ */
ExternalProductMappingResponse externalProductMapping(ExternalProductMappingParam param) throws WxErrorException;
- /** 发品前校验. */
+ /**
+ * 发品前校验店铺类目资质.
+ *
+ * @param param 待发布商品的叶子类目 ID
+ * @return 校验结果和未通过原因
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductCategoryPreCheckResponse categoryPreCheck(ProductCategoryPreCheckParam param) throws WxErrorException;
- /** 获取商品上架策略. */
+ /**
+ * 获取店铺维度的商品上架策略.
+ *
+ * @return 当前上架策略
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductAuditStrategyResponse getProductAuditStrategy() throws WxErrorException;
- /** 设置商品上架策略. */
+ /**
+ * 设置店铺维度的商品上架策略.
+ *
+ * @param param 要设置的上架策略
+ * @return 操作结果
+ * @throws WxErrorException 调用微信接口失败
+ */
WxChannelBaseResponse setProductAuditStrategy(ProductAuditStrategySetParam param) throws WxErrorException;
- /** 获取商品提审限额. */
+ /**
+ * 获取当前店铺的商品提审限额.
+ *
+ * @return 提审总额度和新品剩余额度
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductAuditQuotaResponse getProductAuditQuota() throws WxErrorException;
- /** 商品属性映射及推荐. */
+ /**
+ * 商品属性映射及推荐.
+ *
+ * @param param 叶子类目、商品标题、主图及可选的外部属性
+ * @return 推荐的站内属性
+ * @throws WxErrorException 调用微信接口失败
+ */
ExternalProductMappingNewResponse externalProductMappingNew(ExternalProductMappingNewParam param)
throws WxErrorException;
- /** 商品品牌推荐. */
+ /**
+ * 根据商品信息推荐店铺已有资质的品牌.
+ *
+ * @param param 商品叶子类目、标题和图片
+ * @return 推荐品牌
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductBrandRecommendResponse productBrandRecommend(ProductBrandRecommendParam param) throws WxErrorException;
- /** 新增第三方货源信息. */
+ /**
+ * 新增第三方货源信息.
+ *
+ * @param param 场景、发布方式、货主及货源商品信息
+ * @return 包含第三方货源 ID 的操作结果
+ * @throws WxErrorException 调用微信接口失败
+ */
AddProductThirdPartySourceResponse addProductThirdPartySource(AddProductThirdPartySourceParam param)
throws WxErrorException;
- /** 获取库存流水. */
+ /**
+ * 获取商品库存流水.
+ *
+ * @param param 商品、SKU、库存类型、时间范围和分页参数;pageSize 必填,库存类型非 0 和 1 时 stockTypeId 必填
+ * @return 库存流水及下一页标识
+ * @throws WxErrorException 调用微信接口失败
+ */
ProductStockFlowResponse getStockFlow(ProductStockFlowParam param) throws WxErrorException;
/**
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java
index 3626dfe93..2f17d0e18 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductAuditQuotaResponse.java
@@ -1,6 +1,7 @@
package me.chanjar.weixin.channel.bean.product;
import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
@@ -15,7 +16,9 @@ public class ProductAuditQuotaResponse extends WxChannelBaseResponse {
private AuditQuota auditQuota;
@Data
- public static class AuditQuota {
+ public static class AuditQuota implements Serializable {
+ private static final long serialVersionUID = 6066821247844334714L;
+
@JsonProperty("block_status")
private Integer blockStatus;
@JsonProperty("avail_quota")
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java
index 1e3410cbc..acf31b7f2 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductCategoryClassifyResponse.java
@@ -1,6 +1,7 @@
package me.chanjar.weixin.channel.bean.product;
import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -17,12 +18,16 @@ public class ProductCategoryClassifyResponse extends WxChannelBaseResponse {
private Boolean wrongCat;
@Data
- public static class CategoryInfo {
+ public static class CategoryInfo implements Serializable {
+ private static final long serialVersionUID = -4800760946330901306L;
+
private List cats;
}
@Data
- public static class CategoryLevel {
+ public static class CategoryLevel implements Serializable {
+ private static final long serialVersionUID = 8010801623725584755L;
+
@JsonProperty("cat_info")
private Category catInfo;
@JsonProperty("has_permission")
@@ -30,7 +35,9 @@ public static class CategoryLevel {
}
@Data
- public static class Category {
+ public static class Category implements Serializable {
+ private static final long serialVersionUID = -9013991576741902059L;
+
@JsonProperty("cat_id")
private String catId;
@JsonProperty("cat_name")
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java
index 69388d762..d94df28e8 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductStockFlowResponse.java
@@ -2,6 +2,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
+import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -16,7 +17,9 @@ public class ProductStockFlowResponse extends WxChannelBaseResponse {
private StockFlowData data;
@Data
- public static class StockFlowData {
+ public static class StockFlowData implements Serializable {
+ private static final long serialVersionUID = -4963813730951045381L;
+
@JsonProperty("stock_flow_info_list")
private List stockFlowInfoList;
@JsonProperty("next_key")
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
index a5cdafc65..fea7cbc16 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
@@ -3,6 +3,9 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
import java.util.Arrays;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.product.AddProductThirdPartySourceParam;
@@ -213,6 +216,21 @@ public void shouldGetStockFlowWithRequiredPaginationAndStockTypeId() throws WxEr
assertEquals(result.getData().getNextKey(), "next");
}
+ @Test
+ public void shouldSerializeNestedProductManagementResponses() throws IOException {
+ ProductAuditQuotaResponse.AuditQuota auditQuota = new ProductAuditQuotaResponse.AuditQuota();
+ ProductCategoryClassifyResponse.Category category = new ProductCategoryClassifyResponse.Category();
+ ProductCategoryClassifyResponse.CategoryLevel categoryLevel = new ProductCategoryClassifyResponse.CategoryLevel();
+ ProductCategoryClassifyResponse.CategoryInfo categoryInfo = new ProductCategoryClassifyResponse.CategoryInfo();
+ ProductStockFlowResponse.StockFlowData stockFlowData = new ProductStockFlowResponse.StockFlowData();
+
+ assertSerializable(auditQuota);
+ assertSerializable(category);
+ assertSerializable(categoryLevel);
+ assertSerializable(categoryInfo);
+ assertSerializable(stockFlowData);
+ }
+
private static WxChannelProductServiceImpl productService(RecordingChannelService channelService) {
return new WxChannelProductServiceImpl(channelService);
}
@@ -230,6 +248,13 @@ private static void assertRequest(RecordingChannelService channelService, String
assertEquals(JsonUtils.decode(channelService.getRequestJson(), Object.class), JsonUtils.decode(expectedJson, Object.class));
}
+ private static void assertSerializable(Object value) throws IOException {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ try (ObjectOutputStream objectOutput = new ObjectOutputStream(output)) {
+ objectOutput.writeObject(value);
+ }
+ }
+
private static class RecordingChannelService extends WxChannelServiceHttpClientImpl {
private final String response;
private String url;
From 0a22fcf51a2c7cb2dd8d604fdd2ea5886715c739 Mon Sep 17 00:00:00 2001
From: Binary Wang
Date: Sat, 22 Aug 2026 13:40:50 +0800
Subject: [PATCH 4/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=95=86=E5=93=81?=
=?UTF-8?q?=E7=AE=A1=E7=90=86=E6=8E=A5=E5=8F=A3=E8=AF=84=E5=AE=A1=E6=84=8F?=
=?UTF-8?q?=E8=A7=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../channel/api/WxChannelProductService.java | 2 +-
.../product/ExternalProductMappingNewResponse.java | 14 +++++++++++++-
.../WxChannelProductManagementServiceImplTest.java | 1 +
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
index 85a3ec7c5..fb019eefe 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
@@ -344,7 +344,7 @@ AddProductThirdPartySourceResponse addProductThirdPartySource(AddProductThirdPar
/**
* 获取商品库存流水.
*
- * @param param 商品、SKU、库存类型、时间范围和分页参数;pageSize 必填,库存类型非 0 和 1 时 stockTypeId 必填
+ * @param param 商品、SKU、库存类型、时间范围和分页参数;pageSize 必填,stockType 为 1 时 finderId 必填,库存类型非 0 和 1 时 stockTypeId 必填
* @return 库存流水及下一页标识
* @throws WxErrorException 调用微信接口失败
*/
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java
index 29897d961..8342071a4 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExternalProductMappingNewResponse.java
@@ -1,8 +1,10 @@
package me.chanjar.weixin.channel.bean.product;
import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
import java.util.List;
import lombok.Data;
+import lombok.NoArgsConstructor;
import lombok.EqualsAndHashCode;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
@@ -13,5 +15,15 @@ public class ExternalProductMappingNewResponse extends WxChannelBaseResponse {
private static final long serialVersionUID = 4536547956225312823L;
@JsonProperty("attributes")
- private List attributes;
+ private List attributes;
+
+ /** 推荐属性. */
+ @Data
+ @NoArgsConstructor
+ public static class Attribute implements Serializable {
+ private static final long serialVersionUID = -4072024462101489333L;
+
+ private String key;
+ private String value;
+ }
}
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
index fea7cbc16..9ccaeed3d 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductManagementServiceImplTest.java
@@ -167,6 +167,7 @@ public void shouldMapAndRecommendExternalProductAttributes() throws WxErrorExcep
ExternalProductMappingNewResponse result = productService(channelService).externalProductMappingNew(param);
assertRequest(channelService, "/channels/ec/product/externalproductmappingnew", "{\"cat_id\":6000,\"external_category_name\":\"母婴:童鞋\",\"head_imgs\":[\"https://example.com/head\"],\"title\":\"儿童雨鞋\",\"external_attributes\":[{\"key\":\"材质\",\"value\":\"塑胶\"}]}");
+ assertTrue(result.getAttributes().get(0) instanceof ExternalProductMappingNewResponse.Attribute);
assertEquals(result.getAttributes().get(0).getKey(), "鞋面材质");
}
From 517e8f5b7635c81cb2c6959a7c85e9436b4a216d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 22 Aug 2026 11:12:05 +0000
Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=90=88=E5=B9=B6?=
=?UTF-8?q?=E5=86=B2=E7=AA=81=EF=BC=9A=E5=88=A0=E9=99=A4=E9=87=8D=E5=A4=8D?=
=?UTF-8?q?=E7=9A=84=20SPU=5FGET=5FSTOCK=5FFLOW=5FURL=20=E5=B8=B8=E9=87=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
---
.../weixin/channel/constant/WxChannelApiUrlConstants.java | 2 --
1 file changed, 2 deletions(-)
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
index 9d494b2f3..149bd0390 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
@@ -192,8 +192,6 @@ public interface Spu {
String SPU_GET_STOCK_BATCH_URL = "https://api.weixin.qq.com/channels/ec/product/stock/batchget";
/** 更新商品库存 */
String SPU_UPDATE_STOCK_URL = "https://api.weixin.qq.com/channels/ec/product/stock/update";
- /** 获取库存流水 */
- String SPU_GET_STOCK_FLOW_URL = "https://api.weixin.qq.com/channels/ec/product/stock/getflow";
/** 添加非卖商品 */
String GIFT_PRODUCT_ADD_URL = "https://api.weixin.qq.com/channels/ec/product/gift/add";
/** 更新非卖商品 */