Browse Source

调接口逻辑

master
luoweijian 2 weeks ago
parent
commit
317437ddba
  1. 90
      src/main/java/com/project/logistics/controller/PrintController.java
  2. 45
      src/main/java/com/project/logistics/domain/entity/PrintMachineEntity.java
  3. 44
      src/main/java/com/project/logistics/domain/entity/PrintRecordEntity.java
  4. 20
      src/main/java/com/project/logistics/domain/scheduler/SampleOrderScannerJob.java
  5. 8
      src/main/java/com/project/logistics/domain/service/base/PrintMachineService.java
  6. 9
      src/main/java/com/project/logistics/domain/service/base/PrintRecordService.java
  7. 37
      src/main/java/com/project/logistics/domain/service/base/impl/PrintMachineServiceImpl.java
  8. 21
      src/main/java/com/project/logistics/domain/service/base/impl/PrintRecordServiceImpl.java
  9. 39
      src/main/java/com/project/logistics/domain/strategy/handler/SfCreateOrderHandler.java
  10. 9
      src/main/java/com/project/logistics/mapper/PrintMachineMapper.java
  11. 9
      src/main/java/com/project/logistics/mapper/PrintRecordMapper.java
  12. 2
      src/main/resources/application.yml

90
src/main/java/com/project/logistics/controller/PrintController.java

@ -0,0 +1,90 @@
package com.project.logistics.controller;
import com.project.logistics.domain.entity.PrintRecordEntity;
import com.project.logistics.domain.service.base.PrintMachineService;
import com.project.logistics.domain.service.base.PrintRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/api/logistics/print")
public class PrintController {
@Autowired
private PrintRecordService printRecordService;
@Autowired
private PrintMachineService printMachineService;
/**
* 1. 询问接口我这台机器是否打过这张单
* @return "true" 代表没打过允许打印"false" 代表已打过
*/
@GetMapping("/check")
public String check(@RequestParam("orderNo") String orderNo,
@RequestParam("machineId") String machineId) {
// 只查询打印记录表
boolean alreadyPrinted = printRecordService.lambdaQuery()
.eq(PrintRecordEntity::getOrderNo, orderNo)
.eq(PrintRecordEntity::getMachineId, machineId)
.eq(PrintRecordEntity::getPrintStatus, 1)
.count() > 0;
if (alreadyPrinted) {
return "false";
}
log.info(">>> 机器 {} 请求打印新单据: {}", machineId, orderNo);
return "true";
}
@PostMapping("/heartbeat")
public Map<String, Object> heartbeat(@RequestBody Map<String, Object> params) {
String machineId = (String) params.get("machineId");
String status = (String) params.get("status");
// 更新机器状态和时间
printMachineService.updateHeartbeat(machineId, status);
return Map.of("code", 200, "msg", "pong");
}
/**
* 2. 反馈接口打印成功请记录
*/
@PostMapping("/callback")
public Map<String, Object> callback(@RequestBody Map<String, Object> params) {
String orderNo = (String) params.get("orderNo");
String machineId = (String) params.get("machineId");
Integer printStatus = (Integer) params.get("printStatus");
// 记录或更新打印日志
PrintRecordEntity record = printRecordService.lambdaQuery()
.eq(PrintRecordEntity::getOrderNo, orderNo)
.eq(PrintRecordEntity::getMachineId, machineId)
.one();
if (record == null) {
record = new PrintRecordEntity();
record.setOrderNo(orderNo);
record.setMachineId(machineId);
}
record.setPrintStatus(printStatus);
printRecordService.saveOrUpdate(record);
if (printStatus == 1) {
log.info(">>> 单据 {} 物理打印成功 (机器: {})", orderNo, machineId);
} else {
log.warn(">>> 单据 {} 物理打印失败 (机器: {})", orderNo, machineId);
}
return Map.of("code", 200, "msg", "received");
}
}

45
src/main/java/com/project/logistics/domain/entity/PrintMachineEntity.java

