Commit 4f5e6437 authored by fangxinjiang's avatar fangxinjiang

提前缴费商险兼容:OpenSpec 规范与 V24 方案,HRO is_new_data 与 EKP fd_new_data 对齐。

包含 V24 开发方案/需求文档、openspec 变更与基线 spec,以及 yifu-insurances 分流实现与 DDL。
Co-authored-by: 's avatarCursor <cursoragent@cursor.com>
parent db54e696
...@@ -141,6 +141,7 @@ ...@@ -141,6 +141,7 @@
| 字段 | 含义 | 见费出单典型值 | | 字段 | 含义 | 见费出单典型值 |
| --- | --- | --- | | --- | --- | --- |
| fd_jfcd | 是否见费出单 | 是 | | fd_jfcd | 是否见费出单 | 是 |
| fd_new_data | 是否新数据(1是/0否,默认1) | 历史见费出单:`0`;新提前缴费实缴:`1` |
| fd_3b13b2ecc164aa | 是否全部结算 | 是 | | fd_3b13b2ecc164aa | 是否全部结算 | 是 |
| fd_3af9d11088facc | 实际结算月份 | 空 | | fd_3af9d11088facc | 实际结算月份 | 空 |
| fd_3af9d1441ef7b6 | 有无预估 | 有 | | fd_3af9d1441ef7b6 | 有无预估 | 有 |
...@@ -154,3 +155,4 @@ ...@@ -154,3 +155,4 @@
| 日期 | 说明 | | 日期 | 说明 |
| --- | --- | | --- | --- |
| 2026-06-05 | 初稿:建立 EKP 五模块章节结构,标注待梳理 | | 2026-06-05 | 初稿:建立 EKP 五模块章节结构,标注待梳理 |
| 2026-06-18 | 附录增 `fd_new_data`;HRO `is_new_data` 与 EKP 同值对齐 |
...@@ -125,7 +125,7 @@ ...@@ -125,7 +125,7 @@
| 术语 | 说明 | | 术语 | 说明 |
| --- | --- | | --- | --- |
| 提前缴费 | 商险业务中在常规流程前预先缴费的数据类型 | | 提前缴费 | 商险业务中在常规流程前预先缴费的数据类型 |
| 历史数据 / 新数据 | 通过新增字段标识;历史数据走既有逻辑,新数据走本需求新逻辑 | | 历史数据 / 新数据 | HRO `is_new_data` 与 EKP `fd_new_data` **同义同值**(1=新,0=历史,默认1) |
| 预估数据 | 投保前/投保过程中产生的预估收付数据 | | 预估数据 | 投保前/投保过程中产生的预估收付数据 |
| 实缴数据 | 实际缴纳/import 后的真实收付数据 | | 实缴数据 | 实际缴纳/import 后的真实收付数据 |
| 差额数据 | 预估与实缴之间的差异数据 | | 差额数据 | 预估与实缴之间的差异数据 |
...@@ -135,3 +135,11 @@ ...@@ -135,3 +135,11 @@
| 收款结算 | EKP 侧对客户/项目的收款结算流程 | | 收款结算 | EKP 侧对客户/项目的收款结算流程 |
| BPO 项目 | 业务流程外包类项目,应收为 0,走成本归集 | | BPO 项目 | 业务流程外包类项目,应收为 0,走成本归集 |
| 非 BPO 项目 | 常规项目,应收应付均为实缴金额 | | 非 BPO 项目 | 常规项目,应收应付均为实缴金额 |
### 字段映射(HRO ↔ EKP)
| HRO `is_new_data` | 含义 | EKP `fd_new_data` | 含义 |
| --- | --- | --- | --- |
| `1` | 新提前缴费 | `1` | 是否新数据=是 |
| `0` | 历史提前缴费 | `0` | 是否新数据=否 |
| `NULL` | 非提前缴费 | — | `fd_jfcd=否` 时不写入 |
## Context
HRO 商险见费出单(`isJfcd=0`)当前流程:派单 → 待缴费(6) → 推 EKP 预估 → EKP 收款 → 待投保(1) → 投保成功 → 登记实缴(可生成差额)。EKP 新提前缴费规则要求新数据跳过待缴费与预估,实缴直接按 BPO/非 BPO 推 EKP。
既有代码集中在 `yifu-insurances-biz``TInsuranceDetailServiceImpl`(派单/实缴/退保)和 `DoJointInsuranceTask`(EKP 推送)。参考文档:`V24/HRO-提前缴费商险数据兼容开发方案.md`
## Goals / Non-Goals
**Goals:**
- 通过 `is_history_advance_pay` 字段分流历史/新提前缴费逻辑
- 历史分支(`isHistoryAdvancePay=1` 或 NULL)行为与上线前完全一致
- 新分支实现:派单直接待投保、无预估/差额、实缴登记推 EKP、独立退保规则
- DDL + 存量迁移 + 发布时间切点可配置上线
**Non-Goals:**
- 重构或优化历史见费出单代码块
- 修改 `bpoEnable=是` 不走见费出单的规则
- EKP 侧表单/流程大改(需联调配合,不在 HRO 单端 scope)
- yifu-ui 具体页面改造(仅标注需同步的前端行为)
## Decisions
### D1: 分流入口统一为 `AdvancePaymentHelper`
**选择**: 新增工具类 `AdvancePaymentHelper`,提供 `isLegacyJfcdData` / `isNewJfcdData` / `toEkpFdNewData`
**理由**: 避免散落 `isJfcd` 判断误伤非见费出单;所有分支先判 `isJfcd` 再判历史/新。
**备选**: 直接在 `InsurancesConstants` 加静态方法 — 拒绝,职责不清。
### D2: 历史逻辑「代码块不动」,新逻辑独立 private 方法
**选择**: `initJfcdInfo` 顶部 if-else 分流;历史块原样保留或提取为 `initLegacyJfcdInfo`;新逻辑 `initNewAdvancePayInfo`
**理由**: 最小回归风险;代码 review 时可清晰识别变更边界。
**备选**: 拆到 `advance/` 包下 Handler 类 — 可选,文档建议 P0 可先 private 方法,后续再拆。
### D3: 发布时间切点而非功能开关
**选择**: 配置 `advance-pay.new-data-launch-time`;满足见费出单且 `now >= launchTime``isHistoryAdvancePay=0`
**理由**: 产品已确认;避免误开开关导致新逻辑作用于未就绪环境。
### D4: 数据模型
| 层 | 字段 | 取值 |
|---|---|---|
| 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.isHistoryAdvancePay` | 与库表一致 |
**写入规则**: 存量 `is_jfcd=0` → 迁移为 `1`;新数据派单写 `0`;EKP 推送在 `DoJointInsuranceTask.initValues` 统一转换。
### D5: 新数据派单行为差异
| 项 | 历史 | 新 |
|---|---|---|
| 投保状态 | 待缴费(6) | 待投保(1) |
| 预估 settle | 创建 + pushEstime | 不创建 |
| createInsuranceInfo | 派单时 | 实缴登记时 |
| 待办 processStatus | 7 待缴费 | 3 待投保 |
| pushList | 加入 | 不加入 |
### D6: 新数据实缴 EKP 规则
- `fd_new_data=1``有无预估=否`
- BPO: 应收=0,应付=实缴;非 BPO: 应收=应付=实缴
- 跳过差额生成;`registeredPolicyPremiumCheck` 对无 `defaultSettleId` 放宽
### D7: 新数据退保 vs 历史
| 拦截条件 | 历史 | 新 |
|---|---|---|
| EKP payStatus | 已结算/结算中 → 禁止 | 支出中/已支出 → 禁止 |
| 负数预估/差额 | 有 | 无 |
| 已结算未支出 | — | 允许,推负数实缴 |
### D8: 不需改逻辑的场景(仅注释)
- `callBack`(撤回):新数据不经待缴费,前端禁用按钮
- `deleteInsurance`:现有 `isJfcd=0` 拦截已覆盖新数据
- `callBackInsuranceBuyHandleStatusSub`:新数据 no-op
## Risks / Trade-offs
| 风险 | 缓解 |
|---|---|
| 历史分支被误改引发回归 | 代码 review 强制检查历史注释块;历史数据冒烟 2~3 条 |
| EKP 字段 ID/联调不一致 | `fd_new_data` 与 EKP 确认表单 ID;P2 联调实缴推送 |
| 自动化/续签待办状态不一致 | P1 验证 `updateEmployeeInsurancePre` / `updateEmployeeInsurancePreRenew` 新分支写 3 |
| 列表/详情无预估 settle 展示异常 | P4 兼容 `defaultSettleId` 为空 |
## 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 场景
6. **EKP 联调**: 实缴 `有无预估=否` + `fd_new_data=1`
7. **前端同步**: 禁用撤回/删除;退保前查支出状态
**回滚**: 将 `launchTime` 设为未来时间停止新数据写入;新分支代码可保留(无 `0` 数据不触发);DDL 列可保留(nullable,不影响历史)。
## API / 模块影响
| 模块 | 变更 |
|---|---|
| `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` |
## Open Questions
1. EKP 表单字段 `fd_new_data` 的最终表单 ID(联调确认)
2. `getPaymentSettleStatusFromEkp` 返回的 `payStatus` 枚举值是否与文档一致(实现时对照 EKP 回传)
## 关键代码锚点
| 逻辑 | 类/方法 | 改造 |
|---|---|---|
| 见费出单标识 | `initJfcd` / `initJfcdBatch` | launchTime + 写字段 |
| 派单核心 | `initJfcdInfo` | 分流 |
| 派单后续 | `addInsurance` / `batchInsurance` | 新数据不进 pushList |
| EKP 预估 | `DoJointInsuranceTask.pushEstime` | 历史专用 |
| EKP 实缴 | `initValues` / `insertInsrancesDetail` | 新字段 + 有无预估 |
| 缴费同步 | `updateInsuranceSettleStatus` | 新数据 skip |
| 手动拉取 | `pullPaymentStatus` | 过滤 + skip |
| 登记实缴 | `registeredPolicyPremium` | 新分支无差额 |
| 退保 | `rollBackInsurance` | 新分支独立 |
## Why
HRO 侧见费出单(提前缴费)现有逻辑要求派单后进入待缴费、推送 EKP 预估,与 EKP 新提前缴费业务规则不兼容。需在**不改动历史见费出单行为**的前提下,通过新字段区分历史/新数据,让新提前缴费派单后直接待投保、无预估/差额,实缴按 BPO/非 BPO 规则推送 EKP。
## 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`
- 新增 `AdvancePaymentHelper` 分流工具,历史分支代码块原样保留,新逻辑独立方法/注释块
- 新提前缴费派单:跳过待缴费(6)、不推 EKP 预估、不生成预估 settle/差额;待办直接待投保(3)
- 新提前缴费实缴:登记保单保费时推送实缴(有无预估=否),BPO/非 BPO 应收应付规则;收入/管理费/风险金延至实缴登记
- 新提前缴费退保:独立校验(支出中/已支出禁止);不生成负数预估/差额;按实缴结算状态删实缴或推负数实缴
- EKP 回调/手动拉取对新数据跳过;撤回/删除投保逻辑不改,仅加注释(前端禁用按钮)
- 配置项 `advance-pay.new-data-launch-time` 控制新数据写入切点
## Capabilities
### New Capabilities
(无 — 本需求为既有商险域行为扩展,不引入新 spec 域)
### Modified Capabilities
- `insurances`: 见费出单(提前缴费)需支持历史/新两套分流逻辑;新增字段标识、派单/实缴/退保/EKP 推送规则变更
## Impact
- **模块**: `yifu-insurances``*-api` Entity/VO + `*-biz` Service/Mapper/Task)
- **数据库**: HRO `mvp_insurances.t_insurance_detail`;EKP `ekp.ekp_insurances_info`(DDL + 存量迁移)
- **核心类**: `TInsuranceDetailServiceImpl``DoJointInsuranceTask``InsurancesConstants`、新增 `AdvancePaymentHelper`
- **EKP 联调**: `initValues` / `insertInsrancesDetail` 实缴字段(`fd_new_data``有无预估`
- **前端**(yifu-ui,独立仓库): 新数据禁用撤回/删除按钮;退保前查 `getPaymentSettleStatusFromEkp` 禁用支出中/已支出
- **Non-goals**: 不重构历史见费出单代码块;不改动 `bpoEnable=是` 项目不走见费出单的既有规则;EKP 侧大改不在本 change HRO 范围内(需 EKP 联调配合)
## ADDED Requirements
### 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`).
#### Scenario: Legacy data identification
- **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 after launch time
- **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_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 (`isHistoryAdvancePay=0`), 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
### 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
## MODIFIED Requirements
### 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.
#### Scenario: Create insurance application
- GIVEN an employee eligible for commercial insurance under project rules
- 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
#### 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 for legacy advance-pay only
#### Scenario: Insurance rollback
- GIVEN a purchase in handling state or insured state with advance-pay flag
- WHEN rollback is requested
- 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: 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`.
#### 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: Maintain insurance policy
- GIVEN an insurance company and policy number
- WHEN TInsurancePolicy is configured via `/insurancePolicy`
- THEN policy start/end dates and coverage windows are available for purchase validation
- AND policy detail supports CRUD with permission checks
### Requirement: EKP Integration and Scheduled Tasks
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.
#### Scenario: EKP resend
- GIVEN a failed or pending EKP push
- WHEN TInsuranceEkpController triggers resend
- THEN the insurance settlement event is re-submitted to EKP
- AND push outcome is traceable
#### Scenario: Daily expiry refresh
- GIVEN scheduled task invocation via `@Inner` endpoint `/inner/updateOverdueByTask`
- WHEN the job runs
- THEN overdue insurance records and renewal triggers are refreshed
- AND related pre-tasks or warnings are updated
#### 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 reflect HRO `isHistoryAdvancePay` via standardized conversion
- AND new advance-pay actual push MUST set `有无预估=否` while legacy MUST retain existing estimate flag rules
## 1. 数据层与基础组件(P0)
- [x] 1.1 编写 HRO DDL:`t_insurance_detail` 新增 `is_history_advance_pay``mvp_insurances`
- [x] 1.2 编写 EKP DDL:`ekp_insurances_info` 新增 `fd_new_data``ekp` 库,默认 `1`
- [x] 1.3 编写存量迁移 SQL:HRO `is_jfcd=0``is_history_advance_pay=1`;EKP `fd_jfcd=是``fd_new_data=0`
- [x] 1.4 `yifu-insurances-api``TInsuranceDetail` Entity 增 `isHistoryAdvancePay` 及 VO/DTO/Param 同步
- [x] 1.5 `yifu-insurances-biz`:Mapper XML 增字段映射;列表/详情出参包含新字段
- [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
## 2. 见费出单标识与派单分流(P1)
- [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`:新数据待办状态与待投保一致
- [ ] 2.5 验证自动化商险待办 / 续签待办与新分支状态联动
## 3. EKP 推送与缴费同步(P2)
- [x] 3.1 `DoJointInsuranceTask.initValues``fd_jfcd=是` 时写入 `fd_new_data`;新实缴设 `有无预估=否`
- [x] 3.2 `DoJointInsuranceTask.pushEstime`:确认仅历史数据调用;预估带 `fd_new_data=0`
- [x] 3.3 `DoJointInsuranceTask.insertInsrancesDetail`:新实缴 BPO(应收=0/应付=实缴)与非 BPO(应收=应付=实缴)规则
- [x] 3.4 `registeredPolicyPremiumCheck`:新数据无 defaultSettleId 时放宽 EKP 预估结算校验
- [x] 3.5 `registeredPolicyPremium`:历史分支不变;新分支 `registerNewAdvancePayActualPremium`(无差额、实缴登记时 createInsuranceInfo)
- [x] 3.6 `updateInsuranceSettleStatus`:新数据入口直接 return
- [x] 3.7 `pullPaymentStatus`:查询过滤 legacy only;按 ID 传入新数据 skip
- [ ] 3.8 EKP 联调:实缴推送字段 `fd_new_data=1``有无预估=否`
## 4. 退保与 EKP 回调(P3)
- [x] 4.1 `rollBackInsurance` 入口分流:历史块不动;新分支 `rollBackNewAdvancePayInsurance`
- [x] 4.2 新退保前置校验:`payStatus` 支出中/已支出禁止(复用或扩展 `getPaymentSettleStatusFromEkp`
- [x] 4.3 新退保:无实缴 / 未结算删实缴 / 已结算未支出推负数实缴(type=6);不生成负数预估与差额
- [x] 4.4 `callBackInsuranceBuyHandleStatusSub`:新数据 no-op
- [x] 4.5 `callBack` / `deleteInsurance`:补充注释说明新数据前端禁用,逻辑不改
- [x] 4.6 `successfulInsurance`:补充历史/新分支注释(跳过推预估说明)
## 5. 展示兼容与测试(P4)
- [x] 5.1 详情/列表:`premiumType`、无预估 settle 时 `defaultSettleId` 为空兼容
- [x] 5.2 查询结算状态接口:无 defaultSettleId 时不报错
- [ ] 5.3 历史数据冒烟:派单→待缴费→EKP 回调→待投保→实缴+差额→退保(2~3 条)
- [ ] 5.4 新数据全量场景测试(§9.2 共 14 条,用例见 `test-plan.md`
- [ ] 5.5 协调 yifu-ui:新数据禁用撤回/删除;退保前查支出状态禁用按钮(用例 UI-01 ~ UI-04)
This diff is collapsed.
## Context
当前实现(`hro-advance-pay-insurance-compat`):
| 层 | 历史 | 新 |
|---|---|---|
| HRO `is_history_advance_pay` | `1` | `0` |
| EKP `fd_new_data` | `0` | `1` |
HRO 与 EKP 语义相反,依赖 `AdvancePaymentHelper.toEkpFdNewData` 做翻转。产品侧与 EKP 已统一为「是否新数据」。
## Goals / Non-Goals
**Goals:**
- HRO 列 `is_new_data` 与 EKP `fd_new_data` **同义同值**`1` 新 / `0` 历史,默认 `1`
- 保留 `AdvancePaymentHelper.isLegacyJfcdData` / `isNewJfcdData` 对外语义不变(历史走旧流程、新走新流程)
- 存量 `is_jfcd=0` 数据迁移后行为与改名前完全一致
- 更新 V24 文档与测试计划字段描述
**Non-Goals:**
- 不调整派单/实缴/退保/EKP 回调分支业务规则
- 不修改 EKP DDL
- 不在本 change 内实现 yifu-ui 改造(仅标注)
## Decisions
### D1: 物理列名 `is_new_data`
**选择**: `t_insurance_detail.is_new_data CHAR(1) DEFAULT '1'`,与 `is_jfcd` 命名风格一致。
**备选**: `new_data` 无前缀 — 拒绝,与现有布尔型字段不一致。
### D2: Java 属性 `isNewData`
**选择**: Entity/VO/Param 统一 `isNewData`;MyBatis 列 `IS_NEW_DATA`
**API**: JSON 序列化为 `isNewData`(camelCase)。
### D3: 分流判定(逻辑取反,行为不变)
| 方法 | 旧条件 | 新条件 |
|---|---|---|
| `isLegacyJfcdData` | `isJfcd=0` 且 (`isHistoryAdvancePay` 空或 `1`) | `isJfcd=0` 且 (`isNewData` 空或 `0`) |
| `isNewJfcdData` | `isJfcd=0``isHistoryAdvancePay=0` | `isJfcd=0``isNewData=1` |
| `resolveIsNewDataForNewRecord` | launch 后 → `0`(新) | launch 后 → `1`(新) |
空值:`is_jfcd=0``is_new_data` 空视同历史(`0`),与旧逻辑「空视同 `1` 历史」一致。
### D4: EKP 映射直传
**选择**: `pushParam.setFd_new_data(param.getIsNewData())`;常量 `IS_NEW_DATA_*``EKP_FD_NEW_DATA_*` 可合并为同一组或保留 EKP 前缀别名。
**删除**: `toEkpFdNewData` / `fromEkpFdNewData` 反向转换(或改为 identity 方法留作扩展点)。
### D5: 迁移策略
**已存在 `is_history_advance_pay`**:
```sql
ALTER TABLE t_insurance_detail
ADD COLUMN is_new_data CHAR(1) NULL DEFAULT '1' COMMENT '是否新数据:1是 0否' AFTER is_jfcd;
UPDATE t_insurance_detail SET is_new_data = CASE is_history_advance_pay
WHEN '1' THEN '0' WHEN '0' THEN '1' ELSE NULL END;
UPDATE t_insurance_detail SET is_new_data = '0'
WHERE is_jfcd = '0' AND (is_new_data IS NULL OR is_new_data = '');
ALTER TABLE t_insurance_detail DROP COLUMN is_history_advance_pay;
```
**尚未加列**(直接按 compat 新脚本写 `is_new_data`,存量 `is_jfcd=0``0`)。
### D6: 常量重命名
```java
String IS_NEW_DATA_YES = "1"; // 新提前缴费
String IS_NEW_DATA_NO = "0"; // 历史见费出单
// EKP 可复用相同字面量或保留 EKP_FD_NEW_DATA_YES/NO 指向同值
```
## Risks / Trade-offs
| 风险 | 缓解 |
|---|---|
| 前端仍读 `isHistoryAdvancePay` | proposal 标注 BREAKING;tasks 含 yifu-ui 同步项 |
| 双 change 并行导致字段名混乱 | 本 change 在 compat 之后或同 PR 内一次性替换 |
| 迁移 SQL 值翻转错误 | REG 测试:存量历史明细 `is_new_data=0` 且行为冒烟 |
| 注释/文档残留旧名 | grep 全仓 `is_history_advance_pay` / `isHistoryAdvancePay` |
## Migration Plan
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`
4. 同步 yifu-ui 字段名(若已对接)
5. 更新 V24 与 `test-plan.md` 测试数据模板
**回滚**: 保留迁移前备份;可逆 SQL 将 `is_new_data` 翻回 `is_history_advance_pay`(仅应急)。
## Open Questions
1. 是否在本 change 内合并修订 `hro-advance-pay-insurance-compat` 的 SQL 文件,还是单独 migration 脚本?(建议:修订 compat SQL + 本 change 提供 ALTER 增量脚本)
2. yifu-ui 是否已对接 `isHistoryAdvancePay`?(决定前端 BREAKING 范围)
## 关键改造锚点
| 位置 | 改造 |
|---|---|
| `InsurancesConstants` | `IS_NEW_DATA_YES/NO` |
| `TInsuranceDetail` + VO/Param | `isNewData` |
| `TInsuranceDetailMapper.xml` | `IS_NEW_DATA` |
| `AdvancePaymentHelper` | 分流 + `resolveIsNewDataForNewRecord` |
| `DoJointInsuranceTask.initValues` | `setFd_new_data(param.getIsNewData())` |
| `TInsuranceDetailServiceImpl` | 注释与 `setIsNewData` 调用 |
| `EkpInteractiveParam` | `isNewData`(若推送 param 带该字段) |
| `V24/HRO-提前缴费商险数据兼容开发方案.md` | HRO 字段表、DDL、示例 |
## Why
`hro-advance-pay-insurance-compat` 已在 EKP 侧采用 `fd_new_data`(是否新数据:1是/0否,默认1),HRO 仍使用 `is_history_advance_pay`(1历史/0新),语义相反,需 `toEkpFdNewData` 反向转换,易混淆且与产品文档不一致。将 HRO 字段统一为 **是否新数据**,与 EKP 同义同值,消除映射歧义。
## What Changes
- **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`
- 同步更新 `V24/` 开发方案与 OpenSpec 测试计划中的 HRO 字段描述
## Capabilities
### New Capabilities
(无)
### Modified Capabilities
- `insurances`: 提前缴费数据标识字段由「是否历史提前缴费」改为「是否新数据」,HRO 与 EKP 字段语义对齐;分流/派单/实缴/退保**行为不变**,仅标识读写与映射简化
## Impact
- **模块**: `yifu-insurances``*-api``*-biz`、DDL、Mapper XML)
- **数据库**: HRO `mvp_insurances.t_insurance_detail` 列重命名 + 值翻转迁移(若已上线 `is_history_advance_pay` 则 ALTER + UPDATE + DROP 旧列)
- **API 响应**: 列表/详情 JSON 字段名由 `isHistoryAdvancePay` 变为 `isNewData`**BREAKING** 若前端已对接旧字段)
- **EKP**: 无新需求;推送逻辑简化,仍写 `fd_new_data`
- **前端**(yifu-ui): 若已读 `isHistoryAdvancePay`,需改为 `isNewData` 并反转展示逻辑(1=新,0=历史)
- **Non-goals**: 不改变历史/新提前缴费业务流程;不修改 `advance-pay.new-data-launch-time` 切点机制;不修改 EKP 表结构
- **前置**: 建议在 `hro-advance-pay-insurance-compat` 已合入或同批发布;若库中尚无 `is_history_advance_pay`,可直接 ADD `is_new_data`
## 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, default `1`), synchronized to EKP as `fd_new_data` with **identical values** (`1`=new, `0`=legacy).
#### 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 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
- **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: 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.
#### Scenario: Create insurance application
- GIVEN an employee eligible for commercial insurance under project rules
- 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)
#### 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 for legacy advance-pay only
#### Scenario: Insurance rollback
- GIVEN a purchase in handling state or insured state with advance-pay flag
- WHEN rollback is requested
- 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: EKP Integration and Scheduled Tasks
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
- GIVEN a failed or pending EKP push
- WHEN TInsuranceEkpController triggers resend
- THEN the insurance settlement event is re-submitted to EKP
- AND push outcome is traceable
#### Scenario: Daily expiry refresh
- GIVEN scheduled task invocation via `@Inner` endpoint `/inner/updateOverdueByTask`
- WHEN the job runs
- THEN overdue insurance records and renewal triggers are refreshed
- AND related pre-tasks or warnings are updated
#### 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
## 1. 数据库与迁移
- [x] 1.1 编写 HRO 迁移 SQL:`is_history_advance_pay``is_new_data`(值翻转:`1``0``0``1``is_jfcd=0` 存量刷 `0`);或修订 `hro-advance-pay-insurance-compat.sql` 直接使用 `is_new_data`
- [x] 1.2 确认 EKP `fd_new_data` DDL 无需变更(与 HRO 同义同值)
## 2. API 层(yifu-insurances-api)
- [x] 2.1 `InsurancesConstants``IS_HISTORY_ADVANCE_PAY_*` 重命名为 `IS_NEW_DATA_YES/NO``1`/`0`);EKP 常量与 HRO 同值或保留别名
- [x] 2.2 `TInsuranceDetail``InsuranceDetailVO``InsuranceListVO``InsuranceAddParam``InsuranceBatchParam``EkpInteractiveParam``isHistoryAdvancePay``isNewData`
- [x] 2.3 更新字段 `@Schema` 描述为「是否新数据:1是 0否」
## 3. Mapper 与持久化
- [x] 3.1 `TInsuranceDetailMapper.xml`:列 `IS_HISTORY_ADVANCE_PAY``IS_NEW_DATA`,result/insert/update 全量替换
- [x] 3.2 全局 grep 确认无残留 `is_history_advance_pay` / `IS_HISTORY_ADVANCE_PAY`
## 4. 业务逻辑(yifu-insurances-biz)
- [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 方法名不变,确认分流仍正确
## 5. 文档与测试
- [x] 5.1 同步 `V24/HRO-提前缴费商险数据兼容开发方案.md`:HRO 字段表、DDL、迁移、代码示例改为 `is_new_data`
- [x] 5.2 同步 `V24/HRO-EKP提前缴费商险数据兼容需求.md` 附录映射表(HRO/EKP 同值,无需反向)
- [x] 5.3 更新 `hro-advance-pay-insurance-compat/test-plan.md` 或本 change 测试数据:`is_new_data=0` 历史 / `1` 新;UT-03 改为直传断言
- [x] 5.4 标注 yifu-ui:列表/详情 JSON 字段 `isHistoryAdvancePay``isNewData`(若已对接)→ 见 `ui-sync.md`
## 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.3 全仓 grep:`isHistoryAdvancePay``is_history_advance_pay``IS_HISTORY_ADVANCE_PAY` 零残留(compat change 文档除外时可注明 deprecated)
# yifu-ui 同步说明(独立仓库)
**BREAKING**:商险列表/详情 API 响应字段变更。
| 旧字段 | 新字段 | 取值含义 |
| --- | --- | --- |
| `isHistoryAdvancePay` | `isNewData` | `1`=新提前缴费,`0`=历史见费出单 |
展示文案建议统一为「是否新数据」,与 HRO/EKP 一致。
schema: spec-driven
# Project context shown to AI when creating OpenSpec artifacts.
context: |
Project: yifu — Spring Cloud 微服务 HR/人事档案与薪酬社保平台
Tech stack: Java 8, Spring Boot 2.6.7, Spring Cloud 2021, Spring Cloud Alibaba,
OAuth2 RBAC, MyBatis Plus 3.5, Hutool, XXL-Job, Seata, Swagger
Architecture: Maven 多模块 monorepo;各业务域按 *-api / *-biz 拆分
Package: com.yifu.cloud.plus.v1.*
Modules: yifu-auth, yifu-upms, yifu-archives, yifu-salary, yifu-social,
yifu-order, yifu-check, yifu-job, yifu-msg, yifu-business, yifu-visual 等
Deployment: Docker / Kubernetes (k8s-bash/)
Conventions:
- Controller → Service → Mapper 分层;VO/Entity 在 *-api 模块
- 配置分环境:application.yml + application-{dev,test,prd}.yml
- 数据库映射在 *-biz/src/main/resources/mapper/*.xml
- 中文注释与业务术语(员工档案、社保、薪资、商险等)
Spec layout: openspec/specs/<domain>/spec.md 按业务域组织
Existing specs: platform, archives, salary, social, order, upms, check, insurances, csp
rules:
proposal:
- 明确影响的服务模块(如 yifu-archives-biz)
- 包含 Non-goals 与兼容性说明
design:
- 说明 API 变更、数据库变更、跨服务调用
- 标注需同步的前端模块(yifu-ui,独立仓库)
tasks:
- 按 api → biz → mapper → 配置 顺序拆分
- 单任务粒度控制在 2 小时以内
# Archives
## Purpose
yifu-archives(端口 5001)负责员工档案全生命周期管理,包括入职建档、花名册、合同、电子签、证明开具及与外部系统(瓜子、法大大)的集成。
## Requirements
### Requirement: Employee Master Data
The system SHALL maintain employee master records including roster (花名册), basic profile, family, education, work history, professional qualifications, and disability information.
#### Scenario: Query employee roster
- GIVEN an authorized user with data-scope permissions
- WHEN the user queries the personnel roster with filters
- THEN matching employee records are returned with pagination
- AND results respect MenuUtil data-auth SQL constraints
#### Scenario: Maintain employee sub-profile
- GIVEN an existing employee record
- WHEN the user updates family, education, or work history
- THEN the change is persisted via the corresponding Service and Mapper
- AND operation is logged via `@SysLog` where applicable
### Requirement: Pre-Onboarding Workflow
The system SHALL support pre-employment (预入职) and pending archive creation (入职待建档) workflows before an employee becomes fully archived.
#### Scenario: Pre-employment registration
- GIVEN a pending hire candidate
- WHEN pre-employment main data is submitted
- THEN a pre-employment record is created under `TPreEmpMain`
- AND status transitions are tracked in pre-employment logs
### Requirement: Employee Contract Lifecycle
The system SHALL manage employee contracts through apply, audit, and filing (归档) stages with area-based permission configuration.
#### Scenario: Contract application
- GIVEN an authorized user
- WHEN a contract application is submitted
- THEN the contract appears in the apply page with pending audit status
- AND only data within the user's permission scope is visible
#### Scenario: Contract filing
- GIVEN a contract that passed audit
- WHEN the user queries the filing page
- THEN only approved and archivable contracts are listed
- AND filing status is updated upon completion
#### Scenario: Contract renewal alert
- GIVEN a contract approaching expiry
- WHEN the renewal alert job or query runs
- THEN pending renewal tasks appear in contract renewal todo management
### Requirement: Electronic Signature Integration
The system SHALL integrate with Fadada (法大大) for electronic contract signing, including company accounts, templates, seals, and contract attachments.
#### Scenario: Initiate e-sign contract
- GIVEN a configured Fadada company and contract template
- WHEN a signing request is initiated via Fdd/Fasc controllers
- THEN the contract is sent to Fadada for signing
- AND request/response details are recorded in FddReqLog
### Requirement: Certificate and Proof Issuance
The system SHALL support issuance of employment and salary proofs with audit records.
#### Scenario: Issue salary proof
- GIVEN an employee with valid salary and archive data
- WHEN a salary proof is requested via SalaryProveController
- THEN a proof record is created in TCertRecord
- AND the proof can be exported or delivered per business rules
### Requirement: Archive Completeness Monitoring
The system SHALL monitor archive completeness against configurable rules and alert on missing required fields.
#### Scenario: Completeness check
- GIVEN completeness monitor configuration for a domain
- WHEN an employee archive is evaluated
- THEN completeness score and missing items are calculated
- AND incomplete archives appear in completeness monitoring views
### Requirement: Auto Rule Configuration
The system SHALL allow configuration of archive management rules and social-insurance purchase rules (TAutoEmpRuleInfo, TAutoFundRuleInfo, TAutoInsurRuleInfo) with change logs.
#### Scenario: Rule update
- GIVEN an existing auto rule
- WHEN an administrator modifies the rule
- THEN the new rule takes effect for subsequent automated processing
- AND the change is recorded in TAutoRuleLog
### Requirement: Customer and Settlement Domain
The system SHALL manage customer information, settlement domains, and B-side user-customer relationships for multi-tenant data isolation.
#### Scenario: Settlement domain lookup
- GIVEN a user with settlement-domain permissions
- WHEN querying employees or contracts by domain
- THEN only records within authorized settlement domains are returned
### Requirement: Cross-Service Integration
The archives module SHALL expose APIs consumed by salary, social, and other services via Dapr/HTTP, and sync data with the 瓜子 (GZ) external system.
#### Scenario: Internal service call
- GIVEN a request from yifu-salary or yifu-social with `@Inner` or service token
- WHEN archive data (e.g. settlement domain, employee info) is requested
- THEN the archives service returns the required VO without UI-level auth checks where `@Inner` applies
#### Scenario: GZ system push
- GIVEN a pending GZ integration task
- WHEN push entry is processed via TGzPushEntry
- THEN employee archive data is synchronized per task configuration
- AND task follow-up status is updated
# Check
## Purpose
yifu-check(端口 5022)提供身份证、手机号、银行卡等基础信息校验能力,供档案、社保、薪酬等模块在录入时调用。
## Requirements
### Requirement: Identity Card Validation
The system SHALL validate Chinese resident ID card numbers for format and checksum correctness.
#### Scenario: Valid ID card
- GIVEN a well-formed 18-digit ID card number
- WHEN validated via TCheckIdCardController
- THEN the service returns success with parsed metadata (region, birth date, gender) where supported
- AND invalid checksum or format returns a structured error via R
#### Scenario: Invalid ID card
- GIVEN a malformed or checksum-failing ID number
- WHEN validation is requested
- THEN the service rejects the input without persuring invalid data to downstream modules
### Requirement: Mobile Number Validation
The system SHALL validate mobile phone numbers for format and carrier rules configured in the system.
#### Scenario: Mobile format check
- GIVEN a mobile number string
- WHEN validated via TCheckMobileController
- THEN format compliance is verified against domestic mobile patterns
- AND validation result is returned synchronously for form-level feedback
### Requirement: Bank Account Validation
The system SHALL validate bank card numbers (bank account) for format and BIN rules.
#### Scenario: Bank card check
- GIVEN a bank card number
- WHEN validated via TCheckBankNoController
- THEN Luhn or configured BIN rules are applied
- AND invalid cards are rejected before salary bank binding proceeds
### Requirement: Validation Service Contract
Check endpoints SHALL return responses wrapped in `R<T>` consistent with platform API conventions and be callable from other services.
#### Scenario: Cross-service validation call
- GIVEN an internal service invoking check APIs during employee onboarding
- WHEN ID, mobile, or bank validation is requested
- THEN a uniform R response allows the caller to block or warn on failure
- AND validation is stateless with no side effects on check module data
# CSP (Customer Service Platform)
## Purpose
yifu-csp(端口 5088)是客户服务平台(客户端)模块,负责入离职登记、作业自动化待办、操作日志及与档案、商险、EKP 的协同处理。
## Requirements
### Requirement: Employee Onboarding and Offboarding Registration
The system SHALL manage employee registration forms (入离职登记表) for hire and separation events submitted from the client platform and HR workflows.
#### Scenario: Client-side registration list
- GIVEN a CSP client user
- WHEN querying registration list via `/employeeregistration/page`
- THEN only records with dataSource marked as client-origin are returned
- AND results are paginated per search criteria
#### Scenario: Create registration
- GIVEN valid hire or separation information from the client
- WHEN a new EmployeeRegistration is submitted
- THEN the record is persisted with client data source
- AND SysLog captures the creation operation
#### Scenario: HR todo registration list
- GIVEN an internal HR user with data permissions
- WHEN querying `/employeeregistration/hrPage`
- THEN pending HR todo registrations are returned with MenuUtil auth SQL applied
- AND export of todo tasks is supported
### Requirement: Registration Confirmation Workflow
The system SHALL support confirmation, rejection, and batch processing of onboarding registrations.
#### Scenario: Confirm hire reception
- GIVEN a pending onboarding registration
- WHEN confirm reception is executed
- THEN registration status advances to received/processed state
- AND downstream archive or insurance pre-tasks may be triggered
#### Scenario: Reject onboarding
- GIVEN an invalid or incomplete onboarding application
- WHEN reject onboarding is invoked
- THEN the registration is marked rejected with reason
- AND the client can view updated status on subsequent queries
#### Scenario: Pending confirmation queue
- GIVEN registrations awaiting HR confirmation
- WHEN querying onboarding pending-confirmation lists
- THEN only unconfirmed records appear
- AND batch confirm reception is supported
### Requirement: Automated HR Registration Processing
The system SHALL provide dedicated views and exports for automated onboarding/offboarding job flows.
#### Scenario: Automated registration list
- GIVEN an operator in the automation workflow
- WHEN querying `/employeeregistration/hrRegistrationPage`
- THEN automation-scoped registrations are listed with auth filtering
- AND dedicated export is available for automation batches
#### Scenario: Fetch and mark processed
- GIVEN external automation polling received applications
- WHEN get-received endpoint is called with `@Inner` or authorized access
- THEN confirmed registrations are returned and marked as processed atomically
- AND duplicate processing is prevented
### Requirement: Automated Leave Todo Management
The system SHALL manage automated offboarding todos (自动化离职待办) with batch confirmation and count queries.
#### Scenario: Leave todo pagination
- GIVEN pending leave automation tasks
- WHEN querying `/employeeregistrationleave/getEmployeeRegistrationLeaveTablePage`
- THEN EmployeeRegistrationLeaveTableVo results respect leave-specific auth via setLeaveBaseAuth
- AND pending count is available via getRegistrationLeaveCount
#### Scenario: Batch confirm leave
- GIVEN multiple pending leave todos
- WHEN batch sure leave (BatchSureLeaveVo) is submitted
- THEN selected leave tasks are confirmed in batch
- AND EmployeeRegistrationLeaveLog records operation details
### Requirement: Operation Logging
The system SHALL audit CSP operations for onboarding, offboarding, and general service actions.
#### Scenario: General operation log
- GIVEN a CSP user action on registration or related entities
- WHEN the action completes
- THEN TOperationLog captures operator, action type, and target entity
- AND logs are queryable for compliance review
#### Scenario: Leave automation operation log
- GIVEN automated leave workflow steps
- WHEN leave automation actions occur
- THEN EmployeeRegistrationLeaveLog records step-level history separately from general operation logs
### Requirement: File Upload
The CSP module SHALL provide file upload endpoints for registration attachments and supporting documents.
#### Scenario: Upload registration attachment
- GIVEN a registration requiring supporting documents
- WHEN FileUploadController receives a valid file
- THEN the file is stored and linked to the registration workflow
- AND upload failures return structured ErrorMessage via R
### Requirement: Cross-Module Integration
The CSP module SHALL integrate with yifu-archives for project/dept assignment and pre-archive data, with yifu-insurances for insurance pre-tasks, and with EKP for contract/dept information.
#### Scenario: Update customer service assignment
- GIVEN a registration requiring frontend CS user update
- WHEN customer user info is updated on registration
- THEN EmployeeRegistrationCustomerUserUpdateVo changes propagate to linked business records
- AND archives pre-employment entities remain consistent where shared IDs exist
#### Scenario: Project belong dept lookup
- GIVEN a registration linked to project organization
- WHEN querying TEmployeeProjectBelongDept via CSP endpoints
- THEN project-department mapping from archives is returned for CSP UI selection
- AND EkpDeptContractInfoVo supports EKP contract/dept alignment
#### Scenario: Trigger insurance pre-task
- GIVEN a confirmed hire registration meeting insurance rules
- WHEN CSP/archive events propagate to insurances
- THEN TEmployeeInsurancePre may be created in yifu-insurances
- AND CSP registration status reflects insurance todo linkage where configured
### Requirement: Authorization and Data Scope
CSP endpoints SHALL enforce RBAC and data-scope rules consistent with the platform, with separate visibility for client users versus internal HR operators.
#### Scenario: Client versus HR visibility
- GIVEN a client-platform user
- WHEN accessing client list endpoints
- THEN only client-origin registrations for authorized customers are visible
- AND internal HR endpoints require appropriate menu permissions and MenuUtil SQL scope
#### Scenario: Protected delete
- GIVEN a registration eligible for deletion
- WHEN delete is attempted without `csp_employeeregistration_del` permission
- THEN Spring Security denies the operation
- AND no partial side effects occur on related entities
# Commercial Insurance
## Purpose
yifu-insurances(端口 5005)负责商业保险(商险)的全流程管理,包括投保办理、减员退费、保单维护、险种配置、待办续签及与 EKP、档案、CSP 模块的协同。
## Requirements
### Requirement: Insurance Purchase Processing
The system SHALL manage commercial insurance purchase from application through handling success, including add, batch add, replace, and rollback.
#### Scenario: Create insurance application
- GIVEN an employee eligible for commercial insurance under project rules
- 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
#### 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
#### Scenario: Insurance rollback
- GIVEN a purchase in handling state
- WHEN rollback is requested
- THEN the application returns to the prior workflow state
- AND rollback reason and operator are auditable
### Requirement: Insured and Reduced Employee Management
The system SHALL maintain separate views and workflows for active insured employees and reduced (减员) employees.
#### Scenario: Query insured list
- GIVEN authorized users with area permissions
- WHEN querying insured employees via paginated or non-paginated list endpoints
- THEN only records within TInsuranceAreaRes data scope are returned
- AND settlement month and project changes are supported with change logs
#### Scenario: Process employee reduction
- GIVEN an active insured employee
- WHEN reduction handling is submitted
- THEN the employee moves to reduced status via reduction handling workflow
- AND reduction lists support export and batch import processing
### Requirement: Premium and Policy Registration
The system SHALL support registration of policy premiums, invoice numbers, and policy period maintenance.
#### 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
#### Scenario: Maintain insurance policy
- GIVEN an insurance company and policy number
- WHEN TInsurancePolicy is configured via `/insurancePolicy`
- THEN policy start/end dates and coverage windows are available for purchase validation
- AND policy detail supports CRUD with permission checks
### Requirement: Insurance Product Configuration
The system SHALL configure insurance companies, types, purchase standards, and rate tables as master data.
#### Scenario: Configure insurance type
- GIVEN a commercial insurance product line
- WHEN TInsuranceType and TInsuranceTypeStandard are maintained
- THEN purchase eligibility and standard amounts apply to new applications
- AND TInsuranceTypeRate defines premium rate rules per type
#### Scenario: Area permission for insurance
- GIVEN city-level operators
- WHEN TInsuranceAreaRes assigns area permissions
- THEN insurance queries and operations are scoped to authorized cities
### Requirement: Insurance Pre-Tasks and Renewal
The system SHALL generate and track pre-purchase tasks and renewal todos linked to onboarding and contract events.
#### Scenario: Insurance pre-task from onboarding
- GIVEN an employee registration or archive pre-task triggering insurance purchase
- WHEN TEmployeeInsurancePre is created
- THEN the task appears in pending purchase queues filtered by process status
- AND pending purchase counts are available via getListCount
#### Scenario: Renewal todo management
- GIVEN an insurance policy approaching expiry
- WHEN renewal pre-detail is generated
- THEN TInsurancePreRenewDetail appears in renewal todo management
- AND WeCom notification details are tracked in related QwDetail tables
### Requirement: Refund on Reduction
The system SHALL manage refund calculation and handling when insured employees are reduced.
#### Scenario: Query refund list
- GIVEN reduced employees eligible for premium refund
- WHEN querying `/insuranceRefund` paginated list
- THEN RefundListVo results show refund amounts and handling status
- AND export requires `insurance_custserve_reduction_export` permission where configured
### Requirement: Claims and Warnings
The system SHALL record insurance claims (出险) and surface expiry or anomaly warnings.
#### Scenario: Record claim event
- GIVEN an active insured employee with a claim incident
- WHEN claim is registered via insurance detail endpoints
- THEN claim metadata is attached to the insurance record
- AND subsequent premium or renewal rules reflect claim status
#### Scenario: Insurance warning
- GIVEN policies or tasks meeting warning rules
- WHEN TInsurancesWarn queries run
- THEN operators receive actionable warning lists for follow-up
### Requirement: Attachments and Change Audit
The system SHALL support insurance file uploads and maintain change logs for insurance data modifications.
#### Scenario: Upload insurance enclosure
- GIVEN a handling or insured record
- WHEN files are uploaded via TInsuranceEnclosureController
- THEN attachments are linked to the insurance business entity
- AND files are retrievable for audit and EKP submission
#### Scenario: Track field changes
- GIVEN modifications to insured information or project assignment
- WHEN data is updated
- THEN TInsurancesChangeLog records before/after values
- AND project change logs can be exported
### Requirement: EKP Integration and Scheduled Tasks
The insurances module SHALL integrate with EKP for settlement push/retry and run scheduled jobs for expiry refresh.
#### Scenario: EKP resend
- GIVEN a failed or pending EKP push
- WHEN TInsuranceEkpController triggers resend
- THEN the insurance settlement event is re-submitted to EKP
- AND push outcome is traceable
#### Scenario: Daily expiry refresh
- GIVEN scheduled task invocation via `@Inner` endpoint `/inner/updateOverdueByTask`
- WHEN the job runs
- THEN overdue insurance records and renewal triggers are refreshed
- AND related pre-tasks or warnings are updated
### 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.
#### Scenario: Onboarding-driven purchase task
- GIVEN CSP employee registration confirmed for hire
- WHEN insurance purchase rules match
- THEN TEmployeeInsurancePre is created or updated from archive/CSP events
- AND incomplete onboarding blocks purchase where business rules require it
#### Scenario: Internal service access
- GIVEN `@Inner` calls from job or peer services
- WHEN insurance inner endpoints are invoked with service credentials
- THEN batch updates proceed without UI session auth
- AND responses use platform R wrapper conventions
# Order
## Purpose
yifu-order(端口 5006)负责项目订单的全生命周期管理,以及与 EKP 系统的订单同步。
## Requirements
### Requirement: Project Order Management
The system SHALL manage project orders with list query, detail view, reply tracking, and file attachments.
#### Scenario: Query order list
- GIVEN an authorized user
- WHEN querying orders via `/order/getOrderPageList`
- THEN paginated OrderListVO results are returned filtered by query parameters
- AND non-paginated list is available via `/order/getOrderList`
#### Scenario: View order detail
- GIVEN an existing order ID
- WHEN detail is requested
- THEN OrderDetailVO includes order metadata, status, and related entities
- AND reply history is available via OrderReplyListVO
### Requirement: Order File Management
The system SHALL support order enclosure upload and file sync logging.
#### Scenario: Upload order attachment
- GIVEN an open order
- WHEN a file is uploaded via order endpoints
- THEN the enclosure is stored and linked to the order
- AND TOrderFileSyncLog records sync operations with external systems
### Requirement: EKP Order Integration
The system SHALL synchronize order data with the EKP system via EkpOrderController.
#### Scenario: EKP order sync
- GIVEN an order event requiring EKP notification
- WHEN EkpOrderController processes the sync request
- THEN order state is pushed or pulled per EKP integration rules
- AND sync failures are logged for manual retry
### Requirement: Order Authorization
Order endpoints SHALL enforce RBAC via `@PreAuthorize` consistent with the platform permission model.
#### Scenario: Unauthorized order access
- GIVEN a user without order menu permissions
- WHEN accessing protected order endpoints
- THEN access is denied by Spring Security
- AND no order data is leaked in the response
# Platform
## Purpose
yifu 是基于 Spring Cloud 的人事档案、薪酬、社保、商险等业务管理平台,采用微服务架构与 OAuth2 RBAC 权限体系。
## Requirements
### Requirement: Microservice Module Structure
Each business domain SHALL be organized as a Maven module pair: `*-api` (shared DTOs, entities, Feign interfaces) and `*-biz` (Spring Boot application, controllers, services, mappers).
#### Scenario: New business capability
- GIVEN a new business domain
- WHEN the capability is implemented
- THEN it follows the `yifu-<domain>-api` / `yifu-<domain>-biz` pattern
- AND the biz module exposes REST APIs consumed by yifu-ui or other services
### Requirement: Authentication and Authorization
The system MUST use OAuth2-based RBAC. Protected endpoints SHALL require valid tokens; permissions are managed via yifu-upms.
#### Scenario: Protected API access
- GIVEN an authenticated user with assigned roles
- WHEN the user calls a secured endpoint
- THEN access is granted or denied based on RBAC rules
### Requirement: Data Access Layer
Persistence SHALL use MyBatis Plus with XML mappers under `*-biz/src/main/resources/mapper/`. Services MUST NOT bypass the Mapper layer for database access.
#### Scenario: CRUD operation
- GIVEN a business entity
- WHEN data is read or written
- THEN the operation flows through Service → Mapper → database
### Requirement: Environment Configuration
Each biz module SHALL support environment-specific configuration via `application-{profile}.yml` (dev, test, prd).
#### Scenario: Deploy to production
- GIVEN a service deployed with profile `prd`
- WHEN the application starts
- THEN production datasource and external service URLs from `application-prd.yml` are used
### Requirement: Core Business Domains
The platform SHALL provide distinct microservice modules for auth, user/permission management, employee archives, salary, social insurance, orders, validation, scheduled jobs, and visual tooling.
#### Scenario: Domain module lookup
- GIVEN a business capability such as employee archives
- WHEN a developer locates the implementation
- THEN the code resides in the corresponding `yifu-<domain>-api` and `yifu-<domain>-biz` modules
- AND the module responsibility matches the platform domain table in README
# Salary
## Purpose
yifu-salary(端口 5003)负责薪酬核算、工资报账、薪资配置、审批流程、个税申报统计,以及与档案、社保模块的数据联动。
## Requirements
### Requirement: Salary Standard Management
The system SHALL manage standard salary sheets (标准薪酬) including import, apply, audit, and project association.
#### Scenario: Import standard salary
- GIVEN an uploaded salary file matching configured template
- WHEN the file is imported via SalaryUploadController or TSalaryStandardOriginalController
- THEN salary rows are parsed and stored in TSalaryStandard
- AND import errors are reported to the user
#### Scenario: Standard salary apply workflow
- GIVEN a draft standard salary batch
- WHEN submitted for approval via `/tsalarystandard/pageApply`
- THEN the batch enters the apply workflow with data-scope filtering via MenuUtil
- AND approved records become available for payroll processing
### Requirement: Payroll Account and Payslip
The system SHALL manage payroll accounts (工资报账主表) and line-item details (工资明细) as the core payslip entity.
#### Scenario: Create payroll account
- GIVEN approved standard salary data for a settlement period
- WHEN a payroll account is generated
- THEN TSalaryAccount header and TSalaryAccountItem lines are created
- AND totals reconcile with standard salary source data
#### Scenario: Employee payslip query
- GIVEN a C-side employee with bound mobile
- WHEN querying via TSalaryAccountPhoneController
- THEN the employee sees only their own payslip records
- AND sensitive fields follow access control rules
### Requirement: Salary Configuration
The system SHALL support configurable salary parameters including minimum wage, income tax, bank accounts, payslip column mapping, and project query permissions.
#### Scenario: Minimum wage configuration
- GIVEN regional minimum wage policy
- WHEN an administrator updates TMinSalary or TConfigSalary
- THEN subsequent salary validation uses the new thresholds
- AND SysMessageSalary triggers reminders when violations are detected
#### Scenario: Payslip column configuration
- GIVEN a settlement project
- WHEN payslip display columns are configured via TSalaryStandardSet
- THEN TSalaryStandardSetDetail defines visible fields for that project's payslips
### Requirement: Salary Approval Workflow
The system SHALL route salary batches through multi-node approval with audit records and copy notifications.
#### Scenario: Submit for approval
- GIVEN a completed payroll or standard salary batch
- WHEN submitted to the approval flow
- THEN TAuditRecord and TAuditNodeProocess track node-level progress
- AND TAuditCopyInfo notifies configured copy recipients
#### Scenario: Approval decision
- GIVEN a pending approval node
- WHEN an approver approves or rejects
- THEN the batch status updates accordingly
- AND subsequent nodes or rollback actions follow configured workflow
### Requirement: Salary Employee Registry
The system SHALL maintain a salary-specific employee registry (TSalaryEmployee) synchronized with archive changes.
#### Scenario: Archive change propagation
- GIVEN an employee profile change in yifu-archives
- WHEN the change affects salary-relevant fields
- THEN TSalaryEmpModLog records the modification
- AND salary employee data reflects the update
### Requirement: Tax and Statistical Reporting
The system SHALL support tax declaration statistics including current-period reports, labor remuneration, bonuses, and market return data.
#### Scenario: Current period declaration
- GIVEN a reporting period and declarer configuration
- WHEN generating TStatisticsCurrentReport
- THEN wage, bonus, and labor fee declarations aggregate from approved payroll data
- AND TStatisticsDeclarer links records to declaration targets
### Requirement: Insurance Unpurchase Application
The system SHALL manage applications for projects that do not purchase social insurance due to risk assessment.
#### Scenario: Submit unpurchase apply
- GIVEN a high-risk project requiring insurance waiver
- WHEN TInsuranceUnpurchaseApply is submitted with supporting detail
- THEN the application enters approval workflow
- AND approved waivers are tracked for compliance monitoring
### Requirement: Salary Pause and Zero Declaration
The system SHALL support pausing salary issuance (暂停发放) and zero-declaration (0申报) management for special cases.
#### Scenario: Pause salary
- GIVEN an employee or batch flagged for pause
- WHEN TPauseSalary record is active
- THEN payroll generation excludes affected employees
- AND pause reason and period are auditable
### Requirement: Cross-Module Integration
The salary module SHALL fetch settlement domain and employee context from yifu-archives via Dapr (HttpDaprUtil, DaprArchivesProperties) and expose B-side salary APIs.
#### Scenario: Settlement domain resolution
- GIVEN a salary query scoped by settlement domain
- WHEN domain list is needed
- THEN salary service calls archives APIs to resolve TSettleDomainListVo
- AND results filter payroll data by authorized domains
#### Scenario: B-side salary API
- GIVEN a B-side authenticated client
- WHEN calling BusinessSalaryController endpoints
- THEN salary data is returned per B-side contract and permission model
# Social Insurance
## Purpose
yifu-social(端口 5002)负责社保、公积金的派单购买、缴费管理、基数配置、实缴核验及与 EKP、档案模块的协同。
## Requirements
### Requirement: Social Insurance Dispatch
The system SHALL manage dispatch (派单) workflows for social insurance and provident fund purchase, from pre-dispatch through completion.
#### Scenario: Create dispatch order
- GIVEN an employee eligible for social insurance purchase
- WHEN a dispatch record is created via TDispatchInfoController
- THEN TDispatchInfo captures purchase type, domain, and employee linkage
- AND concurrent dispatch for the same employee is prevented via distributed lock where configured
#### Scenario: Pre-dispatch queue
- GIVEN employees pending insurance purchase
- WHEN listed via TDispatchInfoPre or TPreDispatchInfo
- THEN only employees meeting purchase rules appear
- AND dispatch can be batch-processed per city/date configuration (TDispatchDayConf)
### Requirement: Social Insurance Details
The system SHALL maintain social insurance line-item records (TSocialInfo) with import, export, and change history.
#### Scenario: Query social details
- GIVEN an authorized user with house-hold permissions
- WHEN querying TSocialInfo with filters
- THEN matching social detail records are returned
- AND TSocialLog captures field-level change history
#### Scenario: Import social data
- GIVEN a valid import file
- WHEN uploaded to social detail management
- THEN records are bulk-inserted or updated with validation errors reported per row
### Requirement: Provident Fund Management
The system SHALL manage provident fund (公积金) information separately from social insurance with shared house-hold configuration.
#### Scenario: Provident fund record maintenance
- GIVEN an employee with active provident fund account
- WHEN TProvidentFund data is updated
- THEN fund base, ratio, and status reflect current policy
- AND changes are auditable via social change logs
### Requirement: House-Hold and Base Configuration
The system SHALL configure social insurance houses (社保户), provident fund houses, payment proportions, base amounts, and deadline dates.
#### Scenario: House-hold setup
- GIVEN a city and employer entity
- WHEN SysHouseHoldInfo is configured with SysPayProportion
- THEN dispatch and payment calculations use the configured ratios and bases
- AND THouseHoldLimit enforces cutoff dates per house
#### Scenario: Base amount setting
- GIVEN a policy adjustment period
- WHEN SysBaseSetInfo is updated
- THEN subsequent dispatch uses the new base for premium calculation
- AND TSocialFundHistory records the adjustment history
### Requirement: Payment Library
The system SHALL manage the payment library (缴费库) for consolidated premium records, import logs, and EKP push tracking.
#### Scenario: Payment record import
- GIVEN a payment file from insurer or tax platform
- WHEN imported via TPaymentInfoController
- THEN TPaymentInfo records are created or merged
- AND TPaymentInfoImportLog tracks import batch metadata
#### Scenario: EKP payment push
- GIVEN approved payment records
- WHEN pushed to EKP
- THEN TPaymentSocialPush tracks push IDs
- AND TSendEkpError records failures for retry
### Requirement: Audit Workflow
The system SHALL support audit for social insurance, provident fund, forecast settlements, approval forms, and base changes via TAuditInfo.
#### Scenario: Submit social audit
- GIVEN a dispatch or payment batch requiring approval
- WHEN submitted to audit
- THEN TAuditInfo records audit type, status, and reviewer
- AND approved batches proceed to payment or filing steps
### Requirement: Automated Payment Verification
The system SHALL verify actual payments (实缴) against expected amounts via automated jobs and soldier (社保士兵) integration.
#### Scenario: Auto payment verification
- GIVEN expected premium from dispatch data
- WHEN TAutoPaymentInfo job compares with actual payment
- THEN TAutoPaymentDetail records match/mismatch results
- AND TAutoPaymentError captures discrepancies for operator review
### Requirement: Forecast and Cost Estimation
The system SHALL provide forecast library (预估费用) for premium estimation before actual dispatch.
#### Scenario: Generate forecast
- GIVEN employee roster and base configuration
- WHEN TForecastLibrary calculation runs
- THEN estimated premiums are computed per policy rules
- AND results support settlement preview before dispatch
### Requirement: Alert and Failure Notification
The system SHALL notify operators of dispatch failures, deadline risks, and processing errors.
#### Scenario: Dispatch failure alert
- GIVEN a failed social insurance transaction
- WHEN the failure is recorded
- THEN TSocialAlertInfo notifies responsible users
- AND FailReasonConfig provides standardized failure reason codes
### Requirement: Cross-Module Integration
The social module SHALL integrate with yifu-archives for employee and settlement domain data, and support B-side APIs and tax-friend (税友) document generation.
#### Scenario: Archive data dependency
- GIVEN a dispatch creation request
- WHEN employee or domain validation is required
- THEN social service resolves data from archives via Dapr/HTTP
- AND invalid or incomplete archive blocks dispatch with ErrorMessage
#### Scenario: B-side social API
- GIVEN a B-side client
- WHEN calling DispatchBusinessController
- THEN social status and dispatch operations are exposed per B-side permission model
# UPMS
## Purpose
yifu-upms(端口 4000)是通用用户权限管理模块,提供用户、角色、菜单、部门、字典、数据权限及 OAuth 客户端配置,为全平台 RBAC 提供基础能力。
## Requirements
### Requirement: User Management
The system SHALL manage system users including CRUD, password policies, and department assignment.
#### Scenario: Create user
- GIVEN an administrator with user-management permission
- WHEN a new user is created via UserController
- THEN the user record is persisted with assigned department and roles
- AND the user can authenticate via yifu-auth after activation
#### Scenario: B-side business user
- GIVEN a B-side tenant context
- WHEN managing users via BusinessUserController
- THEN B-side users are scoped to their business relationship
- AND permissions differ from internal admin users
### Requirement: Role and Menu Authorization
The system SHALL bind roles to menus and API permissions for RBAC enforcement across all microservices.
#### Scenario: Assign role menus
- GIVEN a role definition
- WHEN menus are assigned via RoleController and MenuController
- THEN RoleMenuR mappings determine visible menus and `@PreAuthorize` expressions
- AND changes take effect on next token issuance or permission cache refresh
### Requirement: Department Organization
The system SHALL maintain organizational hierarchy via DeptController for data-scope and reporting structure.
#### Scenario: Department tree query
- GIVEN an authenticated user
- WHEN querying the department tree
- THEN hierarchical dept nodes are returned
- AND user-dept permission (SysUserDeptPermission) further restricts visible branches
### Requirement: Dictionary Management
The system SHALL provide system-wide dictionaries (DictController) and external relation dictionaries for cross-system code mapping.
#### Scenario: Dict lookup
- GIVEN a dict type code
- WHEN frontend or services request dict items
- THEN cached dict values are returned from Redis where configured
- AND SysOutRelDict supports external system code translation
### Requirement: Data Authorization
The system SHALL support row-level data authorization via DataAuthController and custom SQL data auth rules.
#### Scenario: Data scope filtering
- GIVEN a user with configured data auth rules
- WHEN a business service calls MenuUtil.setAuthSql
- THEN generated SQL fragments restrict query results to authorized data scope
- AND SysDataAuthDiySql supports custom per-menu SQL templates
### Requirement: OAuth Client Configuration
The system SHALL manage OAuth2 client details (OauthClientDetailsController) consumed by yifu-auth.
#### Scenario: Register OAuth client
- GIVEN a new microservice or frontend application
- WHEN an OAuth client is registered in UPMS
- THEN yifu-auth issues tokens for the client_id with configured scopes and grant types
- AND client secrets are stored securely
### Requirement: System Parameters and Areas
The system SHALL manage public parameters (PublicParamController) and geographic areas (AreaController) as shared reference data.
#### Scenario: Public param lookup
- GIVEN a param key used by business modules
- WHEN PublicParamController is queried
- THEN the current param value is returned
- AND changes propagate without service redeployment where hot-reload is supported
-- HRO 提前缴费商险数据兼容 — DDL + 存量迁移
-- 执行顺序:§1 → §2 → §3 → §4 → 应用发版
-- §1 HRO — t_insurance_detail 新增字段
-- 库:mvp_insurances
-- 若已执行旧版 DDL(is_history_advance_pay),见文件末尾 §1-upgrade 增量脚本。
ALTER TABLE t_insurance_detail
ADD COLUMN is_new_data CHAR(1) NULL DEFAULT '1'
COMMENT '是否新数据:1是(新提前缴费) 0否(历史见费出单),仅 is_jfcd=0 时有效'
AFTER is_jfcd;
-- §2 EKP — ekp_insurances_info 新增字段
-- 库:ekp
-- 若已执行旧版 DDL(fd_is_history_advance_pay),可先加列再转换后删旧列,例如:
-- ALTER TABLE ekp_insurances_info ADD COLUMN fd_new_data CHAR(1) NULL DEFAULT '1' AFTER fd_jfcd;
-- UPDATE ekp_insurances_info SET fd_new_data = CASE fd_is_history_advance_pay WHEN '是' THEN '0' WHEN '否' THEN '1' ELSE '1' END WHERE fd_jfcd = '是';
-- ALTER TABLE ekp_insurances_info DROP COLUMN fd_is_history_advance_pay;
-- 再跳过下方 ADD COLUMN。
ALTER TABLE ekp_insurances_info
ADD COLUMN fd_new_data CHAR(1) NULL DEFAULT '1'
COMMENT '是否新数据:1是 0否,默认1;与 HRO is_new_data 同值,fd_jfcd=是 时写入'
AFTER fd_jfcd;
-- §3 HRO — 存量见费出单刷为「否」(非新数据=历史)
UPDATE t_insurance_detail
SET is_new_data = '0'
WHERE is_jfcd = '0'
AND (is_new_data IS NULL OR is_new_data = '' OR is_new_data = '1');
-- §4 EKP — 既有提前缴费明细刷为「否」(非新数据=历史)
UPDATE ekp_insurances_info
SET fd_new_data = '0'
WHERE fd_jfcd = '是'
AND (fd_new_data IS NULL OR fd_new_data = '' OR fd_new_data = '1');
-- §1-upgrade 从 is_history_advance_pay 升级(仅已执行旧版 §1 的环境)
-- ALTER TABLE t_insurance_detail ADD COLUMN is_new_data CHAR(1) NULL DEFAULT '1'
-- COMMENT '是否新数据:1是 0否' AFTER is_jfcd;
-- UPDATE t_insurance_detail SET is_new_data = CASE is_history_advance_pay
-- WHEN '1' THEN '0' WHEN '0' THEN '1' ELSE NULL END;
-- UPDATE t_insurance_detail SET is_new_data = '0'
-- WHERE is_jfcd = '0' AND (is_new_data IS NULL OR is_new_data = '');
-- ALTER TABLE t_insurance_detail DROP COLUMN is_history_advance_pay;
...@@ -1382,4 +1382,12 @@ public class InsurancesConstants { ...@@ -1382,4 +1382,12 @@ public class InsurancesConstants {
public static final String REFUND_ZH_SETTLE = "费用支出中,禁止重复登记"; public static final String REFUND_ZH_SETTLE = "费用支出中,禁止重复登记";
public static final String REFUND_TYPE = "退费"; public static final String REFUND_TYPE = "退费";
public static final String INSURANCE_REPLACE_TAG_REPLACE = "可替换"; public static final String INSURANCE_REPLACE_TAG_REPLACE = "可替换";
/** 是否新数据:是(新提前缴费) */
public static final String IS_NEW_DATA_YES = "1";
/** 是否新数据:否(历史见费出单) */
public static final String IS_NEW_DATA_NO = "0";
/** EKP fd_new_data,与 HRO is_new_data 同值 */
public static final String EKP_FD_NEW_DATA_YES = IS_NEW_DATA_YES;
public static final String EKP_FD_NEW_DATA_NO = IS_NEW_DATA_NO;
} }
...@@ -187,5 +187,7 @@ public class EkpInsurancesInfo { ...@@ -187,5 +187,7 @@ public class EkpInsurancesInfo {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String fd_jfcd; private String fd_jfcd;
@Schema(description = "是否新数据:1是 0否,默认1;0对应HRO历史提前缴费")
private String fd_new_data;
} }
...@@ -426,6 +426,12 @@ public class TInsuranceDetail extends BaseEntity { ...@@ -426,6 +426,12 @@ public class TInsuranceDetail extends BaseEntity {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String isJfcd; private String isJfcd;
/**
* 是否新数据:1是(新提前缴费) 0否(历史见费出单),仅 isJfcd=0 时有效
*/
@Schema(description = "是否新数据:1是 0否")
private String isNewData;
/** /**
* 购买周期(格式:4 个月/117 天) * 购买周期(格式:4 个月/117 天)
*/ */
......
...@@ -203,6 +203,9 @@ public class EkpInteractiveParam implements Serializable { ...@@ -203,6 +203,9 @@ public class EkpInteractiveParam implements Serializable {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String isJfcd; private String isJfcd;
@Schema(description = "是否新数据:1是 0否")
private String isNewData;
/** /**
* 差额settleId * 差额settleId
*/ */
......
...@@ -256,6 +256,9 @@ public class InsuranceAddParam implements Serializable { ...@@ -256,6 +256,9 @@ public class InsuranceAddParam implements Serializable {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String isJfcd; private String isJfcd;
@Schema(description = "是否新数据:1是 0否")
private String isNewData;
/** /**
* 购买周期 (格式:4个月/117天) * 购买周期 (格式:4个月/117天)
*/ */
......
...@@ -259,6 +259,9 @@ public class InsuranceBatchParam implements Serializable { ...@@ -259,6 +259,9 @@ public class InsuranceBatchParam implements Serializable {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String isJfcd; private String isJfcd;
@Schema(description = "是否新数据:1是 0否")
private String isNewData;
/** /**
* 购买周期 (格式:4个月/117天) * 购买周期 (格式:4个月/117天)
*/ */
......
...@@ -432,6 +432,9 @@ public class InsuranceDetailVO implements Serializable { ...@@ -432,6 +432,9 @@ public class InsuranceDetailVO implements Serializable {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String isJfcd; private String isJfcd;
@Schema(description = "是否新数据:1是 0否")
private String isNewData;
/** /**
* 购买周期 (格式:4个月/117天) * 购买周期 (格式:4个月/117天)
*/ */
......
...@@ -197,6 +197,9 @@ public class InsuranceListVO implements Serializable { ...@@ -197,6 +197,9 @@ public class InsuranceListVO implements Serializable {
@Schema(description = "是否见费出单") @Schema(description = "是否见费出单")
private String isJfcd; private String isJfcd;
@Schema(description = "是否新数据:1是 0否")
private String isNewData;
/** /**
* 购买周期 (格式:4个月/117天) * 购买周期 (格式:4个月/117天)
*/ */
......
...@@ -1090,10 +1090,13 @@ public class TInsuranceDetailController { ...@@ -1090,10 +1090,13 @@ public class TInsuranceDetailController {
if (detail == null) { if (detail == null) {
return R.failed(CommonConstants.NO_DATA_TO_HANDLE); return R.failed(CommonConstants.NO_DATA_TO_HANDLE);
} }
EkpSettleStatusVo vo = tInsuranceDetailService.getSettleStatusFromEkpInsuranceDetail(detail.getId(),detail.getDefaultSettleId()); EkpSettleStatusVo vo = tInsuranceDetailService.getSettleStatusFromEkpInsuranceDetail(detail.getId(), detail.getDefaultSettleId());
if (null != vo){ if (null != vo) {
return R.ok(vo); return R.ok(vo);
} }
if (Common.isEmpty(detail.getDefaultSettleId())) {
return R.ok(new EkpSettleStatusVo());
}
return R.failed(); return R.failed();
} }
/** /**
......
package com.yifu.cloud.plus.v1.yifu.insurances.util;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.insurances.constants.InsurancesConstants;
import com.yifu.cloud.plus.v1.yifu.insurances.entity.TInsuranceDetail;
import com.yifu.cloud.plus.v1.yifu.insurances.vo.EkpInteractiveParam;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* 见费出单(提前缴费)历史/新数据分流工具。
*/
@Component
public class AdvancePaymentHelper {
private static final DateTimeFormatter LAUNCH_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Value("${advance-pay.new-data-launch-time:2099-12-31 23:59:59}")
private String newDataLaunchTime;
public boolean isJfcd(TInsuranceDetail detail) {
return detail != null && CommonConstants.ZERO_STRING.equals(detail.getIsJfcd());
}
public boolean isJfcdParam(String isJfcd) {
return CommonConstants.ZERO_STRING.equals(isJfcd);
}
/** 历史见费出单:isJfcd=0 且 isNewData 为 0 或空 */
public boolean isLegacyJfcdData(TInsuranceDetail detail) {
if (!isJfcd(detail)) {
return false;
}
return isLegacyNewDataFlag(detail.getIsNewData());
}
public boolean isLegacyJfcdParam(EkpInteractiveParam param) {
if (param == null || !isJfcdParam(param.getIsJfcd())) {
return false;
}
return isLegacyNewDataFlag(param.getIsNewData());
}
/** 新提前缴费:isJfcd=0 且 isNewData=1 */
public boolean isNewJfcdData(TInsuranceDetail detail) {
return isJfcd(detail) && InsurancesConstants.IS_NEW_DATA_YES.equals(detail.getIsNewData());
}
public boolean isNewJfcdParam(EkpInteractiveParam param) {
return param != null && isJfcdParam(param.getIsJfcd())
&& InsurancesConstants.IS_NEW_DATA_YES.equals(param.getIsNewData());
}
/**
* 满足见费出单条件时,按发布时间决定是否新数据。
*/
public String resolveIsNewDataForNewRecord() {
try {
LocalDateTime launch = LocalDateTime.parse(newDataLaunchTime.trim(), LAUNCH_TIME_FORMAT);
if (!LocalDateTime.now().isBefore(launch)) {
return InsurancesConstants.IS_NEW_DATA_YES;
}
} catch (Exception ignored) {
// 配置解析失败时保守走历史逻辑
}
return InsurancesConstants.IS_NEW_DATA_NO;
}
/** HRO is_new_data 与 EKP fd_new_data 同值直传 */
public String toEkpFdNewData(String isNewData) {
if (InsurancesConstants.IS_NEW_DATA_YES.equals(isNewData)) {
return InsurancesConstants.IS_NEW_DATA_YES;
}
return InsurancesConstants.IS_NEW_DATA_NO;
}
public String fromEkpFdNewData(String fdValue) {
if (InsurancesConstants.IS_NEW_DATA_YES.equals(fdValue)) {
return InsurancesConstants.IS_NEW_DATA_YES;
}
if (InsurancesConstants.IS_NEW_DATA_NO.equals(fdValue)) {
return InsurancesConstants.IS_NEW_DATA_NO;
}
return null;
}
private boolean isLegacyNewDataFlag(String isNewData) {
return Common.isEmpty(isNewData)
|| InsurancesConstants.IS_NEW_DATA_NO.equals(isNewData);
}
}
...@@ -89,6 +89,9 @@ public class DoJointInsuranceTask { ...@@ -89,6 +89,9 @@ public class DoJointInsuranceTask {
@Autowired @Autowired
private TBusinessOperateService tBusinessOperateService; private TBusinessOperateService tBusinessOperateService;
@Resource
private AdvancePaymentHelper advancePaymentHelper;
/** /**
* @Description: 商险明细推送 * @Description: 商险明细推送
* @Author: huyc * @Author: huyc
...@@ -248,6 +251,9 @@ public class DoJointInsuranceTask { ...@@ -248,6 +251,9 @@ public class DoJointInsuranceTask {
if (Common.isNotNull(viewVo.getId())) { if (Common.isNotNull(viewVo.getId())) {
insuranceId = viewVo.getId().substring(0, 19); insuranceId = viewVo.getId().substring(0, 19);
detail = insuranceDetailMapper.selectById(insuranceId); detail = insuranceDetailMapper.selectById(insuranceId);
if (Common.isNotNull(detail) && advancePaymentHelper.isNewJfcdData(detail)) {
continue;
}
if (Common.isNotNull(detail)) { if (Common.isNotNull(detail)) {
TInsuranceDetail detailOld = new TInsuranceDetail(); TInsuranceDetail detailOld = new TInsuranceDetail();
BeanCopyUtils.copyProperties(detail,detailOld); BeanCopyUtils.copyProperties(detail,detailOld);
...@@ -587,6 +593,9 @@ public class DoJointInsuranceTask { ...@@ -587,6 +593,9 @@ public class DoJointInsuranceTask {
} }
//根据结算类型是合并结算,推送预估保费到ekp(上面已经算好,这里直接判断有预估保费的就推送) //根据结算类型是合并结算,推送预估保费到ekp(上面已经算好,这里直接判断有预估保费的就推送)
for (TInsuranceDetail tInsuranceDetail : successList) { for (TInsuranceDetail tInsuranceDetail : successList) {
if (!advancePaymentHelper.isLegacyJfcdData(tInsuranceDetail)) {
continue;
}
//如果是合并计算或见费出单则推送至EKP //如果是合并计算或见费出单则推送至EKP
if (CommonConstants.ZERO_INT == tInsuranceDetail.getSettleType() if (CommonConstants.ZERO_INT == tInsuranceDetail.getSettleType()
|| CommonConstants.ZERO_STRING.equals(tInsuranceDetail.getIsJfcd())) { || CommonConstants.ZERO_STRING.equals(tInsuranceDetail.getIsJfcd())) {
...@@ -712,10 +721,22 @@ public class DoJointInsuranceTask { ...@@ -712,10 +721,22 @@ public class DoJointInsuranceTask {
} }
if (InsurancesConstants.ACTUAL_SETTLE_BILL.equals(param.getSettleType())){ if (InsurancesConstants.ACTUAL_SETTLE_BILL.equals(param.getSettleType())){
ys = 0L; if (advancePaymentHelper.isNewJfcdParam(param)) {
if (updateFlag){ double actualAmount = null == param.getActualPremium() ? 0.00 : param.getActualPremium().doubleValue();
//应支=0 pushParam.setFd_3af9d1441ef7b6("否");
pushParam.setFd_3adfe6e3911ffe(null==param.getActualPremium()? 0.00:param.getActualPremium().doubleValue()); if ("是".equals(deptInfoVo.getBpoSettle())) {
ys = 0L;
pushParam.setFd_3adfe6e3911ffe(actualAmount);
} else {
ys = actualAmount;
pushParam.setFd_3adfe6e3911ffe(actualAmount);
}
} else {
ys = 0L;
if (updateFlag){
//应支=0
pushParam.setFd_3adfe6e3911ffe(null==param.getActualPremium()? 0.00:param.getActualPremium().doubleValue());
}
} }
} }
//差额 //差额
...@@ -1106,8 +1127,14 @@ public class DoJointInsuranceTask { ...@@ -1106,8 +1127,14 @@ public class DoJointInsuranceTask {
//是否见费出单 //是否见费出单
if (CommonConstants.ZERO_STRING.equals(param.getIsJfcd())){ if (CommonConstants.ZERO_STRING.equals(param.getIsJfcd())){
pushParam.setFd_jfcd("是"); pushParam.setFd_jfcd("是");
//有无预估 pushParam.setFd_new_data(advancePaymentHelper.toEkpFdNewData(param.getIsNewData()));
pushParam.setFd_3af9d1441ef7b6("有"); if (advancePaymentHelper.isNewJfcdParam(param)
&& InsurancesConstants.ACTUAL_SETTLE_BILL.equals(param.getSettleType())) {
pushParam.setFd_3af9d1441ef7b6("否");
} else {
//有无预估
pushParam.setFd_3af9d1441ef7b6("有");
}
}else { }else {
pushParam.setFd_jfcd("否"); pushParam.setFd_jfcd("否");
} }
......
...@@ -41,4 +41,7 @@ wx: ...@@ -41,4 +41,7 @@ wx:
corpsecret: 16kqEL_eU-ARwYyqLgEBWHgxm8gXVnkzv_eJMLy9NpU corpsecret: 16kqEL_eU-ARwYyqLgEBWHgxm8gXVnkzv_eJMLy9NpU
agentid: 1000010 agentid: 1000010
authUrl: https://test-wx.worfu.com/yifu-auth/method/oauth/wxLogin authUrl: https://test-wx.worfu.com/yifu-auth/method/oauth/wxLogin
domainName: https://test-wx.worfu.com domainName: https://test-wx.worfu.com
\ No newline at end of file
advance-pay:
new-data-launch-time: 2099-12-31 23:59:59
\ No newline at end of file
...@@ -41,4 +41,7 @@ wx: ...@@ -41,4 +41,7 @@ wx:
corpsecret: R0nKkvsY-oF41fuQvUXZ-kFG3_g_Ce0bpZt6mByx524 corpsecret: R0nKkvsY-oF41fuQvUXZ-kFG3_g_Ce0bpZt6mByx524
agentid: 1000009 agentid: 1000009
authUrl: https://wx.worfu.com/yifu-auth/method/oauth/wxLogin authUrl: https://wx.worfu.com/yifu-auth/method/oauth/wxLogin
domainName: https://wx.worfu.com domainName: https://wx.worfu.com
\ No newline at end of file
advance-pay:
new-data-launch-time: 2099-12-31 23:59:59
\ No newline at end of file
...@@ -44,3 +44,5 @@ wx: ...@@ -44,3 +44,5 @@ wx:
domainName: https://test-wx.worfu.com domainName: https://test-wx.worfu.com
advance-pay:
new-data-launch-time: 2099-12-31 23:59:59
...@@ -104,3 +104,7 @@ springdoc: ...@@ -104,3 +104,7 @@ springdoc:
- group: insurances - group: insurances
#按包路径匹配 #按包路径匹配
packagesToScan: com.yifu.cloud.plus.v1.yifu.insurances.controller packagesToScan: com.yifu.cloud.plus.v1.yifu.insurances.controller
# 新提前缴费数据写入切点(满足见费出单且当前时间>=此时间时写 isNewData=1)
advance-pay:
new-data-launch-time: 2099-12-31 23:59:59
...@@ -57,6 +57,8 @@ ...@@ -57,6 +57,8 @@
<result property="fd_3c6f0108e05c84" column="fd_3c6f0108e05c84"/> <result property="fd_3c6f0108e05c84" column="fd_3c6f0108e05c84"/>
<result property="fd_usebpo_settle" column="fd_usebpo_settle"/> <result property="fd_usebpo_settle" column="fd_usebpo_settle"/>
<result property="createTime" column="create_time"/> <result property="createTime" column="create_time"/>
<result property="fd_jfcd" column="fd_jfcd"/>
<result property="fd_new_data" column="fd_new_data"/>
</resultMap> </resultMap>
<sql id="Base_Column_List" > <sql id="Base_Column_List" >
...@@ -112,6 +114,8 @@ ...@@ -112,6 +114,8 @@
,a.fd_3c6f0108e05c84 ,a.fd_3c6f0108e05c84
,a.fd_usebpo_settle ,a.fd_usebpo_settle
,a.create_time ,a.create_time
,a.fd_jfcd
,a.fd_new_data
</sql> </sql>
<!-- ekpInsurancesInfo简单分页查询 --> <!-- ekpInsurancesInfo简单分页查询 -->
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
<result property="paymentStatus" column="PAYMENT_STATUS" jdbcType="VARCHAR"/> <result property="paymentStatus" column="PAYMENT_STATUS" jdbcType="VARCHAR"/>
<result property="paymentTime" column="PAYMENT_TIME" jdbcType="VARCHAR"/> <result property="paymentTime" column="PAYMENT_TIME" jdbcType="VARCHAR"/>
<result property="isJfcd" column="IS_JFCD" jdbcType="VARCHAR"/> <result property="isJfcd" column="IS_JFCD" jdbcType="VARCHAR"/>
<result property="isNewData" column="IS_NEW_DATA" jdbcType="VARCHAR"/>
<result property="purchaseCycle" column="PURCHASE_CYCLE" jdbcType="VARCHAR"/> <result property="purchaseCycle" column="PURCHASE_CYCLE" jdbcType="VARCHAR"/>
<result property="preHandleTime" column="PRE_HANDLE_TIME" jdbcType="VARCHAR"/> <result property="preHandleTime" column="PRE_HANDLE_TIME" jdbcType="VARCHAR"/>
...@@ -98,7 +99,7 @@ ...@@ -98,7 +99,7 @@
IS_USE,IS_EFFECT,IS_OVERDUE,REMARK, IS_USE,IS_EFFECT,IS_OVERDUE,REMARK,
CREATE_BY,CREATE_NAME,CREATE_TIME,BPO_FLAG, CREATE_BY,CREATE_NAME,CREATE_TIME,BPO_FLAG,
UPDATE_BY,UPDATE_TIME,DELETE_FLAG,DEFAULT_SETTLE_ID,HANDLED_BY,HANDLED_TIME,ORDER_NO,CREATE_USER_DEPT_ID,CREATE_USER_DEPT_NAME, UPDATE_BY,UPDATE_TIME,DELETE_FLAG,DEFAULT_SETTLE_ID,HANDLED_BY,HANDLED_TIME,ORDER_NO,CREATE_USER_DEPT_ID,CREATE_USER_DEPT_NAME,
DEPT_NAME,UNIT_ID,UNIT_NAME,UNIT_NO,IS_ADRESS,PAYMENT_STATUS,PAYMENT_TIME,IS_JFCD,PURCHASE_CYCLE,PRE_HANDLE_TIME DEPT_NAME,UNIT_ID,UNIT_NAME,UNIT_NO,IS_ADRESS,PAYMENT_STATUS,PAYMENT_TIME,IS_JFCD,IS_NEW_DATA,PURCHASE_CYCLE,PRE_HANDLE_TIME
</sql> </sql>
...@@ -131,6 +132,7 @@ ...@@ -131,6 +132,7 @@
a.PAYMENT_STATUS as paymentStatus, a.PAYMENT_STATUS as paymentStatus,
a.PAYMENT_TIME as paymentTime, a.PAYMENT_TIME as paymentTime,
a.IS_JFCD as isJfcd, a.IS_JFCD as isJfcd,
a.IS_NEW_DATA as isNewData,
a.PURCHASE_CYCLE as purchaseCycle, a.PURCHASE_CYCLE as purchaseCycle,
a.BILLING_TYPE as billingType, a.BILLING_TYPE as billingType,
a.PRE_HANDLE_TIME as preHandleTime, a.PRE_HANDLE_TIME as preHandleTime,
...@@ -241,6 +243,7 @@ ...@@ -241,6 +243,7 @@
a.PAYMENT_STATUS as paymentStatus, a.PAYMENT_STATUS as paymentStatus,
a.PAYMENT_TIME as paymentTime, a.PAYMENT_TIME as paymentTime,
a.IS_JFCD as isJfcd, a.IS_JFCD as isJfcd,
a.IS_NEW_DATA as isNewData,
<!-- a.PURCHASE_CYCLE as purchaseCycle, --> <!-- a.PURCHASE_CYCLE as purchaseCycle, -->
a.PURCHASE_CYCLE as purchaseCycle, a.PURCHASE_CYCLE as purchaseCycle,
a.PRE_HANDLE_TIME as preHandleTime, a.PRE_HANDLE_TIME as preHandleTime,
...@@ -436,7 +439,7 @@ ...@@ -436,7 +439,7 @@
a.REFUND_ID as refundId, a.REFUND_ID as refundId,
a.EXPIRE_REMARK, a.EXPIRE_REMARK,
a.EXPIRE_IGNORE_FLAG, a.EXPIRE_IGNORE_FLAG,
a.IS_ADRESS as isAdress,a.PAYMENT_STATUS,a.PAYMENT_TIME,a.IS_JFCD, a.IS_ADRESS as isAdress,a.PAYMENT_STATUS,a.PAYMENT_TIME,a.IS_JFCD,a.IS_NEW_DATA as isNewData,
a.PURCHASE_CYCLE,a.PRE_HANDLE_TIME a.PURCHASE_CYCLE,a.PRE_HANDLE_TIME
from t_insurance_detail a from t_insurance_detail a
left join t_insurance_settle tis on a.DEFAULT_SETTLE_ID = tis.ID left join t_insurance_settle tis on a.DEFAULT_SETTLE_ID = tis.ID
......
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