diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java index 6fba0dae25..c9d010ecc1 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/ExpressCallbackController.java @@ -1,17 +1,30 @@ package com.ruoyi.web.controller.xkt; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.XmlUtil; +import cn.hutool.json.JSONUtil; import com.ruoyi.common.core.controller.XktBaseController; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.web.controller.xkt.vo.express.ZtoPrintOrderReqVO; import com.ruoyi.web.controller.xkt.vo.express.ZtoPrintOrderRespVO; +import com.ruoyi.xkt.dto.order.StoreOrderExpressTrackAddDTO; +import com.ruoyi.xkt.enums.EExpressChannel; +import com.ruoyi.xkt.enums.EExpressStatus; +import com.ruoyi.xkt.service.IStoreOrderService; +import com.ruoyi.xkt.thirdpart.yto.YtoSignUtil; +import com.ruoyi.xkt.thirdpart.yto.YtoTrackObj; +import com.ruoyi.xkt.thirdpart.zto.ZopDigestUtil; +import com.ruoyi.xkt.thirdpart.zto.ZtoTrackObj; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.w3c.dom.Document; import java.util.concurrent.TimeUnit; @@ -24,8 +37,15 @@ import java.util.concurrent.TimeUnit; @RequestMapping("/rest/v1/express-callback") public class ExpressCallbackController extends XktBaseController { + @Value("${yto.appSecret2:}") + private String ytoAppSecret2; + @Value("${zto.appSecret:}") + private String ztoAppSecret; + @Autowired private RedisCache redisCache; + @Autowired + private IStoreOrderService storeOrderService; /** * 中通-生成面单图片/PDF回推 @@ -43,11 +63,107 @@ public class ExpressCallbackController extends XktBaseController { if (StrUtil.isNotEmpty(vo.getBillCode()) && StrUtil.isNotEmpty(vo.getResult())) { //缓存30分钟 - redisCache.setCacheObject("ZTO-"+vo.getBillCode(),vo.getResult(),30, TimeUnit.MINUTES); + redisCache.setCacheObject("ZTO-" + vo.getBillCode(), vo.getResult(), 30, TimeUnit.MINUTES); return ZtoPrintOrderRespVO.success(); } return ZtoPrintOrderRespVO.failure(); } + @ApiOperation("圆通-轨迹推送") + @RequestMapping(value = "yto/track") + public String ytoTrack(YtoTrackObj.Request request) { + if (StrUtil.isNotBlank(request.getLogistics_interface()) && + //验签 + YtoSignUtil.verify(request.getData_digest(), request.getLogistics_interface(), ytoAppSecret2)) { + logger.info("圆通-轨迹推送数据处理: {}", request); + Document dom = XmlUtil.parseXml(request.getLogistics_interface()); + YtoTrackObj.Info obj = XmlUtil.xmlToBean(dom, YtoTrackObj.class).getUpdateInfo(); + StoreOrderExpressTrackAddDTO trackAddDTO = trans2OrderTrack(obj); + storeOrderService.addTrack(trackAddDTO); + return YtoTrackObj.Response.builder() + .success(true) + .logisticProviderID(obj.getLogisticProviderID()) + .txLogisticID(obj.getTxLogisticID()) + .build() + .toXmlStr(); + } + logger.warn("圆通-轨迹推送数据异常: {}", request); + return YtoTrackObj.Response.builder() + .success(false) + .build() + .toXmlStr(); + } + + @ApiOperation("中通-轨迹推送") + @PostMapping(value = "zto/track") + public String ztoTrack(@RequestBody ZtoTrackObj.Request request) { + if (StrUtil.isNotBlank(request.getData()) && + //验签 + ZopDigestUtil.verify(request.getData_digest(), request.getData(), ztoAppSecret)) { + logger.info("中通-轨迹推送数据处理: {}", request); + ZtoTrackObj.Info obj = JSONUtil.toBean(request.getData(), ZtoTrackObj.Info.class); + StoreOrderExpressTrackAddDTO trackAddDTO = trans2OrderTrack(obj); + storeOrderService.addTrack(trackAddDTO); + return ZtoTrackObj.Response.builder() + .status(true) + .build() + .toJsonStr(); + } + logger.warn("中通-轨迹推送数据异常: {}", request); + return ZtoTrackObj.Response.builder() + .status(false) + .build() + .toJsonStr(); + } + + private StoreOrderExpressTrackAddDTO trans2OrderTrack(ZtoTrackObj.Info ztTrack) { + StoreOrderExpressTrackAddDTO dto = new StoreOrderExpressTrackAddDTO(); + dto.setExpressWaybillNo(ztTrack.getBillCode()); + dto.setAction(ztTrack.getAction()); + dto.setDescription(ztTrack.getActionTime() + " " + ztTrack.getRemark()); + dto.setExpressId(EExpressChannel.ZTO.getExpressId()); + /** + * 事件类型 + *

+ * GOT   收件   网点揽收 + *  DEPARTURE   发件   从网点或分拨中心发出 + *  ARRIVAL   到件   到达网点或分拨中心 + *  DISPATCH   派件   业务员派送 + *  RETURN_SCAN   退件   发生退回或改地址,具体类型见退改类型(returnType)字段 + *  RETURN_SIGNED   退件签收   已经退回至寄件客户 + *  INBOUND   入站   放入快递超市/自提柜/第三方代理点等 + *  HANDOVERSCAN_SIGNED 第三方妥投 入站后妥投成功 + *  DEPARTURE_SIGNED 出站签收   客户从快递超市/自提柜/第三方代理点等取出 + *  SIGNED   签收   客户正常签收 + *  PROBLEM   问题件   网点或中心登记的问题件,问题件类型在问题件编码(problemCode)字段体现 + */ + switch (ztTrack.getAction()) { + case "GOT": + dto.setExpressStatus(EExpressStatus.PICKED_UP); + break; + case "SIGNED": + dto.setExpressStatus(EExpressStatus.COMPLETED); + break; + } + return dto; + } + + private StoreOrderExpressTrackAddDTO trans2OrderTrack(YtoTrackObj.Info ytTrack) { + StoreOrderExpressTrackAddDTO dto = new StoreOrderExpressTrackAddDTO(); + dto.setExpressWaybillNo(ytTrack.getMailNo()); + dto.setAction(ytTrack.getInfoContent()); + dto.setDescription(DateUtil.formatDateTime(ytTrack.getAcceptTime()) + " " + ytTrack.getRemark()); + dto.setExpressId(EExpressChannel.YTO.getExpressId()); + switch (ytTrack.getInfoContent()) { + case "GOT": + dto.setExpressStatus(EExpressStatus.PICKED_UP); + break; + case "SIGNED": + dto.setExpressStatus(EExpressStatus.COMPLETED); + break; + } + return dto; + } + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreOrderController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreOrderController.java index e98c1dbb37..373d9e44f6 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreOrderController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/StoreOrderController.java @@ -26,8 +26,8 @@ import com.ruoyi.xkt.service.IStoreOrderService; import io.jsonwebtoken.lang.Assert; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ResponseHeader; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -53,7 +53,6 @@ public class StoreOrderController extends XktBaseController { @Autowired private List paymentManagers; - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.INSERT) @ApiOperation("创建订单") @PostMapping("create") @@ -69,7 +68,6 @@ public class StoreOrderController extends XktBaseController { return success(respVO); } - @PreAuthorize("@ss.hasPermi('system:order:edit')") @Log(title = "订单", businessType = BusinessType.UPDATE) @ApiOperation("修改订单") @PostMapping("edit") @@ -81,7 +79,6 @@ public class StoreOrderController extends XktBaseController { return success(result.getOrder().getId()); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("支付订单") @PostMapping("pay") @@ -96,7 +93,6 @@ public class StoreOrderController extends XktBaseController { return success(respVO); } - @PreAuthorize("@ss.hasPermi('system:order:edit')") @Log(title = "订单", businessType = BusinessType.UPDATE) @ApiOperation("取消订单") @PostMapping("cancel") @@ -110,7 +106,6 @@ public class StoreOrderController extends XktBaseController { return success(); } - @PreAuthorize("@ss.hasPermi('system:order:query')") @ApiOperation(value = "订单详情") @GetMapping(value = "/{id}") public R getInfo(@PathVariable("id") Long id) { @@ -120,9 +115,9 @@ public class StoreOrderController extends XktBaseController { } - @PreAuthorize("@ss.hasPermi('system:order:list')") @ApiOperation(value = "订单分页查询") @PostMapping("/page") + @ResponseHeader public R> page(@Validated @RequestBody StoreOrderQueryVO vo) { StoreOrderQueryDTO queryDTO = BeanUtil.toBean(vo, StoreOrderQueryDTO.class); if (1 == vo.getSrcPage()) { @@ -134,7 +129,6 @@ public class StoreOrderController extends XktBaseController { return success(PageVO.of(pageDTO, StoreOrderPageItemVO.class)); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("发货-平台物流") @PostMapping("ship-platform") @@ -151,7 +145,6 @@ public class StoreOrderController extends XktBaseController { return success(respList); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("发货-档口物流") @PostMapping("ship-store") @@ -168,7 +161,6 @@ public class StoreOrderController extends XktBaseController { return success(respList); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("打印面单") @PostMapping("print") @@ -184,7 +176,6 @@ public class StoreOrderController extends XktBaseController { return success(rtnList); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("确认收货") @PostMapping("receipt") @@ -194,7 +185,6 @@ public class StoreOrderController extends XktBaseController { return success(); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("申请售后(创建售后订单)") @PostMapping("refund/apply") @@ -230,7 +220,6 @@ public class StoreOrderController extends XktBaseController { return success(afterSaleApplyResult.getStoreOrderId()); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("确认退款") @PostMapping("refund/confirm") @@ -250,7 +239,6 @@ public class StoreOrderController extends XktBaseController { return success(); } - @PreAuthorize("@ss.hasPermi('system:order:add')") @Log(title = "订单", businessType = BusinessType.OTHER) @ApiOperation("拒绝退款") @PostMapping("refund/reject") diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/express/ExpressTrackDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/express/ExpressTrackDTO.java new file mode 100644 index 0000000000..9240549b92 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/express/ExpressTrackDTO.java @@ -0,0 +1,48 @@ +package com.ruoyi.xkt.dto.express; + +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * 代发订单物流轨迹 + * + * @author liangyq + * @date 2025-05-07 11:57:52.599 + **/ +@Data +public class ExpressTrackDTO { + /** + * 物流运单号(快递单号) + */ + private String expressWaybillNo; + /** + * 物流ID + */ + private Long expressId; + /** + * 详情 + */ + private List items; + + @Data + public static class Item { + /** + * 节点事件 + */ + private String action; + /** + * 描述 + */ + private String description; + /** + * 备注 + */ + private String remark; + /** + * 创建时间 + */ + private Date createTime; + } +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/express/ExpressTrackSubReqDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/express/ExpressTrackSubReqDTO.java new file mode 100644 index 0000000000..faa7bd592d --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/express/ExpressTrackSubReqDTO.java @@ -0,0 +1,34 @@ +package com.ruoyi.xkt.dto.express; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author liangyq + * @date 2025-04-16 15:24 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ExpressTrackSubReqDTO { + /** + * 请求号 + */ + private String expressReqNo; + /** + * 物流运单号(快递单号) + */ + private String expressWaybillNo; + /** + * 发货人-电话 + */ + private String originContactPhoneNumber; + /** + * 收货人-电话 + */ + private String destinationContactPhoneNumber; +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderExpressTrackAddDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderExpressTrackAddDTO.java new file mode 100644 index 0000000000..0500cd6b64 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderExpressTrackAddDTO.java @@ -0,0 +1,40 @@ +package com.ruoyi.xkt.dto.order; + +import com.ruoyi.xkt.enums.EExpressStatus; +import lombok.Data; + +import java.util.Date; + +/** + * 代发订单物流轨迹 + * + * @author liangyq + * @date 2025-04-01 11:57:52.599 + **/ +@Data +public class StoreOrderExpressTrackAddDTO { + /** + * 物流运单号(快递单号) + */ + private String expressWaybillNo; + /** + * 节点事件 + */ + private String action; + /** + * 描述 + */ + private String description; + /** + * 备注 + */ + private String remark; + /** + * 物流ID + */ + private Long expressId; + /** + * 物流状态 + */ + private EExpressStatus expressStatus; +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderInfoDTO.java b/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderInfoDTO.java index a5a78df96b..3579ade3a6 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderInfoDTO.java +++ b/xkt/src/main/java/com/ruoyi/xkt/dto/order/StoreOrderInfoDTO.java @@ -1,5 +1,6 @@ package com.ruoyi.xkt.dto.order; +import com.ruoyi.xkt.dto.express.ExpressTrackDTO; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -34,4 +35,6 @@ public class StoreOrderInfoDTO extends StoreOrderDTO { private String destinationCountyName; private List orderDetails; + + private List expressTracks; } diff --git a/xkt/src/main/java/com/ruoyi/xkt/manager/ExpressManager.java b/xkt/src/main/java/com/ruoyi/xkt/manager/ExpressManager.java index 0aee1798b0..af30a83d51 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/manager/ExpressManager.java +++ b/xkt/src/main/java/com/ruoyi/xkt/manager/ExpressManager.java @@ -1,9 +1,6 @@ package com.ruoyi.xkt.manager; -import com.ruoyi.xkt.dto.express.ExpressCancelReqDTO; -import com.ruoyi.xkt.dto.express.ExpressInterceptReqDTO; -import com.ruoyi.xkt.dto.express.ExpressPrintDTO; -import com.ruoyi.xkt.dto.express.ExpressShipReqDTO; +import com.ruoyi.xkt.dto.express.*; import com.ruoyi.xkt.enums.EExpressChannel; import java.util.Collection; @@ -52,4 +49,11 @@ public interface ExpressManager { */ List printOrder(Collection waybillNos); + /** + * 订阅轨迹 + * + * @param trackSubReq + * @return + */ + boolean subscribeTrack(ExpressTrackSubReqDTO trackSubReq); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java index 6d9eae6bbb..6a023ba8c1 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/YtoExpressManagerImpl.java @@ -1,15 +1,13 @@ package com.ruoyi.xkt.manager.impl; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.ruoyi.common.exception.ServiceException; -import com.ruoyi.xkt.dto.express.ExpressCancelReqDTO; -import com.ruoyi.xkt.dto.express.ExpressInterceptReqDTO; -import com.ruoyi.xkt.dto.express.ExpressPrintDTO; -import com.ruoyi.xkt.dto.express.ExpressShipReqDTO; +import com.ruoyi.xkt.dto.express.*; import com.ruoyi.xkt.enums.EExpressChannel; import com.ruoyi.xkt.manager.ExpressManager; import com.ruoyi.xkt.thirdpart.yto.*; @@ -166,6 +164,39 @@ public class YtoExpressManagerImpl implements ExpressManager { return list; } + @Override + public boolean subscribeTrack(ExpressTrackSubReqDTO trackSubReq) { + Assert.notNull(trackSubReq.getExpressWaybillNo()); + YtoSubTrackParam.LogisticsInterface logisticsInterface = new YtoSubTrackParam.LogisticsInterface(); + logisticsInterface.setClientId(appKey2); + logisticsInterface.setWaybillNo(trackSubReq.getExpressWaybillNo()); + YtoSubTrackParam ytoSubTrackParam = new YtoSubTrackParam(); + ytoSubTrackParam.setClient_id(appKey2); + ytoSubTrackParam.setMsg_type("online"); + ytoSubTrackParam.setLogistics_interface(JSONUtil.toJsonStr(logisticsInterface)); + try { + String param = JSONUtil.toJsonStr(ytoSubTrackParam); + String sign = YtoSignUtil.sign("subscribe_adapter", "v1", param, appSecret2); + YtoPublicRequest request = YtoPublicRequest.builder() + .timestamp(System.currentTimeMillis()) + .param(param) + .format(YtoPublicRequest.EFormat.JSON) + .sign(sign).build(); + String rtnStr = HttpUtil.post(gatewayUrl + "open/subscribe_adapter/v1/N364gM/" + appKey2, + JSONUtil.toJsonStr(request)); + log.info("圆通轨迹订阅返回信息: {}", rtnStr); + JSONObject rtnJson = JSONUtil.parseObj(rtnStr); + Boolean success = rtnJson.getBool("success"); + if (BooleanUtil.isTrue(success)) { + return true; + } + } catch (Exception e) { + log.error("圆通轨迹订阅异常", e); + } + log.warn("圆通轨迹订阅失败: {}", trackSubReq); + return false; + } + private YtoCreateOrderParam trans2CreateOrderReq(ExpressShipReqDTO shipReqDTO) { YtoCreateOrderParam reqDTO = new YtoCreateOrderParam(); diff --git a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java index c4a6a2b225..e6d37893dd 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/manager/impl/ZtoExpressManagerImpl.java @@ -2,16 +2,14 @@ package com.ruoyi.xkt.manager.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; -import com.ruoyi.xkt.dto.express.ExpressCancelReqDTO; -import com.ruoyi.xkt.dto.express.ExpressInterceptReqDTO; -import com.ruoyi.xkt.dto.express.ExpressPrintDTO; -import com.ruoyi.xkt.dto.express.ExpressShipReqDTO; +import com.ruoyi.xkt.dto.express.*; import com.ruoyi.xkt.enums.EExpressChannel; import com.ruoyi.xkt.manager.ExpressManager; import com.ruoyi.xkt.thirdpart.zto.*; @@ -44,6 +42,8 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { public static final String ORDER_PRINT_URI = "zto.open.order.print"; + public static final String TRACK_SUB_URI = "zto.merchant.waybill.track.subsrcibe"; + @Value("${zto.appKey:}") private String appKey; @@ -82,7 +82,7 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { String bodyStr = client.execute(request); log.info("中通订单创建返回信息: {}", bodyStr); JSONObject bodyJson = JSONUtil.parseObj(bodyStr); - boolean success = bodyJson.getBool("status"); + boolean success = BooleanUtil.isTrue(bodyJson.getBool("status")); if (success) { return bodyJson.getJSONObject("result").getStr("billCode"); } @@ -108,7 +108,7 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { String bodyStr = client.execute(request); log.info("中通订单取消返回信息: {}", bodyStr); JSONObject bodyJson = JSONUtil.parseObj(bodyStr); - boolean success = bodyJson.getBool("status"); + boolean success = BooleanUtil.isTrue(bodyJson.getBool("status")); if (success) { return true; } @@ -137,120 +137,46 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { String bodyStr = client.execute(request); log.info("中通订单拦截返回信息: {}", bodyStr); /** - * E23101 - * 快件已签收 - * 更换未签收运单发起 - * E23102 - * 订单信息不存在 - * 联系管理员处理 - * E23108 - * 无效的拦截、退改方式 - * 检查入参destinationType - * E23110 - * 无揽收与面单使用网点 - * 联系管理员处理 - * E23111 - * 时效件,无法拦截 - * 更换运单 - * E23112 - * 已第三方进站不允许拦截 - * 更换运单 - * E23113 - * 有转单信息不允许拦截 - * 更换运单 - * E23114 - * 派件网点不支持到付业务 - * 更换运单 - * E23115 - * 派件网点不支持代收业务 - * 更换运单 - * E23116 - * 渠道不一致,不允许重复发起拦截/超过最大拦截次数 - * 更换运单 - * E23118 - * 订购渠道不存在/该渠道不允许拦截 - * 检查入参platform,如确认无误,联系管理员处理 - * E23119 - * 无任何轨迹不允许发起拦截 - * 揽收后再重试 - * E23120 - * 有派件扫描不允许拦截 - * 更换运单 - * E23121 - * 存在相同渠道的拦截件,不允许再次发起 - * 更换运单 - * E23122 - * 目的地停发不允许拦截 - * 更换运单 - * E23123 - * 存在退改件信息不允许拦截 - * 更换运单 - * E23124 - * 轨迹异常不允许拦截 - * 更换运单 - * E23127 - * 已经有相同诉求,不允许再次发起 - * 更换运单或更改入参destinationType或改地址的收件地址 - * E23130 - * 非拦截中拦截件,不能取消 - * 此运单已无法取消拦截,如仍需取消,请再次拦截改回原址 - * E23131 - * 取消网点与订购网点或原单揽收网点不一致,不能取消 - * 联系管理员处理 - * E23135 - * 同拦截发起方不一致,无权取消 - * 联系管理员处理 - * E23136 - * 已发往港澳台,暂不允许拦截 - * 更换运单 - * E23137 - * 有派件网点到件不允许拦截 - * 更换运单 - * E23138 - * 国际件不允许发起拦截 - * 更换运单 - * E23139 - * 不满足拦截发起业务规则 - * 更换运单 - * E23140 - * 包裹已确认遗失 - * 更换运单 - * E23141 - * 包裹已确认弃件 - * 更换运单 - * E23144 - * CRM无权限 - * 联系合作网点在客户管理系统开通拦截权限 - * E23146 - * 跨境客户,不允许发起改地址/退回指定地址 - * 更换运单 - * E23148 - * 联系方式格式错误,请检查后提交或不填写 - * 检查入参receivePhone - * E23149 - * 联系方式是虚拟号,请补全分机号或不填写 - * 检查入参receivePhone - * E23150 - * 联系方式超过16位,请删减 - * 检查入参receivePhone - * E23151 - * 已经有相同诉求,不允许再次发起 - * 更换运单或更改入参destinationType或改地址的收件地址 - * E23153 - * 发起人不属于发起网点 - * 联系管理员处理 - * E23154 - * 单号不属于当前网点,不允许发起 - * 联系管理员处理 - * E23157 - * 该渠道不支持重复发起拦截 - * 更换运单 - * E23160 - * 已存在外部平台发起的拦截,不允许发起 - * 更换运单 + * E23101 快件已签收 更换未签收运单发起 + * E23102 订单信息不存在 联系管理员处理 + * E23108 无效的拦截、退改方式 检查入参destinationType + * E23110 无揽收与面单使用网点 联系管理员处理 + * E23111 时效件,无法拦截 更换运单 + * E23112 已第三方进站不允许拦截 更换运单 + * E23113 有转单信息不允许拦截 更换运单 + * E23114 派件网点不支持到付业务 更换运单 + * E23115 派件网点不支持代收业务 更换运单 + * E23116 渠道不一致,不允许重复发起拦截/超过最大拦截次数 更换运单 + * E23118 订购渠道不存在/该渠道不允许拦截 检查入参platform,如确认无误,联系管理员处理 + * E23119 无任何轨迹不允许发起拦截 揽收后再重试 + * E23120 有派件扫描不允许拦截 更换运单 + * E23121 存在相同渠道的拦截件,不允许再次发起 更换运单 + * E23122 目的地停发不允许拦截 更换运单 + * E23123 存在退改件信息不允许拦截 更换运单 + * E23124 轨迹异常不允许拦截 更换运单 + * E23127 已经有相同诉求,不允许再次发起 更换运单或更改入参destinationType或改地址的收件地址 + * E23130 非拦截中拦截件,不能取消 此运单已无法取消拦截,如仍需取消,请再次拦截改回原址 + * E23131 取消网点与订购网点或原单揽收网点不一致,不能取消 联系管理员处理 + * E23135 同拦截发起方不一致,无权取消 联系管理员处理 + * E23136 已发往港澳台,暂不允许拦截 更换运单 + * E23137 有派件网点到件不允许拦截 更换运单 + * E23138 国际件不允许发起拦截 更换运单 + * E23139 不满足拦截发起业务规则 更换运单 + * E23140 包裹已确认遗失 更换运单 + * E23141 包裹已确认弃件 更换运单 + * E23144 CRM无权限 联系合作网点在客户管理系统开通拦截权限 + * E23146 跨境客户,不允许发起改地址/退回指定地址 更换运单 + * E23148 联系方式格式错误,请检查后提交或不填写 检查入参receivePhone + * E23149 联系方式是虚拟号,请补全分机号或不填写 检查入参receivePhone + * E23150 联系方式超过16位,请删减 检查入参receivePhone + * E23151 已经有相同诉求,不允许再次发起 更换运单或更改入参destinationType或改地址的收件地址 + * E23153 发起人不属于发起网点 联系管理员处理 + * E23154 单号不属于当前网点,不允许发起 联系管理员处理 + * E23157 该渠道不支持重复发起拦截 更换运单 + * E23160 已存在外部平台发起的拦截,不允许发起 更换运单 */ JSONObject bodyJson = JSONUtil.parseObj(bodyStr); - boolean success = bodyJson.getBool("status"); + boolean success = BooleanUtil.isTrue(bodyJson.getBool("status")); if (success) { return true; } @@ -274,7 +200,7 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { String bodyStr = client.execute(request); log.info("中通订单打印返回信息: {}", bodyStr); JSONObject bodyJson = JSONUtil.parseObj(bodyStr); - boolean success = bodyJson.getBool("status"); + boolean success = BooleanUtil.isTrue(bodyJson.getBool("status")); if (success) { continue; } @@ -301,6 +227,34 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { return list; } + @Override + public boolean subscribeTrack(ExpressTrackSubReqDTO trackSubReq) { + Assert.notNull(trackSubReq); + Assert.notEmpty(trackSubReq.getExpressWaybillNo()); + Assert.notEmpty(trackSubReq.getDestinationContactPhoneNumber()); + ZtoSubTrackParam ztoSubTrackParam = new ZtoSubTrackParam(); + ztoSubTrackParam.setBillCode(trackSubReq.getExpressWaybillNo()); + ztoSubTrackParam.setMobilePhone(StrUtil.sub(trackSubReq.getDestinationContactPhoneNumber(), + -1, 4)); + ZopPublicRequest request = new ZopPublicRequest(); + request.setBody(JSONUtil.toJsonStr(ztoSubTrackParam)); + request.setUrl(gatewayUrl + TRACK_SUB_URI); + request.setEncryptionType(EncryptionType.MD5); + try { + String bodyStr = client.execute(request); + log.info("中通轨迹订阅返回信息: {}", bodyStr); + JSONObject bodyJson = JSONUtil.parseObj(bodyStr); + boolean success = BooleanUtil.isTrue(bodyJson.getBool("status")); + if (success) { + return true; + } + } catch (Exception e) { + log.error("中通轨迹订阅异常", e); + } + log.warn("中通轨迹订阅失败: {}", trackSubReq); + return false; + } + /** * 智能解析 * @@ -318,7 +272,7 @@ public class ZtoExpressManagerImpl implements ExpressManager, InitializingBean { String bodyStr = client.execute(request); log.info("中通智能解析返回信息: {}", bodyStr); JSONObject bodyJson = JSONUtil.parseObj(bodyStr); - boolean success = bodyJson.getBool("status"); + boolean success = BooleanUtil.isTrue(bodyJson.getBool("status")); if (success) { return bodyJson.getJSONObject("result"); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java index cc41d82274..cabe9b1ca8 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreOrderService.java @@ -169,5 +169,10 @@ public interface IStoreOrderService { */ void refundSuccess(Long storeOrderId, List storeOrderDetailIds, Long operatorId); - + /** + * 添加轨迹信息 + * + * @param trackAddDTO + */ + void addTrack(StoreOrderExpressTrackAddDTO trackAddDTO); } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java index 903b233573..6792e47c72 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreOrderServiceImpl.java @@ -17,10 +17,7 @@ import com.ruoyi.common.core.domain.XktBaseEntity; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.bean.BeanValidators; import com.ruoyi.xkt.domain.*; -import com.ruoyi.xkt.dto.express.ExpressContactDTO; -import com.ruoyi.xkt.dto.express.ExpressPrintDTO; -import com.ruoyi.xkt.dto.express.ExpressRegionDTO; -import com.ruoyi.xkt.dto.express.ExpressShipReqDTO; +import com.ruoyi.xkt.dto.express.*; import com.ruoyi.xkt.dto.order.*; import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO; import com.ruoyi.xkt.enums.*; @@ -55,6 +52,8 @@ public class StoreOrderServiceImpl implements IStoreOrderService { @Autowired private StoreOrderDetailMapper storeOrderDetailMapper; @Autowired + private StoreOrderExpressTrackMapper storeOrderExpressTrackMapper; + @Autowired private StoreMapper storeMapper; @Autowired private StoreProductMapper storeProductMapper; @@ -627,6 +626,11 @@ public class StoreOrderServiceImpl implements IStoreOrderService { //发货 ExpressShipReqDTO shipReq = createShipReq(order, orderDetails); String expressWaybillNo = expressManager.shipStoreOrder(shipReq); + //订阅轨迹 + ExpressTrackSubReqDTO trackSubReq = new ExpressTrackSubReqDTO(shipReq.getExpressReqNo(), + expressWaybillNo, shipReq.getOriginContactPhoneNumber(), shipReq.getDestinationContactPhoneNumber()); + boolean trackSubSuccess = expressManager.subscribeTrack(trackSubReq); + Assert.isTrue(trackSubSuccess, "物流轨迹订阅失败"); List orderDetailIdList = new ArrayList<>(orderDetails.size()); for (StoreOrderDetail orderDetail : orderDetails) { @@ -1182,6 +1186,58 @@ public class StoreOrderServiceImpl implements IStoreOrderService { financeBillService.entryRefundOrderPaymentBill(order.getId()); } + @Transactional(rollbackFor = Exception.class) + @Override + public void addTrack(StoreOrderExpressTrackAddDTO trackAddDTO) { + Assert.notNull(trackAddDTO.getExpressId()); + Assert.notEmpty(trackAddDTO.getExpressWaybillNo()); + List storeOrderDetails = storeOrderDetailMapper.selectList( + Wrappers.lambdaQuery(StoreOrderDetail.class) + .eq(StoreOrderDetail::getExpressId, trackAddDTO.getExpressId()) + .eq(StoreOrderDetail::getExpressWaybillNo, trackAddDTO.getExpressWaybillNo()) + .eq(SimpleEntity::getDelFlag, Constants.UNDELETED) + ); + for (StoreOrderDetail storeOrderDetail : storeOrderDetails) { + if (storeOrderDetail.getDetailStatus() > 20) { + //售后订单 + continue; + } + if (EExpressStatus.PICKED_UP == trackAddDTO.getExpressStatus()) { + if (storeOrderDetail.getExpressStatus() == null) { + storeOrderDetail.setExpressStatus(EExpressStatus.PICKED_UP.getValue()); + int orderDetailSuccess = storeOrderDetailMapper.updateById(storeOrderDetail); + if (orderDetailSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + } else { + if (storeOrderDetail.getExpressStatus() < EExpressStatus.PICKED_UP.getValue()) { + storeOrderDetail.setExpressStatus(EExpressStatus.PICKED_UP.getValue()); + int orderDetailSuccess = storeOrderDetailMapper.updateById(storeOrderDetail); + if (orderDetailSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + } + } + } + if (EExpressStatus.COMPLETED == trackAddDTO.getExpressStatus()) { + storeOrderDetail.setExpressStatus(EExpressStatus.COMPLETED.getValue()); + int orderDetailSuccess = storeOrderDetailMapper.updateById(storeOrderDetail); + if (orderDetailSuccess == 0) { + throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG); + } + } + StoreOrderExpressTrack storeOrderExpressTrack = new StoreOrderExpressTrack(); + storeOrderExpressTrack.setStoreOrderId(storeOrderDetail.getStoreOrderId()); + storeOrderExpressTrack.setStoreOrderIdDetailId(storeOrderDetail.getId()); + storeOrderExpressTrack.setSort(0); + storeOrderExpressTrack.setAction(trackAddDTO.getAction()); + storeOrderExpressTrack.setDescription(trackAddDTO.getDescription()); + storeOrderExpressTrack.setRemark(trackAddDTO.getRemark()); + storeOrderExpressTrack.setDelFlag(Constants.UNDELETED); + storeOrderExpressTrackMapper.insert(storeOrderExpressTrack); + } + } + /** * 添加操作记录 * diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSignUtil.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSignUtil.java index f4c33b095a..327f1dc468 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSignUtil.java +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSignUtil.java @@ -1,6 +1,7 @@ package com.ruoyi.xkt.thirdpart.yto; import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; /** @@ -22,10 +23,23 @@ public class YtoSignUtil { } - public static String sign(String data, String secret) { + public static String sign(String data1, String data2) { //进行md5加密,然后对数组进行base64编码 - byte[] bytes = DigestUtil.md5(data + secret); + byte[] bytes = DigestUtil.md5(data1 + data2); return Base64.encodeStr(bytes, false, false); } + /** + * 假设xml内容为: , partnerId(客户密钥)为123456, + * 则要签名的内容为123456,然后对123456先进行MD5加密,再转换为base64字符串。 + * 即经过md5(16位byte)和base64后的内容就为LghTkEmsD2tbQ3fsIBRcBg== 。 + * + * @param digest + * @param param + * @param secret + * @return + */ + public static boolean verify(String digest, String param, String secret) { + return StrUtil.equals(digest, sign(StrUtil.emptyIfNull(param), StrUtil.emptyIfNull(secret))); + } } diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSubTrackParam.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSubTrackParam.java new file mode 100644 index 0000000000..f83b0c7007 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoSubTrackParam.java @@ -0,0 +1,40 @@ +package com.ruoyi.xkt.thirdpart.yto; + +import lombok.Data; + +/** + * @author liangyq + * @date 2025-04-29 18:11 + */ +@Data +public class YtoSubTrackParam { + /** + * 客户端id, 由物流公司提供,物流公司开通新渠道后获得 + */ + private String client_id; + /** + * 请求体 + */ + private String logistics_interface; + /** + * 类型(一般填写online) + */ + private String msg_type; + + @Data + public static class LogisticsInterface{ + /** + * 客户端id, 由物流公司提供,物流公司开通新渠道后获得 + */ + private String clientId; + /** + * 运单号 + */ + private String waybillNo; + /** + * 订单号 + */ + private String txLogisticId; + } + +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoTrackObj.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoTrackObj.java new file mode 100644 index 0000000000..25982da418 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/yto/YtoTrackObj.java @@ -0,0 +1,164 @@ +package com.ruoyi.xkt.thirdpart.yto; + +import cn.hutool.core.util.XmlUtil; +import com.ruoyi.common.core.text.CharsetKit; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author liangyq + * @date 2025-05-06 23:00 + */ +@Data +public class YtoTrackObj { + + private Info UpdateInfo; + + @Data + public static class Info { + /** + * 物流公司ID(YTO) + */ + private String logisticProviderID; + /** + * vip客户标识(客户编号) + */ + private String clientID; + /** + * 运单号 + */ + private String mailNo; + /** + * 物流号 + */ + private String txLogisticID; + /** + * 通知类型STATUS:物流状态 + */ + private String infoType; + /** + * 操作,固定为:ACCEPT 接单;ORDER_BOOKING 修改预约取件时间;GOT 已揽收;NOT_SEND 揽收失败;ARRIVAL 已收入;DEPARTURE 已发出;SENT_SCAN 派件;INBOUND 自提柜入柜;SIGNED 签收成功;FAILED 签收失败;TMS_RETURN 退回;FORWARDING 转寄;AIRSEND 航空发货;AIRPICK 航空提货 + */ + private String infoContent; + /** + * 事件发生时间 + */ + private Date acceptTime; + /** + * 备注或失败原因(值为中文原因或备注) + */ + private String remark; + /** + * 揽收重量 + */ + private String weight; + /** + * 网点名称 + */ + private String orgName; + /** + * 网点编号 + */ + private String orgCode; + /** + * 网点客服电话 + */ + private String orgPhone; + /** + * 业务员名称 + */ + private String empName; + /** + * 业务员编号 + */ + private String empCode; + /** + * 当前操作城市 + */ + private String city; + /** + * 当前操作区或者县 + */ + private String district; + /** + * 签收人 + */ + private String signedName; + /** + * 该状态操作人员,签收、派送、揽件 + */ + private String deliveryName; + /** + * 联系方式(包括手机,电话等) + */ + private String contactInfo; + /** + * 异常原因 + */ + private String questionCause; + /** + * 新的预约取件开始时间 + */ + private Date bookingStartTime; + /** + * 新的预约取件结束时间 + */ + private Date bookingEndTime; + /** + * 扩展字段 + */ + private String extendFields; + } + + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Response { + /** + * 物流公司ID + */ + private String logisticProviderID; + /** + * 物流号 + */ + private String txLogisticID; + /** + * 成功失败标识 true-成功;false-失败 + */ + private Boolean success; + /** + * 失败原因 + */ + private String reason; + + public String toXmlStr() { + return XmlUtil.toStr(XmlUtil.beanToXml(this), CharsetKit.UTF_8, false, true); + } + } + + @Data + public static class Request { + /** + * 消息内容 + */ + private String logistics_interface; + /** + * 消息签名 + */ + private String data_digest; + /** + * 客户编码(电商标识) + */ + private String clientId; + /** + * 订单类型(online:在线下单,offline:线下下单) + */ + private String type; + } +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZopDigestUtil.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZopDigestUtil.java index a973a555cd..3d9ff19355 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZopDigestUtil.java +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZopDigestUtil.java @@ -1,5 +1,6 @@ package com.ruoyi.xkt.thirdpart.zto; +import cn.hutool.core.util.StrUtil; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.digest.DigestUtils; @@ -57,4 +58,9 @@ public class ZopDigestUtil { return mac.doFinal(body.getBytes(StandardCharsets.UTF_8)); } + public static boolean verify(String digest, String param, String secret) { + return StrUtil.equals(digest, Base64.encodeBase64String(DigestUtils.md5(StrUtil.emptyIfNull(param) + + StrUtil.emptyIfNull(secret)))); + } + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZtoSubTrackParam.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZtoSubTrackParam.java new file mode 100644 index 0000000000..2df7b7c4ad --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZtoSubTrackParam.java @@ -0,0 +1,20 @@ +package com.ruoyi.xkt.thirdpart.zto; + +import lombok.Data; + +/** + * @author liangyq + * @date 2025-04-29 18:11 + */ +@Data +public class ZtoSubTrackParam { + /** + * 运单号 + */ + private String billCode; + /** + * 收寄人任一方电话号码后4位(手机或座机)。通过电话号码鉴权时必填,鉴权方式可以电子面单账号或电话号码二选一。 + * 选择电子面单账号鉴权时,该字段非必填;选择电话号码鉴权时,可以不绑定下单电子面单账号。 + */ + private String mobilePhone; +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZtoTrackObj.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZtoTrackObj.java new file mode 100644 index 0000000000..4526eeedb9 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/zto/ZtoTrackObj.java @@ -0,0 +1,174 @@ +package com.ruoyi.xkt.thirdpart.zto; + +import cn.hutool.json.JSONUtil; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author liangyq + * @date 2025-05-06 23:00 + */ +@Data +public class ZtoTrackObj { + + @Data + public static class Info { + /** + * 运单号 + */ + private String billCode; + /** + * 事件类型 + *

+ * GOT   收件   网点揽收 + *  DEPARTURE   发件   从网点或分拨中心发出 + *  ARRIVAL   到件   到达网点或分拨中心 + *  DISPATCH   派件   业务员派送 + *  RETURN_SCAN   退件   发生退回或改地址,具体类型见退改类型(returnType)字段 + *  RETURN_SIGNED   退件签收   已经退回至寄件客户 + *  INBOUND   入站   放入快递超市/自提柜/第三方代理点等 + *  HANDOVERSCAN_SIGNED 第三方妥投 入站后妥投成功 + *  DEPARTURE_SIGNED 出站签收   客户从快递超市/自提柜/第三方代理点等取出 + *  SIGNED   签收   客户正常签收 + *  PROBLEM   问题件   网点或中心登记的问题件,问题件类型在问题件编码(problemCode)字段体现 + */ + private String action; + /** + * 操作节点编码 + */ + private String facilityCode; + /** + * 操作节点名称 + */ + private String facilityName; + /** + * 操作节点服务电话 + */ + private String facilityContactPhone; + /** + * 操作节点所属城市 + */ + private String city; + /** + * 操作时间 + */ + private String actionTime; + /** + * 下一站编码 + */ + private String nextNodeCode; + /** + * 下一站名称 + */ + private String nextNodeName; + /** + * 下一站城市 + */ + private String nextCity; + /** + * 末端品牌编码 + */ + private String comCode; + /** + * 末端品牌名称 + */ + private String comName; + /** + * 物流详情描述 + */ + private String desc; + /** + * 快递员名称 + */ + private String courier; + /** + * 快递员电话 + */ + private String courierPhone; + /** + * 签收人名称 + */ + private String expressSigner; + /** + * 地址 + */ + private String address; + /** + * 问题件编码 + */ + private String problemCode; + /** + * (旧)退改类型 + */ + private String returnType; + /** + * (新)退改类型 + */ + private String returnUpdateType; + /** + * 备注 + */ + private String remark; + /** + * 备注1 + */ + private String remark1; + /** + * 备注2 + */ + private String remark2; + + } + + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Response { + /** + * 默认false,中通根据status=true来判断是否推送成功 + */ + private Boolean status; + /** + * 响应说明 + */ + private String message; + /** + * 响应结果 + */ + private String result; + /** + * 响应状态码 + */ + private String statusCode; + + public String toJsonStr() { + return JSONUtil.toJsonStr(this); + } + } + + @Data + public static class Request { + /** + * 消息内容 + */ + private String data; + /** + * 消息签名 + *

+ * data_digest=base64(md5(data+AppSecret)) + */ + private String data_digest; + /** + * 消息类型(Traces) + */ + private String msg_type; + /** + * 应用appKey + */ + private String company_id; + } +}