Commit 2b84a6e7 authored by fangxinjiang's avatar fangxinjiang

见费出单优化文档同步:V24/OpenSpec 移除 launchTime,对齐发版后固定 isNewData=1 与登记实缴校验规则。

Co-authored-by: 's avatarCursor <cursoragent@cursor.com>
parent d142d848
......@@ -8,10 +8,10 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
**Goals:**
- 通过 `is_history_advance_pay` 字段分流历史/新提前缴费逻辑
- 历史分支(`isHistoryAdvancePay=1` 或 NULL)行为与上线前完全一致
- 通过 `is_new_data` 字段分流历史/新提前缴费逻辑
- 历史分支(`isNewData=0` 或 NULL)行为与上线前完全一致
- 新分支实现:派单直接待投保、无预估/差额、实缴登记推 EKP、独立退保规则
- DDL + 存量迁移 + 发布时间切点可配置上线
- DDL + 存量迁移;发版后派单固定 `isNewData=1`(见 `hro-jfcd-optimization-doc-sync`
**Non-Goals:**
......@@ -38,21 +38,23 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
**备选**: 拆到 `advance/` 包下 Handler 类 — 可选,文档建议 P0 可先 private 方法,后续再拆。
### D3: 发布时间切点而非功能开关
### D3: 上线发版模型(非 launchTime 切点)
**选择**: 配置 `advance-pay.new-data-launch-time`;满足见费出单且 `now >= launchTime``isHistoryAdvancePay=0`
**选择**:存量 SQL 刷 `is_new_data=0`;发版后 `initJfcd` 固定写 `isNewData=1`
**理由**: 产品已确认;避免误开开关导致新逻辑作用于未就绪环境。
**理由**:上线模型简单明确;2026-06-18 见费出单优化已移除 `advance-pay.new-data-launch-time`
**备选**:配置切点 — 已废弃。
### D4: 数据模型
| 层 | 字段 | 取值 |
|---|---|---|
| HRO `t_insurance_detail` | `is_history_advance_pay` CHAR(1) | `1` 历史 / `0` / NULL 非提前缴费 |
| HRO `t_insurance_detail` | `is_new_data` CHAR(1) | `1` 新 / `0` 历史 / NULL 非提前缴费 |
| EKP `ekp_insurances_info` | `fd_new_data` CHAR(1) | `1` 新 / `0` 历史;默认 `1` |
| Java | `TInsuranceDetail.isHistoryAdvancePay` | 与库表一致 |
| Java | `TInsuranceDetail.isNewData` | 与库表一致 |
**写入规则**: 存量 `is_jfcd=0` → 迁移为 `1`;新数据派单写 `0`;EKP 推送在 `DoJointInsuranceTask.initValues` 统一转换
**写入规则**: 存量 `is_jfcd=0` → 迁移为 `0`;发版后派单写 `1`;EKP 推送同值直传
### D5: 新数据派单行为差异
......@@ -68,7 +70,7 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
- `fd_new_data=1``有无预估=否`
- BPO: 应收=0,应付=实缴;非 BPO: 应收=应付=实缴
- 跳过差额生成;`registeredPolicyPremiumCheck` 对无 `defaultSettleId` 放宽
- 跳过差额生成;新数据 `registeredPolicyPremiumCheck` 跳过预估 `settleStatus` 拦截,保留 `payStatus` 拦截
### D7: 新数据退保 vs 历史
......@@ -96,14 +98,14 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
## Migration Plan
1. **DDL**: HRO `§2.4.1` → EKP `§2.4.2`
2. **迁移**: HRO `§2.5.1` → EKP `§2.5.2`(全量历史刷 HRO `1` / EKP `0`
3. **发版 HRO**: 含 `AdvancePaymentHelper` + 历史分流 + 新分支(可先不开新数据写入,launchTime 设未来)
4. **验证历史**: 冒烟确认 `isHistoryAdvancePay=1` 行为不变
5. **调整 launchTime**: 到达切点后新派单写 `0`全量测试 §9.2 场景
2. **迁移**: HRO `§2.5.1` → EKP `§2.5.2`(全量历史刷 `is_new_data=0` / `fd_new_data=0`
3. **发版 HRO**: 含 `AdvancePaymentHelper` + 历史分流 + 新分支
4. **验证历史**: 冒烟确认存量 `isNewData=0` 行为不变
5. **验证新数据**: 全量测试 §9.2 场景
6. **EKP 联调**: 实缴 `有无预估=否` + `fd_new_data=1`
7. **前端同步**: 禁用撤回/删除;退保前查支出状态
**回滚**: `launchTime` 设为未来时间停止新数据写入;新分支代码可保留(无 `0` 数据不触发);DDL 列可保留(nullable,不影响历史)。
**回滚**: 回退应用版本;DDL 列可保留(nullable,不影响历史)。
## API / 模块影响
......@@ -111,7 +113,6 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
|---|---|
| `yifu-insurances-api` | `TInsuranceDetail` + VO/DTO 增字段 |
| `yifu-insurances-biz` | Mapper XML、ServiceImpl、DoJointInsuranceTask、Constants、Helper |
| `application-*.yml` | `advance-pay.new-data-launch-time` |
| EKP 双数据源 | `EkpInsurancesInfo``fdNewData` |
| yifu-ui(独立仓库) | 撤回/删除按钮禁用;退保前 `getPaymentSettleStatusFromEkp` |
......@@ -124,7 +125,7 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
| 逻辑 | 类/方法 | 改造 |
|---|---|---|
| 见费出单标识 | `initJfcd` / `initJfcdBatch` | launchTime + 写字段 |
| 见费出单标识 | `initJfcd` / `initJfcdBatch` | 固定 `isNewData=1` |
| 派单核心 | `initJfcdInfo` | 分流 |
| 派单后续 | `addInsurance` / `batchInsurance` | 新数据不进 pushList |
| EKP 预估 | `DoJointInsuranceTask.pushEstime` | 历史专用 |
......
......@@ -4,14 +4,13 @@ HRO 侧见费出单(提前缴费)现有逻辑要求派单后进入待缴费
## What Changes
- 新增 `is_history_advance_pay` 字段(HRO `t_insurance_detail` + EKP `ekp_insurances_info.fd_new_data`),HRO `1/0` 与 EKP `0/1` **反向**映射(EKP 是否新数据:1是/0否,默认1
- 存量 `is_jfcd=0` 数据迁移为历史(`is_history_advance_pay=1`);发布时间之后新增见费出单写 `0`
- 新增 `is_new_data` 字段(HRO `t_insurance_detail` + EKP `fd_new_data`,同义同值 1新/0历史
- 存量 `is_jfcd=0` 数据迁移为历史(`is_new_data=0`);发版后新派单固定 `is_new_data=1`
- 新增 `AdvancePaymentHelper` 分流工具,历史分支代码块原样保留,新逻辑独立方法/注释块
- 新提前缴费派单:跳过待缴费(6)、不推 EKP 预估、不生成预估 settle/差额;待办直接待投保(3)
- 新提前缴费实缴:登记保单保费时推送实缴(有无预估=否),BPO/非 BPO 应收应付规则;收入/管理费/风险金延至实缴登记
- 新提前缴费退保:独立校验(支出中/已支出禁止);不生成负数预估/差额;按实缴结算状态删实缴或推负数实缴
- EKP 回调/手动拉取对新数据跳过;撤回/删除投保逻辑不改,仅加注释(前端禁用按钮)
- 配置项 `advance-pay.new-data-launch-time` 控制新数据写入切点
- EKP 回调/手动拉取对新数据逐条跳过;撤回/删除投保逻辑不改,仅加注释(前端禁用按钮)
## Capabilities
......
......@@ -2,29 +2,29 @@
### Requirement: Advance Payment Data Classification
The system SHALL distinguish legacy advance-pay (见费出单) data from new advance-pay data using `is_history_advance_pay` on `TInsuranceDetail`, synchronized to EKP as `fd_new_data` (`1`历史→`0`, `0`新→`1`;EKP 默认 `1`).
The system SHALL distinguish legacy advance-pay (见费出单) data from new advance-pay data using `is_new_data` on `TInsuranceDetail` (`1`=new, `0`=legacy), synchronized to EKP as `fd_new_data` with identical values. Legacy via migration; new dispatches after release write `isNewData=1` (no launchTime config).
#### Scenario: Legacy data identification
- **WHEN** `isJfcd=0` and (`isHistoryAdvancePay` is `1` or NULL)
- **WHEN** `isJfcd=0` and (`isNewData` is `0` or NULL)
- **THEN** the record MUST follow legacy advance-pay workflow unchanged from pre-release behavior
- **AND** EKP pushes for estimate/actual/difference MUST set `fd_new_data=0`
#### Scenario: New data identification after launch time
#### Scenario: New data identification on dispatch after release
- **WHEN** `isJfcd=0`, `isHistoryAdvancePay=0`, and record created at or after `advance-pay.new-data-launch-time`
- **THEN** the record MUST follow new advance-pay workflow defined in this change
- **WHEN** `isJfcd=0`, advance-pay conditions are met on add or batch add after application release
- **THEN** the system MUST set `isNewData=1` on dispatch
- **AND** EKP actual-premium pushes MUST set `fd_new_data=1`
#### Scenario: Stock data migration
- **WHEN** existing records have `is_jfcd=0` before release
- **THEN** migration MUST set `is_history_advance_pay=1`
- **THEN** migration MUST set `is_new_data=0` (legacy)
- **AND** behavior MUST remain identical to pre-migration legacy advance-pay
### Requirement: New Advance-Pay Dispatch Workflow
For new advance-pay data (`isHistoryAdvancePay=0`), the system SHALL skip pending-payment state and EKP estimate push on dispatch.
For new advance-pay data (`isNewData=1`), the system SHALL skip pending-payment state and EKP estimate push on dispatch.
#### Scenario: Dispatch directly to pending insurance
......@@ -114,7 +114,7 @@ EKP payment callbacks and manual payment pull MUST NOT alter state for new advan
### Requirement: Insurance Purchase Processing
The system SHALL manage commercial insurance purchase from application through handling success, including add, batch add, replace, and rollback. For advance-pay (`isJfcd=0`) records, behavior MUST branch on `isHistoryAdvancePay` between legacy and new workflows.
The system SHALL manage commercial insurance purchase from application through handling success, including add, batch add, replace, and rollback. For advance-pay (`isJfcd=0`) records, behavior MUST branch on `isNewData` between legacy and new workflows.
#### Scenario: Create insurance application
......@@ -122,7 +122,7 @@ The system SHALL manage commercial insurance purchase from application through h
- WHEN a purchase is submitted via `/insuranceDetail` add or batch-add endpoints
- THEN TInsuranceDetail records are created with pending handling status
- AND operation history is recorded in TInsuranceOperate
- AND advance-pay records MUST set `isHistoryAdvancePay` per launch-time rules
- AND advance-pay records MUST set `isNewData=1` on dispatch when advance-pay conditions are met
#### Scenario: Complete insurance handling
......@@ -179,5 +179,5 @@ The insurances module SHALL integrate with EKP for settlement push/retry and run
- GIVEN an advance-pay push to EKP with `fd_jfcd=是`
- WHEN `initValues` builds the push payload
- THEN `fd_new_data` MUST reflect HRO `isHistoryAdvancePay` via standardized conversion
- THEN `fd_new_data` MUST equal HRO `isNewData` (same value, no inversion)
- AND new advance-pay actual push MUST set `有无预估=否` while legacy MUST retain existing estimate flag rules
......@@ -8,11 +8,11 @@
- [x] 1.6 EKP 实体 `EkpInsurancesInfo``fdNewData` 及 Mapper
- [x] 1.7 `InsurancesConstants``IS_HISTORY_ADVANCE_PAY_YES/NO``EKP_FD_NEW_DATA_YES/NO`
- [x] 1.8 新增 `AdvancePaymentHelper``isJfcd``isLegacyJfcdData``isNewJfcdData``toEkpFdNewData`/`fromEkpFdNewData` 转换)
- [x] 1.9 配置项 `advance-pay.new-data-launch-time` 写入 `application.yml` 及各环境 yml
- [x] 1.9 ~~配置项 `advance-pay.new-data-launch-time`~~ **已废弃**(见 `hro-jfcd-optimization-doc-sync`:发版后固定 `isNewData=1`
## 2. 见费出单标识与派单分流(P1)
- [x] 2.1 改造 `initJfcd` / `initJfcdBatch`:满足见费出单时写 `isJfcd=0`按 launchTime 写 `isHistoryAdvancePay``bpoEnable=否` 条件不变)
- [x] 2.1 改造 `initJfcd` / `initJfcdBatch`:满足见费出单时写 `isJfcd=0`固定 `isNewData=1``bpoEnable=否` 条件不变)
- [x] 2.2 改造 `initJfcdInfo`:历史分支原样保留(或提取 `initLegacyJfcdInfo`);新增 `initNewAdvancePayInfo`(待投保、无预估 settle、不写 defaultSettleId)
- [x] 2.3 改造 `addInsurance` / `batchInsurance`:历史进 pushList + 待办 7;新数据不进 pushList、待办 3、不调用 createInsuranceInfo
- [x] 2.4 改造 `updateEmployeeInsurancePre` / `updateEmployeeInsurancePreRenew`:新数据待办状态与待投保一致
......
......@@ -8,7 +8,7 @@
| 层级 | 工具建议 | 覆盖目标 | 优先级 |
|------|----------|----------|--------|
| **L1 单元** | JUnit 5 + Mockito | `AdvancePaymentHelper`、launchTime 切点、HRO↔EKP 字段转换 | P0 |
| **L1 单元** | JUnit 5 + Mockito | `AdvancePaymentHelper` 分流、HRO↔EKP 字段直传 | P0 |
| **L2 服务** | Spring Boot Test + H2/测试库 | `initJfcdInfo` 分流、`registeredPolicyPremium`、退保分支 | P1 |
| **L3 接口** | MockMvc / RestAssured | Controller 入参出参、权限、状态码 | P1 |
| **L4 集成** | 测试环境 + EKP Mock/联调库 | EKP 推送字段、回调、实缴/差额 | P2 |
......@@ -47,27 +47,16 @@
| UT-03-03 | `fromEkpFdNewData` | `0` | `0` |
| UT-03-04 | `fromEkpFdNewData` | `1` | `1` |
### UT-04 `resolveIsNewDataForNewRecord`(launchTime 切点
### UT-04 ~~launchTime 切点~~(已废弃
| 用例 ID | 配置 | 当前时间(Mock) | 期望 |
|---------|------|------------------|------|
| UT-04-01 | `launchTime=2099-01-01` | 2026-06-18 | `0`(历史) |
| UT-04-02 | `launchTime=2026-01-01` | 2026-06-18 | `1`(新) |
| UT-04-03 | `launchTime=2026-06-18 00:00:00` | 同日 00:00:00 | `1` |
| UT-04-04 | 非法配置字符串 | 任意 | `0`(保守走历史) |
**对应方案场景**:§9.2 #12
---
## 二、L2 服务层测试(Mock EKP / 收入服务)
> 2026-06-18 见费出单优化已移除 `resolveIsNewDataForNewRecord` 与 `advance-pay.new-data-launch-time`;派单固定 `isNewData=1`,无需 UT-04。
### SVC-01 派单分流 — 新增 `addInsurance`
| 用例 ID | 数据标识 | 前置 | 操作 | 断言 |
|---------|----------|------|------|------|
| SVC-01-01 | 历史 | 险种见费出单=是,`bpoEnable=否`launchTime 未来 | 新增派单 | `buyHandleStatus=6``defaultSettleId` 非空;`pushEstime` 被调用;待办 `processStatus=7` |
| SVC-01-02 | 新 | 同上,launchTime 已过 | 新增派单 | `buyHandleStatus=1``defaultSettleId` 空;`pushEstime` 未调用;`createInsuranceInfo` 未在派单时调用;待办 `processStatus=3` |
| SVC-01-01 | 历史 | 险种见费出单=是,`bpoEnable=否`DB 存量 `isNewData=0` | 新增派单(仅迁移存量可测历史派单) | `buyHandleStatus=6``defaultSettleId` 非空;`pushEstime` 被调用;待办 `processStatus=7` |
| SVC-01-02 | 新 | 同上,发版后新派单 | 新增派单 | `isNewData=1``buyHandleStatus=1``defaultSettleId` 空;`pushEstime`调用;待办 `processStatus=3` |
| SVC-01-03 | 非见费 | `isJfcd=1` | 新增派单 | `isNewData` 空;走非见费出单逻辑 |
| SVC-01-04 | BPO 项目 | `bpoEnable=是` | 新增派单 | `isJfcd=1`;不走提前缴费 |
......@@ -214,7 +203,7 @@
| 9 | EKP 回调/手动拉取 no-op | SVC-05-01 ~ 04 |
| 10 | 前端退保按钮 | API-04, UI-03 |
| 11 | 删除投保 | SVC-07-01, API-06, UI-02 |
| 12 | launchTime 切点 | UT-04-01 ~ 04 |
| 12 | 发版后派单固定 `isNewData=1` | SVC-01-02 |
| 13 | bpoEnable 不走见费出单 | SVC-01-04 |
| 14 | EKP 字段一致 | UT-03, EKP-01 ~ 06 |
......@@ -236,7 +225,7 @@
# 历史见费出单
is_jfcd=0, is_new_data=0, buy_handle_status=6
# 新提前缴费(launchTime 之后
# 新提前缴费(发版后新派单,initJfcd 固定 isNewData=1
is_jfcd=0, is_new_data=1, buy_handle_status=1, default_settle_id=NULL
# 非见费出单
......
......@@ -44,7 +44,7 @@ HRO 与 EKP 语义相反,依赖 `AdvancePaymentHelper.toEkpFdNewData` 做翻
|---|---|---|
| `isLegacyJfcdData` | `isJfcd=0` 且 (`isHistoryAdvancePay` 空或 `1`) | `isJfcd=0` 且 (`isNewData` 空或 `0`) |
| `isNewJfcdData` | `isJfcd=0``isHistoryAdvancePay=0` | `isJfcd=0``isNewData=1` |
| `resolveIsNewDataForNewRecord` | launch 后 → `0`(新) | launch 后 → `1`(新) |
| `resolveIsNewDataForNewRecord` | ~~launch 后写 `0`(新)~~ | **已删除**`initJfcd` 固定写 `1` |
空值:`is_jfcd=0``is_new_data` 空视同历史(`0`),与旧逻辑「空视同 `1` 历史」一致。
......@@ -91,7 +91,7 @@ String IS_NEW_DATA_NO = "0"; // 历史见费出单
1. 执行 HRO DDL + 值翻转 UPDATE(或合并进 `hro-advance-pay-insurance-compat.sql` 修订版)
2. 发版 Java:Entity/Mapper/Helper/Service 全量替换
3. 验证:历史 `is_new_data=0` 冒烟;launchTime 后新派单 `is_new_data=1`
3. 验证:历史 `is_new_data=0` 冒烟;发版后新派单 `is_new_data=1``initJfcd` 固定)
4. 同步 yifu-ui 字段名(若已对接)
5. 更新 V24 与 `test-plan.md` 测试数据模板
......@@ -109,7 +109,7 @@ String IS_NEW_DATA_NO = "0"; // 历史见费出单
| `InsurancesConstants` | `IS_NEW_DATA_YES/NO` |
| `TInsuranceDetail` + VO/Param | `isNewData` |
| `TInsuranceDetailMapper.xml` | `IS_NEW_DATA` |
| `AdvancePaymentHelper` | 分流 + `resolveIsNewDataForNewRecord` |
| `AdvancePaymentHelper` | 分流`initJfcd` 固定 `isNewData=1` |
| `DoJointInsuranceTask.initValues` | `setFd_new_data(param.getIsNewData())` |
| `TInsuranceDetailServiceImpl` | 注释与 `setIsNewData` 调用 |
| `EkpInteractiveParam` | `isNewData`(若推送 param 带该字段) |
......
......@@ -7,8 +7,8 @@
- **BREAKING(HRO 库表/API 字段)**`t_insurance_detail.is_history_advance_pay` 重命名为 `is_new_data``CHAR(1)`**1=新 / 0=历史**,默认 `'1'`
- Java 全链路:`isHistoryAdvancePay``isNewData`(Entity / VO / Param / Mapper / Service 注释)
- 常量:`IS_HISTORY_ADVANCE_PAY_YES/NO``IS_NEW_DATA_YES/NO``1`/`0`,与 EKP `EKP_FD_NEW_DATA_*` 同值)
- `AdvancePaymentHelper`:分流条件取反(历史=`0` 或空视同历史;新=`1`);`resolveIsNewDataForNewRecord` 在 launchTime 后写 `1`;EKP 推送改为 **直传** `isNewData``fd_new_data`(可删除反向转换)
- 存量迁移:`is_history_advance_pay=1``is_new_data=0``=0``1``is_jfcd=0` 且空 → `0`
- `AdvancePaymentHelper`:分流条件取反;派单固定 `isNewData=1`;EKP 推送 **直传** `fd_new_data`
- 存量迁移:`is_jfcd=0``is_new_data=0`
- 同步更新 `V24/` 开发方案与 OpenSpec 测试计划中的 HRO 字段描述
## Capabilities
......@@ -28,5 +28,5 @@
- **API 响应**: 列表/详情 JSON 字段名由 `isHistoryAdvancePay` 变为 `isNewData`**BREAKING** 若前端已对接旧字段)
- **EKP**: 无新需求;推送逻辑简化,仍写 `fd_new_data`
- **前端**(yifu-ui): 若已读 `isHistoryAdvancePay`,需改为 `isNewData` 并反转展示逻辑(1=新,0=历史)
- **Non-goals**: 不改变历史/新提前缴费业务流程;不修改 `advance-pay.new-data-launch-time` 切点机制;不修改 EKP 表结构
- **Non-goals**: 不改变历史/新提前缴费业务流程;不修改 EKP 表结构
- **前置**: 建议在 `hro-advance-pay-insurance-compat` 已合入或同批发布;若库中尚无 `is_history_advance_pay`,可直接 ADD `is_new_data`
......@@ -12,8 +12,8 @@ The system SHALL distinguish legacy advance-pay (见费出单) data from new adv
#### Scenario: New data identification after launch time
- **WHEN** `isJfcd=0`, `isNewData=1`, and record created at or after `advance-pay.new-data-launch-time`
- **THEN** the record MUST follow new advance-pay workflow defined in advance-pay compat change
- **WHEN** `isJfcd=0`, advance-pay conditions are met on add or batch add after release
- **THEN** the system MUST set `isNewData=1` on dispatch
- **AND** EKP actual-premium pushes MUST set `fd_new_data=1`
#### Scenario: Stock data migration
......@@ -53,7 +53,7 @@ The system SHALL manage commercial insurance purchase from application through h
- WHEN a purchase is submitted via `/insuranceDetail` add or batch-add endpoints
- THEN TInsuranceDetail records are created with pending handling status
- AND operation history is recorded in TInsuranceOperate
- AND advance-pay records MUST set `isNewData` per launch-time rules (`1` after launch, `0` before launch for legacy path)
- AND advance-pay records MUST set `isNewData=1` on dispatch when advance-pay conditions are met
#### Scenario: Complete insurance handling
......
......@@ -16,7 +16,7 @@
## 4. 业务逻辑(yifu-insurances-biz)
- [x] 4.1 `AdvancePaymentHelper`:分流条件改为 `isNewData``resolveIsHistoryAdvancePayForNewRecord``resolveIsNewDataForNewRecord`(launch 后写 `1`);删除或简化 `toEkpFdNewData`/`fromEkpFdNewData`直传
- `AdvancePaymentHelper`:分流条件改为 `isNewData`;~~`resolveIsNewDataForNewRecord`~~ 已删除;`toEkpFdNewData` 同值直传
- [x] 4.2 `TInsuranceDetailServiceImpl``initJfcd`/`initJfcdBatch` 及注释块:`setIsNewData` / `getIsNewData`;注释「isHistoryAdvancePay=0」→「isNewData=1」
- [x] 4.3 `DoJointInsuranceTask.initValues``setFd_new_data(param.getIsNewData())` 直传
- [x] 4.4 其他引用点(`pushEstime` 跳过、`updateInsuranceSettleStatus``pullPaymentStatus` 等):Helper 方法名不变,确认分流仍正确
......@@ -31,5 +31,5 @@
## 6. 验证
- [x] 6.1 存量迁移后 SQL 断言:`is_jfcd=0``is_new_data=0`,行为与改名前历史分支一致
- [x] 6.2 launchTime 后新派单:`is_new_data=1`,EKP 推送 `fd_new_data=1`,无反向转换
- [x] 6.2 发版后新派单:`is_new_data=1``initJfcd` 固定),EKP 推送 `fd_new_data=1` 同值直传
- [x] 6.3 全仓 grep:`isHistoryAdvancePay``is_history_advance_pay``IS_HISTORY_ADVANCE_PAY` 零残留(compat change 文档除外时可注明 deprecated)
## Context
**代码现状**(commit `2bd69554e`)与 **文档现状**(commit `4f5e6437f` 及之前 OpenSpec)的差异:
| 主题 | 文档(旧) | 代码(现) |
| --- | --- | --- |
| 新/历史标识 | `advance-pay.new-data-launch-time` 切点 | 已删除配置;派单固定 `isNewData=1` |
| 历史标识来源 | launchTime 前派单写 `0` | 仅 SQL 存量 `is_jfcd=0``is_new_data=0` |
| Helper | `resolveIsNewDataForNewRecord()` | 方法已删除 |
| 登记实缴校验 | 未区分新数据 settle 拦截 | 新数据跳过 **预估结算状态** 拦截,保留 **支出状态** 拦截 |
| EKP 收款回调 | Controller 全批新数据直接 `R.ok()` | 已移除;`DoJointInsuranceTask``isNewJfcdData``continue` |
## 合理性评估(同步前结论)
### ✅ 合理 — 移除 launchTime,派单固定 `isNewData=1`
- 上线模型清晰:**发版前跑迁移** → 存量历史 `0`**发版后新派单** → 恒为 `1`
- 避免测试/生产配置不一致导致误写 `0` 走新逻辑或误写 `1` 走历史逻辑
- 与注释「上线后的数据都是新数据,历史数据有数据库更新」一致
- **前提**:上线顺序必须是 DDL+刷数 → 再发版应用(文档需强调)
### ✅ 合理 — 登记实缴校验放宽新数据的预估结算拦截
- 新数据无预估 settle,不应被「预估结算中/已结算」规则挡住实缴登记
- 实缴登记后会有 `defaultSettleId`,仍需拦截 **支出中/已支出**`payStatus`),现逻辑保留
- 变更符合 §4.4 新分支「无 defaultSettleId 时放宽预估校验」的延伸
### ✅ 合理 — 移除 Controller 层 EKP 回调批量 skip
- `DoJointInsuranceTask.updateInsuranceSettleStatus` 已对每条 `isNewJfcdData` 执行 `continue`
- Controller skip 为冗余;混合批次场景下移除更安全
- 行为不变:纯新数据回调仍 no-op
### ⚠️ 文档需补充的风险点
1. **发版顺序**:未跑迁移就发版 → 存量 `is_jfcd=0``is_new_data` 为空,分流仍视同历史(Helper 空=历史),但新派单会写 `1` — 可接受
2. **UAT 测历史派单**:发版后无法通过配置模拟「新派单写历史」,需用测试库保留 `is_new_data=0` 的存量或手工改库
3. **AdvancePaymentHelper** 残留未使用 import(`@Value``LocalDateTime`)— 可选代码清理,非本 doc change
## Goals / Non-Goals
**Goals:**
- 文档与 `2bd69554e` 代码行为一致
- 明确上线顺序与 UAT 测历史分支方式
- 更新 test-plan 删除过时 UT-04
**Non-Goals:**
- 修改 Java 实现
- 归档或合并既有 OpenSpec change
## Decisions
### D1: 标识写入规则表述
**新表述**
```
存量:迁移 SQL 将 is_jfcd=0 刷 is_new_data=0
增量:initJfcd/initJfcdBatch 见费出单时写 isNewData=1(固定)
```
### D2: 删除 launchTime 全篇引用
从 V24 §2.3、§6、§9、OpenSpec design/proposal/tasks/test-plan 移除;修订记录增加「2026-06-18 见费出单优化:取消 launchTime,派单固定新数据」。
### D3: 登记实缴校验文档
在 V24 §4.4 或校验章节补充:
-`defaultSettleId` 时查 EKP 状态
- **历史**`settleStatus` 结算中/已结算 → 禁止登记
- **新**:跳过 `settleStatus` 拦截;**共用** `payStatus` 支出中/已支出拦截
## Migration Plan
1. 更新 V24 主方案
2. 更新 `hro-advance-pay-insurance-compat` / `new-data-field` 的 design、proposal、tasks、spec delta、test-plan
3. (可选)`/opsx:sync` 将 delta 合并到 `openspec/specs/insurances/spec.md`
## Open Questions
- 是否将 `hro-advance-pay-insurance-compat` tasks 中 launchTime 相关项标为 superseded(由本 doc sync 说明)— 建议 yes
## Why
提交 `2bd69554e`(见费出单优化)在代码侧做了三处实质调整,但 V24 方案、OpenSpec change(`hro-advance-pay-insurance-compat` / `hro-advance-pay-new-data-field`)及 `test-plan.md` 仍描述 **launchTime 切点**`resolveIsNewDataForNewRecord()` 等已删除逻辑,文档与现网实现不一致,易误导联调与测试。
## What Changes
- 删除/修订所有 `advance-pay.new-data-launch-time` 配置说明
- 派单写 `isNewData` 规则改为:**上线后见费出单派单固定 `1`(新)****历史数据仅依赖 DDL 存量刷数 `0`**
- 删除 `AdvancePaymentHelper.resolveIsNewDataForNewRecord()` 的文档引用
- 补充 `registeredPolicyPremiumCheck`:新数据有实缴 settle 时仍校验 **支出状态**,但不因 **预估结算状态** 拦截
- 说明 EKP 回调 `updateInsuranceSettleStatus`:Controller 层批量 skip 已移除,**逐条 skip 仍在 `DoJointInsuranceTask`**
- 更新测试计划:移除 UT-04 launchTime 用例;调整 §9.2 #12 描述
## Capabilities
### New Capabilities
(无)
### Modified Capabilities
- `insurances`: 新/历史分流标识写入规则由「配置切点」改为「DB 迁移 + 派单固定新」;登记实缴校验对新数据放宽预估结算拦截
## Impact
- **文档**: `V24/HRO-提前缴费商险数据兼容开发方案.md``openspec/changes/hro-advance-pay-*``test-plan.md`
- **代码**: 无(本 change 仅文档同步;实现已在 `2bd69554e`
- **Non-goals**: 不回滚见费出单优化代码;不修改 yifu-ui
## MODIFIED Requirements
### Requirement: Advance Payment Data Classification
The system SHALL distinguish legacy advance-pay (见费出单) data from new advance-pay data using `is_new_data` on `TInsuranceDetail` (`1`=new, `0`=legacy), synchronized to EKP as `fd_new_data` with identical values. **Legacy records MUST be marked by database migration** (`is_jfcd=0``is_new_data=0`); **new dispatches after release MUST write `isNewData=1`** when advance-pay conditions are met, without a runtime launch-time configuration.
#### Scenario: Legacy data identification
- **WHEN** `isJfcd=0` and (`isNewData` is `0` or NULL)
- **THEN** the record MUST follow legacy advance-pay workflow unchanged from pre-release behavior
- **AND** EKP pushes for estimate/actual/difference MUST set `fd_new_data=0`
#### Scenario: New data identification on dispatch after release
- **WHEN** `isJfcd=0`, advance-pay conditions are met on add or batch add, and the application version includes post-optimization dispatch logic
- **THEN** the system MUST set `isNewData=1` on dispatch
- **AND** EKP actual-premium pushes MUST set `fd_new_data=1`
#### Scenario: Stock data migration
- **WHEN** existing records have `is_jfcd=0` before release
- **THEN** migration MUST set `is_new_data=0` (legacy)
- **AND** behavior MUST remain identical to pre-migration legacy advance-pay
### Requirement: Premium and Policy Registration
The system SHALL support registration of policy premiums, invoice numbers, and policy period maintenance. For new advance-pay data, validation MUST tolerate absence of estimate `defaultSettleId`, and MUST NOT block registration based on **estimate settlement status** when an actual-premium settle exists; **expenditure status (`payStatus`)** blocking MUST still apply.
#### Scenario: Register policy premium
- GIVEN a handled insurance record
- WHEN premium registration is submitted
- THEN premium amount and billing metadata are persisted on TInsuranceDetail
- AND invoice number can be registered separately
- AND new advance-pay registration MUST apply BPO/non-BPO EKP amount rules and skip difference generation
#### Scenario: New advance-pay skip estimate settle blocking
- **WHEN** new advance-pay record has `defaultSettleId` pointing to actual premium and EKP estimate settle status is settling or settled
- **THEN** registration MUST NOT be rejected solely for estimate `settleStatus`
- **AND** registration MUST still be rejected when EKP `payStatus` is expenditure-in-progress or expenditure-completed
### Requirement: EKP Payment Callback Isolation for New Data
EKP payment callbacks and manual payment pull MUST NOT alter purchase workflow state for new advance-pay records that never enter pending payment. Per-record skip in `DoJointInsuranceTask` is sufficient; controller-level batch short-circuit is not required.
#### Scenario: Skip EKP settle callback for new data
- **WHEN** `updateInsuranceSettleStatus` processes a callback row for new advance-pay detail
- **THEN** the row MUST be skipped without updating `buyHandleStatus`, `paymentStatus`, or pre-task status
#### Scenario: Exclude new data from manual payment pull
- **WHEN** `pullPaymentStatus` runs
- **THEN** new advance-pay records MUST be excluded from pull list
- **AND** direct pull by new-data ID MUST be skipped without side effects
## 1. V24 主方案
- [x] 1.1 `HRO-提前缴费商险数据兼容开发方案.md` §2.2/§2.3:删除 launchTime;改为「迁移刷历史 + 派单固定 `isNewData=1`
- [x] 1.2 §4.4 登记实缴:补充新数据跳过预估 `settleStatus` 拦截、保留 `payStatus` 拦截
- [x] 1.3 §9.2 #12、§10 待确认项 #5:删除 launchTime 表述
- [x] 1.4 修订记录增加 `2026-06-18 见费出单优化` 条目
## 2. OpenSpec 既有 change 文档
- [x] 2.1 `hro-advance-pay-insurance-compat`:proposal/design/tasks/spec delta/test-plan 移除 launchTime、`resolveIsNewData*`
- [x] 2.2 `hro-advance-pay-new-data-field`:design/proposal/tasks 移除 launchTime 依赖说明
- [x] 2.3 `test-plan.md`:删除 UT-04;SVC-01 去掉 launchTime 前置;更新 §9.2 #12 映射
## 3. 基线 spec(可选)
- [x] 3.1 运行 `/opsx:sync` 或手工合并本 change delta 到 `openspec/specs/insurances/spec.md`
## 4. 验证
- [x] 4.1 grep 文档:`new-data-launch-time``resolveIsNewDataForNewRecord` 零残留(历史修订记录除外)
- [x] 4.2 对照 `2bd69554e` 代码:initJfcd、registeredPolicyPremiumCheck、updateInsuranceSettleStatus 描述一致
......@@ -166,6 +166,33 @@ The insurances module SHALL integrate with EKP for settlement push/retry and run
- THEN overdue insurance records and renewal triggers are refreshed
- AND related pre-tasks or warnings are updated
### Requirement: Advance Payment Data Classification
The system SHALL distinguish legacy advance-pay (见费出单) data from new advance-pay data using `is_new_data` on `TInsuranceDetail` (`1`=new, `0`=legacy), synchronized to EKP as `fd_new_data` with identical values. Legacy records MUST be marked by database migration (`is_jfcd=0``is_new_data=0`); new dispatches after release MUST write `isNewData=1` when advance-pay conditions are met.
#### Scenario: Legacy data identification
- **WHEN** `isJfcd=0` and (`isNewData` is `0` or NULL)
- **THEN** the record MUST follow legacy advance-pay workflow (pending payment, EKP estimate, difference)
- **AND** EKP pushes MUST set `fd_new_data=0`
#### Scenario: New data on dispatch after release
- **WHEN** `isJfcd=0` and advance-pay conditions are met on add or batch add
- **THEN** the system MUST set `isNewData=1` and skip pending payment and EKP estimate on dispatch
#### Scenario: EKP callback skip for new data
- **WHEN** EKP payment callback processes a new advance-pay detail
- **THEN** `DoJointInsuranceTask.updateInsuranceSettleStatus` MUST skip the row without updating purchase workflow state
- **AND** controller-level batch short-circuit is not required
#### Scenario: New advance-pay skip estimate settle blocking on registration
- **WHEN** new advance-pay record has actual premium settle and EKP estimate `settleStatus` is settling or settled
- **THEN** `registeredPolicyPremium` MUST NOT be rejected solely for estimate settlement status
- **AND** registration MUST still be rejected when EKP `payStatus` is expenditure-in-progress or expenditure-completed
### Requirement: Cross-Module Integration
The insurances module SHALL consume employee and onboarding context from yifu-archives and yifu-csp, and expose data to salary risk views where applicable.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment