Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package me.chanjar.weixin.channel.api;

import java.util.List;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.ewaybill.AccountInfoResponse;
import me.chanjar.weixin.channel.bean.ewaybill.AddSubOrderRequest;
import me.chanjar.weixin.channel.bean.ewaybill.CreateOrderRequest;
import me.chanjar.weixin.channel.bean.ewaybill.CreateOrderResponse;
import me.chanjar.weixin.channel.bean.ewaybill.DeliveryListResponse;
import me.chanjar.weixin.channel.bean.ewaybill.OrderDetailResponse;
import me.chanjar.weixin.channel.bean.ewaybill.PreCreateRequest;
import me.chanjar.weixin.channel.bean.ewaybill.PreCreateResponse;
import me.chanjar.weixin.channel.bean.ewaybill.PrintContentResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateConfigResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateCreateRequest;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateIdResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateInfoResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateUpdateRequest;
import me.chanjar.weixin.common.error.WxErrorException;

/**
* 视频号小店电子面单服务接口
*
* @author GitHub Copilot
*/
public interface WxChannelEwaybillService {

TemplateConfigResponse getTemplateConfig() throws WxErrorException;

TemplateIdResponse createTemplate(TemplateCreateRequest req) throws WxErrorException;

WxChannelBaseResponse deleteTemplate(String templateId) throws WxErrorException;

WxChannelBaseResponse updateTemplate(TemplateUpdateRequest req) throws WxErrorException;

TemplateInfoResponse getTemplate(String templateId) throws WxErrorException;

TemplateInfoResponse getTemplateById(String templateId) throws WxErrorException;

AccountInfoResponse getAccount() throws WxErrorException;

DeliveryListResponse getDeliveryList() throws WxErrorException;

PreCreateResponse preCreateOrder(PreCreateRequest req) throws WxErrorException;

CreateOrderResponse createOrder(CreateOrderRequest req) throws WxErrorException;

WxChannelBaseResponse addSubOrder(AddSubOrderRequest req) throws WxErrorException;

WxChannelBaseResponse cancelOrder(String waybillId) throws WxErrorException;

OrderDetailResponse getOrder(String waybillId) throws WxErrorException;

PrintContentResponse getPrintContent(String waybillId) throws WxErrorException;

WxChannelBaseResponse printOrder(String waybillId) throws WxErrorException;

WxChannelBaseResponse batchPrintOrder(List<String> waybillIds) throws WxErrorException;
}

Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,11 @@ public interface WxChannelService extends BaseWxChannelService {
*/
WxChannelLiveDashboardService getLiveDashboardService();

/**
* 电子面单服务
*
* @return 电子面单服务
*/
WxChannelEwaybillService getEwaybillService();

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
private WxChannelVipService vipService = null;
private WxChannelCompassFinderService compassFinderService = null;
private WxChannelLiveDashboardService liveDashboardService = null;
private WxChannelEwaybillService ewaybillService = null;

protected WxChannelConfig config;
private int retrySleepMillis = 1000;
Expand Down Expand Up @@ -473,4 +474,12 @@ public synchronized WxChannelLiveDashboardService getLiveDashboardService() {
return liveDashboardService;
}

@Override
public synchronized WxChannelEwaybillService getEwaybillService() {
if (ewaybillService == null) {
ewaybillService = new WxChannelEwaybillServiceImpl(this);
}
return ewaybillService;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package me.chanjar.weixin.channel.api.impl;

import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.ADD_SUB_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.BATCH_PRINT_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.CANCEL_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.CREATE_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.CREATE_TEMPLATE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.DELETE_TEMPLATE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_ACCOUNT_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_DELIVERY_LIST_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_PRINT_CONTENT_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_TEMPLATE_BY_ID_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_TEMPLATE_CONFIG_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.GET_TEMPLATE_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.PRE_CREATE_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.PRINT_ORDER_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Ewaybill.UPDATE_TEMPLATE_URL;

import java.util.List;
import me.chanjar.weixin.channel.api.WxChannelEwaybillService;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.ewaybill.AccountInfoResponse;
import me.chanjar.weixin.channel.bean.ewaybill.AddSubOrderRequest;
import me.chanjar.weixin.channel.bean.ewaybill.CreateOrderRequest;
import me.chanjar.weixin.channel.bean.ewaybill.CreateOrderResponse;
import me.chanjar.weixin.channel.bean.ewaybill.DeliveryListResponse;
import me.chanjar.weixin.channel.bean.ewaybill.OrderDetailResponse;
import me.chanjar.weixin.channel.bean.ewaybill.PreCreateRequest;
import me.chanjar.weixin.channel.bean.ewaybill.PreCreateResponse;
import me.chanjar.weixin.channel.bean.ewaybill.PrintContentResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateConfigResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateCreateRequest;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateIdParam;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateIdResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateInfoResponse;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateUpdateRequest;
import me.chanjar.weixin.channel.bean.ewaybill.WaybillIdParam;
import me.chanjar.weixin.channel.bean.ewaybill.WaybillIdsParam;
import me.chanjar.weixin.channel.util.ResponseUtils;
import me.chanjar.weixin.common.error.WxErrorException;

/**
* 视频号小店电子面单服务实现。
*
* @author GitHub Copilot
*/
public class WxChannelEwaybillServiceImpl implements WxChannelEwaybillService {

/** 微信商店服务 */
private final BaseWxChannelServiceImpl<?, ?> shopService;

public WxChannelEwaybillServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
this.shopService = shopService;
}

@Override
public TemplateConfigResponse getTemplateConfig() throws WxErrorException {
String resJson = shopService.post(GET_TEMPLATE_CONFIG_URL, "{}");
return ResponseUtils.decode(resJson, TemplateConfigResponse.class);
}

@Override
public TemplateIdResponse createTemplate(TemplateCreateRequest req) throws WxErrorException {
String resJson = shopService.post(CREATE_TEMPLATE_URL, req);
return ResponseUtils.decode(resJson, TemplateIdResponse.class);
}

@Override
public WxChannelBaseResponse deleteTemplate(String templateId) throws WxErrorException {
String resJson = shopService.post(DELETE_TEMPLATE_URL, new TemplateIdParam(templateId));
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

@Override
public WxChannelBaseResponse updateTemplate(TemplateUpdateRequest req) throws WxErrorException {
String resJson = shopService.post(UPDATE_TEMPLATE_URL, req);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

@Override
public TemplateInfoResponse getTemplate(String templateId) throws WxErrorException {
String resJson = shopService.post(GET_TEMPLATE_URL, new TemplateIdParam(templateId));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use template_code for template lookup

For the .../biz/template/get endpoint, the request parameter is the standard template code, while template_id is used by the separate getbyid endpoint below. As written, callers of getTemplate(...) will always post {"template_id":...} to the code-based endpoint, so looking up a standard template returned by getTemplateConfig() fails even with a valid code.

Useful? React with 👍 / 👎.

return ResponseUtils.decode(resJson, TemplateInfoResponse.class);
}

@Override
public TemplateInfoResponse getTemplateById(String templateId) throws WxErrorException {
String resJson = shopService.post(GET_TEMPLATE_BY_ID_URL, new TemplateIdParam(templateId));
return ResponseUtils.decode(resJson, TemplateInfoResponse.class);
}

@Override
public AccountInfoResponse getAccount() throws WxErrorException {
String resJson = shopService.post(GET_ACCOUNT_URL, "{}");
return ResponseUtils.decode(resJson, AccountInfoResponse.class);
}

@Override
public DeliveryListResponse getDeliveryList() throws WxErrorException {
String resJson = shopService.post(GET_DELIVERY_LIST_URL, "{}");
return ResponseUtils.decode(resJson, DeliveryListResponse.class);
}

@Override
public PreCreateResponse preCreateOrder(PreCreateRequest req) throws WxErrorException {
String resJson = shopService.post(PRE_CREATE_ORDER_URL, req);
return ResponseUtils.decode(resJson, PreCreateResponse.class);
}

@Override
public CreateOrderResponse createOrder(CreateOrderRequest req) throws WxErrorException {
String resJson = shopService.post(CREATE_ORDER_URL, req);
return ResponseUtils.decode(resJson, CreateOrderResponse.class);
}

@Override
public WxChannelBaseResponse addSubOrder(AddSubOrderRequest req) throws WxErrorException {
String resJson = shopService.post(ADD_SUB_ORDER_URL, req);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

@Override
public WxChannelBaseResponse cancelOrder(String waybillId) throws WxErrorException {
String resJson = shopService.post(CANCEL_ORDER_URL, new WaybillIdParam(waybillId));
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

@Override
public OrderDetailResponse getOrder(String waybillId) throws WxErrorException {
String resJson = shopService.post(GET_ORDER_URL, new WaybillIdParam(waybillId));
return ResponseUtils.decode(resJson, OrderDetailResponse.class);
}

@Override
public PrintContentResponse getPrintContent(String waybillId) throws WxErrorException {
String resJson = shopService.post(GET_PRINT_CONTENT_URL, new WaybillIdParam(waybillId));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Send waybill_ids when fetching print content

The print-content endpoint takes a list field named waybill_ids (and optional template_id), but this wrapper posts a single waybill_id. Any caller using getPrintContent(...) will therefore omit the required array parameter and be unable to retrieve print payloads; this needs a request object/list form matching the endpoint contract.

Useful? React with 👍 / 👎.

return ResponseUtils.decode(resJson, PrintContentResponse.class);
}

@Override
public WxChannelBaseResponse printOrder(String waybillId) throws WxErrorException {
String resJson = shopService.post(PRINT_ORDER_URL, new WaybillIdParam(waybillId));
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

@Override
public WxChannelBaseResponse batchPrintOrder(List<String> waybillIds) throws WxErrorException {
String resJson = shopService.post(BATCH_PRINT_ORDER_URL, new WaybillIdsParam(waybillIds));
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package me.chanjar.weixin.channel.bean.ewaybill;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* 电子面单通用请求参数容器。
*
* <p>字段按官方文档动态透传,避免非官方字段定义。</p>
*
* @author GitHub Copilot
*/
@Data
@NoArgsConstructor
public abstract class AbstractEwaybillRequest implements Serializable {

private static final long serialVersionUID = 4213577159985597237L;

private Map<String, Object> params = new LinkedHashMap<>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid serializing the params backing map

When any dynamic ewaybill request is populated with addParam, Lombok's @Data also exposes this field as getParams(), while @JsonAnyGetter emits the same entries at the top level. The actual POST body therefore includes both the documented fields and an extra params object (for example {"params":{"order_id":"o_1"},"order_id":"o_1"}), which the new API wrappers send to WeChat and can be rejected as an invalid request; the test only checks that the top-level substrings exist. Please hide this backing map from Jackson or avoid generating a public getter for it.

Useful? React with 👍 / 👎.


@JsonAnySetter
public void addParam(String key, Object value) {
params.put(key, value);
}

@JsonAnyGetter
public Map<String, Object> anyParams() {
return params;
}
Comment on lines +24 to +34
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package me.chanjar.weixin.channel.bean.ewaybill;

import com.fasterxml.jackson.annotation.JsonAnySetter;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;

/**
* 电子面单通用响应参数容器。
*
* <p>未显式声明字段将保存到 extra 字段,便于兼容官方接口变更。</p>
*
* @author GitHub Copilot
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public abstract class AbstractEwaybillResponse extends WxChannelBaseResponse {

private static final long serialVersionUID = -2460196179063989718L;

private Map<String, Object> extra = new LinkedHashMap<>();

@JsonAnySetter
public void addExtra(String key, Object value) {
extra.put(key, value);
}
Comment on lines +25 to +30
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 电子面单网点/账号信息响应。
*
* @author GitHub Copilot
*/
public class AccountInfoResponse extends AbstractEwaybillResponse {
private static final long serialVersionUID = 5682783958522805959L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 电子面单子件追加请求。
*
* @author GitHub Copilot
*/
public class AddSubOrderRequest extends AbstractEwaybillRequest {
private static final long serialVersionUID = 4250200603210217269L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 电子面单取号请求。
*
* @author GitHub Copilot
*/
public class CreateOrderRequest extends AbstractEwaybillRequest {
private static final long serialVersionUID = 2521225918646916853L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 电子面单取号响应。
*
* @author GitHub Copilot
*/
public class CreateOrderResponse extends AbstractEwaybillResponse {
private static final long serialVersionUID = 9115454170108519187L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 开通快递公司列表响应。
*
* @author GitHub Copilot
*/
public class DeliveryListResponse extends AbstractEwaybillResponse {
private static final long serialVersionUID = 494164885034906535L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 面单详情响应。
*
* @author GitHub Copilot
*/
public class OrderDetailResponse extends AbstractEwaybillResponse {
private static final long serialVersionUID = -2406734055149395916L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package me.chanjar.weixin.channel.bean.ewaybill;

/**
* 电子面单预取号请求。
*
* @author GitHub Copilot
*/
public class PreCreateRequest extends AbstractEwaybillRequest {
private static final long serialVersionUID = 3761501770378571724L;
}
Loading