Browse Source

调接口逻辑

master
luoweijian 4 weeks ago
parent
commit
d65d296d5c
  1. 2
      .idea/sqldialects.xml
  2. 2
      src/main/java/com/project/logistics/config/WebDavProperties.java
  3. 1
      src/main/java/com/project/logistics/domain/enums/ShipmentOrderInfoFieldEnum.java
  4. 9
      src/main/java/com/project/logistics/domain/scheduler/ApiRetryJob.java
  5. 55
      src/main/java/com/project/logistics/domain/scheduler/WebDavDirectoryInitJob.java
  6. 18
      src/main/java/com/project/logistics/domain/service/WebDavService.java
  7. 6
      src/main/java/com/project/logistics/domain/service/base/ErpService.java
  8. 3
      src/main/java/com/project/logistics/domain/service/base/impl/ApiRetryTaskServiceImpl.java
  9. 35
      src/main/java/com/project/logistics/domain/service/base/impl/ErpServiceImpl.java
  10. 4
      src/main/java/com/project/logistics/domain/service/base/impl/LogisticsOrderServiceImpl.java
  11. 8
      src/main/java/com/project/logistics/domain/strategy/handler/SfCreateOrderHandler.java
  12. 191
      src/main/java/com/project/receive/controller/ReceiveController.java
  13. 29
      src/main/java/com/project/receive/domain/dto/SfRoutePushRequest.java
  14. 7
      src/main/java/com/project/receive/domain/entity/FeePushLogEntity.java
  15. 2
      src/main/java/com/project/receive/domain/entity/PodPushLogEntity.java
  16. 21
      src/main/java/com/project/receive/domain/entity/RoutePushLogEntity.java
  17. 181
      src/main/java/com/project/receive/domain/service/ReceiveService.java
  18. 7
      src/main/java/com/project/receive/domain/service/base/FeePushLogService.java
  19. 7
      src/main/java/com/project/receive/domain/service/base/PodPushLogService.java
  20. 7
      src/main/java/com/project/receive/domain/service/base/RoutePushLogService.java
  21. 12
      src/main/java/com/project/receive/domain/service/base/impl/FeePushLogServiceImpl.java
  22. 13
      src/main/java/com/project/receive/domain/service/base/impl/PodPushLogServiceImpl.java
  23. 13
      src/main/java/com/project/receive/domain/service/base/impl/RoutePushLogServiceImpl.java
  24. 10
      src/main/java/com/project/receive/mapper/FeePushLogMapper.java
  25. 10
      src/main/java/com/project/receive/mapper/PodPushLogMapper.java
  26. 10
      src/main/java/com/project/receive/mapper/RoutePushLogMapper.java
  27. 58
      src/main/java/com/project/receive/strategy/ErpUpdateFeeHandler.java
  28. 162
      src/main/java/com/project/receivedemo/controller/ReceiveDemoController.java
  29. 2
      src/main/java/com/project/receivedemo/dto/FeeInfo.java
  30. 2
      src/main/java/com/project/receivedemo/dto/OrderStateDetail.java
  31. 2
      src/main/java/com/project/receivedemo/dto/RouteBody.java
  32. 2
      src/main/java/com/project/receivedemo/dto/SfFeeContent.java
  33. 2
      src/main/java/com/project/receivedemo/dto/SfFeeResponse.java
  34. 2
      src/main/java/com/project/receivedemo/dto/SfInnerContent.java
  35. 2
      src/main/java/com/project/receivedemo/dto/SfPicturePushRequest.java
  36. 2
      src/main/java/com/project/receivedemo/dto/SfPicturePushResponse.java
  37. 2
      src/main/java/com/project/receivedemo/dto/SfPushRequest.java
  38. 2
      src/main/java/com/project/receivedemo/dto/SfPushResponse.java
  39. 2
      src/main/java/com/project/receivedemo/dto/SfRoutePushRequest.java
  40. 2
      src/main/java/com/project/receivedemo/dto/SfRouteResponse.java
  41. 2
      src/main/java/com/project/receivedemo/dto/WaybillRoute.java
  42. 2
      src/main/java/com/project/receivedemo/utils/SfDecryptUtil.java
  43. 4
      src/main/resources/application.yml

2
.idea/sqldialects.xml

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/src/main/java/com/project/logistics/domain/service/base/ErpServiceImpl.java" dialect="GenericSQL" />
<file url="file://$PROJECT_DIR$/src/main/java/com/project/logistics/domain/service/base/impl/ErpServiceImpl.java" dialect="GenericSQL" />
</component>
</project>

2
src/main/java/com/project/logistics/config/WebDavProperties.java

@ -42,7 +42,7 @@ public class WebDavProperties {
* 签收回单(POD)的存放根路径
* 例如: /U9_Orders/Signed_Receipts
*/
private String podRoot;
private String podRoot = "/电子签收单";
/**
* 连接超时时间 (毫秒)默认 10000

1
src/main/java/com/project/logistics/domain/enums/ShipmentOrderInfoFieldEnum.java

@ -19,6 +19,7 @@ public enum ShipmentOrderInfoFieldEnum {
expressType("DescFlexField_PrivateDescSeg20","寄付方式") ,
fee("DescFlexField_PrivateDescSeg3" , "运费") ,
resourceCode("DescFlexField_PrivateDescSeg18" , "资源编码"),
quantity("SM_Ship.DescFlexField_PrivateDescSeg2" , "件数") ,
;
private final String fieldName;

9
src/main/java/com/project/logistics/domain/scheduler/ApiRetryJob.java

@ -1,5 +1,7 @@
package com.project.logistics.domain.scheduler;
import cn.hutool.core.util.StrUtil;
import com.project.base.config.ScheduledTaskProperties;
import com.project.logistics.domain.entity.ApiRetryTaskEntity;
import com.project.logistics.domain.entity.LogisticsOrderEntity;
import com.project.logistics.domain.enums.TaskStatusEnum;
@ -29,6 +31,9 @@ public class ApiRetryJob {
// Spring 会自动把所有实现了 ApiTaskHandler 的类注入到这个 List 里
private final Map<String, ApiTaskHandler> handlerMap;
@Autowired
private ScheduledTaskProperties scheduledTaskProperties;
@Autowired
public ApiRetryJob(List<ApiTaskHandler> handlers) {
// 将 List 转换成 Map,方便通过 ActionCode 快速查找对应的处理器
@ -42,6 +47,10 @@ public class ApiRetryJob {
*/
@Scheduled(fixedDelay = 10000)
public void executePendingTasks() throws Exception {
if (StrUtil.equals(scheduledTaskProperties.getOwner() , "local")) {
log.error("跳过ApiRetryJob定时任务");
return;
}
// 1. 从数据库捞取所有 状态=PENDING/FAILED 且 执行时间<=当前时间 的任务
List<ApiRetryTaskEntity> pendingTasks = apiRetryTaskService.listPendingTasks();

55
src/main/java/com/project/logistics/domain/scheduler/WebDavDirectoryInitJob.java

@ -0,0 +1,55 @@
package com.project.logistics.domain.scheduler;
import com.project.logistics.config.WebDavProperties;
import com.project.logistics.domain.service.WebDavService;
import com.project.logistics.domain.utils.FilePathUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component
public class WebDavDirectoryInitJob {
@Autowired
private WebDavService webDavService;
@Autowired
private WebDavProperties webDavProperties;
/**
* 每天凌晨 00:00:01 执行
* 预先创建好当天所有的业务文件夹
*/
@Scheduled(cron = "8 0 0 * * ?")
public void initTodayDirectories() {
log.info(">>> [系统预热] 开始初始化今日 WebDAV 业务目录...");
// 1. 生成今日层级路径: 2026年/2026年3月/2026年3月30日
String datePath = FilePathUtil.getHierarchicalPath(new Date());
try {
// 2. 初始化【待处理出货单】目录 (用户上班要往里放文件)
webDavService.initFolder(webDavProperties.getShipmentRoot(), datePath);
// 3. 初始化【已自动下单出货单】目录 (下单成功后文件会自动移入)
webDavService.initFolder(webDavProperties.getProcessedFolderName(), datePath);
// 4. 初始化【顺丰面单】目录
// 假设你在 WebDavProperties 中定义了 waybillRoot
webDavService.initFolder("顺丰面单", datePath);
// 5. 初始化【签收回单】目录
webDavService.initFolder(webDavProperties.getPodRoot(), datePath);
log.info(">>> [系统预热] 今日所有目录初始化完成!");
} catch (Exception e) {
log.error(">>> [系统预热] 自动创建今日目录失败: {}", e.getMessage());
// 注意:这里失败没关系,业务运行时的 ensureDirectoryExists 还有一次兜底机会
}
}
}

18
src/main/java/com/project/logistics/domain/service/WebDavService.java

@ -145,4 +145,22 @@ public class WebDavService {
String normalized = rawUrl.replaceAll("(?<!:)/+", "/");
return UrlBuilder.ofHttp(normalized, CharsetUtil.CHARSET_UTF_8).build();
}
// 在 WebDavService.java 中增加/确认此方法
/**
* 5. 自动化辅助一键初始化当天的完整层级目录
* @param rootName 业务根目录 ( properties.getShipmentRoot())
* @param datePath 格式化好的日期路径 (2026年/2026年3月/2026年3月30日)
*/
public void initFolder(String rootName, String datePath) throws IOException {
Sardine sardine = getSardine();
// 拼接完整路径并编码
String rawUrl = properties.getUrl() + "/" + rootName + "/" + datePath + "/";
String encodedUrl = getEncodedUrl(rawUrl);
log.info(">>> 正在初始化业务目录: {}", rootName + "/" + datePath);
// 调用之前实现的递归创建逻辑
ensureDirectoryExists(sardine, encodedUrl);
}
}

6
src/main/java/com/project/logistics/domain/service/base/ErpService.java

@ -2,6 +2,8 @@ package com.project.logistics.domain.service.base;
import cn.hutool.json.JSONObject;
import java.math.BigDecimal;
public interface ErpService {
@ -11,4 +13,8 @@ public interface ErpService {
* 回写运单号到 U9
*/
void updateWaybillToErp(String orderNo, String waybillNo , String resourceCode) throws Exception;
void updateStatusToErp(String orderNo, String statusDesc) throws Exception;
void updateFeeToErp(String orderNo, Integer qty, BigDecimal amount) throws Exception;
}

3
src/main/java/com/project/logistics/domain/service/base/ApiRetryTaskServiceImpl.java → src/main/java/com/project/logistics/domain/service/base/impl/ApiRetryTaskServiceImpl.java

@ -1,9 +1,10 @@
package com.project.logistics.domain.service.base;
package com.project.logistics.domain.service.base.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.logistics.domain.entity.ApiRetryTaskEntity;
import com.project.logistics.domain.enums.RetryActionEnum;
import com.project.logistics.domain.enums.TaskStatusEnum;
import com.project.logistics.domain.service.base.ApiRetryTaskService;
import com.project.logistics.mapper.ApiRetryTaskMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

35
src/main/java/com/project/logistics/domain/service/base/ErpServiceImpl.java → src/main/java/com/project/logistics/domain/service/base/impl/ErpServiceImpl.java

@ -1,13 +1,15 @@
package com.project.logistics.domain.service.base;
package com.project.logistics.domain.service.base.impl;
import cn.hutool.json.JSONObject;
import com.project.logistics.domain.enums.ShipmentOrderInfoFieldEnum;
import com.project.logistics.domain.service.base.ErpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Map;
@Service
@ -70,4 +72,35 @@ public class ErpServiceImpl implements ErpService {
throw e; // 抛出异常,触发 ApiRetryJob 的重试机制
}
}
/**
* 通用的状态回写方法 (揽收签收)
*/
@Override
public void updateStatusToErp(String orderNo, String statusDesc) throws Exception {
log.info(">>> [U9回写状态] 单号: {}, 目标状态: {}", orderNo, statusDesc);
// 假设 U9 的状态字段是 StatusDesc,或者是自定义字段 DescFlexField_Pub_2
String sql = "UPDATE SM_Ship SET DescFlexField_Pub_2 = ? WHERE DocNo = ?";
int rows = u9JdbcTemplate.update(sql, statusDesc, orderNo);
if (rows == 0) {
throw new RuntimeException("U9单据不存在,回写状态失败");
}
}
@Override
public void updateFeeToErp(String orderNo, Integer qty, BigDecimal amount) throws Exception {
// 财务安全:确保回写的金额 100% 是两位小数
BigDecimal formattedAmount = amount.setScale(2, java.math.RoundingMode.HALF_UP);
log.info(">>> [U9回写费用] 单号: {}, 最终金额: {}", orderNo, formattedAmount);
String sql = String.format("UPDATE SM_Ship SET %s = ?, %s = ? WHERE DocNo = ?" ,
ShipmentOrderInfoFieldEnum.quantity.getFieldName() ,
ShipmentOrderInfoFieldEnum.fee.getFieldName());
// 执行更新
u9JdbcTemplate.update(sql, qty, formattedAmount, orderNo);
}
}

