Files
jsowell-charger-web/docs/feature-tracker-无交易记录自动结算.md
2026-08-11 14:49:42 +08:00

9.5 KiB
Raw Blame History

功能开发追踪:无交易记录时按实时检测数据自动结算

功能编号: TBD 版本: v0.2 日期: 2026-08-11 项目: 万车充运营管理平台 状态: 方案已确认,开发中 负责模块: jsowell-pile / jsowell-netty / jsowell-quartz


变更记录

版本 日期 变更内容
v0.1 2026-08-11 初稿:需求分析、风险点、实现方案、开发进度追踪框架
v0.2 2026-08-11 确认决策:金额以桩端 chargingAmount 为准;双依据判定都启用;特定站点灰度

一、背景与目标

背景

当前自动结算唯一入口是收到交易记录帧。充电桩在线、充电已停止,但若未收到交易记录(桩端漏发、网络丢帧、交易记录帧异常等),订单将永远停留在「待结算」状态,无法自动结算,导致:

  • 用户预付资金长期冻结,体验差
  • 后台需要人工介入结算,运维成本高

目标

充电桩在线停止充电超过 10 分钟仍未收到交易记录时,平台按最后一条实时检测记录中的耗电量(充电度数)自动结算,替代人工结算,缩短资金冻结周期。

非目标(本期不做)

  • 桩离线场景的自动结算(离线时数据不可信,需人工确认)
  • 尖峰平谷分时明细的补全(实时数据本身不含分时信息)

二、需求分析

2.1 当前逻辑(现状)

环节 现状 代码位置
结算触发 仅收到交易记录帧时触发 settleOrder TransactionRecordsRequestHandler.processOrder() → jsowell-netty/.../TransactionRecordsRequestHandler.java:683
结算数据来源 交易记录 TransactionRecordsData(含尖峰平谷分时电量、单价、金额) 同上
无交易记录时 订单停在「待结算」,不自动结算
桩离线 订单置为异常 updateOrderStatusAsAbnormal YKCBusinessServiceImpl.java:166
人工结算 已支持「无交易记录 → 用最后一条实时数据构造结算数据」 OrderService.manualSettlementOrder() → jsowell-admin/.../OrderService.java:1008-1027

2.2 目标逻辑

定时任务(周期可配,默认如每 10 分钟)扫描待结算订单:
  ├─ 条件 1订单状态 = 待结算 (STAY_SETTLEMENT)
  ├─ 条件 2充电桩在线connector status ≠ "0" 离线)
  ├─ 条件 3充电已停止超过 10 分钟
  │     ├─ 优先依据chargeEndTime 非空 且 距当前 > 10 分钟(桩上报过 0x19 充电结束)
  │     └─ 兜底依据:最后一条实时检测数据 dateTime 距当前 > 10 分钟(桩未上报结束/交易记录)
  └─ 条件 4存在实时检测数据chargingDegree > 0

命中后:
  1. 复用人工结算逻辑,从最后一条实时检测数据构造 TransactionRecordsData
  2. 走 orderLogic.settleOrder(data, orderBasicInfo)

2.3 关键数据来源

数据 字段 说明
累计充电度数 RealTimeMonitorData.chargingDegree 精确到 4 位小数,待机置零
已充金额 RealTimeMonitorData.chargingAmount 桩端计算(电费+服务费)*计损度数
实时数据落库 order_monitor_data 表 / redis PILE_REAL_TIME_MONITOR_DATA 充电中每 10s 上报一次,按分钟保留最后一条
桩在线状态 PileConnectorDataBaseStatusEnum "0"=离线,1/2/3/4=在线
充电结束信号 ChargeEndHandler (0x19) 更新 chargeEndTimeendSoc

三、风险点与应对

# 风险 等级 说明 应对
R1 金额准确性依赖桩端上报 实时数据无尖峰平谷分时明细,结算走「以交易记录金额为准」分支,即完全信任桩端 chargingAmount。若桩端该值有误(充电中途拔枪、数据异常),直接导致扣费/退款不准确 已决策:以桩端 chargingAmount 为准(与人工结算一致)。降低影响:① 异常金额阈值chargingAmount 远超 payAmount时跳过并告警② 特定站点灰度上线,逐步观察
R2 退款联动 chargingAmount < 预付款 payAmount 时走退款流程,金额不准会连带退款不准 结算金额以 chargingAmount 为准,与人工结算一致;金额异常(远超 payAmount时跳过并告警
R3 幂等 / 并发 定时扫描与「交易记录恰好到达」可能并发重复结算 复用现有 settle_order_+transactionCode redis 锁TransactionRecordsRequestHandler.java:602结算前校验订单状态与结算时间
R4 判「停止」时间点模糊 桩只拔枪不上报 0x19 时,chargeEndTime 为空,只能依赖实时数据 dateTime 判定;若桩同时离线则数据停更 已决策:双依据都启用chargeEndTime 优先,最后实时数据 dateTime 兜底)。条件 2在线为安全底线离线订单不结算
R5 影响面扩散 该逻辑影响所有待结算订单,改动结算主链路风险高 不修改结算核心 settleOrder,仅新增定时扫描入口,复用人工结算构造逻辑
R6 灰度与回滚 新逻辑上线初期存在未覆盖场景 已决策:特定站点灰度auto-settle.grayscale-station-ids)。开关关闭即回退到现有行为

四、实现方案

4.1 总体思路

不修改现有结算核心链路,新增定时扫描任务,命中条件后复用人工结算的「实时数据 → TransactionRecordsData」构造逻辑再走既有的 settleOrder

4.2 实现步骤

# 步骤 说明 模块
1 配置开关 新增自动结算开关 + 站点灰度白名单:auto-settle.enabledauto-settle.timeout-minutes=10auto-settle.intervalauto-settle.grayscale-station-ids(特定站点灰度)。默认关闭或仅灰度站点开启 jsowell-pile / application.yml
2 构造结算数据方法 OrderService(或抽到 pile 的公共 Service新增「从最后一条实时数据构造 TransactionRecordsData」方法与人工结算复用同一逻辑 jsowell-admin / jsowell-pile
3 查询待结算订单 新增 mapper 查询:状态=待结算 + 桩在线 + 满足停止条件chargeEndTime/最后实时数据时间 < 当前-10min的订单列表 jsowell-pile
4 定时任务 新增 Quartz Job周期执行扫描+结算,含 redis 分布式锁防并发 jsowell-quartz
5 结算执行 循环命中订单,构造数据 → orderLogic.settleOrder,异常单独捕获不影响整体 jsowell-pile
6 幂等保护 结算前校验订单状态未变更、settle_order_ 锁未占用 jsowell-pile
7 告警日志 结算异常、金额异常chargingAmount 远大于 payAmount时输出 ERROR 日志/告警 各模块

4.3 涉及文件清单(预估)

文件 变更
jsowell-pile/.../OrderBasicInfoService.java 新增查询待结算订单方法
jsowell-pile/.../OrderBasicInfoServiceImpl.java 实现查询逻辑
jsowell-pile/.../OrderBasicInfoMapper.xml 新增 SQL
jsowell-admin/.../OrderService.java 抽取「实时数据→结算数据」构造方法(或下沉到 pile
jsowell-quartz/.../RyTask.java 或新增 Task 新增自动结算定时任务
jsowell-admin/src/main/resources/application*.yml 新增配置项

五、开发进度追踪

状态:⬜ 未开始 / 🟡 进行中 / ✅ 已完成 / 🔴 阻塞

# 任务 模块 负责人 状态 备注
1 需求评审确认(含 R1/R4 决策) - 已完成 2026-08-11 确认:金额以桩端 chargingAmount 为准;双依据判定;特定站点灰度
2 配置开关 jsowell-pile 未开始
3 实时数据→结算数据构造方法 jsowell-admin/pile 未开始
4 待结算订单查询 SQL jsowell-pile 未开始
5 定时任务 jsowell-quartz 未开始
6 幂等保护 jsowell-pile 未开始
7 告警日志 各模块 未开始
8 单元测试 / 集成测试 jsowell-admin 未开始
9 灰度上线(特定站点) - 未开始 先对灰度站点开启,观察稳定后逐步放开
10 上线后监控与复盘 - 未开始

已决策问题

# 问题 决策 决策日期
1 金额策略 以桩端 chargingAmount 为准(与人工结算一致) 2026-08-11
2 停止判定依据 双依据都启用chargeEndTime 优先,最后实时数据 dateTime 兜底 2026-08-11
3 灰度范围 特定站点灰度,先对指定站点开启,观察稳定后再逐步放开 2026-08-11

六、测试计划

# 场景 预期
1 桩在线 + 有 chargeEndTime + 停止>10min + 有实时数据 自动结算成功,金额=实时数据 chargingAmount
2 桩在线 + 无 chargeEndTime + 最后实时数据>10min + 有实时数据 兜底依据触发,自动结算
3 桩离线 不触发(条件 2 拦截)
4 停止 < 10min 不触发
5 无实时检测数据chargingDegree=0 不触发
6 扫描期间交易记录到达 不重复结算(幂等)
7 chargingAmount > payAmount 异常值 跳过并告警
8 配置开关关闭 保持现有行为(不自动结算)