输入文件:
- 租赁任务考核_2026年{1,2,3}月.xlsx (考核源数据)
- {1,2}月.xlsx (客户盈亏表)
- 车辆里程考核与奖金发放规则(V.1.2).docx
输出文件:
- 里程任务考核_{1,2,3}月核算.xlsx (月度核算结果)
- 里程任务考核_Q1汇总.xlsx (含车辆台账)
- 3月客户盈亏表(待填写).xlsx (模版)
.claude_memory: 项目记忆(规则/偏好/架构/测试车辆)
.claude_plans: 历次计划文件
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5.1 KiB
ETC & 电费审核 → 能源账单对齐氢费模式
Context
氢费的完整流程已跑通:API 导入 → 设置 review_status=PENDING → 用户审核通过 → 调用 RawRecordReviewServiceImpl.processReviewedRecord() → 创建 energy_bill_detail → 触发扣款。
ETC 和电费目前的 review 方法只更新了审核状态,没有创建 energy_bill_detail,没有走统一审核服务。需要对齐。
改动范围
1. ETC: EtcTollRecordServiceImpl.review()
文件: modules/etc/service/impl/EtcTollRecordServiceImpl.java
当前 review() 只设 reviewStatus + remark。改为:
- 设 reviewStatus
- 如果 approved → 构建
ReviewedRecordContext,调用reviewService.processReviewedRecord(context) - 把返回的
EnergyBillDetail.id写回EtcTollRecord.billDetailId - batchReview() 同理(逐条调用 review)
ReviewedRecordContext 构建:
ReviewedRecordContext.builder()
.feeType(FeeType.ETC)
.rawRecordId(record.getId())
.rawTableType("etc_toll_record")
.sourceType(record.getSourceType())
.plateNumber(record.getPlateNumber())
.eventTime(record.getTransTime())
.rawUnitPrice(null) // ETC 无单价
.rawAmount(record.getTollFee())
.quantity(null) // ETC 无数量
.stationId(null)
.stationName(null)
.tenantId(...)
.build()
需要注入 IRawRecordReviewService。
2. 电费: ElectricityRecordServiceImpl.review()
文件: modules/electricity/service/impl/ElectricityRecordServiceImpl.java
当前 review() 设 reviewStatus + 直接调 executeDeduction(错误位置)。改为:
- 设 reviewStatus
- 如果 approved → 构建
ReviewedRecordContext,调用reviewService.processReviewedRecord(context) - 把返回的
EnergyBillDetail.id写回ElectricityChargeRecord.billDetailId - 删除
executeDeduction()(扣款由 reviewService 统一处理) - 删除
triggerDeduction()方法 - 删除
IDeductionService依赖
ReviewedRecordContext 构建:
ReviewedRecordContext.builder()
.feeType(FeeType.ELECTRICITY)
.rawRecordId(record.getId())
.rawTableType("electricity_charge_record")
.sourceType(record.getSourceType())
.plateNumber(record.getPlateNumber())
.eventTime(record.getChargingEndTime())
.rawUnitPrice(null)
.rawAmount(record.getTotalAmount())
.quantity(record.getKwh())
.stationId(null)
.stationName(null)
.tenantId(...)
.build()
3. 电费 PO 精简 (同 ETC 模式)
文件: modules/electricity/entity/record/po/ElectricityChargeRecord.java
electricity_charge_record 也是原始账单表,应像 ETC 一样删除关联字段:
- 删除: contract_id, contract_code, customer_id, customer_name, cost_type, payment_mode, contract_matched, deduction_status, bill_id, is_oneos_vehicle
- 保留: bill_detail_id(关联统一账单)
- 对应删除 DB 列
4. 电费 Listener 简化
文件: modules/electricity/listener/ElectricityDetailImportListener.java
当前 listener 做了合同匹配并存到原始记录。因为原始记录不再存这些字段,简化为:
- 仅设 review_status = PENDING
- 移除合同匹配逻辑(交给 reviewService 统一处理)
5. ETC Listener 已OK
当前 EtcDetailImportListener 已经只设 review_status = PENDING,无需改动。
6. 电费 Service 接口清理
文件: modules/electricity/service/IElectricityRecordService.java
- 删除
manualMatch(),triggerDeduction()方法签名
文件: modules/electricity/controller/ElectricityRecordController.java
- 删除
/manual-match端点
7. 电费前端 VO/页面同步
同 ETC 的精简模式:VO 删除关联字段,前端 data.ts 列定义同步更新。
关键文件
| 文件 | 操作 |
|---|---|
etc/service/impl/EtcTollRecordServiceImpl.java |
改 — review() 接入 reviewService |
electricity/service/impl/ElectricityRecordServiceImpl.java |
改 — review() 接入 reviewService, 删除 deduction 逻辑 |
electricity/entity/record/po/ElectricityChargeRecord.java |
改 — 删除关联字段 |
electricity/listener/ElectricityDetailImportListener.java |
改 — 简化,去掉合同匹配 |
electricity/service/IElectricityRecordService.java |
改 — 删除 manualMatch/triggerDeduction |
electricity/controller/ElectricityRecordController.java |
改 — 删除 /manual-match |
electricity/entity/record/vo/ElectricityChargeRecordVO.java |
改 — 删除关联字段 |
electricity/entity/record/query/ElectricityRecordQuery.java |
改 — 删除关联查询条件 |
前端 views/electricity/record/data.ts |
改 — 对齐 VO |
前端 api/electricity/index.ts |
改 — 对齐类型 |
数据库 electricity_charge_record |
ALTER — 删除列 |
验证
- ETC: 导入 → 列表展示 → 审核通过 → energy_bill_detail 有新记录 → bill_detail_id 回填
- 电费: 导入 → 列表展示 → 审核通过 → energy_bill_detail 有新记录 → 扣款由 reviewService 处理
- 三种费用的 energy_bill_detail 表中都有数据,feeType 分别为 1/2/3