Commit a5ce3757 authored by fangxinjiang's avatar fangxinjiang

chore(openspec): 归档 advance-pay 变更并同步商险基线 spec

将两个提前缴费 OpenSpec 变更移入 archive,并把新提前缴费分流、实缴登记与退保规则合并进 openspec/specs/insurances/spec.md。
Co-authored-by: 's avatarCursor <cursoragent@cursor.com>
parent 2b84a6e7
......@@ -8,10 +8,10 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
**Goals:**
- 通过 `is_new_data` 字段分流历史/新提前缴费逻辑
- 历史分支(`isNewData=0` 或 NULL)行为与上线前完全一致
- 通过 `is_history_advance_pay` 字段分流历史/新提前缴费逻辑
- 历史分支(`isHistoryAdvancePay=1` 或 NULL)行为与上线前完全一致
- 新分支实现:派单直接待投保、无预估/差额、实缴登记推 EKP、独立退保规则
- DDL + 存量迁移;发版后派单固定 `isNewData=1`(见 `hro-jfcd-optimization-doc-sync`
- DDL + 存量迁移 + 发布时间切点可配置上线
**Non-Goals:**
......@@ -38,23 +38,21 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
**备选**: 拆到 `advance/` 包下 Handler 类 — 可选,文档建议 P0 可先 private 方法,后续再拆。
### D3: 上线发版模型(非 launchTime 切点)
### D3: 发布时间切点而非功能开关
**选择**:存量 SQL 刷 `is_new_data=0`;发版后 `initJfcd` 固定写 `isNewData=1`
**选择**: 配置 `advance-pay.new-data-launch-time`;满足见费出单且 `now >= launchTime``isHistoryAdvancePay=0`
**理由**:上线模型简单明确;2026-06-18 见费出单优化已移除 `advance-pay.new-data-launch-time`
**备选**:配置切点 — 已废弃。
**理由**: 产品已确认;避免误开开关导致新逻辑作用于未就绪环境。
### D4: 数据模型
| 层 | 字段 | 取值 |
|---|---|---|
| HRO `t_insurance_detail` | `is_new_data` CHAR(1) | `1` 新 / `0` 历史 / NULL 非提前缴费 |
| HRO `t_insurance_detail` | `is_history_advance_pay` CHAR(1) | `1` 历史 / `0` / NULL 非提前缴费 |
| EKP `ekp_insurances_info` | `fd_new_data` CHAR(1) | `1` 新 / `0` 历史;默认 `1` |
| Java | `TInsuranceDetail.isNewData` | 与库表一致 |
| Java | `TInsuranceDetail.isHistoryAdvancePay` | 与库表一致 |
**写入规则**: 存量 `is_jfcd=0` → 迁移为 `0`;发版后派单写 `1`;EKP 推送同值直传
**写入规则**: 存量 `is_jfcd=0` → 迁移为 `1`;新数据派单写 `0`;EKP 推送在 `DoJointInsuranceTask.initValues` 统一转换
### D5: 新数据派单行为差异
......@@ -70,7 +68,7 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
- `fd_new_data=1``有无预估=否`
- BPO: 应收=0,应付=实缴;非 BPO: 应收=应付=实缴
- 跳过差额生成;新数据 `registeredPolicyPremiumCheck` 跳过预估 `settleStatus` 拦截,保留 `payStatus` 拦截
- 跳过差额生成;`registeredPolicyPremiumCheck` 对无 `defaultSettleId` 放宽
### D7: 新数据退保 vs 历史
......@@ -98,14 +96,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`(全量历史刷 `is_new_data=0` / `fd_new_data=0`
3. **发版 HRO**: 含 `AdvancePaymentHelper` + 历史分流 + 新分支
4. **验证历史**: 冒烟确认存量 `isNewData=0` 行为不变
5. **验证新数据**: 全量测试 §9.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 场景
6. **EKP 联调**: 实缴 `有无预估=否` + `fd_new_data=1`
7. **前端同步**: 禁用撤回/删除;退保前查支出状态
**回滚**: 回退应用版本;DDL 列可保留(nullable,不影响历史)。
**回滚**: `launchTime` 设为未来时间停止新数据写入;新分支代码可保留(无 `0` 数据不触发);DDL 列可保留(nullable,不影响历史)。
## API / 模块影响
......@@ -113,6 +111,7 @@ 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` |
......@@ -125,7 +124,7 @@ HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) →
| 逻辑 | 类/方法 | 改造 |
|---|---|---|
| 见费出单标识 | `initJfcd` / `initJfcdBatch` | 固定 `isNewData=1` |
| 见费出单标识 | `initJfcd` / `initJfcdBatch` | launchTime + 写字段 |
| 派单核心 | `initJfcdInfo` | 分流 |
| 派单后续 | `addInsurance` / `batchInsurance` | 新数据不进 pushList |
| EKP 预估 | `DoJointInsuranceTask.pushEstime` | 历史专用 |
......
......@@ -4,13 +4,14 @@ HRO 侧见费出单(提前缴费)现有逻辑要求派单后进入待缴费
## What Changes
- 新增 `is_new_data` 字段(HRO `t_insurance_detail` + EKP `fd_new_data`,同义同值 1新/0历史
- 存量 `is_jfcd=0` 数据迁移为历史(`is_new_data=0`);发版后新派单固定 `is_new_data=1`
- 新增 `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`
- 新增 `AdvancePaymentHelper` 分流工具,历史分支代码块原样保留,新逻辑独立方法/注释块
- 新提前缴费派单:跳过待缴费(6)、不推 EKP 预估、不生成预估 settle/差额;待办直接待投保(3)
- 新提前缴费实缴:登记保单保费时推送实缴(有无预估=否),BPO/非 BPO 应收应付规则;收入/管理费/风险金延至实缴登记
- 新提前缴费退保:独立校验(支出中/已支出禁止);不生成负数预估/差额;按实缴结算状态删实缴或推负数实缴
- EKP 回调/手动拉取对新数据逐条跳过;撤回/删除投保逻辑不改,仅加注释(前端禁用按钮)
- EKP 回调/手动拉取对新数据跳过;撤回/删除投保逻辑不改,仅加注释(前端禁用按钮)
- 配置项 `advance-pay.new-data-launch-time` 控制新数据写入切点
## 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_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).
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`).
#### Scenario: Legacy data identification
- **WHEN** `isJfcd=0` and (`isNewData` is `0` or NULL)
- **WHEN** `isJfcd=0` and (`isHistoryAdvancePay` is `1` 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
#### Scenario: New data identification after launch time
- **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
- **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
- **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)
- **THEN** migration MUST set `is_history_advance_pay=1`
- **AND** behavior MUST remain identical to pre-migration legacy advance-pay
### Requirement: New Advance-Pay Dispatch Workflow
For new advance-pay data (`isNewData=1`), the system SHALL skip pending-payment state and EKP estimate push on dispatch.
For new advance-pay data (`isHistoryAdvancePay=0`), 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 `isNewData` 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 `isHistoryAdvancePay` 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 `isNewData=1` on dispatch when advance-pay conditions are met
- AND advance-pay records MUST set `isHistoryAdvancePay` per launch-time rules
#### 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 equal HRO `isNewData` (same value, no inversion)
- THEN `fd_new_data` MUST reflect HRO `isHistoryAdvancePay` via standardized conversion
- 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`~~ **已废弃**(见 `hro-jfcd-optimization-doc-sync`:发版后固定 `isNewData=1`
- [x] 1.9 配置项 `advance-pay.new-data-launch-time` 写入 `application.yml` 及各环境 yml
## 2. 见费出单标识与派单分流(P1)
- [x] 2.1 改造 `initJfcd` / `initJfcdBatch`:满足见费出单时写 `isJfcd=0`固定 `isNewData=1``bpoEnable=否` 条件不变)
- [x] 2.1 改造 `initJfcd` / `initJfcdBatch`:满足见费出单时写 `isJfcd=0`按 launchTime 写 `isHistoryAdvancePay``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` 分流、HRO↔EKP 字段直传 | P0 |
| **L1 单元** | JUnit 5 + Mockito | `AdvancePaymentHelper`、launchTime 切点、HRO↔EKP 字段转换 | P0 |
| **L2 服务** | Spring Boot Test + H2/测试库 | `initJfcdInfo` 分流、`registeredPolicyPremium`、退保分支 | P1 |
| **L3 接口** | MockMvc / RestAssured | Controller 入参出参、权限、状态码 | P1 |
| **L4 集成** | 测试环境 + EKP Mock/联调库 | EKP 推送字段、回调、实缴/差额 | P2 |
......@@ -47,16 +47,27 @@
| UT-03-03 | `fromEkpFdNewData` | `0` | `0` |
| UT-03-04 | `fromEkpFdNewData` | `1` | `1` |
### UT-04 ~~launchTime 切点~~(已废弃
### UT-04 `resolveIsNewDataForNewRecord`(launchTime 切点
> 2026-06-18 见费出单优化已移除 `resolveIsNewDataForNewRecord` 与 `advance-pay.new-data-launch-time`;派单固定 `isNewData=1`,无需 UT-04。
| 用例 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 / 收入服务)
### SVC-01 派单分流 — 新增 `addInsurance`
| 用例 ID | 数据标识 | 前置 | 操作 | 断言 |
|---------|----------|------|------|------|
| 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-01 | 历史 | 险种见费出单=是,`bpoEnable=否`launchTime 未来 | 新增派单 | `buyHandleStatus=6``defaultSettleId` 非空;`pushEstime` 被调用;待办 `processStatus=7` |
| SVC-01-02 | 新 | 同上,launchTime 已过 | 新增派单 | `buyHandleStatus=1``defaultSettleId` 空;`pushEstime` 未调用;`createInsuranceInfo` 未在派单时调用;待办 `processStatus=3` |
| SVC-01-03 | 非见费 | `isJfcd=1` | 新增派单 | `isNewData` 空;走非见费出单逻辑 |
| SVC-01-04 | BPO 项目 | `bpoEnable=是` | 新增派单 | `isJfcd=1`;不走提前缴费 |
......@@ -203,7 +214,7 @@
| 9 | EKP 回调/手动拉取 no-op | SVC-05-01 ~ 04 |
| 10 | 前端退保按钮 | API-04, UI-03 |
| 11 | 删除投保 | SVC-07-01, API-06, UI-02 |
| 12 | 发版后派单固定 `isNewData=1` | SVC-01-02 |
| 12 | launchTime 切点 | UT-04-01 ~ 04 |
| 13 | bpoEnable 不走见费出单 | SVC-01-04 |
| 14 | EKP 字段一致 | UT-03, EKP-01 ~ 06 |
......@@ -225,7 +236,7 @@
# 历史见费出单
is_jfcd=0, is_new_data=0, buy_handle_status=6
# 新提前缴费(发版后新派单,initJfcd 固定 isNewData=1
# 新提前缴费(launchTime 之后
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`(新)~~ | **已删除**`initJfcd` 固定写 `1` |
| `resolveIsNewDataForNewRecord` | launch 后 → `0`(新) | launch 后 → `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` 冒烟;发版后新派单 `is_new_data=1``initJfcd` 固定)
3. 验证:历史 `is_new_data=0` 冒烟;launchTime 后新派单 `is_new_data=1`
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` | 分流`initJfcd` 固定 `isNewData=1` |
| `AdvancePaymentHelper` | 分流 + `resolveIsNewDataForNewRecord` |
| `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`:分流条件取反;派单固定 `isNewData=1`;EKP 推送 **直传** `fd_new_data`
- 存量迁移:`is_jfcd=0``is_new_data=0`
- `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`
- 同步更新 `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**: 不改变历史/新提前缴费业务流程;不修改 EKP 表结构
- **Non-goals**: 不改变历史/新提前缴费业务流程;不修改 `advance-pay.new-data-launch-time` 切点机制;不修改 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`, advance-pay conditions are met on add or batch add after release
- **THEN** the system MUST set `isNewData=1` on dispatch
- **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
- **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=1` on dispatch when advance-pay conditions are met
- AND advance-pay records MUST set `isNewData` per launch-time rules (`1` after launch, `0` before launch for legacy path)
#### Scenario: Complete insurance handling
......
......@@ -16,7 +16,7 @@
## 4. 业务逻辑(yifu-insurances-biz)
- `AdvancePaymentHelper`:分流条件改为 `isNewData`;~~`resolveIsNewDataForNewRecord`~~ 已删除;`toEkpFdNewData` 同值直传
- [x] 4.1 `AdvancePaymentHelper`:分流条件改为 `isNewData``resolveIsHistoryAdvancePayForNewRecord``resolveIsNewDataForNewRecord`(launch 后写 `1`);删除或简化 `toEkpFdNewData`/`fromEkpFdNewData`直传
- [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 发版后新派单:`is_new_data=1``initJfcd` 固定),EKP 推送 `fd_new_data=1` 同值直传
- [x] 6.2 launchTime 后新派单:`is_new_data=1`,EKP 推送 `fd_new_data=1`,无反向转换
- [x] 6.3 全仓 grep:`isHistoryAdvancePay``is_history_advance_pay``IS_HISTORY_ADVANCE_PAY` 零残留(compat change 文档除外时可注明 deprecated)
......@@ -6,9 +6,125 @@ yifu-insurances(端口 5005)负责商业保险(商险)的全流程管理
## 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**.
#### 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
- **WHEN** `isJfcd=0` and `isNewData=1`
- **THEN** the record MUST follow new advance-pay workflow defined in advance-pay compat changes
- **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: New Advance-Pay Dispatch Workflow
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
- **WHEN** new advance-pay insurance is created via add or batch add
- **THEN** `buyHandleStatus` MUST remain pending insurance (1), not pending payment (6)
- **AND** `processStatus` for pre-tasks MUST be pending insurance (3), not pending payment (7)
#### Scenario: No estimate on dispatch
- **WHEN** new advance-pay dispatch completes
- **THEN** the system MUST NOT create estimate `TInsuranceSettle`, MUST NOT set `defaultSettleId`, and MUST NOT call `pushEstime`
- **AND** the system MUST NOT call `createInsuranceInfo` at dispatch time
#### Scenario: BPO project exclusion unchanged
- **WHEN** project has `bpoEnable=是`
- **THEN** advance-pay (`isJfcd=0`) MUST NOT be triggered, same as existing `initJfcd` rules
### Requirement: New Advance-Pay Actual Premium Registration
For new advance-pay insured records, actual premium registration SHALL push EKP actual settlement without difference generation.
#### Scenario: Register actual premium without difference
- **WHEN** `registeredPolicyPremium` is invoked for new advance-pay data with valid actual premium
- **THEN** the system MUST push actual premium to EKP with `有无预估=否`
- **AND** the system MUST NOT generate difference settle records
#### Scenario: BPO actual premium EKP amounts
- **WHEN** new advance-pay actual premium is registered for a BPO project
- **THEN** EKP receivable MUST be 0 and payable MUST equal actual premium amount
#### Scenario: Non-BPO actual premium EKP amounts
- **WHEN** new advance-pay actual premium is registered for a non-BPO project
- **THEN** EKP receivable and payable MUST both equal actual premium amount
#### Scenario: Deferred revenue on actual premium
- **WHEN** new advance-pay actual premium is successfully registered
- **THEN** `createInsuranceInfo` (or equivalent) MUST run based on actual premium amount
- **AND** revenue/management-fee/risk-fund MUST NOT have been created at dispatch time
#### Scenario: Block registration when expenditure in progress or completed
- **WHEN** new advance-pay record has `defaultSettleId` and EKP `payStatus` is expenditure-in-progress or expenditure-completed
- **THEN** `registeredPolicyPremiumCheck` MUST reject registration with user-visible error
- **AND** legacy estimate settle status checks MAY be skipped for new data without `defaultSettleId`
### Requirement: New Advance-Pay Rollback Rules
New advance-pay rollback SHALL NOT generate negative estimates or differences and SHALL use expenditure-based guard rules distinct from legacy.
#### Scenario: Block rollback when expenditure in progress or completed
- **WHEN** rollback is requested for new advance-pay data and EKP `payStatus` is expenditure-in-progress or expenditure-completed
- **THEN** rollback MUST be rejected with user-visible error
- **AND** frontend MAY disable rollback using `getPaymentSettleStatusFromEkp`
#### Scenario: Rollback without actual premium
- **WHEN** new advance-pay record is pending insurance or in-insurance with no actual premium
- **THEN** rollback MUST set status to rolled-back (4) without negative estimate or actual-premium EKP push
#### Scenario: Rollback with unsettled actual premium
- **WHEN** new advance-pay insured record has actual premium not yet settled in EKP
- **THEN** rollback MUST delete HRO/EKP actual premium data without negative estimate or difference
#### Scenario: Rollback with settled but unexpended actual premium
- **WHEN** new advance-pay insured record has EKP settle status settling or settled but expenditure not started
- **THEN** rollback MUST push negative actual premium to EKP
- **AND** MUST NOT generate negative estimate or difference
### Requirement: EKP Payment Callback Isolation for New Data
EKP payment callbacks and manual payment pull MUST NOT alter state for new advance-pay records that never enter pending payment.
#### Scenario: Skip EKP settle callback for new data
- **WHEN** `updateInsuranceSettleStatus` receives callback for new advance-pay detail
- **THEN** the method MUST return 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
### Requirement: Insurance Purchase Processing
The system SHALL manage commercial insurance purchase from application through handling success, including add, batch add, replace, and rollback.
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
......@@ -16,20 +132,21 @@ 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=1` for post-launch new records (legacy stock via DB migration)
#### Scenario: Complete insurance handling
- GIVEN a pending insurance handling record
- WHEN handling succeeds via import or manual confirmation
- THEN the record moves to insured status with premium and policy linkage
- AND pending payment amounts are updated on the purchase list view
- AND pending payment amounts are updated on the purchase list view for legacy advance-pay only
#### Scenario: Insurance rollback
- GIVEN a purchase in handling state
- GIVEN a purchase in handling state or insured state with advance-pay flag
- WHEN rollback is requested
- THEN the application returns to the prior workflow state
- AND rollback reason and operator are auditable
- THEN legacy advance-pay MUST follow existing rollback (negative estimate + delete EKP actual/difference)
- AND new advance-pay MUST follow new rollback rules without negative estimate or difference
### Requirement: Insured and Reduced Employee Management
......@@ -51,7 +168,7 @@ The system SHALL maintain separate views and workflows for active insured employ
### Requirement: Premium and Policy Registration
The system SHALL support registration of policy premiums, invoice numbers, and policy period maintenance.
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` while still enforcing expenditure guards when actual premium exists.
#### Scenario: Register policy premium
......@@ -59,6 +176,7 @@ The system SHALL support registration of policy premiums, invoice numbers, and p
- 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: Maintain insurance policy
......@@ -150,7 +268,7 @@ The system SHALL support insurance file uploads and maintain change logs for ins
### Requirement: EKP Integration and Scheduled Tasks
The insurances module SHALL integrate with EKP for settlement push/retry and run scheduled jobs for expiry refresh.
The insurances module SHALL integrate with EKP for settlement push/retry and run scheduled jobs for expiry refresh. EKP push MUST include `fd_new_data` for all advance-pay estimate and actual payloads, equal to HRO `isNewData` when `fd_jfcd=是`.
#### Scenario: EKP resend
......@@ -193,6 +311,13 @@ The system SHALL distinguish legacy advance-pay (见费出单) data from new adv
- **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
#### Scenario: EKP field mapping for advance-pay
- GIVEN an advance-pay push to EKP with `fd_jfcd=是`
- WHEN `initValues` builds the push payload
- THEN `fd_new_data` MUST equal HRO `isNewData` without value inversion
- AND new advance-pay actual push MUST set `有无预估=否` while legacy MUST retain existing estimate flag rules
### 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