@ -0,0 +1,45 @@
package com.project.logistics.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "auto_print_machine", indexes = {
@Index(name = "idx_machine_id", columnList = "machine_id", unique = true)
})
@TableName("auto_print_machine")
@Comment("打印机在线状态表")
public class PrintMachineEntity extends BaseEntity {
@Id
@Column(name = "id", columnDefinition = "bigint(20) comment '主键ID'")
private Long id;
@Comment("机器标识 (MAC地址或PC名)")
@Column(name = "machine_id", length = 100, nullable = false)
@TableField("machine_id")
private String machineId;
@Comment("最后心跳时间")
@Column(name = "last_heartbeat_time")
@TableField("last_heartbeat_time")
private LocalDateTime lastHeartbeatTime;
@Comment("在线状态 (ONLINE/OFFLINE)")
@Column(name = "status", length = 20)
@TableField("status")
private String status;
@Comment("客户端版本号")
@Column(name = "client_version", length = 20)
@TableField("client_version")
private String clientVersion;
}

44
src/main/java/com/project/logistics/domain/entity/PrintRecordEntity.java

@ -0,0 +1,44 @@
package com.project.logistics.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.project.base.domain.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Comment;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "auto_print_record", indexes = {
@Index(name = "idx_print_order_no", columnList = "order_no", unique = true)
})
@TableName("auto_print_record")
@Comment("面单物理打印记录表")
public class PrintRecordEntity extends BaseEntity {
@Id
@Column(name = "id", columnDefinition = "bigint(20) comment '主键ID'")
private Long id;
@Comment("业务单号 (U9单号)")
@Column(name = "order_no", length = 64, nullable = false)
@TableField("order_no")
private String orderNo;
@Comment("执行打印的机器标识 (MAC地址或PC名)")
@Column(name = "machine_id", length = 100)
@TableField("machine_id")
private String machineId;
@Comment("打印时的文件MD5 (校验用)")
@Column(name = "file_md5", length = 64)
@TableField("file_md5")
private String fileMd5;
@Comment("打印状态 (1:成功)")
@Column(name = "status")
@TableField("status")
private Integer printStatus;
}

20
src/main/java/com/project/logistics/domain/scheduler/SampleOrderScannerJob.java

@ -131,16 +131,16 @@ public class SampleOrderScannerJob {
return false;
}
// 获取今天的日期字符串 (格式: yyyy-MM-dd)
String today = cn.hutool.core.date.DateUtil.today();
// 截取 U9 时间字符串的前 10 位进行比较 (防止 U9 返回的是 yyyy-MM-dd HH:mm:ss)
String actualSendDate = actualSendTimeStr.trim().substring(0, 10);
if (!today.equals(actualSendDate)) {
log.info("样品单号 {} 实际发货时间 [{}] 不是当天 [{}], 不执行自动下单",
orderNo, actualSendDate, today);
return false;
}
// // 获取今天的日期字符串 (格式: yyyy-MM-dd)
// String today = cn.hutool.core.date.DateUtil.today();
// // 截取 U9 时间字符串的前 10 位进行比较 (防止 U9 返回的是 yyyy-MM-dd HH:mm:ss)
// String actualSendDate = actualSendTimeStr.trim().substring(0, 10);
//
// if (!today.equals(actualSendDate)) {
// log.info("样品单号 {} 实际发货时间 [{}] 不是当天 [{}], 不执行自动下单",
// orderNo, actualSendDate, today);
// return false;
// }
// 持久化订单:跳过上传资源步骤,直接设置为 RESOURCE_CREATED
LogisticsOrderEntity order = new LogisticsOrderEntity();

8
src/main/java/com/project/logistics/domain/service/base/PrintMachineService.java

@ -0,0 +1,8 @@
package com.project.logistics.domain.service.base;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.logistics.domain.entity.PrintMachineEntity;
public interface PrintMachineService extends IService<PrintMachineEntity> {
void updateHeartbeat(String machineId, String status);
}

9
src/main/java/com/project/logistics/domain/service/base/PrintRecordService.java

@ -0,0 +1,9 @@
package com.project.logistics.domain.service.base;
import com.baomidou.mybatisplus.extension.service.IService;
import com.project.logistics.domain.entity.PrintRecordEntity;
public interface PrintRecordService extends IService<PrintRecordEntity> {
boolean isPrintedByThisMachine(String orderNo, String machineId);
}

