# 还车费用核算模块 — 完整实施计划

## Context

还车费用核算（ReturnSettlement）模块框架已搭建，但与需求文档（`docs/还车费用核算-业务流程与时序.md`）对比存在多个 Gap：审批流转未对接 Warm-Flow、驳回重置未实现、无生成账单接口、无权限/状态校验、全量 `Map<String,Object>` 传参（已有强类型 VO/Req 未使用）。本计划按"先重构后补功能"策略分阶段实施。

---

## Phase 0: 代码质量重构（强类型替换 Map）

**目标：** 消除运行时字段错误风险，为后续所有功能奠定基础。

### 0.1 Controller 签名替换

| 当前 | 替换为 |
|------|--------|
| `page(@RequestParam Map<String, Object>)` → `Map` | `page(ReturnSettlementQuery)` → `IPage<SettlementListVO>` |
| `getDetail(Long id)` → `Map` | → `SettlementDetailVO` |
| `saveBusiness(@RequestBody Map)` | `@RequestBody @Valid SaveBusinessReq` |
| `saveEnergy(@RequestBody Map)` | `@RequestBody @Valid SaveEnergyReq` |
| `saveOperation(@RequestBody Map)` | `@RequestBody @Valid SaveOperationReq` |
| `saveSafety(@RequestBody Map)` | `@RequestBody @Valid SaveSafetyReq` |

submit 方法与 save 使用相同 Req 类。

### 0.2 Service 接口签名同步

`ReturnSettlementService` 中所有方法签名从 `Map` 改为强类型。

### 0.3 ServiceImpl 内部重构

- `convertToListVO` → 返回 `SettlementListVO`
- `getDetail` → 构建 `SettlementDetailVO` 而非手动 put Map
- `saveBusinessData` / `saveEnergyData` / `saveOperationData` → 接收强类型 Req
- 删除 `getStr()`, `getBigDecimal()`, `getInt()` 工具方法

### 0.4 VO 字段补齐

`SettlementDetailVO` 内嵌类需补充字段：
- `DeptStatusVO` 增加 `status` (Integer, 0/1/2 三态) + `totalAmount` (BigDecimal)
- `BusinessFeeVO` 增加 `id`, `seq`, `isFixed`
- `OperationFeeVO` 增加 `id`, `seq`, `isFixed`, `isReadonly`
- `TireTreadVO` 增加 `id`

### 0.5 N+1 查询优化

`page()` 方法中批量查所有 settlementId 对应的 deptStatus，构建 `Map<Long, List<DeptStatus>>` 缓存，避免列表每条记录单独查询。

### 验证

- 编译通过
- Postman 调用 page、detail、save、submit 接口，JSON 结构与前端兼容
- 前端页面功能无回归

### 关键文件

- `ReturnSettlementController.java`
- `ReturnSettlementService.java`
- `ReturnSettlementServiceImpl.java`
- `SettlementDetailVO.java` / `SettlementListVO.java`
- `SaveBusinessReq.java` / `SaveEnergyReq.java` / `SaveOperationReq.java` / `SaveSafetyReq.java`
- `ReturnSettlementQuery.java`

---

## Phase 1: 权限与状态校验

**目标：** 堵住安全漏洞。

### 1.1 权限校验

新增公共方法：

```java
private void assertDeptPermission(SettlementDeptCode requiredDept) {
    String userDept = resolveUserDept();
    if (userDept != null && !requiredDept.getCode().equals(userDept)) {
        throw new ServiceException("您没有权限操作" + requiredDept.getName() + "的数据");
    }
}
```

在所有 save/submit/revoke 方法开头调用。

### 1.2 审批状态前置校验

```java
private void assertEditableStatus(Long settlementId) {
    ReturnSettlement s = assertSettlementExists(settlementId);
    if (s.getApprovalStatus() >= SettlementApprovalStatus.PENDING_APPROVAL.getCode()) {
        throw new ServiceException("结算单已进入审批流程，无法编辑");
    }
}
```

### 1.3 部门提交状态校验

- submit 校验当前部门状态不为 SUBMITTED（防重复提交）
- revoke 校验状态为 SUBMITTED

### 验证

- 不同角色账号跨部门操作 → 403
- 审批中状态下 save → 被拦截

### 关键文件

- `ReturnSettlementServiceImpl.java`

---

## Phase 2: Warm-Flow 审批对接

**目标：** submitReview 启动工作流，审批完成/驳回通过 Listener 回调。

### 2.1 submitReview 对接

注入 `RemoteWorkflowService`（`@DubboReference`），submitReview 中调用 `startCompleteTask` 启动流程。

- businessId 格式：`"ReturnSettlement_" + id`
- flowCode：`returnSettlement`（需在 Warm-Flow 后台配置）
- 状态直接写 `APPROVING(20)`（startCompleteTask 完成第一个任务后已在审批中）

### 2.2 revokeReview 对接

调用 `remoteWorkflowService.cancelProcessApply` 撤销流程实例。

### 2.3 新增 Dubbo 远程接口

在 `ln-asset-api` 新增 `RemoteReturnSettlementService`：

