feat: 物流轨迹
parent
73015745f1
commit
59ab724173
|
|
@ -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());
|
||||
/**
|
||||
* 事件类型
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PaymentManager> 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<StoreOrderInfoVO> 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<PageVO<StoreOrderPageItemVO>> 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")
|
||||
|
|
|
|||
|
|
@ -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<Item> items;
|
||||
|
||||
@Data
|
||||
public static class Item {
|
||||
/**
|
||||
* 节点事件
|
||||
*/
|
||||
private String action;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<StoreOrderDetailInfoDTO> orderDetails;
|
||||
|
||||
private List<ExpressTrackDTO> expressTracks;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ExpressPrintDTO> printOrder(Collection<String> waybillNos);
|
||||
|
||||
/**
|
||||
* 订阅轨迹
|
||||
*
|
||||
* @param trackSubReq
|
||||
* @return
|
||||
*/
|
||||
boolean subscribeTrack(ExpressTrackSubReqDTO trackSubReq);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,5 +169,10 @@ public interface IStoreOrderService {
|
|||
*/
|
||||
void refundSuccess(Long storeOrderId, List<Long> storeOrderDetailIds, Long operatorId);
|
||||
|
||||
|
||||
/**
|
||||
* 添加轨迹信息
|
||||
*
|
||||
* @param trackAddDTO
|
||||
*/
|
||||
void addTrack(StoreOrderExpressTrackAddDTO trackAddDTO);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Long> 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<StoreOrderDetail> 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加操作记录
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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内容为:<order></order> , partnerId(客户密钥)为123456,
|
||||
* 则要签名的内容为<order></order>123456,然后对<order></order>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)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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))));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
/**
|
||||
* 事件类型
|
||||
* <p>
|
||||
* 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;
|
||||
/**
|
||||
* 消息签名
|
||||
* <p>
|
||||
* data_digest=base64(md5(data+AppSecret))
|
||||
*/
|
||||
private String data_digest;
|
||||
/**
|
||||
* 消息类型(Traces)
|
||||
*/
|
||||
private String msg_type;
|
||||
/**
|
||||
* 应用appKey
|
||||
*/
|
||||
private String company_id;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue