From cf01ad029914e3716b92ae3081cc3121a03503b7 Mon Sep 17 00:00:00 2001 From: caojia <1301869380@qq.com> Date: Tue, 22 Sep 2026 10:29:13 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=AE=A2=E6=88=B7=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/TmsOrderBillStatusController.java | 59 +++++++++++++ .../domain/vo/TmsOrderBillStatusResult.java | 47 +++++++++++ .../price/enums/BillCreditArrearsStatus.java | 17 ++++ .../price/enums/BillCustomerActiveStatus.java | 17 ++++ .../price/enums/TmsOrderBillMatchType.java | 39 +++++++++ .../price/mapper/PrcOrderBillMapper.java | 3 + .../price/service/IPrcOrderBillService.java | 4 + .../service/impl/PrcOrderBillServiceImpl.java | 84 ++++++++++++++++++- .../mapper/price/PrcOrderBillMapper.xml | 18 ++++ .../sql/price/tms_order_bill_status_query.sql | 30 +++++++ 10 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TmsOrderBillStatusController.java create mode 100644 bms-back/ruoyi-system/src/main/java/com/ruoyi/price/domain/vo/TmsOrderBillStatusResult.java create mode 100644 bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/TmsOrderBillMatchType.java create mode 100644 bms-back/sql/price/tms_order_bill_status_query.sql diff --git a/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TmsOrderBillStatusController.java b/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TmsOrderBillStatusController.java new file mode 100644 index 00000000..e2ad6854 --- /dev/null +++ b/bms-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TmsOrderBillStatusController.java @@ -0,0 +1,59 @@ +package com.ruoyi.web.controller.api; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.annotation.Anonymous; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.config.properties.TmsApiProperties; +import com.ruoyi.price.domain.vo.TmsOrderBillStatusResult; +import com.ruoyi.price.service.IPrcOrderBillService; + +/** + * TMS 订单客户状态查询接口。 + * + *

该接口不要求登录 Token,但必须携带 X-Api-Code。 + * identifier 会按订单号、运单号、转单号进行精确匹配。

+ */ +@Anonymous +@RestController +@RequestMapping("/api/tms/order-bill") +public class TmsOrderBillStatusController extends BaseController { + private static final String HEADER_API_CODE = "X-Api-Code"; + + @Autowired + private IPrcOrderBillService prcOrderBillService; + + @Autowired + private TmsApiProperties tmsApiProperties; + + /** + * 查询订单对应客户是否正常、额度是否欠费。 + * + *

接口只返回查询事实和状态字段,不判断上游是否继续处理。

+ */ + @GetMapping("/status") + public AjaxResult status( + @RequestHeader(value = HEADER_API_CODE, required = false) String headerApiCode, + @RequestParam(value = "identifier", required = false) String identifier) { + assertApiCode(headerApiCode); + TmsOrderBillStatusResult result = prcOrderBillService.queryTmsOrderBillStatus(identifier); + return success(result); + } + + private void assertApiCode(String headerApiCode) { + String expected = tmsApiProperties.getApiCode(); + if (StringUtils.isEmpty(expected)) { + throw new ServiceException("API_CODE_NOT_CONFIGURED: bms.tms.api-code is empty"); + } + if (StringUtils.isEmpty(headerApiCode) || !expected.equals(headerApiCode.trim())) { + throw new ServiceException("API_CODE_INVALID: missing or invalid X-Api-Code"); + } + } +} diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/domain/vo/TmsOrderBillStatusResult.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/domain/vo/TmsOrderBillStatusResult.java new file mode 100644 index 00000000..93cb0663 --- /dev/null +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/domain/vo/TmsOrderBillStatusResult.java @@ -0,0 +1,47 @@ +package com.ruoyi.price.domain.vo; + +import lombok.Data; + +/** + * TMS 查询订单计费状态的业务结果。 + * + *

该结果不直接返回完整订单计费数据,只返回订单匹配结果和相关状态事实。

+ */ +@Data +public class TmsOrderBillStatusResult { + /** + * 是否查询到计费订单。 + */ + private boolean found; + + /** + * 匹配到的记录数,最多返回 2 条用于判断是否存在歧义。 + */ + private int matchedCount; + + /** + * 命中类型:ORDER_NO/ TRACKING_NO/TRANSFER_NO/MULTIPLE。 + */ + private String matchType; + + /** + * 计费订单标识,仅在唯一命中时返回。 + */ + private String billId; + + private String orderNo; + private String trackingNo; + private String transferNo; + private Long customerId; + private String customerCode; + + /** + * 客户生效状态:ACTIVE/MISSING/DISABLED。 + */ + private String customerActiveStatus; + + /** + * 额度欠费状态:NORMAL/ARREARS。 + */ + private String creditArrearsStatus; +} diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCreditArrearsStatus.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCreditArrearsStatus.java index c7336f51..cb2851ff 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCreditArrearsStatus.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCreditArrearsStatus.java @@ -20,4 +20,21 @@ public enum BillCreditArrearsStatus { return code; } + + /** 将数据库或接口中的状态值转换为枚举;未知值返回 null。 */ + public static BillCreditArrearsStatus of(String code) + { + if (code == null) + { + return null; + } + for (BillCreditArrearsStatus status : values()) + { + if (status.code.equalsIgnoreCase(code.trim())) + { + return status; + } + } + return null; + } } diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCustomerActiveStatus.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCustomerActiveStatus.java index 9d4be226..aa68f813 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCustomerActiveStatus.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/BillCustomerActiveStatus.java @@ -21,4 +21,21 @@ public enum BillCustomerActiveStatus { return code; } + + /** 将数据库或接口中的状态值转换为枚举;未知值返回 null。 */ + public static BillCustomerActiveStatus of(String code) + { + if (code == null) + { + return null; + } + for (BillCustomerActiveStatus status : values()) + { + if (status.code.equalsIgnoreCase(code.trim())) + { + return status; + } + } + return null; + } } diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/TmsOrderBillMatchType.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/TmsOrderBillMatchType.java new file mode 100644 index 00000000..9bbbc9a8 --- /dev/null +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/enums/TmsOrderBillMatchType.java @@ -0,0 +1,39 @@ +package com.ruoyi.price.enums; + +/** + * TMS 查询订单计费数据时的标识匹配类型。 + */ +public enum TmsOrderBillMatchType { + /** + * 按订单号匹配。 + */ + ORDER_NO("ORDER_NO", "订单号"), + /** + * 按运单号匹配。 + */ + TRACKING_NO("TRACKING_NO", "运单号"), + /** + * 按转单号匹配。 + */ + TRANSFER_NO("TRANSFER_NO", "转单号"), + /** + * 同一标识匹配到多条记录,无法唯一确定订单。 + */ + MULTIPLE("MULTIPLE", "多条匹配"); + + private final String code; + private final String label; + + TmsOrderBillMatchType(String code, String label) { + this.code = code; + this.label = label; + } + + public String getCode() { + return code; + } + + public String getLabel() { + return label; + } +} diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/mapper/PrcOrderBillMapper.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/mapper/PrcOrderBillMapper.java index 2d22ea67..265d85a7 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/mapper/PrcOrderBillMapper.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/mapper/PrcOrderBillMapper.java @@ -13,6 +13,9 @@ public interface PrcOrderBillMapper public PrcOrderBill selectPrcOrderBillByTransferNo(String transferNo); + /** TMS 状态查询:按订单号、运单号或转单号精确匹配,最多返回两条用于识别歧义。 */ + List selectPrcOrderBillByTmsIdentifier(@Param("identifier") String identifier); + public PrcOrderBill selectPrcOrderBillById(String billId); public List selectPrcOrderBillList(PrcOrderBill bill); diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcOrderBillService.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcOrderBillService.java index 2c9f7cd6..9a03e35c 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcOrderBillService.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/IPrcOrderBillService.java @@ -4,6 +4,7 @@ import java.util.List; import com.ruoyi.price.domain.PrcOrderBill; import com.ruoyi.price.domain.vo.TmsPriceBillRequest; import com.ruoyi.price.domain.vo.TmsPriceQuoteResult; +import com.ruoyi.price.domain.vo.TmsOrderBillStatusResult; /** 订单计费:落库 prc_order_bill + prc_income_bill/+fee + prc_pay_bill/+fee。 */ public interface IPrcOrderBillService @@ -24,4 +25,7 @@ public interface IPrcOrderBillService TmsPriceQuoteResult getBill(String billId); TmsPriceQuoteResult getBillByOrderNo(String orderNo); + + /** 提供给 TMS 判断订单是否可以继续处理的客户状态查询。 */ + TmsOrderBillStatusResult queryTmsOrderBillStatus(String identifier); } diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcOrderBillServiceImpl.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcOrderBillServiceImpl.java index aff29cef..bf8cff81 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcOrderBillServiceImpl.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/price/service/impl/PrcOrderBillServiceImpl.java @@ -27,10 +27,12 @@ import com.ruoyi.price.domain.PrcOrderBillExt; import com.ruoyi.price.domain.PrcPayBill; import com.ruoyi.price.domain.PrcPayBillFee; import com.ruoyi.price.domain.vo.TmsPriceBillRequest; +import com.ruoyi.price.domain.vo.TmsOrderBillStatusResult; import com.ruoyi.price.domain.vo.TmsPriceQuoteFeeLine; import com.ruoyi.price.domain.vo.TmsPriceQuoteResult; import com.ruoyi.price.enums.BillCreditArrearsStatus; import com.ruoyi.price.enums.BillCustomerActiveStatus; +import com.ruoyi.price.enums.TmsOrderBillMatchType; import com.ruoyi.price.mapper.PrcIncomeBillFeeMapper; import com.ruoyi.price.mapper.PrcIncomeBillMapper; import com.ruoyi.price.mapper.PrcOrderBillExtMapper; @@ -199,6 +201,85 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService payBillFeeMapper.selectByBillId(bill.getBillId())); } + /** 查询 TMS 后续流程所需的客户状态,只返回订单数据和状态事实,不代替上游做业务决策。 */ + @Override + @Transactional(readOnly = true) + public TmsOrderBillStatusResult queryTmsOrderBillStatus(String identifier) + { + String value = StringUtils.trim(identifier); + if (StringUtils.isEmpty(value)) + { + throw new ServiceException("订单号、运单号或转单号不能为空"); + } + if (value.length() > 64) + { + throw new ServiceException("订单号、运单号或转单号长度不能超过64个字符"); + } + + List bills = orderBillMapper.selectPrcOrderBillByTmsIdentifier(value); + if (bills == null || bills.isEmpty()) + { + TmsOrderBillStatusResult result = new TmsOrderBillStatusResult(); + result.setMatchedCount(0); + return result; + } + if (bills.size() > 1) + { + TmsOrderBillStatusResult result = new TmsOrderBillStatusResult(); + result.setFound(true); + result.setMatchedCount(bills.size()); + result.setMatchType(TmsOrderBillMatchType.MULTIPLE.getCode()); + return result; + } + + PrcOrderBill bill = bills.get(0); + TmsOrderBillStatusResult result = new TmsOrderBillStatusResult(); + result.setFound(true); + result.setMatchedCount(1); + result.setMatchType(resolveTmsMatchType(value, bill).getCode()); + result.setBillId(bill.getBillId()); + result.setOrderNo(bill.getOrderNo()); + result.setTrackingNo(bill.getTrackingNo()); + result.setTransferNo(bill.getTransferNo()); + result.setCustomerId(bill.getCustomerId()); + result.setCustomerCode(bill.getCustomerCode()); + result.setCustomerActiveStatus(normalizeCustomerActiveStatus(bill.getCustomerActiveStatus())); + result.setCreditArrearsStatus(normalizeCreditArrearsStatus(bill.getCreditArrearsStatus())); + return result; + } + + private TmsOrderBillMatchType resolveTmsMatchType(String identifier, PrcOrderBill bill) + { + if (identifier.equalsIgnoreCase(StringUtils.trim(bill.getOrderNo()))) + { + return TmsOrderBillMatchType.ORDER_NO; + } + if (identifier.equalsIgnoreCase(StringUtils.trim(bill.getTrackingNo()))) + { + return TmsOrderBillMatchType.TRACKING_NO; + } + return TmsOrderBillMatchType.TRANSFER_NO; + } + + private String normalizeCustomerActiveStatus(String status) + { + BillCustomerActiveStatus statusEnum = BillCustomerActiveStatus.of(status); + return statusEnum == null ? normalizeUnknownStatus(status) : statusEnum.getCode(); + } + + private String normalizeCreditArrearsStatus(String status) + { + BillCreditArrearsStatus statusEnum = BillCreditArrearsStatus.of(status); + return statusEnum == null ? normalizeUnknownStatus(status) : statusEnum.getCode(); + } + + /** 保留未知状态的原始值(统一为大写),便于上游识别新状态或脏数据。 */ + private String normalizeUnknownStatus(String status) + { + String normalized = StringUtils.trim(status); + return StringUtils.isEmpty(normalized) ? null : normalized.toUpperCase(); + } + private void persistBill(TmsPriceBillRequest request, BigDecimal weight, Date bizDate, TmsPriceQuoteResult result) { @@ -390,7 +471,8 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService cmd.setAmount(delta.abs()); customerAccountApi.releaseCredit(cmd); } - saveCreditEsLog(bill, cmd, action, true, markArrears ? "ARREARS" : null); + saveCreditEsLog(bill, cmd, action, true, + markArrears ? BillCreditArrearsStatus.ARREARS.getCode() : null); return markArrears ? arrears : normal; } catch (RuntimeException e) diff --git a/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml b/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml index de1eb16a..53a93b78 100644 --- a/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml +++ b/bms-back/ruoyi-system/src/main/resources/mapper/price/PrcOrderBillMapper.xml @@ -104,6 +104,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" limit 1 + + +