```java
public interface RemoteReturnSettlementService {
    boolean updateApprovalStatus(Long settlementId, Integer approvalStatus);
    boolean resetDeptStatuses(Long settlementId);
}
```

在 `ln-asset-management` 实现 `RemoteReturnSettlementServiceImpl`。

### 2.4 新增 Warm-Flow Listener

参照 `ContractStatusChangeListener.java` 模式：

- `SettlementApprovalListener.java` — 审批通过 → `updateApprovalStatus(id, 30)`
- `SettlementRejectListener.java` — 审批驳回 → `updateApprovalStatus(id, 40)` + `resetDeptStatuses(id)`

### 2.5 审批驳回重置逻辑

`resetDeptStatuses`：4个部门状态全部重置为 `PENDING(0)`，清空 submitBy/submitByName/submitTime，主表 approvalStatus 置为 `PENDING_SUBMIT(0)`。

### 审批状态机

```
0(待提交) --submitReview--> 20(审批中) --approve--> 30(审批完成)
                                      --reject-->  40(驳回) --reset--> 0(待提交)
           <--revokeReview-- 20(审批中) --> 1(撤回)
```

### 验证

- 启动微服务集群 → 创建结算单 → 4部门填报 → submitReview → 工作流待办出现
- 审批通过 → approvalStatus = 30
- 审批驳回 → approvalStatus = 40 + 4个 deptStatus 回到 0
- revokeReview → 工作流实例撤销

### 关键文件

- `ReturnSettlementServiceImpl.java`
- 新增 `RemoteReturnSettlementService.java` (ln-asset-api)
- 新增 `RemoteReturnSettlementServiceImpl.java` (ln-asset-management)
- 新增 `SettlementApprovalListener.java` (ln-cloud/ruoyi-workflow)
- 新增 `SettlementRejectListener.java` (ln-cloud/ruoyi-workflow)
- 参照 `ContractStatusChangeListener.java`
- 参照 `RemoteContractService.java`

---

## Phase 3: 生成账单

**目标：** 审批完成后财务可生成账单。

### 3.1 Controller 新增端点

```java
@PostMapping("/generate-bill/{id}")
public R<Long> generateBill(@PathVariable Long id)
```

### 3.2 Service 实现

1. 校验 approvalStatus == 30
2. 校验权限（仅 superadmin/财务）
3. 幂等检查（ReturnSettlement 主表增加 `bill_id` 字段）
4. 从结算单构建 `Bills` 对象（参照 `BillGenerateService.createBills`）
5. 保存 Bills，回写 bill_id

### 3.3 前端补充

`return-payment/index.ts` 新增 `generateBill(id)` API。列表页增加"生成账单"按钮（仅 approvalStatus=30 + 财务角色可见）。

### 验证

- 审批完成的结算单调用 generate-bill → Bills 表有记录
- 非完成状态调用 → 错误
- 重复调用 → 幂等

### 关键文件

- `ReturnSettlementController.java`
- `ReturnSettlementService.java` / `ReturnSettlementServiceImpl.java`
- `ReturnSettlement.java` (新增 bill_id 字段)
- 前端 `return-payment/index.ts`
- 参照 `BillsServiceImpl.java`

---

## Phase 4: 能源余额拉取 + 租金自动计算

**目标：** 补充业务计算逻辑，独立于 Phase 1-3，可并行。

### 4.1 能源余额

注入 `RemoteEnergyAccountService`（`@DubboReference`），在 `createInitialEnergy` 中拉取 userBalance。调用失败降级为 ZERO + warn 日志。

### 4.2 租金自动计算

在 `createInitialRent` 中：`actualRent = (月租金 / 30) * (交车日到还车日天数)`，业务组 save 时可手动覆盖。

### 验证

- 创建结算单 → energy.userBalance 正确
- rent.actualRent 正确计算
- ln-energy 不可用时降级不阻断

### 关键文件

- `ReturnSettlementServiceImpl.java`

---

## Phase 5: 低优先级

### 5.1 倒计时字段

VO 增加 `deadline` (Date) + `remainingDays` (Integer)。

### 5.2 导出 Excel

新增 `GET /return-settlement/export`。

### 5.3 无忧包减免后端校验

saveOperationData 中校验 worryFreeDiscount > 0 时对应保险标识为 1。

---

## 依赖关系

```
Phase 0 (重构) ─────┐
                    ├──► Phase 1 (权限+状态) ──► Phase 2 (审批) ──► Phase 3 (账单)
Phase 4 (能源+租金) ─┘ (可与 Phase 1/2 并行)

Phase 5 (低优先级) — 独立
```

## 新增文件清单

| 文件 | 位置 | 用途 |
|------|------|------|
| `RemoteReturnSettlementService.java` | ln-asset-api | Dubbo 远程接口 |
| `RemoteReturnSettlementServiceImpl.java` | ln-asset-management | Dubbo 实现 |
| `SettlementApprovalListener.java` | ln-cloud/ruoyi-workflow | 审批通过监听 |
| `SettlementRejectListener.java` | ln-cloud/ruoyi-workflow | 审批驳回监听 |