37
src/main/java/com/project/logistics/domain/service/base/impl/PrintMachineServiceImpl.java

@ -0,0 +1,37 @@
package com.project.logistics.domain.service.base.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.logistics.domain.entity.PrintMachineEntity;
import com.project.logistics.domain.service.base.PrintMachineService;
import com.project.logistics.mapper.PrintMachineMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
@Slf4j
public class PrintMachineServiceImpl extends ServiceImpl<PrintMachineMapper, PrintMachineEntity>
implements PrintMachineService {
@Override
@Transactional(rollbackFor = Exception.class)
public void updateHeartbeat(String machineId, String status) {
// 使用 MyBatis-Plus 的 LambdaQuery 检查是否存在记录
PrintMachineEntity machine = this.lambdaQuery()
.eq(PrintMachineEntity::getMachineId, machineId)
.one();
if (machine == null) {
machine = new PrintMachineEntity();
machine.setMachineId(machineId);
}
machine.setStatus(status);
machine.setLastHeartbeatTime(LocalDateTime.now());
// 保存或更新
this.saveOrUpdate(machine);
}
}

21
src/main/java/com/project/logistics/domain/service/base/impl/PrintRecordServiceImpl.java

@ -0,0 +1,21 @@
package com.project.logistics.domain.service.base.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.logistics.domain.entity.PrintRecordEntity;
import com.project.logistics.domain.service.base.PrintRecordService;
import com.project.logistics.mapper.PrintRecordMapper;
import org.springframework.stereotype.Service;
@Service
public class PrintRecordServiceImpl extends ServiceImpl<PrintRecordMapper, PrintRecordEntity>
implements PrintRecordService {
@Override
public boolean isPrintedByThisMachine(String orderNo, String machineId) {
return this.lambdaQuery()
.eq(PrintRecordEntity::getOrderNo, orderNo)
.eq(PrintRecordEntity::getMachineId, machineId)
.eq(PrintRecordEntity::getPrintStatus, 1)
.count() > 0; }
}

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

