Skip to content
Merged
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,78 @@
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.PrintOrderRequest;
import me.chanjar.weixin.channel.bean.ewaybill.BatchPrintOrderRequest;
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 {

/** 获取可用的标准面单模板。 @return 模板配置 @throws WxErrorException 微信接口调用失败 */
TemplateConfigResponse getTemplateConfig() throws WxErrorException;

/** 创建商家面单模板。 @param req 官方模板创建字段 @return 新模板 ID @throws WxErrorException 调用失败 */
TemplateIdResponse createTemplate(TemplateCreateRequest req) throws WxErrorException;
Comment thread
binarywang marked this conversation as resolved.

/** 删除商家面单模板。 @param templateId 模板 ID @return 操作结果 @throws WxErrorException 调用失败 */
WxChannelBaseResponse deleteTemplate(String templateId) throws WxErrorException;

/** 更新商家面单模板。 @param req 官方模板更新字段 @return 操作结果 @throws WxErrorException 调用失败 */
WxChannelBaseResponse updateTemplate(TemplateUpdateRequest req) throws WxErrorException;

/** 查询标准模板信息。 @param templateCode 标准模板编码 @return 模板详情 @throws WxErrorException 调用失败 */
TemplateInfoResponse getTemplate(String templateCode) throws WxErrorException;

/** 按模板 ID 查询商家模板。 @param templateId 模板 ID @return 模板详情 @throws WxErrorException 调用失败 */
TemplateInfoResponse getTemplateById(String templateId) throws WxErrorException;

/** 查询已开通电子面单的网点和账号。 @return 账号信息 @throws WxErrorException 调用失败 */
AccountInfoResponse getAccount() throws WxErrorException;

/** 查询已开通电子面单的快递公司。 @return 快递公司列表 @throws WxErrorException 调用失败 */
DeliveryListResponse getDeliveryList() throws WxErrorException;

/** 预取电子面单号。 @param req 官方预取号字段 @return 预取号结果 @throws WxErrorException 调用失败 */
PreCreateResponse preCreateOrder(PreCreateRequest req) throws WxErrorException;

/** 获取电子面单号。 @param req 官方取号字段,含收寄件信息 @return 面单号结果 @throws WxErrorException 调用失败 */
CreateOrderResponse createOrder(CreateOrderRequest req) throws WxErrorException;

/** 追加电子面单子件。 @param req 官方子件字段 @return 操作结果 @throws WxErrorException 调用失败 */
WxChannelBaseResponse addSubOrder(AddSubOrderRequest req) throws WxErrorException;

/** 取消电子面单下单。 @param waybillId 运单 ID @return 操作结果 @throws WxErrorException 调用失败 */
WxChannelBaseResponse cancelOrder(PrintOrderRequest req) throws WxErrorException;

/** 查询电子面单详情。 @param waybillId 运单 ID @return 面单详情 @throws WxErrorException 调用失败 */
OrderDetailResponse getOrder(String ewaybillOrderId) throws WxErrorException;

/** 获取打印报文。 @param waybillIds 运单 ID 列表 @param templateId 可选模板 ID @return 打印内容 @throws WxErrorException 调用失败 */
PrintContentResponse getPrintContent(String ewaybillOrderId, String templateId)
throws WxErrorException;

/** 通知单个运单打印成功。 @param waybillId 运单 ID @return 操作结果 @throws WxErrorException 调用失败 */
WxChannelBaseResponse printOrder(PrintOrderRequest req) throws WxErrorException;

/** 批量通知运单打印成功。 @param waybillIds 运单 ID 列表 @return 操作结果 @throws WxErrorException 调用失败 */
WxChannelBaseResponse batchPrintOrder(BatchPrintOrderRequest req) throws WxErrorException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,13 @@ public interface WxChannelService extends BaseWxChannelService {
*/
WxChannelFavoriteService getFavoriteService();

/**
* 电子面单服务
*
* @return 电子面单服务
*/
default WxChannelEwaybillService getEwaybillService() {
throw new UnsupportedOperationException("当前 WxChannelService 实现不支持电子面单服务");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
private WxChannelQicService qicService = null;
private WxTalentService talentService = null;
private WxChannelFavoriteService favoriteService = null;
private WxChannelEwaybillService ewaybillService = null;

protected WxChannelConfig config;
private int retrySleepMillis = 1000;
Expand Down Expand Up @@ -235,7 +236,8 @@ protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E

try {
T result = executor.execute(uriWithAccessToken, data, WxType.Channel);
log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog,
log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken,
printResult ? dataForLog : "...",
printResult ? result : "...");
return result;
} catch (WxErrorException e) {
Expand All @@ -262,12 +264,14 @@ protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E
}

if (error.getErrorCode() != 0) {
log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken,
printResult ? dataForLog : "...", error);
throw new WxErrorException(error, e);
}
return null;
} catch (IOException e) {
log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken,
printResult ? dataForLog : "...", e.getMessage());
throw new WxRuntimeException(e);
}
}
Expand Down Expand Up @@ -509,4 +513,12 @@ public synchronized WxChannelFavoriteService getFavoriteService() {
return favoriteService;
}

@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,165 @@
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.EwaybillOrderIdParam;
import me.chanjar.weixin.channel.bean.ewaybill.PrintOrderRequest;
import me.chanjar.weixin.channel.bean.ewaybill.BatchPrintOrderRequest;
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.PrintContentParam;
import me.chanjar.weixin.channel.bean.ewaybill.TemplateCodeParam;
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.JsonUtils;
import me.chanjar.weixin.channel.util.ResponseUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;

/**
* 视频号小店电子面单服务实现。
*
* @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 = post(GET_TEMPLATE_CONFIG_URL, "{}");
return ResponseUtils.decode(resJson, TemplateConfigResponse.class);
}

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

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

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

@Override
public TemplateInfoResponse getTemplate(String templateCode) throws WxErrorException {
String resJson = post(GET_TEMPLATE_URL, new TemplateCodeParam(templateCode));
return ResponseUtils.decode(resJson, TemplateInfoResponse.class);
}

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

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

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

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

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

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

@Override
public WxChannelBaseResponse cancelOrder(PrintOrderRequest req) throws WxErrorException {
String resJson = post(CANCEL_ORDER_URL, req);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

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

@Override
public PrintContentResponse getPrintContent(String ewaybillOrderId, String templateId)
throws WxErrorException {
String resJson = post(GET_PRINT_CONTENT_URL, new PrintContentParam(ewaybillOrderId, templateId));
return ResponseUtils.decode(resJson, PrintContentResponse.class);
}

@Override
public WxChannelBaseResponse printOrder(PrintOrderRequest req) throws WxErrorException {
String resJson = post(PRINT_ORDER_URL, req);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

@Override
public WxChannelBaseResponse batchPrintOrder(BatchPrintOrderRequest req) throws WxErrorException {
String resJson = post(BATCH_PRINT_ORDER_URL, req);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}

private String post(String url, Object request) throws WxErrorException {
return shopService.executeWithoutLog(
SimplePostRequestExecutor.create(shopService), url, JsonUtils.encode(request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package me.chanjar.weixin.channel.bean.ewaybill;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
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;

@JsonIgnore
private Map<String, Object> params = new LinkedHashMap<>();

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

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

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
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;

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

@JsonAnySetter
public void addExtra(String key, Object value) {
extra.put(key, value);
}
}
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;
}
Loading