1
0
mirror of synced 2026-10-19 14:06:31 +08:00

🆕 #4104 【视频号】补齐微信小店商品管理的13 个服务接口与数据模型

This commit is contained in:
Binary Wang
2026-08-22 20:42:45 +08:00
committed by GitHub
parent 9a616de2a5
commit 5bb9deeb5d
27 changed files with 1057 additions and 2 deletions

3
.gitignore vendored
View File

@@ -51,6 +51,9 @@ sonar-project.properties
!/.mvn/wrapper/maven-wrapper.jar
*.versionsBackup
# Local Superpowers planning artifacts
docs/superpowers/
# STS
.factorypath
*.zip

View File

@@ -13,6 +13,26 @@ import me.chanjar.weixin.channel.bean.product.GiftProductGetResponse;
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,123 @@ public interface WxChannelProductService {
*/
ProductTagLinkResponse getProductTagLink(String productId) throws WxErrorException;
/**
* 获取商品的移动应用跳转 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 必填,stockType 为 1 时 finderId 必填,库存类型非 0 和 1 时 stockTypeId 必填
* @return 库存流水及下一页标识
* @throws WxErrorException 调用微信接口失败
*/
ProductStockFlowResponse getStockFlow(ProductStockFlowParam param) throws WxErrorException;
/**
* 添加非卖商品
*

View File

@@ -2,18 +2,45 @@ package me.chanjar.weixin.channel.api.impl;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.CANCEL_AUDIT_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.DELETE_LIMIT_TASK_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_ACTIVITY_ADD_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_ACTIVITY_DELETE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_ACTIVITY_STOP_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_PRODUCT_ADD_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_PRODUCT_GET_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_PRODUCT_LIST_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.GIFT_PRODUCT_ON_SALE_SET_URL;
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_URL;
import java.util.Collections;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxChannelGiftService;
@@ -24,6 +51,13 @@ import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.limit.LimitTaskAddResponse;
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;
import me.chanjar.weixin.channel.bean.product.GiftProductAddResponse;
@@ -31,6 +65,21 @@ import me.chanjar.weixin.channel.bean.product.GiftProductGetResponse;
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.SkuStockResponse;
import me.chanjar.weixin.channel.bean.product.SpuFastInfo;
@@ -216,6 +265,85 @@ public class WxChannelProductServiceImpl implements WxChannelProductService {
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 extends WxChannelBaseResponse> T postAndDecode(String url, Object param, Class<T> 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 {
return giftService.addGiftProduct(info);

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<String> headImgs;
@JsonProperty("detail_imgs")
private List<String> detailImgs;
private String title;
@JsonProperty("external_attributes")
private List<ExternalAttribute> externalAttributes;
@Data
public static class ExternalAttribute implements Serializable {
private static final long serialVersionUID = 300805187240781417L;
private String key;
private String value;
}
}

View File

@@ -0,0 +1,29 @@
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;
/** 商品属性映射及推荐响应. */
@Data
@EqualsAndHashCode(callSuper = true)
public class ExternalProductMappingNewResponse extends WxChannelBaseResponse {
private static final long serialVersionUID = 4536547956225312823L;
@JsonProperty("attributes")
private List<Attribute> attributes;
/** 推荐属性. */
@Data
@NoArgsConstructor
public static class Attribute implements Serializable {
private static final long serialVersionUID = -4072024462101489333L;
private String key;
private String value;
}
}

View File

@@ -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;
}

View File

@@ -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<String> internalAttributeValue;
}

View File

@@ -0,0 +1,39 @@
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;
/** 商品提审限额响应. */
@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 implements Serializable {
private static final long serialVersionUID = 6066821247844334714L;
@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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<String> headImgs;
@JsonProperty("detail_imgs")
private List<String> detailImgs;
private String title;
}

View File

@@ -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;
}

View File

@@ -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<String> headImgs;
@JsonProperty("cat_id")
private String catId;
}

View File

@@ -0,0 +1,48 @@
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;
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<CategoryInfo> categories;
@JsonProperty("wrong_cat")
private Boolean wrongCat;
@Data
public static class CategoryInfo implements Serializable {
private static final long serialVersionUID = -4800760946330901306L;
private List<CategoryLevel> cats;
}
@Data
public static class CategoryLevel implements Serializable {
private static final long serialVersionUID = 8010801623725584755L;
@JsonProperty("cat_info")
private Category catInfo;
@JsonProperty("has_permission")
private Boolean hasPermission;
}
@Data
public static class Category implements Serializable {
private static final long serialVersionUID = -9013991576741902059L;
@JsonProperty("cat_id")
private String catId;
@JsonProperty("cat_name")
private String catName;
@JsonProperty("is_shop_no_audit")
private Boolean shopNoAudit;
}
}

View File

@@ -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;
}

View File

@@ -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<String> failReasons;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<Integer> opTypeList;
@JsonProperty("page_size")
private Integer pageSize;
@JsonProperty("next_key")
private String nextKey;
@JsonProperty("stock_type_id")
private String stockTypeId;
}

View File

@@ -0,0 +1,28 @@
package me.chanjar.weixin.channel.bean.product;
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;
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 implements Serializable {
private static final long serialVersionUID = -4963813730951045381L;
@JsonProperty("stock_flow_info_list")
private List<JsonNode> stockFlowInfoList;
@JsonProperty("next_key")
private String nextKey;
}
}

View File

@@ -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;
}

View File

@@ -158,16 +158,40 @@ public class WxChannelApiUrlConstants {
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";
/** 更新商品库存 */
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";
/** 更新非卖商品 */

View File

@@ -0,0 +1,283 @@
package me.chanjar.weixin.channel.api.impl;
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;
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\":\"塑胶\"}]}");
assertTrue(result.getAttributes().get(0) instanceof ExternalProductMappingNewResponse.Attribute);
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");
}
@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);
}
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 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;
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;
}
}
}

View File

@@ -3,6 +3,7 @@
<suite name="Weixin-java-tool-suite" verbose="1">
<test name="Result_Test">
<classes>
<class name="me.chanjar.weixin.channel.api.impl.WxChannelProductManagementServiceImplTest"/>
<!--<class name="me.chanjar.weixin.open.bean.result.WxFastMaAccountBasicInfoResultTest"/>
<class name="me.chanjar.weixin.open.bean.result.WxFastMaCanSetCategoryResultTest"/>
<class name="me.chanjar.weixin.open.bean.result.WxFastMaBeenSetCategoryResultTest"/>-->