@ -76,32 +76,39 @@ public class SfCreateOrderHandler implements ApiTaskHandler {
String transportMethod = u9Data.getString(ShipmentOrderInfoFieldEnum.transportMethod.name());
if (StrUtil.isBlank(transportMethod) || !transportMethod.contains("顺丰")) {
// 需要终止任务,匹配字段失败,失败原因:运输方式及货场名称不为顺丰
terminateBusinessTask(task, order, "匹配字段失败:运输方式及货场名称不为顺丰 (" + transportMethod + ")");
return;
throw new RuntimeException("校验不通过,等待重试:运输方式及货场名称不为顺丰 (" + transportMethod + ")");
}
String payer = u9Data.getString(ShipmentOrderInfoFieldEnum.payer.name());
SfPayMethodEnum senderPayByU9Desc = SfPayMethodEnum.getSenderPayByU9Desc(payer);
if (Objects.isNull(senderPayByU9Desc)) {
// 需要终止任务,匹配字段失败,失败原因:运费承担字段匹配失败
terminateBusinessTask(task, order, "匹配字段失败:运费承担字段 (" + payer + ") 无法匹配顺丰付款方式");
return;
throw new RuntimeException("校验不通过,等待重试:运费承担字段 (" + payer + ") 无法匹配顺丰付款方式");
}
String expressType = u9Data.getString(ShipmentOrderInfoFieldEnum.expressType.name());
SfExpressTypeEnum sfStandardExpressByCode = SfExpressTypeEnum.getSfStandardExpressByCode(expressType);
if (Objects.isNull(sfStandardExpressByCode)) {
// 需要终止任务,匹配字段失败,失败原因:未匹配快件产品类别
terminateBusinessTask(task, order, "匹配字段失败:单据产品类别 (" + expressType + ") 未匹配到顺丰业务类型");
return;
throw new RuntimeException("校验不通过,等待重试:单据产品类别 (" + expressType + ") 未匹配到顺丰业务类型");
}
if (StrUtil.equals(order.getOrderType() , OrderTypeEnum.SHIPMENT.name()) &&
StrUtil.isBlank(order.getResourceCode())) {
terminateBusinessTask(task, order, "常规出货单缺少资源编码");
return;
throw new RuntimeException("校验不通过,等待重试:常规出货单缺少资源编码");
}
String recipientContact = u9Data.getString(ShipmentOrderInfoFieldEnum.recipientContact.name());
if (StrUtil.isBlank(recipientContact)) {
throw new RuntimeException("校验不通过,等待重试:收货人不能为空");
}
String sendContact = SfPayMethodEnum.SENDER_PAY.equals(senderPayByU9Desc) ?
u9Data.getString(ShipmentOrderInfoFieldEnum.salesman.name()) :
fixedRuleProperties.getSenderPayContact();
if (StrUtil.isBlank(sendContact)) {
throw new RuntimeException("校验不通过,等待重试:寄件人不能为空");
}
msgData.put("cargoDesc", "交换机");
JSONArray cargoDetails = new JSONArray();
JSONObject item = new JSONObject();
@ -116,9 +123,7 @@ public class SfCreateOrderHandler implements ApiTaskHandler {
JSONObject sender = new JSONObject();
sender.put("contactType", SfContactTypeEnum.SENDER.getCode());
// 寄付取业务的名字,到付取固定
sender.put("contact", SfPayMethodEnum.SENDER_PAY.equals(senderPayByU9Desc) ?
u9Data.getString(ShipmentOrderInfoFieldEnum.salesman.name()) :
fixedRuleProperties.getSenderPayContact());
sender.put("contact", sendContact);
sender.put("mobile", fixedRuleProperties.getSenderMobile());
sender.put("address", fixedRuleProperties.getSenderAddress());
contactInfoList.add(sender);
@ -126,7 +131,7 @@ public class SfCreateOrderHandler implements ApiTaskHandler {
// 收件方 (从 U9 快照中动态获取)
JSONObject receiver = new JSONObject();
receiver.put("contactType", SfContactTypeEnum.RECIPIENT.getCode());
receiver.put("contact", u9Data.getString(ShipmentOrderInfoFieldEnum.recipientContact.name()));
receiver.put("contact", recipientContact);
receiver.put("mobile", u9Data.getString(ShipmentOrderInfoFieldEnum.recipientMobile.name()));
receiver.put("address", u9Data.getString(ShipmentOrderInfoFieldEnum.recipientAddress.name()));
contactInfoList.add(receiver);
@ -217,10 +222,8 @@ public class SfCreateOrderHandler implements ApiTaskHandler {
logisticsOrderService.updateById(order);
// 2. 将当前任务设为取消/死信状态,防止定时任务继续重试
task.setTaskStatus(TaskStatusEnum.CANCELLED.getCode());
task.setTaskStatus(TaskStatusEnum.FAILED.getCode());
task.setErrorMessage(reason);
// 注意:任务表的最终 update 会由 ApiRetryJob 在 handle 执行完后统一处理
// 此处抛出一个特定异常或正常返回即可。由于 ApiRetryJob 会根据异常重试,
// 我们这里选择不抛异常,让 ApiRetryJob 认为执行“结束”了(但状态已改)。
}
}

9
src/main/java/com/project/logistics/mapper/PrintMachineMapper.java

@ -0,0 +1,9 @@
package com.project.logistics.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.logistics.domain.entity.PrintMachineEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PrintMachineMapper extends BaseMapper<PrintMachineEntity> {
}

9
src/main/java/com/project/logistics/mapper/PrintRecordMapper.java

@ -0,0 +1,9 @@
package com.project.logistics.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.project.logistics.domain.entity.PrintRecordEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PrintRecordMapper extends BaseMapper<PrintRecordEntity> {
}

2
src/main/resources/application.yml

@ -115,4 +115,4 @@ fixed-rule:
senderAddress: '广东省广州市番禺区石碁镇南荔东路56号'
monthlyCard: '7551234567'
scheduled-task:
owner: test
owner: local
Loading…
Cancel
Save