diff --git a/bms-back/doc/TMS订单账单状态查询接口说明.md b/bms-back/doc/TMS订单账单状态查询接口说明.md index 7d3218de..9dd2cc3c 100644 --- a/bms-back/doc/TMS订单账单状态查询接口说明.md +++ b/bms-back/doc/TMS订单账单状态查询接口说明.md @@ -2,7 +2,7 @@ ## 1. 接口用途 -TMS 根据订单号、运单号或转单号查询 BMS 中的订单计费记录,以及该订单对应的客户状态和额度状态。 +TMS 根据订单号、运单号或转单号查询 BMS 中的订单计费记录,并获取该订单关联客户的当前启用状态和订单计费记录中的欠费状态快照。 ## 2. 基本信息 @@ -31,7 +31,7 @@ TMS 根据订单号、运单号或转单号查询 BMS 中的订单计费记录 | 参数名 | 类型 | 必填 | 长度 | 说明 | |---|---|---|---|---| -| `identifier` | String | 是 | 1~64 | 订单号、运单号或转单号,三者只传一个 | +| `identifier` | String | 是 | 1~64 | 单个订单号、运单号或转单号 | 接口会对 `identifier` 做首尾空格清理,然后使用精确匹配: @@ -41,7 +41,9 @@ OR tracking_no = identifier OR transfer_no = identifier ``` -请勿传递模糊查询字符,也不要在一次请求中传递多个 `identifier`。 +请勿传递模糊查询字符,也不要在一次请求中传递多个 `identifier`。同一标识命中多条订单时,接口不会任选其中一条返回。 + +若同一条订单的多个字段恰好与 `identifier` 相同,`matchType` 按 `ORDER_NO`、`TRACKING_NO`、`TRANSFER_NO` 的顺序返回。 ## 4. 请求示例 @@ -89,17 +91,18 @@ curl --location \ | 字段 | 类型 | 说明 | |---|---|---| -| `found` | Boolean | 是否查询到数据 | -| `matchedCount` | Integer | 匹配记录数;接口最多统计返回 `2`,大于 `1` 表示存在歧义 | -| `matchType` | String | 唯一命中类型:`ORDER_NO`、`TRACKING_NO`、`TRANSFER_NO`;多条匹配为 `MULTIPLE` | +| `found` | Boolean | 是否查询到订单计费记录;订单不存在时为 `false` | +| `matchedCount` | Integer | 匹配记录数;接口最多读取 `2` 条,返回 `2` 表示至少匹配到两条,存在歧义 | +| `matchType` | String | `NOT_FOUND` 未找到订单;唯一命中为 `ORDER_NO`、`TRACKING_NO`、`TRANSFER_NO`;多条匹配为 `MULTIPLE` | | `billId` | String | BMS 计费订单 ID;唯一命中时返回 | | `orderNo` | String | 订单号;唯一命中时返回 | | `trackingNo` | String | 运单号;唯一命中时返回 | | `transferNo` | String | 转单号;唯一命中时返回 | -| `customerId` | Long | 客户 ID;唯一命中时返回 | -| `customerCode` | String | 客户编码;唯一命中时返回 | +| `customerId` | Long | 订单计费记录保存的客户 ID;唯一命中时返回,不代表当前客户档案一定存在 | +| `customerCode` | String | 订单计费记录保存的客户编码;唯一命中时返回,不代表当前客户档案一定存在 | +| `customerFound` | Boolean | 当前客户是否存在;唯一命中时返回;订单未找到或多条匹配时为 `null` | | `customerActiveStatus` | String | 客户生效状态:`ACTIVE` 正常、`MISSING` 不存在、`DISABLED` 停用 | -| `creditArrearsStatus` | String | 额度欠费状态:`NORMAL` 正常、`ARREARS` 欠费 | +| `creditArrearsStatus` | String | 订单计费记录当前保存的额度欠费状态快照:`NORMAL` 正常、`ARREARS` 欠费 | ## 6. 返回示例 @@ -119,6 +122,7 @@ curl --location \ "transferNo": "TRANSFER001", "customerId": 140, "customerCode": "C00142", + "customerFound": true, "customerActiveStatus": "ACTIVE", "creditArrearsStatus": "NORMAL" } @@ -133,12 +137,14 @@ curl --location \ "msg": "操作成功", "data": { "found": false, - "matchedCount": 0 + "matchedCount": 0, + "matchType": "NOT_FOUND", + "customerFound": null } } ``` -未命中时不会返回客户或账单数据。是否继续后续流程由 TMS 根据自身业务规则决定。 +未命中时不会查询客户档案,也不会返回账单、客户或状态数据。逻辑上的 `customerFound`、`customerActiveStatus`、`creditArrearsStatus` 均为 `null`;实际 JSON 是否省略 `null` 字段取决于 BMS 的序列化配置。 ### 6.3 匹配到多条数据 @@ -149,12 +155,63 @@ curl --location \ "data": { "found": true, "matchedCount": 2, - "matchType": "MULTIPLE" + "matchType": "MULTIPLE", + "customerFound": null } } ``` -匹配多条时,接口不随机返回其中一条账单详情。TMS 应根据自身规则处理该结果;如需唯一查询,优先使用唯一的订单号。 +匹配多条时,接口不查询客户档案,也不随机返回其中一条账单详情;`matchedCount=2` 表示至少两条。TMS 应根据自身规则处理该结果;如需唯一查询,优先使用唯一的订单号。 + +### 6.4 订单存在但客户不存在 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "found": true, + "matchedCount": 1, + "matchType": "ORDER_NO", + "billId": "4c1f0d1e-6f6d-4a5e-9ab5-7a7f5d3b6e01", + "orderNo": "TMS20260918005496762601", + "trackingNo": "UBI89033506177CN", + "transferNo": "TRANSFER001", + "customerId": 140, + "customerCode": "C00142", + "customerFound": false, + "customerActiveStatus": "MISSING", + "creditArrearsStatus": "ARREARS" + } +} +``` + +`MISSING` 表示订单存在,但根据订单中的 `customerId` 未找到有效客户,包括客户不存在、已逻辑删除或客户 ID 为空/无效。此时 `customerActiveStatus` 返回 `MISSING`。 + +`creditArrearsStatus` 与客户当前是否存在相互独立,仍按 `prc_order_bill.credit_arrears_status` 的订单快照返回,不代表客户当前实时欠费状态;如果订单快照本身为空,则返回 `null`。 + +### 6.5 订单存在且客户已停用 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "found": true, + "matchedCount": 1, + "matchType": "TRACKING_NO", + "billId": "4c1f0d1e-6f6d-4a5e-9ab5-7a7f5d3b6e02", + "orderNo": "TMS20260918005496762602", + "trackingNo": "UBI89033506178CN", + "transferNo": "TRANSFER002", + "customerId": 141, + "customerCode": "C00143", + "customerFound": true, + "customerActiveStatus": "DISABLED", + "creditArrearsStatus": "NORMAL" + } +} +``` ## 7. 状态字段说明 @@ -162,20 +219,19 @@ curl --location \ | 值 | 含义 | |---|---| -| `ACTIVE` | 客户存在且正常生效 | -| `MISSING` | 未找到对应客户 | -| `DISABLED` | 客户存在但已停用 | -| 其他非空值 | BMS 保留并原样转大写返回,供 TMS 识别新状态或异常数据 | -| `null` | BMS 中该状态为空 | +| `ACTIVE` | `bms_customer.is_enable = '0'`,客户存在且正常生效 | +| `MISSING` | 订单存在,但未找到对应的有效客户;包括客户不存在、已逻辑删除或客户 ID 无效 | +| `DISABLED` | `bms_customer.is_enable = '1'`,客户存在但已停用;客户启用状态为空或异常时也按非正常状态返回 `DISABLED` | +| `null` | 订单不存在或匹配到多条订单时,不判断客户状态 | ### 7.2 额度欠费状态 `creditArrearsStatus` | 值 | 含义 | |---|---| -| `NORMAL` | 额度正常 | -| `ARREARS` | 额度欠费 | -| 其他非空值 | BMS 保留并原样转大写返回,供 TMS 识别新状态或异常数据 | -| `null` | BMS 中该状态为空 | +| `NORMAL` | 订单计费记录中保存的额度正常快照 | +| `ARREARS` | 订单计费记录中保存的额度欠费快照 | +| 其他非空值 | BMS 保留并原样转大写返回,表示订单快照数据异常或扩展状态 | +| `null` | 订单计费记录中的该状态为空;订单不存在或多条匹配时也不返回该状态 | ## 8. 异常情况 @@ -183,10 +239,13 @@ curl --location \ |---|---| | 缺少 `X-Api-Code` | 请求失败,返回 `API_CODE_INVALID` | | `X-Api-Code` 错误 | 请求失败,返回 `API_CODE_INVALID` | +| BMS 未配置 `X-Api-Code` | 请求失败,返回 `API_CODE_NOT_CONFIGURED` | | `identifier` 为空或全为空格 | 请求失败,提示标识不能为空 | | `identifier` 超过 64 个字符 | 请求失败,提示标识长度不能超过 64 个字符 | -| 数据库未查询到记录 | HTTP 业务响应正常,`data.found=false` | +| 数据库未查询到订单记录 | HTTP 业务响应正常,`data.found=false`、`data.matchType=NOT_FOUND` | +| 订单存在但客户不存在 | HTTP 业务响应正常,`data.found=true`、`data.customerFound=false`、`data.customerActiveStatus=MISSING` | | 同一标识匹配多条记录 | HTTP 业务响应正常,`data.matchType=MULTIPLE` | +| 数据库或系统异常 | 请求失败,不会伪装为 `NOT_FOUND` 或 `MISSING`;TMS 应按非 `200` 的业务响应处理 | > 当前项目统一使用 `AjaxResult` 返回异常,具体 HTTP 状态码以 BMS 网关和全局异常处理配置为准。TMS 集成时应优先判断响应体中的 `code`,再读取 `data`。 @@ -194,8 +253,9 @@ curl --location \ 1. TMS 每次只传一个 `identifier`,不要同时传订单号、运单号和转单号。 2. 先判断响应体 `code` 是否为 `200`,再判断 `data.found`。 -3. `found=false`、`matchedCount>1`、状态为空或出现未知状态时,不要当作唯一有效订单使用;具体处理策略由 TMS 自行决定。 -4. 建议设置连接超时和读取超时,并对网络异常进行有限次数重试;查询接口本身是只读接口,可安全重试。 -5. `X-Api-Code` 属于接口凭证,应通过配置中心或密钥管理方式保存,不要硬编码到 TMS 代码仓库或日志中。 - - +3. `found=false` 且 `matchType=NOT_FOUND` 表示订单不存在;此时不应把客户状态为空理解为客户不存在。 +4. `found=true` 且 `customerFound=false` 表示订单存在但客户不存在;`matchedCount>1` 或 `matchType=MULTIPLE` 表示订单匹配有歧义;具体处理策略由 TMS 自行决定。 +5. `customerActiveStatus` 只返回 `ACTIVE`、`MISSING`、`DISABLED` 三种约定状态;只有 `ACTIVE` 表示客户当前启用,其他状态由 TMS 根据自身规则处理。 +6. `creditArrearsStatus` 是订单计费记录中的状态快照,不代表客户当前实时额度状态。 +7. 建议设置连接超时和读取超时,并对网络异常进行有限次数重试;查询接口本身是只读接口,可安全重试。 +8. `X-Api-Code` 属于接口凭证,应通过配置中心或密钥管理方式保存,不要硬编码到 TMS 代码仓库或日志中。 diff --git a/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customerinfo/mapper/BmsCustomerMapper.java b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customerinfo/mapper/BmsCustomerMapper.java index 672e5ad8..c015ff53 100644 --- a/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customerinfo/mapper/BmsCustomerMapper.java +++ b/bms-back/ruoyi-system/src/main/java/com/ruoyi/customer/customerinfo/mapper/BmsCustomerMapper.java @@ -23,6 +23,9 @@ public interface BmsCustomerMapper */ public BmsCustomer selectBmsCustomerByCustomerId(Long customerId); + /** 轻量查询客户当前状态;不存在或已逻辑删除时返回 null。 */ + public BmsCustomer selectCustomerStatusByCustomerId(Long customerId); + /** * 只取客户档案物理额度列(credit_ed 在通用查询里是账户可用额度的子查询别名, * 账户首次初始化时必须读取档案原始值) 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 index 93cb0663..2b9d54a8 100644 --- 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 @@ -20,7 +20,7 @@ public class TmsOrderBillStatusResult { private int matchedCount; /** - * 命中类型:ORDER_NO/ TRACKING_NO/TRANSFER_NO/MULTIPLE。 + * 命中类型:NOT_FOUND/ORDER_NO/TRACKING_NO/TRANSFER_NO/MULTIPLE。 */ private String matchType; @@ -35,6 +35,11 @@ public class TmsOrderBillStatusResult { private Long customerId; private String customerCode; + /** + * 订单关联的当前客户是否存在;订单未找到或匹配到多条时为 null。 + */ + private Boolean customerFound; + /** * 客户生效状态:ACTIVE/MISSING/DISABLED。 */ 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 index 9bbbc9a8..a22b1c36 100644 --- 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 @@ -4,6 +4,8 @@ package com.ruoyi.price.enums; * TMS 查询订单计费数据时的标识匹配类型。 */ public enum TmsOrderBillMatchType { + /** 没有匹配到订单。 */ + NOT_FOUND("NOT_FOUND", "未找到订单"), /** * 按订单号匹配。 */ 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 a67119d4..35403e8d 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 @@ -24,6 +24,8 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.sign.Md5Utils; +import com.ruoyi.customer.customerinfo.domain.BmsCustomer; +import com.ruoyi.customer.customerinfo.mapper.BmsCustomerMapper; import com.ruoyi.price.domain.PrcIncomeBill; import com.ruoyi.price.domain.PrcIncomeBillFee; import com.ruoyi.price.domain.PrcOrderBill; @@ -68,6 +70,10 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService @Autowired private PrcOrderBillMapper orderBillMapper; + /** TMS 实时状态查询使用客户主档案,不读取订单上的历史状态快照。 */ + @Autowired + private BmsCustomerMapper bmsCustomerMapper; + @Autowired private PrcOrderBillExtMapper orderBillExtMapper; @@ -468,6 +474,7 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService { TmsOrderBillStatusResult result = new TmsOrderBillStatusResult(); result.setMatchedCount(0); + result.setMatchType(TmsOrderBillMatchType.NOT_FOUND.getCode()); return result; } if (bills.size() > 1) @@ -490,7 +497,12 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService result.setTransferNo(bill.getTransferNo()); result.setCustomerId(bill.getCustomerId()); result.setCustomerCode(bill.getCustomerCode()); - result.setCustomerActiveStatus(normalizeCustomerActiveStatus(bill.getCustomerActiveStatus())); + // customer_active_status 是计费时的历史快照;TMS 状态接口必须读取客户当前启用状态。 + BmsCustomer customer = bill.getCustomerId() == null || bill.getCustomerId() <= 0 ? null + : bmsCustomerMapper.selectCustomerStatusByCustomerId(bill.getCustomerId()); + result.setCustomerFound(customer != null); + result.setCustomerActiveStatus(resolveCurrentCustomerActiveStatus(customer)); + // 欠费状态仍按订单计费时保存的快照返回,与当前客户是否存在相互独立。 result.setCreditArrearsStatus(normalizeCreditArrearsStatus(bill.getCreditArrearsStatus())); return result; } @@ -543,10 +555,32 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService return TmsOrderBillMatchType.TRANSFER_NO; } - private String normalizeCustomerActiveStatus(String status) + /** + * 将客户主表的启用状态转换为 TMS 接口状态。 + * 客户不存在或已被逻辑删除时返回 MISSING,不能回退使用订单上的历史快照。 + */ + private String resolveCurrentCustomerActiveStatus(BmsCustomer customer) { - BillCustomerActiveStatus statusEnum = BillCustomerActiveStatus.of(status); - return statusEnum == null ? normalizeUnknownStatus(status) : statusEnum.getCode(); + if (customer == null) + { + return BillCustomerActiveStatus.MISSING.getCode(); + } + String normalized = StringUtils.trim(customer.getIsEnable()); + if (StringUtils.isEmpty(normalized)) + { + // 客户存在但启用状态为空时按非正常状态处理,确保接口只返回约定枚举。 + return BillCustomerActiveStatus.DISABLED.getCode(); + } + if ("0".equals(normalized)) + { + return BillCustomerActiveStatus.ACTIVE.getCode(); + } + if ("1".equals(normalized)) + { + return BillCustomerActiveStatus.DISABLED.getCode(); + } + // 客户存在但状态值异常时按非正常状态处理,确保接口只返回约定枚举。 + return BillCustomerActiveStatus.DISABLED.getCode(); } private String normalizeCreditArrearsStatus(String status) diff --git a/bms-back/ruoyi-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml b/bms-back/ruoyi-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml index 034cd76c..f8730bd4 100644 --- a/bms-back/ruoyi-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml +++ b/bms-back/ruoyi-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml @@ -94,6 +94,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where c.customer_id = #{customerId} and c.del_flag = '0' + + + @@ -661,4 +669,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update bms_customer_contact set del_flag = '2' where contact_id = #{contactId} - \ No newline at end of file +