4
src/main/java/com/project/logistics/domain/service/base/LogisticsOrderServiceImpl.java → src/main/java/com/project/logistics/domain/service/base/impl/LogisticsOrderServiceImpl.java

@ -1,4 +1,4 @@
package com.project.logistics.domain.service.base;
package com.project.logistics.domain.service.base.impl;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -8,6 +8,8 @@ import com.project.logistics.domain.enums.OrderStatusEnum;
import com.project.logistics.domain.enums.OrderTypeEnum;
import com.project.logistics.domain.enums.RetryActionEnum;
import com.project.logistics.domain.enums.TaskStatusEnum;
import com.project.logistics.domain.service.base.ApiRetryTaskService;
import com.project.logistics.domain.service.base.LogisticsOrderService;
import com.project.logistics.mapper.LogisticsOrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

8
src/main/java/com/project/logistics/domain/strategy/handler/SfCreateOrderHandler.java

@ -79,6 +79,12 @@ public class SfCreateOrderHandler implements ApiTaskHandler {
terminateBusinessTask(task, order, "匹配字段失败:单据产品类别 (" + expressType + ") 未匹配到顺丰业务类型");
return;
}
if (StrUtil.equals(order.getOrderType() , OrderTypeEnum.SHIPMENT.name()) &&
StrUtil.isBlank(order.getResourceCode())) {
terminateBusinessTask(task, order, "常规出货单缺少资源编码");
return;
}
msgData.put("cargoDesc", "交换机");
JSONArray cargoDetails = new JSONArray();
JSONObject item = new JSONObject();
@ -102,7 +108,7 @@ public class SfCreateOrderHandler implements ApiTaskHandler {
// 收件方 (从 U9 快照中动态获取)
JSONObject receiver = new JSONObject();
receiver.put("contactType", SfContactTypeEnum.SENDER.getCode());
receiver.put("contactType", SfContactTypeEnum.RECIPIENT.getCode());
receiver.put("contact", u9Data.getString(ShipmentOrderInfoFieldEnum.recipientContact.name())); // 假设 U9 字段名是这个
receiver.put("mobile", u9Data.getString(ShipmentOrderInfoFieldEnum.recipientMobile.name()));
receiver.put("address", u9Data.getString(ShipmentOrderInfoFieldEnum.recipientAddress.name()));

191
src/main/java/com/project/receive/controller/ReceiveController.java

@ -1,162 +1,87 @@
package com.project.receive.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.receive.dto.*;
import com.project.receive.utils.SfDecryptUtil;
import com.project.receive.domain.dto.SfRoutePushRequest;
import com.project.receive.domain.service.ReceiveService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.FileOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
@RestController
@Slf4j
@RequestMapping("/api/")
@RestController
@RequestMapping("/api/sf/callback")
public class ReceiveController {
private static final String SF_CHECKWORD = "ZXmoWOQdSd2UTBmSP6Kv3VW9Q4N5dJqz";
@Autowired
private ReceiveService receiveService;
/**
* 接收顺丰订单状态推送接口
* 对应文档 2.6 JSON 示例
* 1. 路由状态回调 (揽收/签收)
* 对应接口: PushOrderState
*/
@PostMapping("/pushOrderState")
public SfPushResponse receiveOrderState(@RequestBody SfPushRequest request) {
// 1. 打印接收到的原始数据日志
log.info("==== 收到顺丰状态推送 ====");
log.info("Request ID: {}", request.getRequestId());
log.info("Timestamp: {}", request.getTimestamp());
@PostMapping("/route")
public Map<String, Object> handleRoutePush(@RequestBody SfRoutePushRequest request) {
log.info(">>> 收到顺丰路由推送,包含节点数: {}",
(request.getBody() != null && request.getBody().getWaybillRoute() != null) ?
request.getBody().getWaybillRoute().size() : 0);
if (request.getOrderState() != null) {
request.getOrderState().forEach(state -> {
log.info("订单号: {}, 运单号: {}, 状态码: {}, 描述: {}",
state.getOrderNo(),
state.getWaybillNo(),
state.getOrderStateCode(),
state.getOrderStateDesc());
});
}
try {
// 业务处理逻辑
receiveService.processRoutePush(request);
// 2. 根据文档 2.7 节,返回成功响应
return SfPushResponse.ok();
// 返回顺丰要求的成功格式
return successResponse();
} catch (Exception e) {
log.error(">>> 路由解析处理失败", e);
return failResponse(e.getMessage());
}
}
/**
* 接收顺丰路由推送
* 对应文档 2.5 JSON 示例
* 2. 费用与重量回调
* 对应接口: EXP_RECE_WAYBILLS_FEE_PUSH
*/
@PostMapping("/pushRoute")
public SfRouteResponse receiveRoute(@RequestBody SfRoutePushRequest request) {
log.info(">>>> 收到顺丰路由信息推送 <<<<");
if (request.getBody() != null && request.getBody().getWaybillRoute() != null) {
for (WaybillRoute route : request.getBody().getWaybillRoute()) {
log.info("运单号: {}, 订单号: {}, 时间: {}, 状态: {}, 备注: {}",
route.getMailno(),
route.getOrderid(),
route.getAcceptTime(),
route.getOpCode(),
route.getRemark());
}
} else {
log.warn("收到的路由数据内容为空");
@PostMapping("/fee")
public Map<String, Object> handleFeePush(@RequestParam("content") String content) {
log.info(">>> 收到顺丰【运费重量】推送: {}", content);
try {
receiveService.saveFeeLog(content);
return successResponse();
} catch (Exception e) {
log.error("运费处理异常", e);
return failResponse(e.getMessage());
}
// 根据文档 2.6,必须返回 0000 告知顺丰接收成功,否则顺丰会重复推送
return SfRouteResponse.ok();
}
@RequestMapping("/pushOrderStateRaw")
public String receiveRaw(@RequestBody String rawBody) {
log.info("收到原始报文: {}", rawBody);
// 返回 JSON 格式的成功字符串
return "{\"success\":\"true\",\"code\":\"0\",\"msg\":\"\"}";
}
@Autowired
private ObjectMapper objectMapper;
/**
* 接收顺丰运费推送
* 报文类型: application/x-www-form-urlencoded
* 3. 电子回单图片回调
* 对应接口: 图片注册及推送接口
*/
@PostMapping(value = "/pushFee", consumes = "application/x-www-form-urlencoded")
public SfFeeResponse receiveFee(
@RequestParam("content") String content,
@RequestParam(value = "sign", required = false) String sign) {
log.info(">>>> 收到顺丰运费推送 <<<<");
log.info("签名(sign): {}", sign);
log.info("原始内容(content): {}", content);
@PostMapping("/pod-picture")
public Map<String, Object> handlePodPicturePush(@RequestParam("content") String content) {
log.info(">>> 收到顺丰【电子回单图片】推送 (内容较长,不完整打印)");
try {
// 将 content 字符串解析为 Java 对象
SfFeeContent feeData = objectMapper.readValue(content, SfFeeContent.class);
log.info("解析成功 - 运单号: {}, 订单号: {}, 计费重量: {}",
feeData.getWaybillNo(),
feeData.getOrderNo(),
feeData.getMeterageWeightQty());
if (feeData.getFeeList() != null) {
feeData.getFeeList().forEach(fee -> {
log.info("费用项 - 类型: {}, 金额: {}", fee.getFeeTypeCode(), fee.getFeeAmt());
});
}
// 返回成功响应 (code 必须为 200)
return SfFeeResponse.ok("your_partner_code");
receiveService.savePodPictureLog(content);
return successResponse();
} catch (Exception e) {
log.error("解析顺丰运费推送失败", e);
SfFeeResponse error = new SfFeeResponse();
error.setCode(400);
error.setMessage("解析异常");
return error;
log.error("回单图片处理异常", e);
return failResponse(e.getMessage());
}
}
@PostMapping("/pushElectronicReceipt")
public SfPicturePushResponse receiveReceipt(@RequestBody SfPicturePushRequest request) {
log.info(">>>> 收到顺丰电子回单(IN149)推送, 运单号: {} <<<<", request.getWaybillNo());
try {
// 步骤 1:解密最外层的 content 得到内部 JSON 字符串
byte[] firstLevelDecrypted = SfDecryptUtil.decrypt(request.getContent(), SF_CHECKWORD);
String innerJsonStr = new String(firstLevelDecrypted, "UTF-8");
log.info("第一层解密成功");
// 步骤 2:解析内部 JSON 获取文件密文
SfInnerContent innerContent = objectMapper.readValue(innerJsonStr, SfInnerContent.class);
String encryptedFileBase64 = innerContent.getContent();
// 步骤 3:对文件密文进行第二层 AES 解密 (根据文档示例,文件内容也是加密的)
// 先 Base64 解码,再 AES 解密
byte[] pdfBytes = SfDecryptUtil.decrypt(encryptedFileBase64, SF_CHECKWORD);
log.info("第二层解密(文件流)成功,大小: {} bytes", pdfBytes.length);
// 步骤 4:保存为 PDF 文件到当前目录
String fileName = request.getWaybillNo() + "_receipt.pdf";
Path path = Paths.get(System.getProperty("user.dir"), fileName);
try (FileOutputStream fos = new FileOutputStream(path.toFile())) {
fos.write(pdfBytes);
fos.flush();
}
log.info("电子回单已保存至: {}", path.toAbsolutePath());
return SfPicturePushResponse.ok();
private Map<String, Object> successResponse() {
Map<String, Object> res = new HashMap<>();
res.put("success", true);
res.put("errorCode", "S0000");
return res;
}
} catch (Exception e) {
log.error("处理电子回单推送失败", e);
SfPicturePushResponse error = new SfPicturePushResponse();
error.setReturnCode("1000");
error.setReturnMsg("解析保存失败: " + e.getMessage());
return error;
}
private Map<String, Object> failResponse(String msg) {
Map<String, Object> res = new HashMap<>();
res.put("success", false);
res.put("errorMsg", msg);
return res;
}
}
}

29
src/main/java/com/project/receive/domain/dto/SfRoutePushRequest.java

@ -0,0 +1,29 @@
package com.project.receive.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class SfRoutePushRequest {
@JsonProperty("Body") // 必须对应顺丰的大写 Body
private RouteBody body;
@Data
public static class RouteBody {
@JsonProperty("WaybillRoute") // 必须对应顺丰的大写 WaybillRoute
private List<WaybillRouteDetail> waybillRoute;
}
@Data
public static class WaybillRouteDetail {
private String mailno; // 顺丰运单号
private String orderid; // 客户订单号 (U9单号)
private String acceptAddress; // 发生地址
private String acceptTime; // 发生时间
private String remark; // 备注内容
private String opCode; // 操作码 (50:揽收, 80:签收)
private String id; // 推送ID
}
}

7
src/main/java/com/project/logistics/domain/entity/FeePushLogEntity.java → src/main/java/com/project/receive/domain/entity/FeePushLogEntity.java

@ -1,4 +1,4 @@
package com.project.logistics.domain.entity;
package com.project.receive.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@ -30,6 +30,11 @@ public class FeePushLogEntity extends BaseEntity {
@TableField("order_no")
private String orderNo;
@Comment("件数")
@Column(name = "item_count")
@TableField("item_count")
private Integer itemCount;
@Comment("关联顺丰运单号")
@Column(name = "waybill_no", length = 64, nullable = false)
@TableField("waybill_no")

2
src/main/java/com/project/logistics/domain/entity/PodPushLogEntity.java → src/main/java/com/project/receive/domain/entity/PodPushLogEntity.java

@ -1,4 +1,4 @@
package com.project.logistics.domain.entity;
package com.project.receive.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;

21
src/main/java/com/project/logistics/domain/entity/RoutePushLogEntity.java → src/main/java/com/project/receive/domain/entity/RoutePushLogEntity.java

@ -1,4 +1,4 @@
package com.project.logistics.domain.entity;
package com.project.receive.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
@ -33,15 +33,20 @@ public class RoutePushLogEntity extends BaseEntity {
@TableField("order_no")
private String orderNo;
@Comment("顺丰路由状态代码")
@Column(name = "order_state_code", length = 32)
@TableField("order_state_code")
private String orderStateCode;
@Comment("操作时间")
@Column(name = "accept_time", length = 200)
@TableField("accept_time")
private String acceptTime;
@Comment("路由操作码 (顺丰opCode, 京东status等)")
@Column(name = "op_code", length = 32)
@TableField("op_code")
private String opCode;
@Comment("顺丰路由状态描述(如:已收取、派件中、签收成功等)")
@Column(name = "order_state_desc", length = 255)
@TableField("order_state_desc")
private String orderStateDesc;
@Column(name = "remark", length = 2000)
@TableField("remark")
private String remark;
@Comment("收派员工号")
@Column(name = "emp_code", length = 100)

181
src/main/java/com/project/receive/domain/service/ReceiveService.java

@ -0,0 +1,181 @@
package com.project.receive.domain.service;
import com.jayway.jsonpath.JsonPath;
import com.project.logistics.domain.entity.LogisticsOrderEntity;
import com.project.logistics.domain.enums.*;
import com.project.logistics.domain.service.base.*;
import com.project.receive.domain.dto.SfRoutePushRequest;
import com.project.receive.domain.entity.FeePushLogEntity;
import com.project.receive.domain.entity.PodPushLogEntity;
import com.project.receive.domain.entity.RoutePushLogEntity;
import com.project.receive.domain.service.base.FeePushLogService;
import com.project.receive.domain.service.base.PodPushLogService;
import com.project.receive.domain.service.base.RoutePushLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
@Slf4j
@Service
public class ReceiveService {
@Autowired
private LogisticsOrderService logisticsOrderService;
@Autowired
private ApiRetryTaskService apiRetryTaskService;
@Autowired
private RoutePushLogService routePushLogService;
@Autowired
private FeePushLogService feePushLogService;
@Autowired
private PodPushLogService podPushLogService;
/**
* 处理路由推送识别揽收与签收
*/
public void processRoutePush(SfRoutePushRequest request) throws Exception {
if (request.getBody() == null || request.getBody().getWaybillRoute() == null) {
return;
}
// 循环处理顺丰推过来的每一个路由节点
for (SfRoutePushRequest.WaybillRouteDetail detail : request.getBody().getWaybillRoute()) {
log.info(">>> 正在解析路由: 单号={}, 操作码={}, 描述={}",
detail.getOrderid(), detail.getOpCode(), detail.getRemark());
// 1. 存入流水日志
saveToLogTable(detail);
// 2. 状态机流转 (仅针对揽收50和签收80)
handleStatusMachine(detail);
}
}
private void handleStatusMachine(SfRoutePushRequest.WaybillRouteDetail detail) throws Exception {
String orderNo = detail.getOrderid();
String opCode = detail.getOpCode();
// 尝试获取本地订单
LogisticsOrderEntity order = logisticsOrderService.getByOrderNo(orderNo);
if (order == null) {
log.warn(">>> 收到路由推送,但本地库找不到单号: {}", orderNo);
return;
}
// 判断操作码
if (SfRouteOpCodeEnum.PICKED_UP.getCode().equals(opCode)) {
// 已揽收
order.setOrderStatus(OrderStatusEnum.PICKED_UP.getCode());
logisticsOrderService.updateById(order);
// 触发回写 ERP 任务
apiRetryTaskService.createNextTask(orderNo, RetryActionEnum.ERP_UPDATE_PICKED_UP);
}
else if (SfRouteOpCodeEnum.DELIVERED.getCode().equals(opCode)) {
// 已签收
order.setOrderStatus(OrderStatusEnum.DELIVERED.getCode());
logisticsOrderService.updateById(order);
// 触发回写 ERP 任务
apiRetryTaskService.createNextTask(orderNo, RetryActionEnum.ERP_UPDATE_DELIVERED);
}
}
private void saveToLogTable(SfRoutePushRequest.WaybillRouteDetail detail) {
RoutePushLogEntity logEntity = new RoutePushLogEntity();
logEntity.setOrderNo(detail.getOrderid());
logEntity.setWaybillNo(detail.getMailno());
logEntity.setOpCode(detail.getOpCode());
logEntity.setRemark(detail.getRemark());
logEntity.setAcceptTime(detail.getAcceptTime());
routePushLogService.save(logEntity);
}
/**
* 处理运费推送
*/
@Transactional(rollbackFor = Exception.class)
public void saveFeeLog(String rawJson) {
try {
// 1. 提取基础信息
String orderNo = JsonPath.read(rawJson, "$.orderNo");
String waybillNo = JsonPath.read(rawJson, "$.waybillNo");
// 提取件数 (quantity)
Object qtyObj = JsonPath.read(rawJson, "$.quantity");
Integer itemCount = new java.math.BigDecimal(String.valueOf(qtyObj)).intValue();
// 提取重量 (meterageWeightQty)
Object weightObj = JsonPath.read(rawJson, "$.meterageWeightQty");
BigDecimal weight = new java.math.BigDecimal(String.valueOf(weightObj))
.setScale(3, java.math.RoundingMode.HALF_UP);
// 2. 【核心】计算总费用
// 从 feeList 数组中提取所有 feeAmt 并求和
List<Double> fees = JsonPath.read(rawJson, "$.feeList[*].feeAmt");
BigDecimal totalFee = BigDecimal.ZERO;
if (fees != null) {
for (Object f : fees) {
totalFee = totalFee.add(new BigDecimal(String.valueOf(f)));
}
}
totalFee = totalFee.setScale(2, java.math.RoundingMode.HALF_UP);
log.info(">>> 解析运费报文: 单号={}, 件数={}, 重量={}, 总费={}",
orderNo, itemCount, weight, totalFee);
// 3. 存入数据库
FeePushLogEntity feeEntity = new FeePushLogEntity();
feeEntity.setOrderNo(orderNo);
feeEntity.setWaybillNo(waybillNo);
feeEntity.setItemCount(itemCount);
feeEntity.setRealWeightQty(weight);
feeEntity.setTotalFeeAmt(totalFee);
feeEntity.setSyncStatus(SyncStatusEnum.WAIT.getCode());
feeEntity.setRawPushData(rawJson);
feePushLogService.save(feeEntity);
// 4. 驱动状态机与回写任务
// 找到主订单,如果当前状态是已揽收,则推进到“运费已清点”状态
LogisticsOrderEntity order = logisticsOrderService.getByOrderNo(orderNo);
if (order != null) {
// 只有状态处于 PICKED_UP 时才更新主表状态,避免覆盖更高级的 DELIVERED 状态
if (OrderStatusEnum.PICKED_UP.getCode().equals(order.getOrderStatus())) {
order.setOrderStatus(OrderStatusEnum.ERP_FEE_UPDATED.getCode());
logisticsOrderService.updateById(order);
}
// 无论主表状态如何,都要触发一次“回写运费到ERP”的任务
apiRetryTaskService.createNextTask(orderNo, RetryActionEnum.ERP_UPDATE_FEE);
}
} catch (Exception e) {
log.error(">>> 运费报文解析失败: {}", rawJson, e);
throw new RuntimeException("FEE_PARSE_ERROR");
}
}
/**
* 处理 POD 图片推送
*/
public void savePodPictureLog(String content) throws Exception {
// 关键:POD 推送包含巨大的 Base64 字节,这里只做存库。
// 具体的解析、下载、传 WebDAV 交由后续的 SF_DOWNLOAD_POD 任务去重试执行。
String waybillNo = JsonPath.read(content, "$.waybillNo");
PodPushLogEntity podLog = new PodPushLogEntity();
podLog.setWaybillNo(waybillNo);
podLog.setRawPushData(content); // 存入 LONGTEXT 字段
podLog.setProcessStatus(SyncStatusEnum.WAIT.getCode());
podPushLogService.save(podLog);
// 查找订单号并触发“处理图片”的异步任务
LogisticsOrderEntity order = logisticsOrderService.lambdaQuery()
.eq(LogisticsOrderEntity::getSfWaybillNo, waybillNo).one();
if (order != null) {
apiRetryTaskService.createNextTask(order.getOrderNo(), RetryActionEnum.SF_DOWNLOAD_POD);
}
}
}

7
src/main/java/com/project/receive/domain/service/base/FeePushLogService.java

@ -0,0 +1,7 @@
package com.project.receive.domain.service.base;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.receive.domain.entity.FeePushLogEntity;
public interface FeePushLogService extends IService<FeePushLogEntity> {
}

7
src/main/java/com/project/receive/domain/service/base/PodPushLogService.java

@ -0,0 +1,7 @@
package com.project.receive.domain.service.base;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.receive.domain.entity.PodPushLogEntity;
public interface PodPushLogService extends IService<PodPushLogEntity> {
}

7
src/main/java/com/project/receive/domain/service/base/RoutePushLogService.java

@ -0,0 +1,7 @@
package com.project.receive.domain.service.base;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.receive.domain.entity.RoutePushLogEntity;
public interface RoutePushLogService extends IService<RoutePushLogEntity> {
}

12
src/main/java/com/project/receive/domain/service/base/impl/FeePushLogServiceImpl.java

@ -0,0 +1,12 @@
package com.project.receive.domain.service.base.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.receive.domain.entity.FeePushLogEntity;
import com.project.receive.domain.service.base.FeePushLogService;
import com.project.receive.mapper.FeePushLogMapper;
import org.springframework.stereotype.Service;
@Service
public class FeePushLogServiceImpl extends ServiceImpl<FeePushLogMapper , FeePushLogEntity>
implements FeePushLogService {
}

13
src/main/java/com/project/receive/domain/service/base/impl/PodPushLogServiceImpl.java

@ -0,0 +1,13 @@
package com.project.receive.domain.service.base.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.receive.domain.entity.PodPushLogEntity;
import com.project.receive.domain.service.base.PodPushLogService;
import com.project.receive.mapper.PodPushLogMapper;
import org.springframework.stereotype.Service;
@Service
public class PodPushLogServiceImpl extends ServiceImpl<PodPushLogMapper, PodPushLogEntity>
implements PodPushLogService {
}

13
src/main/java/com/project/receive/domain/service/base/impl/RoutePushLogServiceImpl.java

@ -0,0 +1,13 @@
package com.project.receive.domain.service.base.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.receive.domain.entity.RoutePushLogEntity;
import com.project.receive.domain.service.base.RoutePushLogService;
import com.project.receive.mapper.RoutePushLogMapper;
import org.springframework.stereotype.Service;
@Service
public class RoutePushLogServiceImpl extends ServiceImpl<RoutePushLogMapper, RoutePushLogEntity>
implements RoutePushLogService {
}

10
src/main/java/com/project/receive/mapper/FeePushLogMapper.java

@ -0,0 +1,10 @@
package com.project.receive.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.receive.domain.entity.FeePushLogEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface FeePushLogMapper extends BaseMapper<FeePushLogEntity> {
}

10
src/main/java/com/project/receive/mapper/PodPushLogMapper.java

@ -0,0 +1,10 @@
package com.project.receive.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.receive.domain.entity.PodPushLogEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PodPushLogMapper extends BaseMapper<PodPushLogEntity> {
}

10
src/main/java/com/project/receive/mapper/RoutePushLogMapper.java

@ -0,0 +1,10 @@
package com.project.receive.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.receive.domain.entity.RoutePushLogEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RoutePushLogMapper extends BaseMapper<RoutePushLogEntity> {
}

58
src/main/java/com/project/receive/strategy/ErpUpdateFeeHandler.java

@ -0,0 +1,58 @@
package com.project.receive.strategy;
import com.project.logistics.domain.entity.ApiRetryTaskEntity;
import com.project.logistics.domain.entity.LogisticsOrderEntity;
import com.project.logistics.domain.enums.RetryActionEnum;
import com.project.logistics.domain.enums.SyncStatusEnum;
import com.project.logistics.domain.service.base.ErpService;
import com.project.logistics.domain.strategy.ApiTaskHandler;
import com.project.receive.domain.entity.FeePushLogEntity;
import com.project.receive.domain.service.base.FeePushLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ErpUpdateFeeHandler implements ApiTaskHandler {
@Autowired
private ErpService erpService;
@Autowired
private FeePushLogService feePushLogService;
@Override
public String getActionCode() {
return RetryActionEnum.ERP_UPDATE_FEE.getCode();
}
@Override
public void handle(ApiRetryTaskEntity task, LogisticsOrderEntity order) throws Exception {
log.info(">>> 开始回写运费件数到 ERP,单号: {}", order.getOrderNo());
// 1. 获取顺丰推过来的费用明细 (取最新的一条)
FeePushLogEntity feeLog = feePushLogService.lambdaQuery()
.eq(FeePushLogEntity::getOrderNo, order.getOrderNo())
.orderByDesc(FeePushLogEntity::getCreateTime)
.last("limit 1")
.one();
if (feeLog == null) {
throw new RuntimeException("尚未收到顺丰的计费推送报文,任务等待重试");
}
// 2. 调用 U9 专线执行更新
erpService.updateFeeToErp(
order.getOrderNo(),
feeLog.getItemCount(),
feeLog.getTotalFeeAmt()
);
// 3. 更新费用日志的同步状态
feeLog.setSyncStatus(SyncStatusEnum.SUCCESS.getCode());
feePushLogService.updateById(feeLog);
log.info(">>> ERP 费用回写成功,单号: {}", order.getOrderNo());
}
}

162
src/main/java/com/project/receivedemo/controller/ReceiveDemoController.java

@ -0,0 +1,162 @@
package com.project.receivedemo.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.receivedemo.dto.*;
import com.project.receivedemo.utils.SfDecryptUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.FileOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@Slf4j
@RequestMapping("/api/")
public class ReceiveDemoController {
private static final String SF_CHECKWORD = "ZXmoWOQdSd2UTBmSP6Kv3VW9Q4N5dJqz";
/**
* 接收顺丰订单状态推送接口
* 对应文档 2.6 JSON 示例
*/
@PostMapping("/pushOrderState")
public SfPushResponse receiveOrderState(@RequestBody SfPushRequest request) {
// 1. 打印接收到的原始数据日志
log.info("==== 收到顺丰状态推送 ====");
log.info("Request ID: {}", request.getRequestId());
log.info("Timestamp: {}", request.getTimestamp());
if (request.getOrderState() != null) {
request.getOrderState().forEach(state -> {
log.info("订单号: {}, 运单号: {}, 状态码: {}, 描述: {}",
state.getOrderNo(),
state.getWaybillNo(),
state.getOrderStateCode(),
state.getOrderStateDesc());
});
}
// 2. 根据文档 2.7 节,返回成功响应
return SfPushResponse.ok();
}
/**
* 接收顺丰路由推送
* 对应文档 2.5 JSON 示例
*/
@PostMapping("/pushRoute")
public SfRouteResponse receiveRoute(@RequestBody SfRoutePushRequest request) {
log.info(">>>> 收到顺丰路由信息推送 <<<<");
if (request.getBody() != null && request.getBody().getWaybillRoute() != null) {
for (WaybillRoute route : request.getBody().getWaybillRoute()) {
log.info("运单号: {}, 订单号: {}, 时间: {}, 状态: {}, 备注: {}",
route.getMailno(),
route.getOrderid(),
route.getAcceptTime(),
route.getOpCode(),
route.getRemark());
}
} else {
log.warn("收到的路由数据内容为空");
}
// 根据文档 2.6,必须返回 0000 告知顺丰接收成功,否则顺丰会重复推送
return SfRouteResponse.ok();
}
@RequestMapping("/pushOrderStateRaw")
public String receiveRaw(@RequestBody String rawBody) {
log.info("收到原始报文: {}", rawBody);
// 返回 JSON 格式的成功字符串
return "{\"success\":\"true\",\"code\":\"0\",\"msg\":\"\"}";
}
@Autowired
private ObjectMapper objectMapper;
/**
* 接收顺丰运费推送
* 报文类型: application/x-www-form-urlencoded
*/
@PostMapping(value = "/pushFee", consumes = "application/x-www-form-urlencoded")
public SfFeeResponse receiveFee(
@RequestParam("content") String content,
@RequestParam(value = "sign", required = false) String sign) {
log.info(">>>> 收到顺丰运费推送 <<<<");
log.info("签名(sign): {}", sign);
log.info("原始内容(content): {}", content);
try {
// 将 content 字符串解析为 Java 对象
SfFeeContent feeData = objectMapper.readValue(content, SfFeeContent.class);
log.info("解析成功 - 运单号: {}, 订单号: {}, 计费重量: {}",
feeData.getWaybillNo(),
feeData.getOrderNo(),
feeData.getMeterageWeightQty());
if (feeData.getFeeList() != null) {
feeData.getFeeList().forEach(fee -> {
log.info("费用项 - 类型: {}, 金额: {}", fee.getFeeTypeCode(), fee.getFeeAmt());
});
}
// 返回成功响应 (code 必须为 200)
return SfFeeResponse.ok("your_partner_code");
} catch (Exception e) {
log.error("解析顺丰运费推送失败", e);
SfFeeResponse error = new SfFeeResponse();
error.setCode(400);
error.setMessage("解析异常");
return error;
}
}
@PostMapping("/pushElectronicReceipt")
public SfPicturePushResponse receiveReceipt(@RequestBody SfPicturePushRequest request) {
log.info(">>>> 收到顺丰电子回单(IN149)推送, 运单号: {} <<<<", request.getWaybillNo());
try {
// 步骤 1:解密最外层的 content 得到内部 JSON 字符串
byte[] firstLevelDecrypted = SfDecryptUtil.decrypt(request.getContent(), SF_CHECKWORD);
String innerJsonStr = new String(firstLevelDecrypted, "UTF-8");
log.info("第一层解密成功");
// 步骤 2:解析内部 JSON 获取文件密文
SfInnerContent innerContent = objectMapper.readValue(innerJsonStr, SfInnerContent.class);
String encryptedFileBase64 = innerContent.getContent();
// 步骤 3:对文件密文进行第二层 AES 解密 (根据文档示例,文件内容也是加密的)
// 先 Base64 解码,再 AES 解密
byte[] pdfBytes = SfDecryptUtil.decrypt(encryptedFileBase64, SF_CHECKWORD);
log.info("第二层解密(文件流)成功,大小: {} bytes", pdfBytes.length);
// 步骤 4:保存为 PDF 文件到当前目录
String fileName = request.getWaybillNo() + "_receipt.pdf";
Path path = Paths.get(System.getProperty("user.dir"), fileName);
try (FileOutputStream fos = new FileOutputStream(path.toFile())) {
fos.write(pdfBytes);
fos.flush();
}
log.info("电子回单已保存至: {}", path.toAbsolutePath());
return SfPicturePushResponse.ok();
} catch (Exception e) {
log.error("处理电子回单推送失败", e);
SfPicturePushResponse error = new SfPicturePushResponse();
error.setReturnCode("1000");
error.setReturnMsg("解析保存失败: " + e.getMessage());
return error;
}
}
}

2
src/main/java/com/project/receive/dto/FeeInfo.java → src/main/java/com/project/receivedemo/dto/FeeInfo.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/OrderStateDetail.java → src/main/java/com/project/receivedemo/dto/OrderStateDetail.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/RouteBody.java → src/main/java/com/project/receivedemo/dto/RouteBody.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfFeeContent.java → src/main/java/com/project/receivedemo/dto/SfFeeContent.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfFeeResponse.java → src/main/java/com/project/receivedemo/dto/SfFeeResponse.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfInnerContent.java → src/main/java/com/project/receivedemo/dto/SfInnerContent.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfPicturePushRequest.java → src/main/java/com/project/receivedemo/dto/SfPicturePushRequest.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfPicturePushResponse.java → src/main/java/com/project/receivedemo/dto/SfPicturePushResponse.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfPushRequest.java → src/main/java/com/project/receivedemo/dto/SfPushRequest.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfPushResponse.java → src/main/java/com/project/receivedemo/dto/SfPushResponse.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfRoutePushRequest.java → src/main/java/com/project/receivedemo/dto/SfRoutePushRequest.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

2
src/main/java/com/project/receive/dto/SfRouteResponse.java → src/main/java/com/project/receivedemo/dto/SfRouteResponse.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

2
src/main/java/com/project/receive/dto/WaybillRoute.java → src/main/java/com/project/receivedemo/dto/WaybillRoute.java

@ -1,4 +1,4 @@
package com.project.receive.dto;
package com.project.receivedemo.dto;
import lombok.Data;

2
src/main/java/com/project/receive/utils/SfDecryptUtil.java → src/main/java/com/project/receivedemo/utils/SfDecryptUtil.java

@ -1,4 +1,4 @@
package com.project.receive.utils;
package com.project.receivedemo.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;

4
src/main/resources/application.yml

@ -97,4 +97,6 @@ fixed-rule:
senderPayContact: '王盛荣'
senderMobile: '13480155048'
senderAddress: '广东省广州市番禺区石碁镇南荔东路56号'
monthlyCard: '7551234567'
monthlyCard: '7551234567'
scheduled-task:
owner: local
Loading…
Cancel
Save