Files
jsowell-charger-web/docs/feature-tracker-无交易记录自动结算-附录.md
jsowell 864d04ccfb docs: 补充无交易记录自动结算功能文档
新增文档:
- feature-tracker-无交易记录自动结算-实施总结.md - 完整实施总结,包含部署指南、监控方案、风险应对
- feature-tracker-无交易记录自动结算-附录.md - 功能设计附录

文档内容:
- 开发进度总结(8个任务全部完成)
- 核心实现详解(配置、数据转换、业务逻辑、定时任务、幂等保护、数据校验)
- 文件清单(3个新增文件、7个修改文件)
- 部署指南(代码合并、配置更新、定时任务添加、4阶段灰度发布流程)
- 监控方案(日志监控、数据库监控、Redis监控)
- 风险点与应对(6类风险及解决方案)
- 后续优化建议(5个方向)
- 验收标准(功能、性能、稳定性)
2026-08-11 16:48:41 +08:00

274 lines
9.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 附录:无交易记录自动结算功能
本文档为 `feature-tracker-无交易记录自动结算.md` 的附录部分
---
## 八、附录
### 8.1 关键代码位置索引
| 代码位置 | 说明 | 行号 |
|---------|------|------|
| `TransactionRecordsRequestHandler.processOrder()` | 交易记录触发结算入口 | jsowell-netty/.../TransactionRecordsRequestHandler.java:683 |
| `OrderService.manualSettlementOrder()` | 人工结算逻辑(可复用实时数据构造) | jsowell-admin/.../OrderService.java:1008-1027 |
| `YKCBusinessServiceImpl` | 桩离线标记异常订单 | jsowell-netty/.../YKCBusinessServiceImpl.java:166 |
| `ChargeEndHandler` | 0x19充电结束帧处理 | jsowell-netty/.../ChargeEndHandler.java |
| `RealTimeMonitorData` | 实时检测数据实体类 | jsowell-common/.../domain/RealTimeMonitorData.java |
| `order_monitor_data` 表 | 实时数据落库 | MySQL |
| Redis `PILE_REAL_TIME_MONITOR_DATA` | 实时数据缓存 | Redis |
| `settle_order_` 锁前缀 | 结算分布式锁 | Redis |
### 8.2 数据流程图
```mermaid
sequenceDiagram
participant Timer as 定时任务
participant DB as 数据库
participant Redis as Redis
participant OrderLogic as 结算逻辑
participant Alert as 告警系统
Timer->>Timer: 检查配置开关
alt 开关关闭
Timer->>Timer: 退出
end
Timer->>DB: 查询待结算订单<br/>(状态=待结算 + 桩在线 + 停止>10min)
DB-->>Timer: 订单列表限batch-size条
loop 遍历每个订单
Timer->>Redis: 尝试获取锁<br/>settle_order_{orderId}
alt 获取锁失败
Timer->>Timer: 跳过该订单
end
Timer->>DB: 查询最后一条实时数据
alt 数据异常检查
Timer->>Timer: 检查 chargingDegree > 0
Timer->>Timer: 检查 chargingAmount > 0
Timer->>Timer: 检查金额阈值
alt 任一检查不通过
Timer->>Alert: 发送告警
Timer->>Timer: 跳过该订单
end
end
Timer->>Timer: 构造 TransactionRecordsData
Timer->>OrderLogic: settleOrder(data, orderInfo)
OrderLogic-->>Timer: 结算结果
alt 结算成功
Timer->>Timer: 记录成功日志
else 结算失败
Timer->>Alert: 发送告警
Timer->>Timer: 记录失败日志
end
Timer->>Redis: 释放锁
end
```
### 8.3 状态流转图
```mermaid
stateDiagram-v2
[*] --> 充电中: 开始充电
充电中 --> 待结算: 收到0x19结束帧<br/>或桩停止上报
待结算 --> 已结算: 收到交易记录帧<br/>(现有逻辑)
待结算 --> 已结算: 定时任务自动结算<br/>(新增逻辑)
待结算 --> 已结算: 人工结算
待结算 --> 异常订单: 桩离线<br/>(现有逻辑)
已结算 --> [*]
异常订单 --> [*]
note right of 待结算
定时任务触发条件:
1. 桩在线
2. 停止>10分钟
3. 有实时数据
4. 在灰度站点范围内
end note
```
### 8.4 配置项完整清单
```yaml
# application.yml 或 application-{env}.yml
auto-settle:
# ========== 基础配置 ==========
enabled: false # 总开关,默认关闭
timeout-minutes: 10 # 停止超时阈值(分钟)
interval: '0 */10 * * * ?' # 扫描周期Cron表达式每10分钟
grayscale-station-ids: # 灰度站点白名单
- 1001
- 1002
# ========== 金额与数据校验 ==========
amount-threshold-ratio: 1.5 # 金额异常阈值倍数chargingAmount > payAmount * 1.5 时告警)
batch-size: 100 # 单次扫描订单数量上限
data-freshness-minutes: 30 # 实时数据新鲜度阈值(分钟)
# ========== 并发与容错 ==========
alert-enabled: true # 告警开关
lock-timeout-seconds: 60 # redis分布式锁超时时间
retry-on-failure: false # 失败是否重试建议false等下一轮
# ========== 监控指标 ==========
metrics:
enabled: true # 是否启用Prometheus指标
prefix: "auto_settle" # 指标前缀
```
### 8.5 数据库查询SQL示例
#### 查询待结算订单方案D直接JOIN
```sql
SELECT
obi.order_id,
obi.order_no,
obi.pile_connector_id,
obi.pay_amount,
obi.charge_end_time,
obi.station_id,
pci.connector_status,
omd.charging_degree,
omd.charging_amount,
omd.date_time as last_monitor_time
FROM order_basic_info obi
INNER JOIN pile_connector_info pci
ON obi.pile_connector_id = pci.connector_id
LEFT JOIN (
SELECT
order_id,
charging_degree,
charging_amount,
date_time,
ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY date_time DESC, id DESC) as rn
FROM order_monitor_data
) omd ON obi.order_id = omd.order_id AND omd.rn = 1
WHERE obi.order_status = 'STAY_SETTLEMENT' -- 待结算
AND pci.connector_status != '0' -- 桩在线
AND obi.station_id IN (?, ?, ...) -- 灰度站点
AND (
-- 依据1有充电结束时间且超过10分钟
(obi.charge_end_time IS NOT NULL
AND obi.charge_end_time < DATE_SUB(NOW(), INTERVAL 10 MINUTE))
OR
-- 依据2最后实时数据超过10分钟
(omd.date_time IS NOT NULL
AND omd.date_time < DATE_SUB(NOW(), INTERVAL 10 MINUTE))
)
AND omd.charging_degree > 0 -- 有充电度数
AND omd.charging_amount > 0 -- 有充电金额
AND omd.date_time > DATE_SUB(NOW(), INTERVAL 30 MINUTE) -- 数据新鲜度
LIMIT 100;
```
#### 查询最后一条实时数据
```sql
SELECT *
FROM order_monitor_data
WHERE order_id = ?
ORDER BY date_time DESC, id DESC
LIMIT 1;
```
### 8.6 Redis Key 设计
| Key 模式 | 说明 | 过期时间 | 示例值 |
|---------|------|---------|--------|
| `settle_order_{orderId}` | 结算分布式锁 | 60秒 | `settle_order_123456` |
| `PILE_REAL_TIME_MONITOR_DATA:{connectorId}` | 实时数据缓存 | 持久化 | `PILE_REAL_TIME_MONITOR_DATA:ABC001-1` |
| `auto_settle_alert:{orderId}` | 告警去重(可选) | 3600秒 | `auto_settle_alert_123456` |
### 8.7 日志规范
#### INFO 级别日志
```java
log.info("[自动结算] 开始扫描待结算订单,灰度站点数量:{}", stationIds.size());
log.info("[自动结算] 扫描到{}个待结算订单", orders.size());
log.info("[自动结算] 订单{}自动结算成功,金额:{}元,耗时:{}ms",
orderId, chargingAmount, duration);
```
#### WARN 级别日志
```java
log.warn("[自动结算] 订单{}充电度数异常:{},跳过结算", orderId, chargingDegree);
log.warn("[自动结算] 订单{}充电金额异常:{},跳过结算", orderId, chargingAmount);
log.warn("[自动结算] 订单{}状态已变更,跳过结算", orderId);
log.warn("[自动结算] 订单{}获取锁失败,跳过", orderId);
```
#### ERROR 级别日志(需发送告警)
```java
log.error("[自动结算] 订单{}金额异常:实际{}元 > 预付{}元 * {},跳过结算",
orderId, chargingAmount, payAmount, threshold);
log.error("[自动结算] 订单{}结算失败:{}", orderId, e.getMessage(), e);
log.error("[自动结算] 定时任务执行失败:{}", e.getMessage(), e);
```
### 8.8 Prometheus 监控指标
```java
// 建议采集的指标
auto_settle_scan_count // 扫描次数
auto_settle_order_found_count // 发现待结算订单数
auto_settle_success_count // 结算成功数
auto_settle_skip_count{reason="lock_failed"} // 跳过数(锁失败)
auto_settle_skip_count{reason="data_invalid"} // 跳过数(数据异常)
auto_settle_skip_count{reason="amount_exceed"} // 跳过数(金额超限)
auto_settle_failure_count // 结算失败数
auto_settle_duration_seconds // 扫描耗时
auto_settle_order_duration_seconds // 单个订单结算耗时
```
---
## 九、审查意见总结
### ✅ 文档优点
1. **风险识别全面**6个风险点覆盖了金额准确性、并发、影响面等核心问题
2. **决策清晰**对R1金额策略、R4停止判定都有明确决策并记录
3. **实现思路稳健**:不改核心链路,新增入口,灰度上线
4. **业务条件合理**桩在线、停止超10分钟、有实时数据三个条件都是必要的
### ⚠️ 需补充内容(已在第六章列出)
| 类别 | 问题编号 | 状态 | 优先级 |
|------|---------|------|--------|
| 并发幂等 | 6.1, 6.5 | ⬜ 待回答 | P0 |
| 数据校验 | 6.2, 6.4, 6.7 | ⬜ 待回答 | P0 |
| 性能优化 | 6.3 | ⬜ 待回答 | P1 |
| 业务逻辑 | 6.6 | ⬜ 待回答 | P0 |
| 配置设计 | 6.8 | ⬜ 待回答 | P1 |
**建议行动路径**
1. ✅ 步骤1需求评审确认已完成
2. 🔴 步骤2回答第六章的8个待明确问题**当前阻塞**
3. ⬜ 步骤3更新文档版本号为 v0.4
4. ⬜ 步骤4进入开发阶段第五章进度追踪
---
## 十、版本历史
| 版本 | 日期 | 变更内容 | 作者 |
|------|------|---------|------|
| v0.1 | 2026-08-11 | 初稿:需求分析、风险点、实现方案、开发进度追踪框架 | - |
| v0.2 | 2026-08-11 | 确认决策:金额以桩端 chargingAmount 为准;双依据判定都启用;特定站点灰度 | - |
| v0.3 | 2026-08-11 | 新增8个待明确问题第六章扩充测试计划至29个场景第七章新增附录 | Claude |
| v0.4 | 2026-08-11 | ✅ 完成8个问题的决策回答更新已决策问题列表11个决策状态更新为"方案已确认,待开发" | Claude |
---
**文档结束**