From 5f20c5794ca50f3deb473e431d19ad053b4eac56 Mon Sep 17 00:00:00 2001 From: tangweijie <877588133@qq.com> Date: Fri, 27 Mar 2026 10:12:34 +0800 Subject: [PATCH] docs: add rev-004 legacy finance migration planning artifacts --- ...REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md | 487 ++++++++++++++++++ ...04-batch1-code-conversion-dictionary-v1.md | 185 +++++++ .../rev004-batch1-detailed-mapping-v1.md | 240 +++++++++ .../rev004-field-mapping-matrix-v1.md | 140 +++++ .../rev004-gap-assessment-contract.md | 42 ++ .../rev004-identifier-mapping-matrix-v1.md | 104 ++++ .../rev004-legacy-mapping-contract.md | 55 ++ .../rev004-old-to-new-mapping-matrix-v1.md | 80 +++ .../rev004-status-mapping-matrix-v1.md | 100 ++++ .../rev004-trial-migration-checklist-v1.md | 168 ++++++ .../data-model.md | 145 ++++++ .../plan.md | 162 ++++++ .../quickstart.md | 97 ++++ .../research.md | 85 +++ .../spec.md | 170 ++++++ 15 files changed, 2260 insertions(+) create mode 100644 docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-code-conversion-dictionary-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-detailed-mapping-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-field-mapping-matrix-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-gap-assessment-contract.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-identifier-mapping-matrix-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-legacy-mapping-contract.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-old-to-new-mapping-matrix-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-status-mapping-matrix-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/contracts/rev004-trial-migration-checklist-v1.md create mode 100644 specs/008-rev004-legacy-finance-migration/data-model.md create mode 100644 specs/008-rev004-legacy-finance-migration/plan.md create mode 100644 specs/008-rev004-legacy-finance-migration/quickstart.md create mode 100644 specs/008-rev004-legacy-finance-migration/research.md create mode 100644 specs/008-rev004-legacy-finance-migration/spec.md diff --git a/docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md b/docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md new file mode 100644 index 0000000..046966a --- /dev/null +++ b/docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md @@ -0,0 +1,487 @@ +# REV-004 旧账务数据迁移实施方案 v0 + +## 1. 文档定位 + +本文档用于起草福建水务营收系统中“旧账务模型迁移到新系统模型”的第一版实施方案,重点聚焦 `REV-004` 账务处理一期及其直接关联的收费、预存、退款、冲正、坏账、发票追溯对象。 + +本文档不是最终迁移脚本,也不是最终数据口径裁决书,而是后续正式立项、迁移设计、实现拆解和验收校对的基础方案。 + +## 2. 背景与目标 + +当前仓库已经明确: + +- `REV-004` 当前正式模型是“账务处理控制模型” +- 旧系统数据字典体现的是“营业账 + 收费 + 预存账户 + 调整申请单 + 发票”的业务财务模型 +- 新系统不计划机械复制旧系统的全部精细账务台账表族 +- 但若存在旧业务继续迁移与历史查询要求,则必须保证迁移后数据可承接、可追溯、可核对 + +因此,本方案的目标不是“把旧表名原样搬过来”,而是: + +1. 识别旧账务对象与新系统能力边界 +2. 明确哪些数据进入新系统在线主模型 +3. 明确哪些数据作为历史只读保留 +4. 明确哪些数据只保留映射与追溯关系 +5. 形成可执行的迁移批次、校验规则和风险控制方案 + +## 3. 迁移范围 + +### 3.1 本轮纳入范围 + +- `AT_CHARGES`、`AT_CHARGE_DETAILS` +- `CT_ACCOUNTS`、`CT_ACCOUNT_LOGS` +- `AT_REFUNDS` +- `PM_ACCOUNT_RECORDS`、`PM_ACCOUNT_RECORD_DETAILS` +- `PM_AMOUNT_RECORDS`、`PM_AMOUNT_RECORD_DETAILS` +- `PM_PRICE_RECORDS`、`PM_PRICE_RECORD_DETAILS` +- `PM_PAYMENT_RECORDS`、`PM_PAYMENT_RECORD_DETAILS` +- `PM_KNOTTY_RECORDS`、`PM_KNOTTY_RECORD_DETAILS` +- `PM_LATEFEE_RECORDS`、`PM_LATEFEE_RECORD_DETAILS` +- `PM_PAY_COLLECTS`、`PM_PAY_SUBTOTALS`、`PM_PAY_DETAILS` +- `IV_INVOICE_INFOS`、`IV_INVOICE_DETAIL_INFOS`、`IV_CHARGE_INVOICE_MAPPINGS` + +### 3.2 本轮关联参考范围 + +- `营收数据字典.md` +- `docs/guides/BACKEND_TABLE_MAPPING.md` +- `docs/design/02_Detailed_Design/12_REV_Detailed.md` 中 `REV-004` 迁移补充 +- `docs/design/03_Technical_Design/03_Interface_Design.md` 中“历史查询与迁移校验接口口径” + +### 3.3 本轮暂不纳入范围 + +- 独立总账、明细账、会计分录体系重建 +- 独立账务中台或账本引擎 +- 旧审批流引擎的完整在线复刻 +- 超出 `REV-004` 一期范围的新业务规则扩展 + +## 4. 迁移原则 + +### 4.1 语义迁移优先于表结构平移 + +迁移对象首先是业务语义、状态语义、追溯语义和查询语义,而不是旧表结构本身。 + +### 4.2 在线承接与历史保留分层 + +新系统中必须明确区分: + +- 在线主模型承接 +- 历史只读承接 +- 映射追溯承接 + +不得把所有历史表都作为在线业务表原样重建。 + +### 4.3 汇总对账与明细追溯并重 + +迁移验收必须同时支持: + +- 汇总级核对 +- 明细级追溯 + +避免只对总数、不支持差异定位。 + +### 4.4 新旧标识必须保留映射 + +迁移后至少应保留以下映射能力: + +- 原账单号 ↔ 新账单号 +- 原流水号 ↔ 新流水号 +- 原申请单 ↔ 新业务单号 +- 原发票号 ↔ 新发票对象 +- 原处理记录 ↔ 新留痕记录 + +### 4.5 历史查询只读 + +历史查询接口只承担查询、比对和审计职责,不承担迁移修正、状态补写或在线业务处理职责。 + +## 5. 新旧模型差异判断 + +### 5.1 旧模型特征 + +旧模型主要表现为: + +- 以 `FeeId` 为核心的营业账模型 +- 以 `AccountId / AccLogId` 为核心的预存账户与流水模型 +- 以“汇总表 + 明细表 + 流程字段”构成的账务申请单模型 +- 以收费汇总、小计、明细、实时收费日志构成的收费结果模型 +- 以发票主表、发票明细、账单映射表构成的发票模型 + +### 5.2 新模型特征 + +当前 `REV-004` 正式口径主要表现为: + +- 统一入口:`IF-REV-007` +- 统一场景:水量调整、金额调整、退款、冲正、坏账申请 +- 统一共性控制:范围校验、状态校验、原交易校验、留痕、审批边界 +- 统一结果表达:`AccountingResult` +- 统一留痕对象:`OperationLog` +- 在线主模型承接以 `biz_charge*`、`bk_transaction*`、`biz_operat_log*` 为主 + +### 5.3 迁移结论 + +本次迁移不应追求“旧表 = 新表”的结构兼容,而应采用三层承接模型: + +1. 标准业务承接层 + 由新系统正式在线对象承接当前有效业务数据与后续处理能力。 + +2. 兼容映射层 + 记录旧标识、新标识、状态映射、来源类型和迁移批次,支撑核对和追溯。 + +3. 历史只读层 + 保留旧系统难以在线抽象但必须可查的历史明细、审批痕迹与台账信息。 + +## 6. 迁移分层设计 + +### 6.1 在线主模型承接层 + +建议由以下对象主承接: + +- `biz_charge` / `biz_charge_detail` +- `bk_transaction*` +- `biz_operat_log*` +- `biz_invoice*` +- `biz_cust_invoice` +- `biz_collection` / `bk_*` 支付与对账对象 + +适合进入在线主模型的典型数据: + +- 当前有效账单 +- 当前有效账单明细 +- 当前有效收费结果 +- 当前有效发票结果 +- 当前可继续参与账务处理的退款、冲正、坏账关联对象 + +### 6.2 兼容映射层 + +建议新增或规划一组“迁移映射对象”,至少覆盖: + +- `legacy_charge_mapping` +- `legacy_account_log_mapping` +- `legacy_finance_record_mapping` +- `legacy_invoice_mapping` +- `legacy_business_trace_mapping` + +每条映射建议至少保留: + +- `legacySystem` +- `legacyTable` +- `legacyId` +- `legacyBizNo` +- `targetDomain` +- `targetId` +- `targetBizNo` +- `mappingType` +- `migrationBatchNo` +- `migrationTime` +- `mappingStatus` + +### 6.3 历史只读层 + +以下对象默认优先按历史只读保留: + +- 旧审批节点痕迹 +- 旧汇总/明细台账中的页面型冗余字段 +- 旧系统专门为菜单、导出、统计、补打而拆出的历史辅助表 + +历史只读层必须满足: + +- 能按原单号、客户号、账期、处理类型查询 +- 能返回新旧标识映射 +- 能支持迁移验收和审计追溯 + +## 7. 迁移对象分类与策略 + +| 对象类别 | 典型旧表 | 建议策略 | 说明 | +| --- | --- | --- | --- | +| 账单主明细 | `AT_CHARGES`、`AT_CHARGE_DETAILS` | 在线承接 + 映射 | 属于新系统核心主对象,必须进入在线模型 | +| 账户余额与流水 | `CT_ACCOUNTS`、`CT_ACCOUNT_LOGS` | 在线承接 + 映射 + 历史补充 | 预存相关场景必须可追溯 | +| 收费结果 | `PM_PAY_*`、实时收费日志 | 在线承接 + 历史只读 | 主结果进入在线模型,细粒度日志可保留只读 | +| 退款对象 | `AT_REFUNDS`、`PM_ACCOUNT_RECORD*` | 在线承接场景语义 + 历史明细只读 | 统一挂到退款场景,不强求一对一新实体 | +| 调整对象 | `PM_AMOUNT_*`、`PM_PRICE_*`、`PM_PAYMENT_*` | 场景归并 + 映射 + 历史只读 | 进入金额/水量调整、冲正等统一场景 | +| 坏账对象 | `PM_KNOTTY_*` | 场景归并 + 映射 | 统一纳入坏账申请场景 | +| 滞纳金减免 | `PM_LATEFEE_*` | 场景归并 + 历史只读 | 视为账务处理衍生场景 | +| 发票对象 | `IV_*` | 在线承接 + 历史映射 | 发票主对象与账单关系必须保留 | + +## 8. 推荐迁移批次 + +### 批次 1:基础主数据与主业务对象 + +目标: + +- 锁定客户、账户、账单主明细的迁移基线 + +对象: + +- 客户相关主数据 +- `CT_ACCOUNTS` +- `AT_CHARGES` +- `AT_CHARGE_DETAILS` + +输出: + +- 账单主键映射 +- 账户主键映射 +- 批次级基础对账报告 + +### 批次 2:收费结果与交易对象 + +目标: + +- 锁定收费、核销、支付、对账相关迁移基线 + +对象: + +- `PM_PAY_COLLECTS` +- `PM_PAY_SUBTOTALS` +- `PM_PAY_DETAILS` +- 实时收费日志 +- `bk_transaction*` 对应交易承接对象 + +输出: + +- 收费汇总对账 +- 明细流水映射 +- 异常流水清单 + +### 批次 3:账务处理历史对象 + +目标: + +- 锁定 `REV-004` 相关旧账务处理历史的承接方式 + +对象: + +- `PM_ACCOUNT_RECORD*` +- `PM_AMOUNT_*` +- `PM_PRICE_*` +- `PM_PAYMENT_*` +- `PM_KNOTTY_*` +- `PM_LATEFEE_*` +- `AT_REFUNDS` + +输出: + +- 场景归并结果表 +- 新旧状态映射表 +- 历史只读查询口径 + +### 批次 4:发票对象与账单关系 + +目标: + +- 锁定账单与发票的历史关系、结果状态和追溯路径 + +对象: + +- `IV_INVOICE_INFOS` +- `IV_INVOICE_DETAIL_INFOS` +- `IV_CHARGE_INVOICE_MAPPINGS` + +输出: + +- 发票映射表 +- 账单-发票关系校验报告 +- 历史补打与历史查询口径 + +## 9. 必要映射矩阵 + +本方案落地前,至少需要产出以下四份矩阵: + +### 9.1 旧表到新对象映射矩阵 + +字段建议: + +- 旧表名 +- 旧对象语义 +- 新对象域 +- 新对象名 +- 承接方式 +- 是否在线承接 +- 是否历史只读 +- 风险说明 + +### 9.2 旧字段到新字段映射矩阵 + +字段建议: + +- 旧字段 +- 新字段 +- 转换规则 +- 默认值规则 +- 是否允许为空 +- 是否需要枚举转换 +- 是否需要补充追溯字段 + +### 9.3 旧状态到新状态映射矩阵 + +字段建议: + +- 旧表名 +- 旧状态字段 +- 旧状态值 +- 新状态字段 +- 新状态值 +- 是否完全等价 +- 若不等价的补充字段 + +### 9.4 新旧标识映射矩阵 + +字段建议: + +- 原系统单号 +- 原表主键 +- 新系统业务单号 +- 新系统主键 +- 迁移批次 +- 映射状态 +- 是否核验通过 + +## 10. 最小兼容字段建议 + +若新模型需要完整支撑迁移与追溯,建议至少预留以下兼容字段或扩展属性: + +- `legacySystem` +- `legacyTable` +- `legacyId` +- `legacyBizNo` +- `legacyState` +- `sourceFeeId` +- `sourceAccLogId` +- `sourceInvoiceId` +- `targetBizNo` +- `migrationBatchNo` +- `migrationRemark` +- `tracePayload` + +这些字段不一定都进入核心业务主表,但必须有稳定承接位置。 + +## 11. 迁移校验方案 + +### 11.1 数量校验 + +至少校验: + +- 账单总数 +- 账单明细总数 +- 账户总数 +- 账户流水总数 +- 收费明细总数 +- 发票总数 +- 迁移历史记录总数 + +### 11.2 金额校验 + +至少校验: + +- 应收金额汇总 +- 实收金额汇总 +- 预存余额汇总 +- 退款金额汇总 +- 坏账金额汇总 +- 发票金额汇总 + +### 11.3 关系校验 + +至少校验: + +- 账单 ↔ 账单明细 +- 账单 ↔ 收费明细 +- 账单 ↔ 发票映射 +- 账户 ↔ 账户流水 +- 调整记录 ↔ 原账单 / 新账单 +- 退款记录 ↔ 原流水 / 目标流水 + +### 11.4 业务抽样校验 + +建议每类场景至少抽样: + +- 1 笔预存退款 +- 1 笔已销调整 +- 1 笔价差调整 +- 1 笔坏账申请 +- 1 笔发票回写 +- 1 笔收费红冲 + +要求在新系统中能完整回答: + +- 原记录是谁 +- 对应新记录是谁 +- 状态是否一致 +- 金额是否一致 +- 关联关系是否完整 +- 审计追溯是否可查 + +## 12. 查询与验收接口要求 + +迁移后至少应满足以下查询能力: + +- 按原账单号 / 新账单号查询迁移关系 +- 按原流水号 / 新流水号查询收费与退款关系 +- 按客户号、账期、处理类型查询历史账务处理记录 +- 按发票号、申请单号查询账单与发票关系 +- 按迁移批次查看汇总对账结果与差异明细 + +这些查询能力应优先挂靠现有 `IF-REV-*` 接口族扩展,不建议为迁移单独发明新的正式接口编号体系。 + +## 13. 风险清单 + +### 风险 1:旧模型一表多义 + +部分旧表同时承载业务申请、审批流程、结果记录和页面展示字段,难以直接映射到新系统单一对象。 + +应对: + +- 拆分“在线承接字段”和“历史只读字段” +- 不强行一对一建表 + +### 风险 2:状态机不完全等价 + +旧系统中的 `State`、`ProcType`、`BusinessType`、审批节点状态与新系统结果状态不一定一一对应。 + +应对: + +- 必做状态映射矩阵 +- 对不等价状态保留 `legacyState` + +### 风险 3:旧审批流无法在线复刻 + +旧模型中大量存在 `TaskId`、`StepId`、`FlowRemark`,但当前 `REV-004` 只保留审批能力位。 + +应对: + +- 流程痕迹优先按历史只读保留 +- 在线模型仅保留审批边界和结果位 + +### 风险 4:收费、发票、退款链条断链 + +若只迁主对象,不迁关联映射,后续核对、审计和客户查询会断链。 + +应对: + +- 强制保留新旧标识映射 +- 发票、收费、退款场景必须建立关系校验 + +## 14. 推荐实施顺序 + +1. 完成旧对象清单与迁移分层判断 +2. 完成四类映射矩阵 +3. 补齐新模型兼容字段与映射承接设计 +4. 设计迁移批次与回滚策略 +5. 再进入迁移脚本开发与试迁 +6. 最后执行汇总校验、明细抽样校验和差异修正 + +## 15. 当前待补充项 + +本方案作为 v0 草稿,下一轮至少还需要补以下内容: + +- 旧表到当前 backend 真实表的逐表映射 +- `REV-004` 新模型兼容字段的正式落位位置 +- 迁移批次的执行窗口与冻结策略 +- 试迁环境、脚本入口和回滚方案 +- 差异处理与复迁规则 + +## 16. 参考来源 + +- `docs/design/04_Appendix/Archive/05_Data_Dictionary/营收数据字典.md` +- `docs/guides/BACKEND_TABLE_MAPPING.md` +- `docs/design/02_Detailed_Design/12_REV_Detailed.md` +- `docs/design/03_Technical_Design/03_Interface_Design.md` +- `docs/design/00_Management/07_Migration_Mapping_Template.md` diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-code-conversion-dictionary-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-code-conversion-dictionary-v1.md new file mode 100644 index 0000000..e14d0b4 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-code-conversion-dictionary-v1.md @@ -0,0 +1,185 @@ +# Dictionary: REV-004 第一批次编码转换字典 v1 + +## 1. 目标 + +本字典用于补齐第一批次试迁中最容易导致字段映射失真的编码转换规则。 + +当前仅覆盖三类核心编码: + +- `PriceListId` +- `PriceCode` +- `PriceItemId` + +它们分别影响: + +- 账单主表中的调价号 / 调价快照承接 +- 账单主表与明细中的用水性质 / 价格模板承接 +- 明细中的费用组成承接 + +## 2. 使用原则 + +- 本字典当前是 v1 规划字典,不假定所有旧编码与新编码已经一一建立物理映射表。 +- 若当前 backend 已存在稳定编码主数据,应优先落到现有主数据对象。 +- 若当前尚未确认稳定编码表,则先保留“旧值 + 映射占位 + 追溯字段”,不要在脚本里硬编码不可验证的转换结果。 + +## 3. 编码转换规则总览 + +| 旧字段 | 旧语义 | 新承接字段 | 当前转换方式 | 当前状态 | 备注 | +| --- | --- | --- | --- | --- | --- | +| `PriceListId` | 调价号 / 水价调整编号 | `adjustmentSnapCode` | `legacy int -> new string code` | `needs-mapping` | 需要形成调价号到快照编码的转换字典 | +| `PriceCode` | 用水性质 / 价格类别编码 | `priceTemplateCode` | `legacy int -> new string template code` | `needs-mapping` | 需要形成旧用水性质到新价格模板编码的转换字典 | +| `PriceItemId` | 费用组成 ID | `costComponentCode` | `legacy int -> new string component code` | `needs-mapping` | 需要形成旧费用项到新费用组成编码的转换字典 | + +## 4. `PriceListId` 转换字典 + +### 4.1 承接目标 + +| 旧字段 | 新字段 | 说明 | +| --- | --- | --- | +| `AT_CHARGES.PriceListId` | `biz_charge.adjustmentSnapCode` | 账单主表调价快照编码 | +| `AT_CHARGE_DETAILS.PriceListId` | `biz_charge_detail.adjustmentSnapCode` | 账单明细调价快照编码 | + +### 4.2 当前转换策略 + +在未建立完整字典前,建议采用两段式处理: + +1. 迁移脚本先保留原值到映射层 +2. 主表字段使用可验证的新编码规则转换,若无法确定则标记待补 + +### 4.3 推荐映射结构 + +| 字段 | 说明 | +| --- | --- | +| `legacyPriceListId` | 旧调价号 | +| `targetAdjustmentSnapCode` | 新调价快照编码 | +| `mappingSource` | 来源:主数据 / 规则推导 / 手工补录 | +| `mappingStatus` | `planned / verified / unresolved` | +| `remark` | 备注 | + +### 4.4 当前脚本建议 + +- 若存在稳定调价快照表和唯一编码,可直接转换。 +- 若不存在稳定映射来源: + - `adjustmentSnapCode` 可先按约定规则生成占位值 + - 同时必须写入 `legacyPriceListId` + - `mappingStatus` 标记为 `unresolved` + +## 5. `PriceCode` 转换字典 + +### 5.1 承接目标 + +| 旧字段 | 新字段 | 说明 | +| --- | --- | --- | +| `AT_CHARGES.PriceCode` | `biz_charge.priceTemplateCode` | 账单主表价格模板编码 | +| `AT_CHARGE_DETAILS.PriceCode` | `biz_charge_detail.priceTemplateCode` | 账单明细价格模板编码 | + +### 5.2 当前转换策略 + +`PriceCode` 在旧模型里是整数型“用水性质”,在新模型里更接近字符串型模板编码。 + +因此本轮不建议简单字符串化后直接当正式编码使用,而应采用: + +- `legacyPriceCode` 保留旧值 +- `targetPriceTemplateCode` 记录新值 +- 明确映射来源 + +### 5.3 推荐映射结构 + +| 字段 | 说明 | +| --- | --- | +| `legacyPriceCode` | 旧用水性质编码 | +| `targetPriceTemplateCode` | 新价格模板编码 | +| `priceCategoryName` | 可选,用于人工核对 | +| `mappingSource` | 来源:价格模板表 / 规则推导 / 手工补录 | +| `mappingStatus` | `planned / verified / unresolved` | + +### 5.4 当前脚本建议 + +- 若已有价格模板主数据且存在旧编码字段,优先按主数据表映射。 +- 若无稳定映射来源,暂不把脚本写成“旧值转字符串”这种伪映射。 +- 所有无法确认的值必须落差异清单。 + +## 6. `PriceItemId` 转换字典 + +### 6.1 承接目标 + +| 旧字段 | 新字段 | 说明 | +| --- | --- | --- | +| `AT_CHARGE_DETAILS.PriceItemId` | `biz_charge_detail.costComponentCode` | 明细费用组成编码 | + +### 6.2 当前转换策略 + +`PriceItemId` 旧模型是费用组成主键,当前新模型更偏编码型字段 `costComponentCode`。 + +这类转换比 `PriceListId` 和 `PriceCode` 更敏感,因为它直接影响费用构成、统计汇总和开票明细。 + +### 6.3 推荐映射结构 + +| 字段 | 说明 | +| --- | --- | +| `legacyPriceItemId` | 旧费用组成 ID | +| `targetCostComponentCode` | 新费用组成编码 | +| `targetCostComponentName` | 新费用组成名称 | +| `mappingSource` | 来源:费用组成主数据 / 手工字典 | +| `mappingStatus` | `planned / verified / unresolved` | + +### 6.4 当前脚本建议 + +- 没有稳定费用组成字典前,不要直接迁移到正式 `costComponentCode`。 +- 可先写入映射表,待字典确认后再回填主表。 +- 对无法映射的费用项必须记录差异,不能静默丢弃。 + +## 7. 第一批次最小字典表建议 + +后续如果进入脚本实施,建议至少准备三张字典或等价数据集: + +| 字典名称 | 用途 | +| --- | --- | +| `legacy_price_list_mapping` | `PriceListId -> adjustmentSnapCode` | +| `legacy_price_code_mapping` | `PriceCode -> priceTemplateCode` | +| `legacy_price_item_mapping` | `PriceItemId -> costComponentCode` | + +每张字典至少包含: + +- `legacyCode` +- `targetCode` +- `targetName` +- `mappingSource` +- `mappingStatus` +- `remark` + +## 8. 当前 v1 的直接结论 + +### 8.1 可以先不阻塞试迁的项 + +- `PriceListId` +- `PriceCode` + +前提是: + +- 原值必须保留 +- 差异必须可追踪 +- 未确认映射不得伪造正式编码 + +### 8.2 不能随便糊过去的项 + +- `PriceItemId` + +因为它直接影响: + +- 费用组成 +- 开票明细 +- 金额汇总 +- 后续统计与审计 + +所以 `PriceItemId` 的字典确认优先级高于前两者。 + +## 9. 后续动作 + +本字典之后,建议继续补: + +1. 第一批次枚举值对照表 + 重点是 `PayState`、`FeeState`、`AccountState` + +2. 第一批次差异清单模板 + 专门记录编码映射缺口、无法确认项和人工补录项 diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-detailed-mapping-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-detailed-mapping-v1.md new file mode 100644 index 0000000..cd9fe73 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-batch1-detailed-mapping-v1.md @@ -0,0 +1,240 @@ +# Matrix: REV-004 第一批次真实迁移映射矩阵细化版 v1 + +## 1. 目标 + +本矩阵用于把第一批次迁移对象细化到“可以直接指导脚本设计”的程度。 + +第一批次范围限定为: + +- `AT_CHARGES` +- `AT_CHARGE_DETAILS` +- `CT_ACCOUNTS` + +本版重点不是覆盖旧表所有字段,而是先锁定: + +- 主键与核心业务标识 +- 核心业务字段 +- 关键状态字段 +- 必要关系字段 +- 映射落库要求 + +## 2. 第一批次总原则 + +- 账单主明细和账户对象属于在线主模型优先承接范围。 +- 旧主键和旧业务标识必须进入映射层,不允许只保留新主键。 +- 当前不能稳定落入主表的旧字段,先进入映射层或历史只读层,不强行污染主对象。 +- 第一批次试迁后必须能回答:原账单是谁、原账户是谁、新对象是谁、金额和状态是否一致。 + +## 3. 表级落位总览 + +| 旧表 | 目标主对象 | 目标映射对象 | 当前 backend 证据 | 当前结论 | +| --- | --- | --- | --- | --- | +| `AT_CHARGES` | `biz_charge` | `legacy_charge_mapping` | `ChargeDO.java` | 可直接作为第一批次主对象 | +| `AT_CHARGE_DETAILS` | `biz_charge_detail` | `legacy_charge_detail_mapping` | `ChargeDetailDO.java` | 可直接作为第一批次明细对象 | +| `CT_ACCOUNTS` | `biz_account` | `legacy_account_mapping` | `AccountDO.java` | 可直接作为第一批次账户对象 | + +## 4. `AT_CHARGES -> biz_charge` 细化映射 + +### 4.1 主键与标识 + +| 旧字段 | 新字段/位置 | 策略 | 备注 | +| --- | --- | --- | --- | +| `FeeId` | `biz_charge.id` | 直接承接或保留旧值映射 | 是否复用旧主键需由迁移脚本策略决定,但映射表必须保留 | +| `FeeId` | `legacy_charge_mapping.legacyId` | 必填 | 新旧账单主线标识 | +| 原账单号(如存在) | `legacy_charge_mapping.legacyBizNo` | 必填 | 若旧表无独立账单号,可用 `FeeId` 兼任 | +| 新账单号(如生成) | `legacy_charge_mapping.targetBizNo` | 选填 | 若新系统仅用主键,可暂为空 | + +### 4.2 核心业务字段 + +| 旧字段 | 新字段 | 策略 | 备注 | +| --- | --- | --- | --- | +| `RecordId` | `recordId` | 直接映射 | 抄表记录引用 | +| `BillMonth` | `billMonth` | 直接映射 | 核心账期字段 | +| `OrgId` | `deptId` | 转换映射 | 旧站点字段名与新部门字段名不同 | +| `BookId` | `bookId` | 直接映射 | 册本引用 | +| `BookSortIndex` | `bookSortIndex` | 直接映射 | 册内顺序 | +| `CustId` | `custId` | 直接映射 | 客户主键 | +| `CustCode` | `custCode` | 直接映射 | 客户编号 | +| `CustName` | `custName` | 直接映射 | 客户名称 | +| `CustAddress` | `custAddress` | 直接映射 | 客户地址 | +| `Populine` | `population` | 字段改名映射 | 旧字段拼写与新字段不同 | +| `PayMethod` | `payMethod` | 直接/枚举转换 | 需核对枚举值是否一致 | +| `LastReading` | `lastReading` | 类型转换映射 | 旧 `int` 到新 `BigDecimal` | +| `LastChildReading` | `lastChildReading` | 类型转换映射 | 同上 | +| `LastReadWater` | `lastReadWater` | 类型转换映射 | 同上 | +| `LastReadDate` | `lastReadDate` | 直接映射 | 时间字段 | +| `LastReadStateId` | `lastReadStateId` | 直接映射 | 状态引用 | +| `Reading` | `reading` | 类型转换映射 | 旧 `int` 到新 `BigDecimal` | +| `ChildReading` | `childReading` | 类型转换映射 | 同上 | +| `ReadWater` | `readWater` | 类型转换映射 | 同上 | +| `ReadDate` | `readDate` | 直接映射 | 时间字段 | +| `ReadStateId` | `readStateId` | 直接映射 | 状态引用 | +| `ReadTimes` | `readTimes` | 直接映射 | 抄次 | +| `MeterReaderId` | `meterReaderId` | 直接映射 | 抄表员 | +| `PriceListId` | `adjustmentSnapCode` 或扩展映射 | 暂按转换映射 | 旧调价号是 `int`,新对象用 `String adjustmentSnapCode` | +| `PriceCode` | `priceTemplateCode` | 转换映射 | 旧用水性质编码映射到新价格模板编码 | +| `TotalWater` | `totalWater` | 类型转换映射 | 旧 `int` 到新 `BigDecimal` | +| `ReplaceWater` | `replaceWater` | 类型转换映射 | 同上 | +| `BillWater` | `billWater` | 类型转换映射 | 同上 | +| `BillAmount` | `billAmount` | 直接映射 | 金额核心字段 | +| `ExtendedAmount` | `extendedAmount` | 直接映射 | 应收金额核心字段 | +| `LastChange` | `lastChange` | 直接映射 | 零头字段 | +| `Change` | `change` | 直接映射 | 零头字段 | +| `BillerId` | `billerId` | 直接映射 | 开账人 | +| `BillDate` | `billDate` | 直接映射 | 开账时间 | +| `LateFeeBeginDate` | `lateFeeBeginDate` | 直接映射 | 滞纳金起算日 | +| `LateFee` | `lateFee` | 直接映射 | 核心金额字段 | +| `CashierId` | `cashierId` | 直接映射 | 收费员 | +| `PayDate` | `payDate` | 直接映射 | 收费时间 | +| `CheckoutDate` | `checkoutDate` | 直接映射 | 结账时间 | +| `ChargeMethod` | `chargeMethod` | 直接/枚举转换 | 需核对枚举 | +| `ChargeWay` | `chargeWay` | 直接/枚举转换 | 需核对枚举 | + +### 4.3 状态与结果字段 + +| 旧字段 | 新字段/位置 | 策略 | 备注 | +| --- | --- | --- | --- | +| `PayState` | `biz_charge.payState` | 状态转换 | 必须按状态矩阵归并 | +| `FeeState` | `biz_charge.feeState` 或 `legacyState` | 状态转换 + 保留旧值 | 若新字段无法完整表达,保留旧值 | +| `InvoiceState` | `biz_charge.invoiceState` + 发票映射层 | 状态转换 | 需与发票主对象一致 | +| `InvoiceError` | `biz_charge.invoiceError` | 直接映射 | 开票失败原因 | +| `PrintState` | `biz_charge.printState` | 直接映射 | 打印状态 | +| `PrintTimes` | `biz_charge.printTimes` | 直接映射 | 打印次数 | +| `LockNum` | `biz_charge.lockNum` | 直接映射 | 锁定编号 | +| `LockoutEndTime` | `biz_charge.lockoutEndTime` | 直接映射 | 锁定时间 | + +### 4.4 关系和追溯字段 + +| 旧字段 | 新字段/位置 | 策略 | 备注 | +| --- | --- | --- | --- | +| `AdjustType` | `biz_charge.adjustType` + `tracePayload.adjustType` | 直接映射 + 追溯保留 | 当前新对象已有该字段 | +| `ContrastFeeId` | `biz_charge.contrastFeeId` + `legacy_charge_mapping.relatedFeeId` | 直接映射 + 映射保留 | 调整前后关系 | +| `ParentFeeId` | `legacy_charge_mapping.sourceFeeId` | 追溯保留 | 新 `ChargeDO` 未见同名字段,必须进映射层 | +| `InvoiceCode` | `biz_charge.invoiceCode` | 直接映射 | 发票代码 | +| `InvoiceDate` | `biz_charge.invoiceDate` | 直接映射 | 开票日期 | +| `InvoiceNumber` | `biz_charge.invoiceNumber` | 直接映射 | 发票号码 | +| `RefundWater` | `biz_charge.refundWater` + `tracePayload.refundWater` | 直接映射 + 追溯保留 | 当前新对象已有该字段 | + +### 4.5 第一批次对 `AT_CHARGES` 的直接建议 + +- `AT_CHARGES` 可直接作为第一批次最优先迁移主表。 +- 需要额外设计: + - `PriceListId -> adjustmentSnapCode` + - `PriceCode -> priceTemplateCode` + - `ParentFeeId` 的映射层保留 + - `PayState / FeeState / InvoiceState` 的状态归并规则 + +## 5. `AT_CHARGE_DETAILS -> biz_charge_detail` 细化映射 + +### 5.1 主键与关系 + +| 旧字段 | 新字段/位置 | 策略 | 备注 | +| --- | --- | --- | --- | +| 明细主键 `Id` | `biz_charge_detail.id` | 直接承接或映射保留 | 视脚本主键策略决定 | +| `FeeId` | `biz_charge_detail.feeId` | 直接映射 | 必须保持主明细关系 | +| 明细主键 | `legacy_charge_detail_mapping.legacyId` | 必填 | 保留旧明细主键 | + +### 5.2 核心业务字段 + +| 旧字段 | 新字段 | 策略 | 备注 | +| --- | --- | --- | --- | +| `PriceListId` | `adjustmentSnapCode` | 转换映射 | 与主账一致,需要调价号转换 | +| `PriceCode` | `priceTemplateCode` | 转换映射 | 与主账一致 | +| `PriceDetailId` | `costAdjustmentId` 或扩展字段 | `tbd` | 需进一步确认新字段语义是否等价 | +| `PriceItemId` | `costComponentCode` | 转换映射 | 旧费用组成 ID 到新费用组成编码 | +| `CalcMode` | `calcMode` | 直接映射 | 计费方式 | +| `LevelType` | `levelType` | 直接映射 | 阶梯模式 | +| `LevelIndex` | `levelIndex` | 直接映射 | 阶梯级别 | +| `StartMonth` | `startMonth` | 直接映射 | 开始月份 | +| `EndMonth` | `endMonth` | 直接映射 | 结束月份 | +| `StartWater` | `startWater` | 类型转换映射 | 旧 `int` 到新 `BigDecimal` | +| `EndWater` | `endWater` | 类型转换映射 | 同上 | +| `SettleMethod` | `settleMethod` | 直接映射 | 分摊方式 | +| `SettleValues` | `settleValues` | 类型转换映射 | 旧 `float` 到新 `BigDecimal` | +| `Price` | `price` | 直接映射 | 单价 | +| `Water` | `water` | 类型转换映射 | 应收水量 | +| `DiscountWater` | `discountWater` | 类型转换映射 | 优惠水量 | +| `WaterNum` | `waterNum` | 直接映射 | 水量系数 | +| `Money` | `money` | 直接映射 | 明细金额 | +| `State` | `state` | 状态转换 | 明细状态需核对枚举 | +| `IsPreferential` | `isPreferential` | 直接映射 | 是否优惠 | +| `BasicNumber` | `basicNumber` | 直接映射 | 基数 | +| `InvoicedState` | `invoicedState` | 状态转换 | 开票状态 | +| `DiscountMoney` | `discountMoney` | 直接映射 | 优惠金额 | +| `OriginalMoney` | `originalMoney` | 直接映射 | 优惠前金额 | +| `IsWaterOver` | `isWaterOver` | 直接映射 | 是否超计划 | +| `ItemInvoiceError` | `itemInvoiceError` | 直接映射 | 明细开票错误 | +| `ItemInvoiceState` | `itemInvoiceState` | 直接映射 | 明细开票状态 | +| `ItemInvoiceType` | `itemInvoiceType` | 直接映射 | 明细开票类型 | + +### 5.3 第一批次对 `AT_CHARGE_DETAILS` 的直接建议 + +- 明细对象整体与 `ChargeDetailDO` 对应度较高,可以直接进入第一批次。 +- 主要需要额外确认的点: + - `PriceDetailId -> costAdjustmentId` 是否语义等价 + - `PriceItemId -> costComponentCode` 的编码转换规则 + +## 6. `CT_ACCOUNTS -> biz_account` 细化映射 + +### 6.1 主键与关系 + +| 旧字段 | 新字段/位置 | 策略 | 备注 | +| --- | --- | --- | --- | +| `AccountId` | `biz_account.id` | 直接承接或映射保留 | 是否复用旧主键由脚本策略决定 | +| `AccountId` | `legacy_account_mapping.legacyId` | 必填 | 账户迁移主线 | +| 原账户编号 | `legacy_account_mapping.legacyBizNo` | 选填 | 若旧系统无独立业务账户号,可用主键兼任 | +| `CustId` | `biz_account.custId` | 直接映射 | 账户与客户关系核心字段 | + +### 6.2 核心业务字段 + +| 旧字段 | 新字段 | 策略 | 备注 | +| --- | --- | --- | --- | +| `Deposit` | `deposit` | 直接映射 | 预存余额 | +| `UnCheckMoney` | `uncheckMoney` | 直接映射 | 未到账金额 | +| `Overdraft` | `overdraft` | 直接映射 | 透支额度 | +| `AccountState` | `status` | 状态转换 | 旧账户状态需与新 `status` 枚举核对 | + +### 6.3 第一批次对 `CT_ACCOUNTS` 的直接建议 + +- `CT_ACCOUNTS` 与 `AccountDO` 的字段匹配度较高,可以直接进入第一批次。 +- 关键点不在字段缺失,而在于: + - `AccountState -> status` 的枚举值核对 + - 账户与客户主数据的一致性校验 + +## 7. 第一批次试迁时必须同步落库的映射对象 + +建议至少同时生成以下映射记录: + +| 映射对象 | 作用 | +| --- | --- | +| `legacy_charge_mapping` | 保留旧账单到新账单关系 | +| `legacy_charge_detail_mapping` | 保留旧账单明细到新明细关系 | +| `legacy_account_mapping` | 保留旧账户到新账户关系 | + +每条映射记录最少包括: + +- `legacyTable` +- `legacyId` +- `legacyBizNo` +- `targetDomain` +- `targetId` +- `targetBizNo` +- `migrationBatchNo` +- `mappingStatus` + +## 8. 第一批次最小脚本出口条件 + +在进入实际试迁脚本开发前,第一批次至少应满足: + +- `AT_CHARGES` 字段映射规则已稳定 +- `AT_CHARGE_DETAILS` 字段映射规则已稳定 +- `CT_ACCOUNTS` 字段映射规则已稳定 +- 三类主对象的状态映射规则已确认 +- 三类主对象的标识映射结构已确认 + +## 9. 当前仍待补的小项 + +本版之后,第一批次还建议继续补两项: + +1. `PriceListId / PriceCode / PriceItemId` 的编码转换字典 +2. `PayState / FeeState / AccountState` 的枚举值对照表 diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-field-mapping-matrix-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-field-mapping-matrix-v1.md new file mode 100644 index 0000000..4dd8329 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-field-mapping-matrix-v1.md @@ -0,0 +1,140 @@ +# Matrix: REV-004 旧字段到新字段映射矩阵 v1 + +## 1. 说明 + +本矩阵用于在“旧对象 -> 新对象”映射基础上,进一步明确关键字段如何承接、转换和保留。 + +本版只覆盖迁移中最关键的字段: + +- 主键与业务标识 +- 账期与客户标识 +- 金额 / 水量 / 滞纳金 +- 退款 / 冲正 / 坏账相关核心字段 +- 账户余额与流水字段 +- 发票状态与票据标识字段 +- 历史追溯必须保留的流程痕迹字段 + +## 2. 字段级承接策略说明 + +- `direct`:可直接映射到现有新字段 +- `transform`:需要转换、重算或状态归并 +- `mapping-only`:不进入在线主对象,仅写入映射层 +- `readonly-retain`:只在历史只读层保留 +- `tbd`:当前需要进一步核对 backend 真实字段或实现 + +## 3. 字段映射矩阵 + +| 旧表 | 旧字段 | 字段语义 | 新对象 | 新字段 / 承接位置 | 承接策略 | 说明 | +| --- | --- | --- | --- | --- | --- | --- | +| `AT_CHARGES` | `FeeId` | 账单主键 | `ChargeAggregate` | `biz_charge.id` + `legacy_charge_mapping.legacyId` | `direct` + `mapping-only` | 新旧账单主键必须双保留 | +| `AT_CHARGES` | `BillMonth` | 账务年月 | `ChargeAggregate` | `biz_charge.billMonth` | `direct` | 核心账期字段直接承接 | +| `AT_CHARGES` | `CustId` | 客户 ID | `ChargeAggregate` | `biz_charge.custId` | `direct` | 与客户主数据联动 | +| `AT_CHARGES` | `CustCode` | 客户编号 | `ChargeAggregate` | `biz_charge.custCode` | `direct` | 用于查询和迁移验收 | +| `AT_CHARGES` | `BillWater` | 开账水量 | `ChargeAggregate` | `biz_charge.billWater` | `direct` | 核心业务量字段 | +| `AT_CHARGES` | `BillAmount` | 开账金额 | `ChargeAggregate` | `biz_charge.billAmount` | `direct` | 与应收金额共同校验 | +| `AT_CHARGES` | `ExtendedAmount` | 应收金额 | `ChargeAggregate` | `biz_charge.extendedAmount` | `direct` | 迁移金额核对核心字段 | +| `AT_CHARGES` | `LateFee` | 滞纳金 | `ChargeAggregate` | `biz_charge.lateFee` | `direct` | 需与减免对象联动核查 | +| `AT_CHARGES` | `PayState` | 收费状态 | `ChargeAggregate` | `biz_charge.payState` + 状态映射表 | `transform` | 需与新收费状态语义核对 | +| `AT_CHARGES` | `InvoiceState` | 开票状态 | `ChargeAggregate` / `InvoiceRelation` | `biz_charge.invoiceState` + `legacy_invoice_mapping` | `transform` | 账单侧状态与发票主对象需联动校验 | +| `AT_CHARGES` | `ParentFeeId` | 调整原始 FeeId | `CompatibilityMappingRecord` | `legacy_charge_mapping.sourceFeeId` | `mapping-only` | 是迁移后追溯原账单的关键字段 | +| `AT_CHARGES` | `ContrastFeeId` | 对应费用编号 | `CompatibilityMappingRecord` | `legacy_charge_mapping.relatedFeeId` | `mapping-only` | 用于比对调整前后关系 | +| `AT_CHARGES` | `AdjustType` | 调整类型 | `AccountingEvidence` / 映射层 | `tracePayload.adjustType` | `transform` | 当前新模型统一挂场景,不建议原样主表承接 | +| `AT_CHARGES` | `RefundWater` | 退补水量 | `AccountingEvidence` | `tracePayload.refundWater` | `mapping-only` | 与退款/调整场景相关,保留追溯值 | +| `AT_CHARGE_DETAILS` | `FeeId` | 账单外键 | `ChargeAggregate` | `biz_charge_detail.chargeId` | `direct` | 必须保持主明细关系 | +| `AT_CHARGE_DETAILS` | `PriceItemId` | 费用组成 | `ChargeAggregate` | `biz_charge_detail.priceItemId` | `direct` | 核心费用项映射 | +| `AT_CHARGE_DETAILS` | `Water` | 应收水量 | `ChargeAggregate` | `biz_charge_detail.water` | `direct` | 明细层水量 | +| `AT_CHARGE_DETAILS` | `Money` | 明细金额 | `ChargeAggregate` | `biz_charge_detail.money` | `direct` | 明细层金额 | +| `AT_CHARGE_DETAILS` | `InvoicedState` | 明细开票状态 | `InvoiceRelation` / 映射层 | `legacy_invoice_mapping.detailInvoiceState` | `mapping-only` | 明细开票状态优先保留关系层 | +| `CT_ACCOUNTS` | `AccountId` | 账户主键 | `AccountBalance` | `biz_account.id` + `legacy_account_log_mapping.accountLegacyId` | `direct` + `mapping-only` | 账户主键双保留 | +| `CT_ACCOUNTS` | `CustId` | 客户 ID | `AccountBalance` | `biz_account.custId` | `direct` | 账户与客户绑定核心字段 | +| `CT_ACCOUNTS` | `Deposit` | 预存余额 | `AccountBalance` | `biz_account.deposit` | `direct` / `tbd` | 需最终确认 backend 账户表字段命名 | +| `CT_ACCOUNTS` | `UnCheckMoney` | 未到账金额 | `AccountBalance` | `biz_account.unCheckMoney` 或扩展字段 | `tbd` | 需确认新系统是否有对应字段 | +| `CT_ACCOUNTS` | `Overdraft` | 透支额度 | `AccountBalance` | `biz_account.overdraft` 或扩展字段 | `tbd` | 需核实现有表结构 | +| `CT_ACCOUNT_LOGS` | `AccLogId` | 账户流水主键 | `CompatibilityMappingRecord` | `legacy_account_log_mapping.legacyId` | `mapping-only` | 流水主键必须可追溯 | +| `CT_ACCOUNT_LOGS` | `PayDetailId` | 来源编号 | `CompatibilityMappingRecord` | `legacy_account_log_mapping.sourceDetailId` | `mapping-only` | 用于关联收费或退款来源 | +| `CT_ACCOUNT_LOGS` | `AccLogType` | 暂收类型 | `HistoricalReadonlyRecord` | `legacy_account_log_mapping.legacyType` | `readonly-retain` | 新模型当前未显式在线承接该分类 | +| `CT_ACCOUNT_LOGS` | `AccInOut` | 进出标志 | `HistoricalReadonlyRecord` | `legacy_account_log_mapping.inOutFlag` | `readonly-retain` | 作为账户流水查询语义保留 | +| `CT_ACCOUNT_LOGS` | `LastDeposit` | 上次余额 | `HistoricalReadonlyRecord` | `summarySnapshot.lastDeposit` | `readonly-retain` | 用于迁移验收对账 | +| `CT_ACCOUNT_LOGS` | `InOutMoney` | 收支金额 | `HistoricalReadonlyRecord` / `Transaction` | `summarySnapshot.inOutMoney` | `readonly-retain` / `tbd` | 需结合新交易对象最终判定 | +| `CT_ACCOUNT_LOGS` | `Deposit` | 本次余额 | `HistoricalReadonlyRecord` | `summarySnapshot.deposit` | `readonly-retain` | 用于余额核对 | +| `PM_ACCOUNT_RECORD_DETAILS` | `CustId` | 客户 ID | `AccountingEvidence` | `tracePayload.custId` | `mapping-only` | 退款详情应保留客户维度 | +| `PM_ACCOUNT_RECORD_DETAILS` | `RefundDeposit` | 退款金额 | `AccountingEvidence` / `Transaction` | `tracePayload.refundAmount` + 交易对象金额 | `transform` | 核心退款金额,需和新交易金额对齐 | +| `PM_ACCOUNT_RECORD_DETAILS` | `Deposit` | 原预存金额 | `AccountingEvidence` | `tracePayload.originalDeposit` | `mapping-only` | 用于退款前后余额审计 | +| `PM_ACCOUNT_RECORD_DETAILS` | `AccountLogId` | 被调整流水记录 | `CompatibilityMappingRecord` | `legacy_account_log_mapping.sourceAccountLogId` | `mapping-only` | 退款场景断链风险最高字段之一 | +| `PM_ACCOUNT_RECORD_DETAILS` | `TargetAccountLogId` | 目标流水记录 | `CompatibilityMappingRecord` | `legacy_account_log_mapping.targetAccountLogId` | `mapping-only` | 用于转退款 / 转销账链路追溯 | +| `PM_ACCOUNT_RECORD_DETAILS` | `ProcType` | 处理方式 | `AccountingResult` / 映射层 | `tracePayload.procType` | `transform` | 当前新模型只保留统一结果位,原处理方式需保留映射 | +| `PM_AMOUNT_RECORD_DETAILS` | `FeeId` | 原账单 ID | `CompatibilityMappingRecord` | `legacy_charge_mapping.sourceFeeId` | `mapping-only` | 调整前账单引用 | +| `PM_AMOUNT_RECORD_DETAILS` | `NewFeeId` | 新账单 ID | `CompatibilityMappingRecord` | `legacy_charge_mapping.targetFeeId` | `mapping-only` | 调整后账单引用 | +| `PM_AMOUNT_RECORD_DETAILS` | `ExtendedAmount` | 调整前账单金额 | `AccountingEvidence` | `tracePayload.beforeExtendedAmount` | `mapping-only` | 核心差异字段 | +| `PM_AMOUNT_RECORD_DETAILS` | `NewExtendedAmount` | 调整后账单金额 | `AccountingEvidence` | `tracePayload.afterExtendedAmount` | `mapping-only` | 核心差异字段 | +| `PM_AMOUNT_RECORD_DETAILS` | `BillWater` | 调整前开账水量 | `AccountingEvidence` | `tracePayload.beforeBillWater` | `mapping-only` | 水量调整场景核心字段 | +| `PM_AMOUNT_RECORD_DETAILS` | `NewBillWater` | 调整后开账水量 | `AccountingEvidence` | `tracePayload.afterBillWater` | `mapping-only` | 水量调整场景核心字段 | +| `PM_AMOUNT_RECORD_DETAILS` | `Reading` | 原底码 | `AccountingEvidence` | `tracePayload.beforeReading` | `mapping-only` | 旧抄表依据必须保留 | +| `PM_AMOUNT_RECORD_DETAILS` | `NewReading` | 新底码 | `AccountingEvidence` | `tracePayload.afterReading` | `mapping-only` | 调整后依据必须保留 | +| `PM_PAYMENT_RECORD_DETAILS` | `FeeId` | 原账单 ID | `CompatibilityMappingRecord` | `legacy_charge_mapping.sourceFeeId` | `mapping-only` | 已销调整/冲正场景核心引用 | +| `PM_PAYMENT_RECORD_DETAILS` | `NewFeeId` | 新账单 ID | `CompatibilityMappingRecord` | `legacy_charge_mapping.targetFeeId` | `mapping-only` | 如有重构账单必须保留 | +| `PM_PAYMENT_RECORD_DETAILS` | `ActualMoney` | 实收金额 | `Transaction` | `bk_transaction.amount` 或扩展金额字段 | `transform` | 需与原交易金额比对 | +| `PM_PAYMENT_RECORD_DETAILS` | `DeductionAmount` | 抵扣金额 | `AccountingEvidence` | `tracePayload.deductionAmount` | `mapping-only` | 当前新模型未见统一在线字段 | +| `PM_PAYMENT_RECORD_DETAILS` | `AccountLogId` | 被调整流水记录 | `CompatibilityMappingRecord` | `legacy_account_log_mapping.sourceAccountLogId` | `mapping-only` | 冲正场景关键追溯字段 | +| `PM_PAYMENT_RECORD_DETAILS` | `TargetAccountLogId` | 目标流水记录 | `CompatibilityMappingRecord` | `legacy_account_log_mapping.targetAccountLogId` | `mapping-only` | 冲正后目标记录追溯 | +| `PM_KNOTTY_RECORD_DETAILS` | `FeeId` | 账单 ID | `CompatibilityMappingRecord` | `legacy_charge_mapping.sourceFeeId` | `mapping-only` | 坏账与账单关系必须保留 | +| `PM_KNOTTY_RECORD_DETAILS` | `BillMonth` | 账务年月 | `AccountingEvidence` | `tracePayload.billMonth` | `mapping-only` | 用于坏账账龄与核对 | +| `PM_KNOTTY_RECORD_DETAILS` | `ExtendedAmount` | 账单应收金额 | `AccountingEvidence` | `tracePayload.extendedAmount` | `mapping-only` | 与坏账金额核对 | +| `PM_KNOTTY_RECORD_DETAILS` | `ProcType` | 处理方式 | `AccountingResult` / 映射层 | `tracePayload.procType` | `transform` | 坏账类型和结果需映射 | +| `IV_INVOICE_INFOS` | `Id` | 发票主键 | `InvoiceRecord` | `biz_invoice.id` + `legacy_invoice_mapping.legacyInvoiceId` | `direct` + `mapping-only` | 发票主键双保留 | +| `IV_INVOICE_INFOS` | `FeeId` | 费用 ID | `InvoiceRelation` | `legacy_invoice_mapping.sourceFeeId` | `mapping-only` | 账单与发票主关系核心字段 | +| `IV_INVOICE_INFOS` | `SerialNo` | 交易流水号 | `InvoiceRecord` / `Transaction` | `biz_invoice.sysRequestNo` 或关系映射 | `transform` | 需与当前发票协同请求号核对 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 发票状态 | `InvoiceRecord` | `biz_invoice.invoiceState` + 状态映射表 | `transform` | 必做旧状态到新状态映射 | +| `IV_INVOICE_INFOS` | `InvoiceCode` | 发票代码 | `InvoiceRecord` | `biz_invoice.invoiceCode` | `direct` | 核心票据标识 | +| `IV_INVOICE_INFOS` | `InvoiceNumber` | 发票号码 | `InvoiceRecord` | `biz_invoice.invoiceNumber` | `direct` | 核心票据标识 | +| `IV_INVOICE_INFOS` | `InvoiceDate` | 发票日期 | `InvoiceRecord` | `biz_invoice.invoiceDate` | `direct` | 核心票据时间 | +| `IV_INVOICE_INFOS` | `InvoicePath` | 电子票地址 | `InvoiceRecord` | `biz_invoice.fileUrl` 或等价字段 | `transform` | 需核对当前 DO/VO 字段名 | +| `IV_INVOICE_INFOS` | `CndnCode` | 原发票代码 | `InvoiceRecord` | `biz_invoice.originalInvoiceCode` 或扩展字段 | `tbd` | 当前新系统存在类似字段,但需最终核实命名 | +| `IV_INVOICE_INFOS` | `CndnNumber` | 原发票号码 | `InvoiceRecord` | `biz_invoice.originalInvoiceNumber` 或扩展字段 | `tbd` | 与红冲、作废场景强关联 | +| `IV_INVOICE_INFOS` | `LastTryTime` | 最后查询时间 | `InvoiceRecord` | `biz_invoice.lastTryTime` | `direct` | 当前 REV-005 已引入类似重试字段 | +| `IV_INVOICE_INFOS` | `NextTryTime` | 下一次查询时间 | `InvoiceRecord` | `biz_invoice.nextTryTime` | `direct` | 当前 REV-005 已引入类似重试字段 | +| `IV_INVOICE_INFOS` | `TryCount` | 查询次数 | `InvoiceRecord` | `biz_invoice.tryCount` | `direct` | 当前 REV-005 已引入类似字段 | + +## 4. 当前 v1 的直接落地建议 + +### 4.1 可直接进入字段级迁移设计的对象 + +- `AT_CHARGES` +- `AT_CHARGE_DETAILS` +- `IV_INVOICE_INFOS` + +这些对象的核心字段与当前新模型最接近,可以优先进入试迁字段设计。 + +### 4.2 必须补“映射层字段”的对象 + +- `CT_ACCOUNT_LOGS` +- `PM_ACCOUNT_RECORD_DETAILS` +- `PM_AMOUNT_RECORD_DETAILS` +- `PM_PAYMENT_RECORD_DETAILS` +- `PM_KNOTTY_RECORD_DETAILS` + +这些对象的关键价值不在于在线主字段一一映射,而在于: + +- 原账单引用 +- 原流水引用 +- 前后差异值 +- 处理方式 +- 原始处理痕迹 + +### 4.3 当前仍需进一步核实的字段 + +以下字段建议进入下一轮字段核实清单: + +- `CT_ACCOUNTS.Deposit / UnCheckMoney / Overdraft` 在当前 backend 的精确落点 +- `PM_PAY_DETAILS.ActualMoney` 到 `bk_transaction*` 的最终字段承接方式 +- `IV_INVOICE_INFOS.SerialNo` 与当前发票协同请求号 / 受理号的对应关系 +- `IV_INVOICE_INFOS.CndnCode / CndnNumber` 在当前新模型中的正式字段名 + +## 5. 后续动作 + +后续建议继续补两张矩阵: + +1. `旧状态 -> 新状态` 映射矩阵 +2. `新旧标识` 映射矩阵 + +字段级矩阵完成后,才适合正式设计迁移脚本的字段转换逻辑。 diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-gap-assessment-contract.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-gap-assessment-contract.md new file mode 100644 index 0000000..c417672 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-gap-assessment-contract.md @@ -0,0 +1,42 @@ +# Contract: REV-004 功能缺失判定矩阵 + +## 1. 目标 + +本合同用于统一判定旧账务对象相对当前 backend 的承接成熟度,避免将“旧表缺失”直接误判为“功能缺失”。 + +## 2. 判定字段 + +| Field | Required | Description | +| --- | --- | --- | +| `legacyObjectName` | Yes | 旧对象名称 | +| `legacyTable` | Yes | 旧表名 | +| `expectedCapability` | Yes | 旧对象期望承载的业务能力 | +| `currentVerdict` | Yes | `implemented` / `partial` / `readonly` / `missing` | +| `evidenceType` | Yes | `controller` / `service` / `do` / `mapping-doc` / `none` | +| `evidencePath` | Yes | 证据路径或文档路径 | +| `whyNotFullyImplemented` | No | 为什么不能判定为完全实现 | +| `recommendedHandling` | Yes | `reuse` / `extend` / `readonly-retain` / `implement-later` | +| `migrationImpact` | Yes | 对迁移的影响:低 / 中 / 高 | +| `notes` | No | 其他补充说明 | + +## 3. 判定规则 + +- `implemented`:当前 backend 已有稳定在线能力,且核心业务语义可被当前对象直接承接。 +- `partial`:已有部分能力、控制器、服务或数据对象,但无法完整表达旧模型全部语义。 +- `readonly`:不建议在线重建,只要求查询、比对和追溯能力。 +- `missing`:当前未看到稳定承接能力或映射出口,后续需补设计或开发。 + +## 4. 使用约束 + +- 不允许仅凭“未看到同名表”判定为 `missing`。 +- 必须优先核对统一场景入口、服务逻辑、日志承接和历史只读口径。 +- 对于旧审批流相关对象,若当前只保留审批能力位,可优先判为 `readonly` 或 `partial`,而不是默认 `missing`。 + +## 5. 示例 + +| legacyObjectName | currentVerdict | evidencePath | recommendedHandling | 说明 | +| --- | --- | --- | --- | --- | +| 营业账 | implemented | `ChargeDO.java` / `biz_charge` | reuse | 已有主对象承接 | +| 预存退款详情 | partial | `ChargeServiceImpl.adjustAccounting` + `bk_transaction*` | extend | 退款语义已有,旧细明台账未一对一落地 | +| 账单-呆坏账详情 | partial | `ChargeServiceImpl.adjustAccounting` | extend | 坏账申请语义已有,但旧细表未独立承接 | +| 特账明细 | missing | `BACKEND_TABLE_MAPPING.md` | implement-later or readonly-retain | 当前未见稳定承接 | diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-identifier-mapping-matrix-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-identifier-mapping-matrix-v1.md new file mode 100644 index 0000000..e5490bb --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-identifier-mapping-matrix-v1.md @@ -0,0 +1,104 @@ +# Matrix: REV-004 新旧标识映射矩阵 v1 + +## 1. 说明 + +本矩阵用于定义迁移后必须保留的新旧标识关系,确保以下能力不丢失: + +- 迁移验收对账 +- 历史明细追溯 +- 审计与问题定位 +- 旧单据到新业务对象的关系恢复 + +如果没有这张矩阵,即使数据迁过去,后续也很容易出现“查得到结果,但找不回原单据链”的问题。 + +## 2. 标识映射原则 + +- 每一类核心业务对象都必须保留“旧主键 + 旧业务单号 + 新主键 + 新业务单号”的最小映射能力。 +- 对于账单、流水、申请单、发票号等强业务标识,不允许只保留新值不保留旧值。 +- 若新系统不存在完全等价的新业务单号,至少保留新主键和映射批次号。 +- 新旧标识映射对象必须可按批次、对象类型和映射状态查询。 + +## 3. 映射矩阵 + +| 旧对象 | 旧主键 | 旧业务标识 | 新对象 | 新主键 | 新业务标识 | 映射承接层 | 最低保留要求 | 说明 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 营业账 | `FeeId` | 原账单号 / 历史账单编号 | `biz_charge` | `chargeId` | 新账单号或业务编号 | `mapping-layer` | `legacyId`、`targetId`、`legacyBizNo`、`targetBizNo` | 账单是迁移核查主线之一 | +| 营业账明细 | `Id` 或明细主键 | 无统一业务单号时可为空 | `biz_charge_detail` | `chargeDetailId` | 可选 | `mapping-layer` | `legacyId`、`targetId`、`sourceFeeId` | 明细至少能挂回主账单 | +| 账户 | `AccountId` | 原账户编号 | 账户承接对象 | `accountId` | 新账户编号 | `mapping-layer` | `legacyId`、`targetId`、`legacyBizNo`、`targetBizNo` | 预存余额迁移核查主线 | +| 账户流水 | `AccLogId` | 原流水号 / 原暂收流水号 | 账户流水承接对象或只读映射 | `accountLogId` 或映射主键 | 新流水号 | `mapping-layer` + `history-readonly` | `legacyId`、`legacyBizNo`、`targetId/targetBizNo` | 退款、冲正、转预存必须依赖该链路 | +| 收费汇总 | `CollectId` | 结账批次号 / 汇总编号 | 收费汇总承接对象 | `collectId` | 新汇总编号 | `mapping-layer` + `history-readonly` | `legacyId`、`targetId`、批次号 | 汇总核对主线 | +| 收费小计 | `SubtotalId` | 原小计编号 | 小计承接对象或只读映射 | `subtotalId` | 新小计编号 | `history-readonly` | `legacyId`、`targetId` | 一般不作为主业务单号,但需追溯 | +| 收费明细 | `DetailId` | `TradeCode` / `ThirdPartyNum` / 第三方流水号 | 交易对象 / 收费明细承接对象 | `transactionId` 或映射主键 | 新交易流水号 | `mapping-layer` | `legacyId`、`legacyBizNo`、`targetId`、`targetBizNo` | 收费、退款、冲正核查关键链路 | +| 退款账 | `RefundId` | 原退款单号 | 退款场景映射对象 | 映射主键 | 新调整单号 / 新退款单号 | `mapping-layer` | `legacyId`、`targetBizNo` | 若新系统无独立退款主键,至少保留新业务单号 | +| 预存退款汇总 | `Id` | 原申请单号 | 退款申请映射对象 | 映射主键 | 新调整单号 | `mapping-layer` + `history-readonly` | `legacyId`、`legacyBizNo`、`targetBizNo` | 旧申请单是历史审批追溯主线 | +| 预存退款详情 | `Id` | 原详情单号 | 退款明细映射对象 | 映射主键 | 新明细引用 | `mapping-layer` + `history-readonly` | `legacyId`、`sourceAccountLogId`、`targetAccountLogId` | 重点保留原流水到目标流水关系 | +| 调整减免汇总 | `Id` | 原调整申请单号 | 调整场景映射对象 | 映射主键 | 新调整单号 | `mapping-layer` + `history-readonly` | `legacyId`、`legacyBizNo`、`targetBizNo` | 金额/水量调整的历史入口 | +| 调整减免明细 | `Id` | 无统一业务单号 | 调整明细映射对象 | 映射主键 | 新账单引用 / 新明细引用 | `mapping-layer` | `legacyId`、`sourceFeeId`、`targetFeeId` | 前后账单链必须保留 | +| 价差调整汇总 | `Id` | 原价差调整申请单号 | 价差调整映射对象 | 映射主键 | 新调整单号 | `mapping-layer` + `history-readonly` | `legacyId`、`legacyBizNo`、`targetBizNo` | 若不单独在线化,也必须保留申请号映射 | +| 已销调整汇总 | `Id` | 原已销调整申请单号 | 冲正/调整映射对象 | 映射主键 | 新调整单号 | `mapping-layer` + `history-readonly` | `legacyId`、`legacyBizNo`、`targetBizNo` | 与收费结果链强关联 | +| 坏账汇总 | `Id` | 原坏账申请单号 | 坏账申请映射对象 | 映射主键 | 新调整单号 / 新申请单号 | `mapping-layer` + `history-readonly` | `legacyId`、`legacyBizNo`、`targetBizNo` | 坏账审批与生效查询主线 | +| 坏账明细 | `Id` | 无统一业务单号 | 坏账明细映射对象 | 映射主键 | 新账单引用 | `mapping-layer` | `legacyId`、`sourceFeeId` | 保证坏账记录能追到原账单 | +| 发票主表 | `Id` / `InvoiceInfoId` | `InvoiceCode + InvoiceNumber` / `OrderNo` / `SerialNo` | `biz_invoice` | `invoiceId` | 新申请单号 / 新受理号 / 新发票号 | `mapping-layer` | `legacyId`、`legacyBizNo`、`targetId`、`targetBizNo` | 发票查询、补打和对账主线 | +| 发票明细 | `Id` | 无统一业务单号 | 发票明细承接对象或只读映射 | `invoiceDetailId` | 可选 | `mapping-layer` + `history-readonly` | `legacyId`、`targetId`、`invoiceId` | 明细至少挂回发票主对象 | +| 营业账开票映射 | `Id` | 账单号 + 发票号组合 | 发票关系映射对象 | 映射主键 | 新账单号 + 新发票号组合 | `mapping-layer` | `sourceFeeId`、`targetChargeId`、`legacyInvoiceNo`、`targetInvoiceNo` | 发票关系迁移验收的核心对象 | + +## 4. 映射记录建议字段 + +建议统一的标识映射记录至少包含: + +| Field | Description | +| --- | --- | +| `mappingId` | 映射记录主键 | +| `legacySystem` | 原系统标识 | +| `legacyTable` | 旧表名 | +| `legacyId` | 旧主键 | +| `legacyBizNo` | 旧业务单号 / 流水号 / 发票号 | +| `targetDomain` | 新领域名称 | +| `targetId` | 新主键 | +| `targetBizNo` | 新业务单号 / 受理号 / 发票号 | +| `sourceLegacyId` | 源旧主键(用于前后关系对象) | +| `sourceTargetId` | 源新主键 | +| `mappingStatus` | `planned / migrated / verified / failed` | +| `migrationBatchNo` | 迁移批次号 | +| `verifiedAt` | 校验时间 | +| `remark` | 备注 | + +## 5. 当前 v1 的直接结论 + +### 5.1 必须优先落映射的主线标识 + +以下标识是迁移最容易断链、也最必须优先保留的: + +- `FeeId` +- `AccLogId` +- 收费流水号 / 第三方流水号 +- 旧调整申请单号 +- 旧坏账申请单号 +- 发票代码 + 发票号码 +- 发票申请单号 / 订单号 / 受理号 + +### 5.2 最容易被忽略但必须保留的关系标识 + +- `ParentFeeId` +- `ContrastFeeId` +- `AccountLogId` +- `TargetAccountLogId` +- 账单与发票映射关系中的组合标识 + +这些字段如果不在迁移时显式保留,后续几乎无法恢复“调整前后”“退款前后”“原交易与后续交易”“原账单与新账单”的链路。 + +### 5.3 对后续脚本设计的直接约束 + +迁移脚本设计时,不允许只写“插入新表”逻辑,还必须同步写: + +1. 标识映射入库逻辑 +2. 关系标识补链逻辑 +3. 批次号和映射状态回写逻辑 + +## 6. 后续动作 + +在对象、字段、状态、标识四张矩阵都具备后,下一步建议进入: + +1. 试迁校验清单 +2. 差异分类与复迁规则 +3. 批次化执行与回滚方案 diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-legacy-mapping-contract.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-legacy-mapping-contract.md new file mode 100644 index 0000000..952290f --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-legacy-mapping-contract.md @@ -0,0 +1,55 @@ +# Contract: REV-004 旧账务迁移映射矩阵 + +## 1. 目标 + +本合同用于统一旧账务对象到新系统承接对象的映射矩阵结构,供后续迁移实施、校验和差异定位复用。 + +## 2. 映射矩阵字段 + +| Field | Required | Description | +| --- | --- | --- | +| `legacyTable` | Yes | 旧表名 | +| `legacyObjectName` | Yes | 旧对象名称 | +| `legacyPrimaryKey` | Yes | 旧主键字段 | +| `legacyBusinessKey` | No | 旧业务单号 / 流水号 / 外部单号 | +| `legacyMeaning` | Yes | 业务语义说明 | +| `targetDomain` | Yes | 新承接领域 | +| `targetCarrier` | Yes | 新承接物理对象或只读对象 | +| `carrierLayer` | Yes | `online-main` / `mapping-layer` / `history-readonly` | +| `mappingType` | Yes | `one-to-one` / `many-to-one` / `one-to-many` / `readonly-only` | +| `statusMappingRequired` | Yes | 是否需要状态映射 | +| `identifierMappingRequired` | Yes | 是否需要新旧标识映射 | +| `historicalRetentionRequired` | Yes | 是否必须保留历史只读 | +| `evidenceSource` | Yes | backend / doc / archive 证据来源 | +| `migrationAction` | Yes | `migrate-online` / `retain-readonly` / `mapping-only` / `implement-later` | +| `riskNote` | No | 风险说明 | + +## 3. 填写规则 + +- 不允许只填写旧表名,不说明业务语义。 +- 每个旧对象必须明确进入哪个承接层。 +- 若 `carrierLayer = online-main`,必须明确在线主模型对象和主键映射规则。 +- 若 `carrierLayer = history-readonly`,必须明确最小查询维度和原始标识保留要求。 +- 若 `mappingAction = implement-later`,必须附功能缺失理由和后续建议。 + +## 4. 最小保留字段要求 + +对于需要迁移或只读保留的旧对象,最少保留以下类型字段: + +- 原单据标识 +- 原账单标识 +- 原流水标识 +- 处理类型 +- 处理原因 +- 处理前后金额或水量 +- 申请时间、审批时间、生效时间 +- 经办人 +- 附件或依据引用 + +## 5. 示例判定 + +| legacyObjectName | targetDomain | carrierLayer | migrationAction | 说明 | +| --- | --- | --- | --- | --- | +| 预存退款 | AccountingRequest / Transaction | online-main + history-readonly | migrate-online | 核心退款结果需在线承接,旧审批细节可只读保留 | +| 价差调整明细 | ChargeAggregate / OperationLog | online-main + mapping-layer | migrate-online | 调整结果进入账单主对象,旧明细字段保留映射 | +| 特账明细 | HistoricalReadonlyRecord | history-readonly | retain-readonly | 当前未见稳定在线承接能力 | diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-old-to-new-mapping-matrix-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-old-to-new-mapping-matrix-v1.md new file mode 100644 index 0000000..bcdfb26 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-old-to-new-mapping-matrix-v1.md @@ -0,0 +1,80 @@ +# Matrix: REV-004 旧表到新对象映射矩阵 v1 + +## 1. 说明 + +本矩阵用于回答三个问题: + +1. 旧表在新系统中由谁承接。 +2. 该承接属于在线主模型、兼容映射层还是历史只读层。 +3. 当前应判定为复用、扩展、只读保留还是后续补实现。 + +本矩阵是 v1,只覆盖 `REV-004` 迁移中最核心的账单、账户、收费、调整、退款、坏账、发票对象。 + +## 2. 承接层定义 + +- `online-main`:进入新系统在线主模型,后续继续参与业务处理。 +- `mapping-layer`:不直接承载在线业务,但保存新旧标识、状态和关系映射。 +- `history-readonly`:只提供查询、审计和迁移验收,不参与在线处理。 + +## 3. 映射矩阵 + +| 旧表名 | 旧对象名称 | 旧语义摘要 | 新承接领域 | 新承接对象 | 承接层 | 当前判定 | 建议动作 | 备注 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `AT_CHARGES` | 营业账 | 账单主对象,承接账期、应收、收费、开票、调整痕迹 | `ChargeAggregate` | `biz_charge` | `online-main` | `implemented` | `reuse` | 新系统账单主表核心承接对象 | +| `AT_CHARGE_DETAILS` | 营业账明细 | 账单费用组成、水量、金额、开票状态 | `ChargeAggregate` | `biz_charge_detail` | `online-main` | `implemented` | `reuse` | 明细层已存在稳定承接对象 | +| `CT_ACCOUNTS` | 账户信息 | 预存余额、未到账金额、透支额度 | `AccountBalance` | `biz_account` / 账户相关对象 | `online-main` | `partial` | `extend` | 需进一步确认与旧 `CT_ACCOUNTS` 字段对齐程度 | +| `CT_ACCOUNT_LOGS` | 账户流水 | 预存进出、余额变化、暂收流水 | `AccountTransaction` | `legacy_account_log_mapping` + 账户流水承接对象 | `mapping-layer` + `history-readonly` | `partial` | `extend` | 当前 `REV-004` 正式主口径未把账户流水建成核心在线对象 | +| `PM_PAY_COLLECTS` | 收费汇总 | 结账周期、收费总笔数、总金额、柜员/网点汇总 | `CollectionSummary` | `biz_collection` + 汇总查询结果 | `online-main` + `history-readonly` | `partial` | `extend` | 汇总语义可承接,旧统计台账宜只读保留 | +| `PM_PAY_SUBTOTALS` | 收费小计 | 按渠道、收费类型、收退标识的小计结果 | `CollectionSummary` | `biz_collection` + 汇总查询结果 | `history-readonly` | `readonly` | `retain-readonly` | 不建议为旧小计表单独在线重建 | +| `PM_PAY_DETAILS` | 收费明细 | 实收、实销、滞纳金、红冲关联、收费员 | `Transaction` / `CollectionDetail` | `bk_transaction*` + 收费结果关系 | `online-main` + `mapping-layer` | `partial` | `extend` | 需补旧收费明细到新交易对象的映射关系 | +| `AT_REFUNDS` | 退款账 | 退款金额、退款状态、退款时间、退款人 | `AccountingRequest` / `Transaction` | `IF-REV-007` 退款场景 + `bk_transaction*` | `online-main` + `mapping-layer` | `partial` | `extend` | 退款语义已有,旧退款账未见独立在线对象 | +| `PM_ACCOUNT_RECORDS` | 预存退款汇总 | 预存退款申请单、申请人、流程审批信息 | `AccountingRequest` | `legacy_finance_record_mapping` | `mapping-layer` + `history-readonly` | `partial` | `extend` | 在线保留申请语义,旧审批字段按只读保留 | +| `PM_ACCOUNT_RECORD_DETAILS` | 预存退款详情 | 客户、退款金额、原流水、目标流水、处理方式 | `AccountingEvidence` / `Transaction` | `legacy_finance_record_mapping` + `bk_transaction*` | `mapping-layer` + `history-readonly` | `partial` | `extend` | 需要重点保留原流水、目标流水和退款金额映射 | +| `PM_AMOUNT_RECORDS` | 调整减免汇总 | 水量/金额调整申请、原因、流程审批 | `AccountingRequest` | `IF-REV-007` 调整场景 + `legacy_finance_record_mapping` | `mapping-layer` + `history-readonly` | `partial` | `extend` | 新系统已有统一入口,但旧申请单结构未一对一承接 | +| `PM_AMOUNT_RECORD_DETAILS` | 调整减免明细 | 原账单、新账单、前后金额/水量、底码、累积量变化 | `AccountingEvidence` / `ChargeAggregate` | `biz_charge` / `biz_charge_detail` + 映射层 | `online-main` + `mapping-layer` | `partial` | `extend` | 关键是保留前后差异和新旧账单关联 | +| `PM_PRICE_RECORDS` | 价差调整汇总 | 调价差额修正申请、调价号、原因、审批 | `AccountingRequest` | `legacy_finance_record_mapping` | `mapping-layer` + `history-readonly` | `partial` | `extend` | 汇总申请宜按迁移映射保留 | +| `PM_PRICE_RECORD_DETAILS` | 价差调整明细 | 原账单、新账单、调价前后金额、滞纳金差额 | `ChargeAggregate` / `AccountingEvidence` | `biz_charge` / `biz_charge_detail` + 映射层 | `online-main` + `mapping-layer` | `partial` | `extend` | 语义已部分被账单重算能力承接 | +| `PM_PAYMENT_RECORDS` | 已销调整汇总 | 已收费后修正申请单、原因、流程 | `AccountingRequest` | `legacy_finance_record_mapping` | `mapping-layer` + `history-readonly` | `partial` | `extend` | 不建议按旧汇总表在线重建 | +| `PM_PAYMENT_RECORD_DETAILS` | 已销调整明细 | 原账单、新账单、实收金额、抵扣金额、退款人员 | `AccountingEvidence` / `Transaction` | `IF-REV-007` 冲正场景 + `bk_transaction*` + 映射层 | `online-main` + `mapping-layer` | `partial` | `extend` | 与冲正、退款、原交易校验强相关 | +| `PM_KNOTTY_RECORDS` | 呆坏账汇总 | 坏账申请单、申请原因、审批流程 | `AccountingRequest` | `IF-REV-007` 坏账场景 + `legacy_finance_record_mapping` | `mapping-layer` + `history-readonly` | `partial` | `extend` | 坏账申请语义已有,旧流程单需映射保留 | +| `PM_KNOTTY_RECORD_DETAILS` | 呆坏账明细 | 账单、账期、坏账金额、处理人、处理时间 | `AccountingEvidence` / `AccountingResult` | `biz_charge` + `biz_operat_log*` + 映射层 | `online-main` + `mapping-layer` | `partial` | `extend` | 需保留账龄、原因、结果和核销状态 | +| `PM_LATEFEE_RECORDS` | 违约金减免汇总 | 滞纳金减免申请、原因、审批 | `AccountingRequest` | `legacy_finance_record_mapping` | `mapping-layer` + `history-readonly` | `readonly` | `retain-readonly` | 当前一期不建议独立在线化 | +| `PM_LATEFEE_RECORD_DETAILS` | 违约金减免明细 | 原滞纳金、减免金额、调整后滞纳金 | `AccountingEvidence` | `legacy_finance_record_mapping` | `history-readonly` | `readonly` | `retain-readonly` | 保留明细追溯即可 | +| `IV_INVOICE_INFOS` | 发票信息表 | 发票状态、发票号、票据结果、查询重试、原票关联 | `InvoiceRecord` | `biz_invoice*` | `online-main` | `partial` | `reuse` + `extend` | 发票主对象已有,但旧字段需逐项核对 | +| `IV_INVOICE_DETAIL_INFOS` | 发票明细表 | 商品项、税率、税额、数量、单价 | `InvoiceRecord` | `biz_invoice*` + 历史明细映射 | `online-main` + `history-readonly` | `partial` | `extend` | 视当前 `biz_invoice` 明细承接能力决定在线化粒度 | +| `IV_CHARGE_INVOICE_MAPPINGS` | 营业账合并开票映射 | 账单与发票的多对多关系 | `InvoiceRelation` | `legacy_invoice_mapping` + 账单发票关系承接 | `mapping-layer` | `partial` | `extend` | 是迁移验收和历史补打的重要关系层 | + +## 4. 当前 v1 的直接判断 + +### 4.1 已有稳定在线承接基础的对象 + +- `AT_CHARGES` +- `AT_CHARGE_DETAILS` + +### 4.2 已有业务语义承接,但需要扩展映射与历史只读能力的对象 + +- `CT_ACCOUNTS` +- `CT_ACCOUNT_LOGS` +- `PM_PAY_*` +- `AT_REFUNDS` +- `PM_ACCOUNT_RECORD*` +- `PM_AMOUNT_RECORD*` +- `PM_PRICE_RECORD*` +- `PM_PAYMENT_RECORD*` +- `PM_KNOTTY_RECORD*` +- `IV_*` + +### 4.3 当前更适合历史只读保留的对象 + +- `PM_LATEFEE_RECORDS` +- `PM_LATEFEE_RECORD_DETAILS` + +## 5. 基于 v1 的后续动作 + +后续至少继续补三张矩阵: + +1. 旧字段到新字段映射矩阵 +2. 旧状态到新状态映射矩阵 +3. 新旧标识映射矩阵 + +在这三张矩阵完成前,不建议直接进入批量迁移脚本开发。 diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-status-mapping-matrix-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-status-mapping-matrix-v1.md new file mode 100644 index 0000000..e0f5ae9 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-status-mapping-matrix-v1.md @@ -0,0 +1,100 @@ +# Matrix: REV-004 旧状态到新状态映射矩阵 v1 + +## 1. 说明 + +本矩阵用于定义旧账务模型中的关键状态、处理方式和流程状态,如何映射到当前新系统对象中的状态表达。 + +本版重点覆盖: + +- 账单收费状态 +- 发票状态 +- 退款 / 冲正 / 坏账相关状态 +- 旧流程字段与新审批能力位的关系 + +## 2. 映射原则 + +- 不允许只保留旧状态值而不说明新状态语义。 +- 若新系统无法一一表达旧状态,必须采用“新状态 + 扩展追溯字段”组合承接。 +- 若旧状态只对历史查询有意义,不强制进入在线主状态机,但必须保留 `legacyState`。 +- 审批节点级状态本轮优先保留为历史只读,不在线复刻完整流转。 + +## 3. 状态映射矩阵 + +| 旧对象 | 旧字段 | 旧值/旧语义 | 新对象 | 新状态字段 | 新状态值/新语义 | 映射方式 | 备注 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| `AT_CHARGES` | `PayState` | 未收费 | `ChargeAggregate` | `payState` | 未收费 | `direct/transform` | 需与当前 backend 枚举最终对齐 | +| `AT_CHARGES` | `PayState` | 已收费 | `ChargeAggregate` | `payState` | 已收费 | `direct/transform` | 是退款/冲正前置条件 | +| `AT_CHARGES` | `PayState` | 坏账 | `ChargeAggregate` | `payState` | `UNCOLLECTIBLE` / 坏账 | `transform` | 当前 backend 已见 `PayStateEnum.UNCOLLECTIBLE(-2)` | +| `AT_CHARGES` | `FeeState` | 正常 / 作废 / 特定旧费用状态 | `ChargeAggregate` | `chargeState` 或 `legacyState` | 当前有效状态 / 历史状态 | `transform` + `readonly-retain` | 若新系统无完全等价字段,则保留 `legacyState` | +| `AT_CHARGES` | `InvoiceState` | 未开票 | `InvoiceRecord` / `ChargeAggregate` | `invoiceState` | 待开票 / 未开票 | `transform` | 账单侧与发票主对象需保持一致 | +| `AT_CHARGES` | `InvoiceState` | 开票中 / 查询中 | `InvoiceRecord` | `invoiceState` | `PENDING` / 处理中 | `transform` | 当前新模型发票结果采用异步申请 + 查询兜底 | +| `AT_CHARGES` | `InvoiceState` | 已开票 | `InvoiceRecord` | `invoiceState` | `SUCCESS` | `transform` | 同时回写账单开票状态 | +| `AT_CHARGES` | `InvoiceState` | 开票失败 | `InvoiceRecord` | `invoiceState` | `FAIL` | `transform` | 失败原因保留在扩展字段或返回消息中 | +| `AT_CHARGES` | `InvoiceState` | 红冲 / 作废相关旧状态 | `InvoiceRecord` | `invoiceState` | `INVALID` / `RED_INK` | `transform` | 与 REV-005 二期口径保持一致 | +| `AT_REFUNDS` | `RefundState` | 申请中 / 未处理 | `AccountingResult` | `resultStatus` | `PENDING_APPROVAL` 或 `PENDING` | `transform` | 需结合是否存在审批链字段判定 | +| `AT_REFUNDS` | `RefundState` | 已退款成功 | `AccountingResult` | `resultStatus` | `SUCCESS` | `transform` | 同时要求 `writeBackStatus=WRITTEN` 或等价值 | +| `AT_REFUNDS` | `RefundState` | 退款失败 | `AccountingResult` | `resultStatus` | `FAIL` | `transform` | 保留失败原因 | +| `AT_REFUNDS` | `RefundState` | 已作废 / 已取消 | `HistoricalReadonlyRecord` | `legacyState` | 原状态保留 | `readonly-retain` | 不强制进入在线状态机 | +| `PM_ACCOUNT_RECORDS` | `State` | 正常 / 流程中 | `AccountingResult` | `resultStatus` | `PENDING_APPROVAL` / `PENDING` | `transform` | 汇总申请单优先映射为“待处理”状态 | +| `PM_ACCOUNT_RECORDS` | `State` | 作废 | `HistoricalReadonlyRecord` | `legacyState` | 原状态保留 | `readonly-retain` | 历史流程单保留只读即可 | +| `PM_AMOUNT_RECORDS` | `State` | 正常 | `AccountingResult` | `resultStatus` | `SUCCESS` / `PENDING_APPROVAL` | `transform` | 需结合是否已生效区分 | +| `PM_AMOUNT_RECORDS` | `State` | 作废 | `HistoricalReadonlyRecord` | `legacyState` | 原状态保留 | `readonly-retain` | 不强制在线复刻 | +| `PM_PRICE_RECORDS` | `State` | 正常 | `AccountingResult` | `resultStatus` | `SUCCESS` / `PENDING_APPROVAL` | `transform` | 调价差额生效逻辑需通过生效时间补充判断 | +| `PM_PRICE_RECORDS` | `State` | 作废 | `HistoricalReadonlyRecord` | `legacyState` | 原状态保留 | `readonly-retain` | 历史记录保留 | +| `PM_PAYMENT_RECORDS` | `State` | 正常 | `AccountingResult` | `resultStatus` | `SUCCESS` | `transform` | 主要对应冲正/已销调整结果 | +| `PM_PAYMENT_RECORDS` | `State` | 作废 | `HistoricalReadonlyRecord` | `legacyState` | 原状态保留 | `readonly-retain` | 历史记录保留 | +| `PM_KNOTTY_RECORDS` | `State` | 申请中 / 未审批 | `AccountingResult` | `resultStatus` | `PENDING_APPROVAL` | `transform` | 坏账申请典型待审批状态 | +| `PM_KNOTTY_RECORDS` | `State` | 已生效 / 已确认坏账 | `AccountingResult` | `resultStatus` | `SUCCESS` | `transform` | 同时影响账单收费状态为坏账 | +| `PM_KNOTTY_RECORDS` | `State` | 作废 / 驳回 | `AccountingResult` / `HistoricalReadonlyRecord` | `resultStatus` 或 `legacyState` | `FAIL` 或原状态保留 | `transform` + `readonly-retain` | 若驳回语义明确,优先映射为 `FAIL` | +| `PM_LATEFEE_RECORDS` | `State` | 正常 / 作废 | `HistoricalReadonlyRecord` | `legacyState` | 原状态保留 | `readonly-retain` | 当前一期不强制在线化 | +| `PM_ACCOUNT_RECORD_DETAILS` | `ProcType` | 转预存 | `AccountingResult` / `tracePayload` | `writeBackStatus` + `procType` | 结果已回写 + `TRANSFER_TO_DEPOSIT` | `transform` + `mapping-only` | 当前新模型需通过扩展字段保留旧处理方式 | +| `PM_ACCOUNT_RECORD_DETAILS` | `ProcType` | 转退款 | `AccountingResult` / `tracePayload` | `resultStatus` + `procType` | `SUCCESS` + `REFUND` | `transform` + `mapping-only` | 退款主语义进入结果状态,旧处理方式保留映射 | +| `PM_ACCOUNT_RECORD_DETAILS` | `ProcType` | 转销账 | `AccountingResult` / `tracePayload` | `writeBackStatus` + `procType` | 结果回写 + `WRITE_OFF` | `transform` + `mapping-only` | 当前新模型未见等价主字段,保留追溯值 | +| `PM_ACCOUNT_RECORD_DETAILS` | `ProcType` | 线下退款 | `AccountingResult` / `tracePayload` | `resultStatus` + `procType` | `SUCCESS/FAIL` + `OFFLINE_REFUND` | `transform` + `mapping-only` | 线下路径必须与普通退款区分 | +| `PM_AMOUNT_RECORD_DETAILS` | `ProcType` | 账务处理方式 | `AccountingResult` / `tracePayload` | `resultStatus` + `procType` | 统一结果位 + 原处理方式 | `transform` + `mapping-only` | 不建议原样进入主状态机 | +| `PM_PAYMENT_RECORD_DETAILS` | `ProcType` | 已销调整处理方式 | `AccountingResult` / `tracePayload` | `resultStatus` + `procType` | `SUCCESS/FAIL` + 原处理方式 | `transform` + `mapping-only` | 与冲正、退款结果强相关 | +| `PM_KNOTTY_RECORD_DETAILS` | `ProcType` | 呆坏账处理方式 | `AccountingResult` / `tracePayload` | `resultStatus` + `procType` | `PENDING_APPROVAL/SUCCESS/FAIL` + 原处理方式 | `transform` + `mapping-only` | 需结合坏账申请场景 | +| `PM_*_RECORDS` | `TaskId` | 审批流程任务 ID | `HistoricalReadonlyRecord` | `legacyTaskId` | 原值保留 | `readonly-retain` | 当前不在线复刻旧流程 | +| `PM_*_RECORDS` | `StepId` | 流程节点 ID | `HistoricalReadonlyRecord` | `legacyStepId` | 原值保留 | `readonly-retain` | 当前不在线复刻旧流程 | +| `PM_*_RECORDS` | `FlowRemark` | 流程审批意见 | `HistoricalReadonlyRecord` | `legacyFlowRemark` | 原值保留 | `readonly-retain` | 作为迁移验收与审计依据 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 未申请 / 初始 | `InvoiceRecord` | `invoiceState` | `INIT` / `PENDING` | `transform` | 需与当前发票流程状态定义对齐 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 已受理 / 查询中 | `InvoiceRecord` | `invoiceState` | `PENDING` | `transform` | 对应当前异步申请中间态 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 开票成功 | `InvoiceRecord` | `invoiceState` | `SUCCESS` | `transform` | 核心票据结果 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 开票失败 | `InvoiceRecord` | `invoiceState` | `FAIL` | `transform` | 失败消息保留在返回消息字段 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 已作废 | `InvoiceRecord` | `invoiceState` | `INVALID` | `transform` | 对应当前作废场景 | +| `IV_INVOICE_INFOS` | `InvoiceState` | 已红冲 | `InvoiceRecord` | `invoiceState` | `RED_INK` | `transform` | 对应当前红冲场景 | + +## 4. 当前 v1 的关键判断 + +### 4.1 可较稳定归并到新状态机的状态 + +- 账单收费状态中的“未收费 / 已收费 / 坏账” +- 发票状态中的“处理中 / 成功 / 失败 / 作废 / 红冲” +- 坏账申请中的“待审批 / 已生效 / 驳回” +- 退款结果中的“待处理 / 成功 / 失败” + +### 4.2 更适合保留为 `legacyState` 或历史只读的状态 + +- 各类旧汇总表中的“作废”细分状态 +- 旧流程引擎相关 `TaskId / StepId / FlowRemark` +- 旧处理方式 `ProcType` 中难以直接等价为新主状态的值 + +### 4.3 迁移实现时必须补的辅助字段 + +若要保证状态迁移后可追溯,建议至少补以下扩展字段: + +- `legacyState` +- `legacyTaskId` +- `legacyStepId` +- `legacyFlowRemark` +- `procType` +- `writeBackStatus` + +## 5. 后续动作 + +下一步建议补: + +1. `新旧标识映射矩阵` +2. `试迁校验清单` + +只有状态矩阵和标识矩阵都具备后,迁移脚本的转换规则才能稳定落地。 diff --git a/specs/008-rev004-legacy-finance-migration/contracts/rev004-trial-migration-checklist-v1.md b/specs/008-rev004-legacy-finance-migration/contracts/rev004-trial-migration-checklist-v1.md new file mode 100644 index 0000000..a5ea300 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/contracts/rev004-trial-migration-checklist-v1.md @@ -0,0 +1,168 @@ +# Checklist: REV-004 试迁校验清单 v1 + +**Purpose**: 用于指导 `REV-004` 旧账务数据试迁后的最小验收校验,确保数量、金额、关系、状态和追溯链条在试迁阶段就能被发现问题。 +**Created**: 2026-03-23 +**Feature**: [spec.md](/Volumes/Dpan/github/water-workspace/water-docs/specs/008-rev004-legacy-finance-migration/spec.md) + +## 1. 使用方式 + +- 本清单面向“试迁批次”使用,不是最终割接验收清单。 +- 每完成一个迁移批次,都应至少完成一次数量校验、金额校验、关系校验和抽样校验。 +- 若某项校验失败,不应直接进入下一批次,而应先定位是: + - 映射矩阵问题 + - 字段转换问题 + - 状态归并问题 + - 标识断链问题 + +## 2. 批次 1:账户与营业账主明细 + +### 2.1 数量校验 + +- [ ] `AT_CHARGES` 迁移记录数与 `biz_charge` 承接数一致,或差异已登记并有解释 +- [ ] `AT_CHARGE_DETAILS` 迁移记录数与 `biz_charge_detail` 承接数一致,或差异已登记并有解释 +- [ ] `CT_ACCOUNTS` 迁移记录数与账户承接对象一致,或差异已登记并有解释 + +### 2.2 金额校验 + +- [ ] 旧 `AT_CHARGES.ExtendedAmount` 汇总与新账单主对象应收金额汇总一致 +- [ ] 旧 `AT_CHARGES.BillAmount` 汇总与新账单主对象开账金额汇总一致 +- [ ] 旧 `AT_CHARGES.LateFee` 汇总与新账单主对象滞纳金汇总一致 +- [ ] 旧 `CT_ACCOUNTS.Deposit` 汇总与新账户余额汇总一致,或差异已解释 + +### 2.3 关系校验 + +- [ ] 每条迁移后的账单主记录都能找到对应明细记录 +- [ ] 每条旧账单都能通过映射表找到新账单主键 +- [ ] 若存在 `ParentFeeId` / `ContrastFeeId`,迁移后仍能定位原账单与目标账单关系 + +### 2.4 抽样校验 + +- [ ] 随机抽 3 笔普通账单,核对客户号、账期、金额、状态一致 +- [ ] 随机抽 2 笔带调整关系的账单,核对原账单与新账单映射关系一致 +- [ ] 随机抽 2 个账户,核对余额和客户关系一致 + +## 3. 批次 2:收费结果与交易对象 + +### 3.1 数量校验 + +- [ ] `PM_PAY_COLLECTS`、`PM_PAY_SUBTOTALS`、`PM_PAY_DETAILS` 迁移或承接数量已核对 +- [ ] 旧收费明细与新交易对象 / 收费承接对象数量差异已解释 +- [ ] 实时收费日志如仅保留历史只读,其归档记录数已校对 + +### 3.2 金额校验 + +- [ ] 旧收费明细 `ActualMoney` 汇总与新交易金额汇总一致 +- [ ] 旧收费明细 `SoldMoney` 汇总与新核销金额汇总一致,或差异已解释 +- [ ] 旧收费汇总 `TotalMoney` 与新汇总结果一致 +- [ ] 第三方交易流水涉及的金额抽样与新交易对象一致 + +### 3.3 关系校验 + +- [ ] 每笔收费明细都能追到原账单或新账单映射 +- [ ] 每笔收费明细的重要流水号都能追到新交易对象 +- [ ] 若存在红冲引用,原收费记录与后续记录链条未断裂 + +### 3.4 抽样校验 + +- [ ] 随机抽 3 笔柜台收费,核对原流水号、金额、收费时间、收费员 +- [ ] 随机抽 2 笔第三方渠道收费,核对第三方流水号与新交易号映射 +- [ ] 随机抽 1 笔红冲关联收费,核对原单与后续记录关系 + +## 4. 批次 3:账务处理历史对象 + +### 4.1 数量校验 + +- [ ] `PM_ACCOUNT_RECORD*`、`PM_AMOUNT_RECORD*`、`PM_PRICE_RECORD*`、`PM_PAYMENT_RECORD*`、`PM_KNOTTY_RECORD*` 已按对象分类统计 +- [ ] 每类旧账务处理对象都已判定为在线承接、历史只读或映射保留之一 +- [ ] 当前未在线承接的对象,历史只读记录数已归档核对 + +### 4.2 金额校验 + +- [ ] 预存退款金额汇总与新退款承接结果或映射结果一致 +- [ ] 调整前后金额差额与新账单差异值一致,或差异已解释 +- [ ] 坏账金额汇总与新坏账场景承接结果一致,或差异已解释 +- [ ] 已销调整 / 价差调整的关键差额字段已核对 + +### 4.3 关系校验 + +- [ ] 每笔退款类记录都能追到原流水和目标流水 +- [ ] 每笔调整类记录都能追到原账单和目标账单 +- [ ] 每笔坏账记录都能追到原账单和处理结果 +- [ ] `TaskId`、`StepId`、`FlowRemark` 等审批痕迹已进入历史只读或追溯字段 + +### 4.4 抽样校验 + +- [ ] 随机抽 2 笔预存退款,核对申请、原流水、目标流水、退款金额 +- [ ] 随机抽 2 笔金额/水量调整,核对前后金额/水量和原账单、新账单关系 +- [ ] 随机抽 1 笔已销调整或冲正,核对原收费记录与后续处理关系 +- [ ] 随机抽 1 笔坏账申请,核对账单、金额、审批痕迹、结果状态 + +## 5. 批次 4:发票对象与账单关系 + +### 5.1 数量校验 + +- [ ] `IV_INVOICE_INFOS` 迁移数与新发票承接对象数量一致,或差异已解释 +- [ ] `IV_INVOICE_DETAIL_INFOS` 若进入在线承接或历史只读,记录数已校对 +- [ ] `IV_CHARGE_INVOICE_MAPPINGS` 关系数已校对 + +### 5.2 金额校验 + +- [ ] 发票总金额汇总与新发票对象金额汇总一致 +- [ ] 发票与账单映射的金额汇总一致 + +### 5.3 关系校验 + +- [ ] 每张旧发票都能找到新发票主键或新业务单号 +- [ ] 每张旧发票都能追到原账单或新账单关系 +- [ ] 原发票代码 / 原发票号码在红冲或作废场景下未断链 + +### 5.4 抽样校验 + +- [ ] 随机抽 2 张正常发票,核对发票号、账单号、状态、电子票地址 +- [ ] 随机抽 1 张作废或红冲相关发票,核对原票引用链是否完整 +- [ ] 随机抽 1 张多账单映射发票,核对账单关系是否一致 + +## 6. 通用状态与标识校验 + +### 6.1 状态校验 + +- [ ] 收费状态已按状态矩阵归并,未出现无法解释的孤立状态 +- [ ] 发票状态已按状态矩阵归并,未出现成功/失败/作废/红冲混乱 +- [ ] 退款 / 冲正 / 坏账相关状态已按结果状态和 `legacyState` 双层承接 + +### 6.2 标识校验 + +- [ ] `FeeId` ↔ 新账单主键映射可查 +- [ ] `AccLogId` ↔ 新流水映射可查 +- [ ] 旧申请单号 ↔ 新调整单号映射可查 +- [ ] 发票代码 / 号码 ↔ 新发票对象映射可查 + +## 7. 差异分类规则 + +若试迁中发现差异,优先按以下类型记录: + +- [ ] A 类:对象映射错误 +- [ ] B 类:字段转换错误 +- [ ] C 类:状态归并错误 +- [ ] D 类:标识断链 +- [ ] E 类:历史只读遗漏 +- [ ] F 类:真实功能缺失 + +## 8. 通过标准 + +一次试迁批次至少满足以下条件,才允许进入下一批次: + +- [ ] 数量差异已全部解释 +- [ ] 关键金额差异已全部解释 +- [ ] 主关系链未断裂 +- [ ] 抽样场景能完整追溯 +- [ ] 状态和标识映射无重大断链 +- [ ] 所有未解决问题已形成差异清单 + +## 9. 后续动作 + +本清单完成后,下一步应补: + +1. 差异清单模板 +2. 复迁规则 +3. 批次回滚方案 diff --git a/specs/008-rev004-legacy-finance-migration/data-model.md b/specs/008-rev004-legacy-finance-migration/data-model.md new file mode 100644 index 0000000..a323c83 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/data-model.md @@ -0,0 +1,145 @@ +# Data Model: REV-004 旧账务迁移映射与功能缺失分析 + +## 1. 模型目标 + +本模型用于定义旧账务迁移规划阶段的核心对象,重点覆盖: + +- 旧对象如何分类 +- 新系统如何承接 +- 映射记录如何表达 +- 功能缺失如何判定 +- 迁移批次如何组织 + +## 2. Core Entities + +### 2.1 LegacyFinanceObject + +表示旧系统中的一个业务财务对象。 + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `legacyTable` | string | Yes | 旧表名,如 `AT_CHARGES`、`PM_ACCOUNT_RECORDS` | +| `legacyObjectName` | string | Yes | 旧对象名称,如“营业账”“预存退款” | +| `domainCategory` | string | Yes | 领域分类:账单 / 账户 / 收费 / 调整 / 退款 / 坏账 / 发票 | +| `primaryIdentifier` | string | Yes | 旧对象主标识,如 `FeeId`、`AccLogId`、`InvoiceInfoId` | +| `businessMeaning` | string | Yes | 旧对象业务语义 | +| `containsWorkflowFields` | boolean | Yes | 是否携带审批或流程字段 | +| `containsHistoricalOnlyData` | boolean | Yes | 是否包含明显历史只读数据 | + +### 2.2 TargetDomainObject + +表示新系统中用于承接旧语义的目标对象。 + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `targetDomain` | string | Yes | 新领域名,如 `ChargeAggregate`、`Transaction`、`OperationLog` | +| `targetPhysicalCarrier` | string | Yes | 物理承接对象,如 `biz_charge`、`bk_transaction` | +| `carrierType` | string | Yes | `online-main` / `mapping-layer` / `history-readonly` | +| `supportsOnlineProcessing` | boolean | Yes | 是否参与在线业务处理 | +| `supportsHistoricalQuery` | boolean | Yes | 是否支持历史查询 | + +### 2.3 CompatibilityMappingRecord + +表示旧对象与新对象之间的映射关系。 + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `legacySystem` | string | Yes | 原系统标识 | +| `legacyTable` | string | Yes | 旧表名 | +| `legacyId` | string | Yes | 旧主键值 | +| `legacyBizNo` | string | No | 旧业务单号/流水号 | +| `targetDomain` | string | Yes | 目标领域 | +| `targetId` | string | No | 新主键值 | +| `targetBizNo` | string | No | 新业务单号 | +| `mappingType` | string | Yes | `one-to-one` / `many-to-one` / `one-to-many` / `readonly-only` | +| `mappingStatus` | string | Yes | `planned` / `migrated` / `verified` / `failed` | +| `migrationBatchNo` | string | Yes | 迁移批次号 | +| `tracePayload` | string | No | 扩展追溯信息 | + +### 2.4 HistoricalReadonlyRecord + +表示仅保留查询与审计用途的历史记录。 + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `legacyTable` | string | Yes | 原表名 | +| `legacyId` | string | Yes | 原主键 | +| `legacyStatus` | string | No | 原状态 | +| `originalIdentifiers` | string[] | Yes | 原单号、原账单号、原流水号等 | +| `summarySnapshot` | string | Yes | 历史摘要 | +| `queryDimensions` | string[] | Yes | 可查询维度,如客户号、账期、处理类型 | +| `readonlyReason` | string | Yes | 为什么只读保留 | + +### 2.5 GapVerdict + +表示旧对象相对于当前 backend 的承接状态判定。 + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `legacyObjectName` | string | Yes | 旧对象名称 | +| `verdict` | string | Yes | `implemented` / `partial` / `readonly` / `missing` | +| `evidenceType` | string | Yes | `controller` / `service` / `do` / `table-mapping` / `doc-only` | +| `evidencePath` | string | Yes | 证据路径 | +| `gapDescription` | string | No | 缺失说明 | +| `recommendedAction` | string | Yes | `reuse` / `extend` / `readonly-retain` / `implement-later` | + +### 2.6 MigrationBatch + +表示一个迁移批次。 + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `batchNo` | string | Yes | 批次编号 | +| `batchName` | string | Yes | 批次名称 | +| `scope` | string[] | Yes | 纳入对象列表 | +| `dependsOn` | string[] | No | 前置批次 | +| `validationFocus` | string[] | Yes | 校验重点 | +| `rollbackScope` | string[] | Yes | 回滚范围 | + +## 3. Relationships + +```text +LegacyFinanceObject + -> maps to -> TargetDomainObject + -> produces -> CompatibilityMappingRecord + -> may retain as -> HistoricalReadonlyRecord + -> is judged by -> GapVerdict + +MigrationBatch + -> groups -> LegacyFinanceObject + -> validates -> CompatibilityMappingRecord / GapVerdict +``` + +## 4. Validation Rules + +- 每个 `LegacyFinanceObject` 必须至少对应一种承接方式:在线主模型、兼容映射层或历史只读层之一。 +- 每个被判定为 `implemented` 或 `partial` 的 `GapVerdict` 必须绑定 backend 证据路径。 +- 每个 `HistoricalReadonlyRecord` 必须能返回原系统标识和最小查询维度。 +- 每个 `CompatibilityMappingRecord` 必须带 `migrationBatchNo` 和 `mappingStatus`。 +- 每个迁移批次必须先定义校验重点,再进入实际迁移脚本设计。 + +## 5. Recommended State Semantics + +### 5.1 Mapping Status + +```text +planned -> migrated -> verified +planned -> failed +migrated -> failed +``` + +### 5.2 Gap Verdict + +```text +implemented +partial +readonly +missing +``` + +语义说明: + +- `implemented`:当前 backend 已有稳定在线承接能力 +- `partial`:已有部分承接,但与旧模型仍有明显差距 +- `readonly`:不建议在线重建,仅保留历史查询与追溯 +- `missing`:当前确实未见稳定承接能力,后续需补设计或实现 diff --git a/specs/008-rev004-legacy-finance-migration/plan.md b/specs/008-rev004-legacy-finance-migration/plan.md new file mode 100644 index 0000000..f52db6d --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/plan.md @@ -0,0 +1,162 @@ +# Implementation Plan: REV-004 旧账务迁移映射与功能缺失分析 + +**Branch**: `008-rev004-legacy-finance-migration` | **Date**: 2026-03-23 | **Spec**: `/specs/008-rev004-legacy-finance-migration/spec.md` +**Input**: Feature specification from `/specs/008-rev004-legacy-finance-migration/spec.md` + +**Note**: This plan is document-first and brownfield-evidence aware. The current round focuses on migration planning artifacts rather than migration code execution. + +## Summary + +本轮围绕 `REV-004` 旧账务迁移规划形成一套可直接衔接后续实施的 planning 产物,核心目标有两项:一是明确旧账务对象如何形成迁移映射,按在线主模型、兼容映射层和历史只读层三层承接;二是明确当前 backend 相对旧模型存在的已承接能力、弱映射点和功能缺失,避免后续把“旧表未原样存在”误判为“必须整表重建”。 + +本次计划输出以现有正式文档和 backend 证据为准:继续保持 `REV-004` 账务处理一期的统一控制模型,不新增独立账本引擎,不直接写迁移脚本;后续迁移实施按“映射矩阵先行、批次设计其次、试迁与校验最后”的顺序组织。 + +## Repository Scope + +- **Formal workflow home**: `water-docs` +- **Target repos in scope**: + - `water-docs`: Yes + - `water-backend`: Yes + - `water-frontend`: No +- **Primary delivery mode**: Document closure / Code evidence alignment + +## Code Baseline + +- **Backend baseline**: `water-backend` `HEAD` @ `1c47b922ceca9256482b7f5d2a39040fd2ef99e2` +- **Frontend baseline**: `water-frontend` `HEAD` @ `ae65939045449894c0fccab53fee08521e538ddd` +- **Baseline capture plan**: 所有功能缺失或已承接判断都绑定到当前 backend baseline,并在 `research.md` 中记录代码路径、DO、Controller、Service 或测试证据。 + +## Technical Context + +**Primary Work Product**: 迁移规划工件,包括研究结论、迁移数据模型、映射合同、缺失分析合同和执行 quickstart。 +**Source of Truth Documents**: +- `specs/008-rev004-legacy-finance-migration/spec.md` +- `.specify/memory/constitution.md` +- `docs/design/02_Detailed_Design/12_REV_Detailed.md` +- `docs/design/03_Technical_Design/03_Interface_Design.md` +- `docs/design/03_Technical_Design/01_Database_Design.md` +- `docs/guides/BACKEND_TABLE_MAPPING.md` +**Reference Sources**: +- `docs/design/04_Appendix/Archive/05_Data_Dictionary/营收数据字典.md` +- `docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md` +- `docs/design/00_Management/07_Migration_Mapping_Template.md` +- `water-backend/sw-business/.../ChargeController.java` +- `water-backend/sw-business/.../ChargeServiceImpl.java` +- `water-backend/sw-business/.../ChargeServiceAccountingAdjustTest.java` +**Validation Commands**: +- `make validate-file FILE=specs/008-rev004-legacy-finance-migration/spec.md` +- `make validate-file FILE=specs/008-rev004-legacy-finance-migration/plan.md` +- `make validate-file FILE=specs/008-rev004-legacy-finance-migration/research.md` +- `make validate-file FILE=specs/008-rev004-legacy-finance-migration/data-model.md` +- `make validate-file FILE=specs/008-rev004-legacy-finance-migration/quickstart.md` +- `make check-links` +**Target Scope**: +- `REV-004` 旧账务迁移映射方法 +- `REV-004` 相关旧对象的功能缺失判定 +- 映射矩阵结构、迁移分批、最小校验动作 +- 历史只读与迁移验收查询边界 +**Project Type**: 文档治理仓库 + 多仓实现协作 +**Constraints**: +- 不新增平行正式主稿 +- 不发明超出主文档与 Archive 交集的新业务规则 +- 本轮不写迁移脚本、不改 backend 业务代码 +- 历史查询接口只读,不承担状态修正 +- 不把旧表未原样存在直接等同于功能缺失 +- 相对路径与现有 `IF-*` 编号体系保持稳定 +**Scale/Scope**: 跨文档 migration planning,覆盖 1 份 spec、1 份 plan、1 份 research、1 份 data-model、2 份 contracts 和 1 份 quickstart。 + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +- [x] **主文档归属已确认**:本轮 planning 产物落在 `specs/008-rev004-legacy-finance-migration/`,后续正式结论仍应回写 `12_REV_Detailed.md`、`03_Interface_Design.md`、`01_Database_Design.md`,不新增平行正式主稿。 +- [x] **多仓范围已确认**:本轮涉及 `water-docs` 规划工件与 `water-backend` 取证,不涉及 `water-frontend`。 +- [x] **代码基线已确认**:backend 和 frontend baseline 已记录,用于绑定当前实现判断和排除前端范围。 +- [x] **Archive 使用方式合规**:`营收数据字典.md` 仅作为旧模型来源和迁移核对依据,不直接替代正式口径。 +- [x] **一致性影响已列出**:已识别旧对象命名、新旧状态映射、账单/流水/发票关系、历史查询接口口径与功能缺失判定标准。 +- [x] **校验与台账动作已规划**:已明确 planning 产物最小校验命令;本轮仅生成规划工件,暂不强制更新 `01_Project_Progress.md` 与 `03_Task_Checklist.md`。 + +## Project Structure + +### Feature Artifacts + +```text +specs/008-rev004-legacy-finance-migration/ +├── spec.md +├── plan.md +├── research.md +├── data-model.md +├── quickstart.md +└── contracts/ + ├── rev004-legacy-mapping-contract.md + └── rev004-gap-assessment-contract.md +``` + +### Repository Touchpoints + +```text +water-docs/ +├── docs/design/ +├── docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md +├── docs/guides/BACKEND_TABLE_MAPPING.md +└── .specify/ + +water-backend/ +└── sw-business/sw-business-server/src/main/java/... +``` + +**Structure Decision**: +- `spec.md`:定义迁移映射规划与功能缺失分析的边界、验收和工件范围。 +- `plan.md`:组织本轮研究、设计、合同和 quickstart 结构。 +- `research.md`:沉淀迁移分层模型、映射形成方法、功能缺失判定标准和现状结论。 +- `data-model.md`:定义迁移映射对象、历史只读对象、缺失判定对象和批次对象。 +- `contracts/rev004-legacy-mapping-contract.md`:固化旧对象到新对象的映射矩阵结构与字段规则。 +- `contracts/rev004-gap-assessment-contract.md`:固化功能缺失判定的字段、取值和证据要求。 +- `quickstart.md`:给后续迁移实施前的工件准备、批次顺序和最小校验动作提供统一入口。 + +## Phase 0: Research & Alignment + +### Research Inputs + +- 如何从“旧表平移”转成“语义映射 + 三层承接”? +- 哪些旧对象可视为已被当前 backend 语义承接? +- 哪些旧对象属于弱映射或真正功能缺失? +- 迁移验收需要保留哪些最小查询字段和关系? +- 后续迁移实施前必须先补哪些映射矩阵? + +### Deliverables + +- `research.md` + +## Phase 1: Design & Contracts + +### Planned Artifacts + +- `data-model.md` +- `contracts/rev004-legacy-mapping-contract.md` +- `contracts/rev004-gap-assessment-contract.md` +- `quickstart.md` + +### Design Decisions + +- 采用“在线主模型 + 兼容映射层 + 历史只读层”三层迁移结构。 +- 映射单元以旧业务对象语义为主,不以旧表名平移为主。 +- 功能缺失按“已承接 / 部分承接 / 历史只读 / 功能缺失”四类判定。 +- 后续迁移实施优先补映射矩阵和批次设计,再进入脚本开发与试迁。 + +## Validation Plan + +- **Document validation**: `make validate-file FILE=specs/008-rev004-legacy-finance-migration/.md`、`make check-links` +- **Backend validation**: 本轮以代码路径与测试证据核对为主,N/A for compile +- **Frontend validation**: N/A +- **Evidence output**: `research.md`、`data-model.md`、`contracts/*`、`quickstart.md` + +## Ledger Sync Plan + +- **Project progress update required**: No +- **Task checklist update required**: No +- **Evidence or verification summary update required**: No + +## Complexity Tracking + +本计划未发生 Constitution 违规项,无需豁免说明。 diff --git a/specs/008-rev004-legacy-finance-migration/quickstart.md b/specs/008-rev004-legacy-finance-migration/quickstart.md new file mode 100644 index 0000000..bd9b682 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/quickstart.md @@ -0,0 +1,97 @@ +# Quickstart: REV-004 旧账务迁移规划评审与最小校验 + +## 1. 评审入口 + +本轮目标是: + +- 明确旧账务迁移映射如何形成 +- 明确当前 backend 相对旧模型的功能缺失、弱映射点和历史只读对象 +- 为后续迁移脚本设计、试迁和迁移验收提供统一规划入口 + +本轮验收重点检查: + +- 映射方法是否稳定 +- 功能缺失判定是否有证据 +- 后续迁移批次和矩阵工件是否可直接执行 + +## 2. 评审步骤 + +### 步骤一:映射方法校验 + +确认方案采用以下原则: + +- 以业务语义映射为主,而不是旧表逐表平移 +- 采用在线主模型、兼容映射层、历史只读层三层承接 +- 不把所有旧精细台账都当成必须重建的在线对象 + +### 步骤二:功能缺失判定校验 + +确认每个旧对象都按以下四类之一判定: + +- `implemented` +- `partial` +- `readonly` +- `missing` + +并确认每条判定都绑定 backend 或文档证据。 + +### 步骤三:最小保留集校验 + +确认迁移最少保留: + +- 原单据标识 +- 原账单标识 +- 原流水标识 +- 原发票标识 +- 处理前后金额/水量 +- 处理原因 +- 申请/审批/生效时间 +- 经办人与依据 + +### 步骤四:批次顺序校验 + +确认后续迁移按以下顺序推进: + +1. 账户与营业账主明细 +2. 收费结果与交易对象 +3. 账务处理历史对象 +4. 发票对象与账单关系 + +### 步骤五:接口边界校验 + +确认历史查询与迁移验收遵循以下边界: + +- 接口只读 +- 统一挂靠既有 `IF-REV-*` 接口族 +- 同时支持汇总对账和明细追溯 +- 返回新旧标识映射 + +## 3. 后续实施前必须补齐的工件 + +后续正式进入迁移脚本开发前,至少补齐: + +1. 旧表到新对象映射矩阵 +2. 旧字段到新字段映射矩阵 +3. 旧状态到新状态映射矩阵 +4. 新旧标识映射矩阵 + +## 4. 最小校验命令 + +```bash +make validate-file FILE=specs/008-rev004-legacy-finance-migration/spec.md +make validate-file FILE=specs/008-rev004-legacy-finance-migration/plan.md +make validate-file FILE=specs/008-rev004-legacy-finance-migration/research.md +make validate-file FILE=specs/008-rev004-legacy-finance-migration/data-model.md +make validate-file FILE=specs/008-rev004-legacy-finance-migration/quickstart.md +make check-links +``` + +## 5. 通过标准 + +满足以下条件即可进入下一阶段: + +- 映射方法和三层承接模型已明确 +- 功能缺失判定标准已明确 +- 后续必做矩阵工件已明确 +- 迁移分批顺序已明确 +- 历史查询和迁移验收边界已明确 diff --git a/specs/008-rev004-legacy-finance-migration/research.md b/specs/008-rev004-legacy-finance-migration/research.md new file mode 100644 index 0000000..f7d32ac --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/research.md @@ -0,0 +1,85 @@ +# Phase 0 Research: REV-004 旧账务迁移映射与功能缺失分析 + +## Decision 1: 迁移映射以“业务语义”而非“旧表平移”为主 + +- **Decision**: 迁移映射的基本单元定义为“旧业务对象语义”,如营业账、账户流水、预存退款、已销调整、价差调整、坏账、发票关系,而不是直接按旧表名原样对应一个新表。 +- **Rationale**: 旧模型以“汇总表 + 明细表 + 流程字段”承载很多业务,而新 `REV-004` 正式模型强调统一账务控制入口和共性规则;若按旧表名逐表平移,会破坏现有正式口径并导致在线模型过度回退。 +- **Alternatives considered**: + - 旧表逐表原样在线重建:被否决,因为与当前 `REV-004` 主口径“不新增独立账务台账表族”冲突。 + - 完全忽略旧表结构,只保留抽象结论:被否决,因为不满足迁移验收和历史追溯要求。 + +## Decision 2: 采用“三层承接模型”组织迁移 + +- **Decision**: 新系统迁移承接采用三层结构:在线主模型承接层、兼容映射层、历史只读层。 +- **Rationale**: `12_REV_Detailed.md` 已明确旧精细账务台账不要求全部转为独立在线实体,但必须形成可追溯闭环;`03_Interface_Design.md` 也要求历史查询接口只读且支持汇总对账与明细追溯。三层结构能同时满足在线处理、迁移核查和审计要求。 +- **Alternatives considered**: + - 所有旧数据统一进入在线主模型:被否决,因为会污染新模型并放大状态机复杂度。 + - 所有旧数据只做历史归档:被否决,因为当前有效账单、收费、发票和部分账务场景仍需在线承接。 + +## Decision 3: 在线主模型优先承接账单、交易、留痕和发票主对象 + +- **Decision**: 在线主模型优先由 `biz_charge`、`biz_charge_detail`、`bk_transaction*`、`biz_operat_log*`、`biz_invoice*`、`biz_cust_invoice` 等对象承接。 +- **Rationale**: `BACKEND_TABLE_MAPPING.md` 和当前 backend 代码已明确这些对象存在;`ChargeServiceImpl.adjustAccounting` 也证明退款、冲正、坏账申请等场景已开始围绕账单、原交易和操作日志形成统一处理骨架。 +- **Alternatives considered**: + - 为退款、坏账、价差、已销调整分别新增独立在线主实体:被否决,因为当前 backend 未形成稳定一一对应对象,且与正式文档边界不一致。 + +## Decision 4: 功能缺失判定必须区分四类状态 + +- **Decision**: 对旧对象相对当前 backend 的承接状态,统一使用四类判定:`已承接`、`部分承接`、`历史只读`、`功能缺失`。 +- **Rationale**: 当前仓库已出现大量“旧对象无同名表,但语义已被新对象承接”的情况;若只用“有表/没表”二元判断,会把语义承接误判为缺失。四类判定更适合迁移规划和后续开发排优先级。 +- **Alternatives considered**: + - 仅用“已实现 / 未实现”:被否决,因为无法表达历史只读与弱映射。 + - 仅用“有表 / 无表”:被否决,因为结构缺失不等于业务能力缺失。 + +## Decision 5: 当前 `REV-004` 核心账务控制能力已具备“部分承接”基础 + +- **Decision**: 当前 backend 对 `REV-004` 已具备部分承接基础,主要证据是: + - `ChargeController` 存在 `/business/charge/accounting-adjust` + - `ChargeServiceImpl.adjustAccounting` 已支持 `AMOUNT`、`WATER`、`REFUND`、`REVERSE`、`BAD_DEBT` 等调整类型 + - `ChargeServiceAccountingAdjustTest` 已覆盖退款、冲正、坏账申请等关键路径 + - `ChargeDO` / `ChargeDetailDO` / `OperatLogDO` / `OperatLogDetailDO` 已承接账单与留痕 +- **Rationale**: 这些证据说明新系统不是从零开始,而是已经具备统一账务处理入口、原交易校验和日志留痕能力。 +- **Alternatives considered**: + - 将 `REV-004` 判定为完全未实现:被否决,因为已有明确控制器、服务和测试证据。 + - 将 `REV-004` 判定为完全闭环:被否决,因为旧模型的大量精细对象并未一一在线承接。 + +## Decision 6: 当前明显缺失的是“精细账务对象的独立在线承接”和“迁移专用映射/只读能力” + +- **Decision**: 相对旧数据字典,当前 backend 明显缺失或未明确形成稳定在线承接的主要是: + - 退款账独立对象 + - 特账 / 特账明细 + - 跨周期水量 + - 阶梯累计量 + - 预存退款 / 已销调整 / 价差调整 / 滞纳金减免 / 呆坏账等旧汇总表和明细表的一对一在线对象 + - 专门面向迁移验收的新旧标识映射层 + - 历史只读查询的统一在线出口 +- **Rationale**: `BACKEND_TABLE_MAPPING.md` 已明确这些属于弱映射或当前缺口;`ChargeServiceImpl` 虽有统一账务调整入口,但并未等价于旧模型的每类精细台账对象都已在线落地。 +- **Alternatives considered**: + - 认为这些缺失都必须在线重建:被否决,因为部分对象应以历史只读和映射承接。 + +## Decision 7: 旧审批流字段优先保留为历史只读,不在线复刻 + +- **Decision**: 旧模型中的 `TaskId`、`StepId`、`FlowRemark` 等审批痕迹,本轮规划为优先按历史只读和追溯字段保留,不要求在线复刻完整审批引擎。 +- **Rationale**: 当前 `REV-004` 一期正式口径只保留审批能力位与边界说明;若迁移阶段强行复刻旧审批流,会显著扩大范围。 +- **Alternatives considered**: + - 在线完整复刻旧审批流:被否决,因为超出一期边界。 + - 完全丢弃审批痕迹:被否决,因为不满足迁移验收和审计要求。 + +## Decision 8: 后续迁移实施必须先补四类矩阵工件 + +- **Decision**: 正式进入脚本开发前,必须先补四类矩阵:旧表到新对象映射、旧字段到新字段映射、旧状态到新状态映射、新旧标识映射。 +- **Rationale**: 当前最大风险不是“脚本写不出来”,而是没有统一映射基线会导致每个批次各自理解旧模型,最终差异不可控。 +- **Alternatives considered**: + - 先写 SQL,再回头补映射:被否决,因为会放大返工和核对成本。 + +## Decision 9: 迁移实施按“基础主对象 -> 收费结果 -> 账务处理历史 -> 发票关系”分批 + +- **Decision**: 推荐四个迁移批次: + 1. 账户与营业账主明细 + 2. 收费结果与交易对象 + 3. 账务处理历史对象 + 4. 发票对象与账单关系 +- **Rationale**: 这种顺序能先锁定主键和核心关系,再逐步迁入衍生对象,降低断链风险。 +- **Alternatives considered**: + - 按模块菜单顺序迁移:被否决,因为会打乱主键和依赖关系。 + - 按表名前缀整体迁移:被否决,因为无法体现业务依赖。 diff --git a/specs/008-rev004-legacy-finance-migration/spec.md b/specs/008-rev004-legacy-finance-migration/spec.md new file mode 100644 index 0000000..4b26c31 --- /dev/null +++ b/specs/008-rev004-legacy-finance-migration/spec.md @@ -0,0 +1,170 @@ +# Feature Specification: REV-004 旧账务迁移映射与功能缺失分析 + +**Feature Branch**: `008-rev004-legacy-finance-migration` +**Created**: 2026-03-23 +**Status**: Draft +**Input**: User description: "帮我根据这份文档进行规划下 怎么形成迁移 映射 ?以及是否存在功能缺失" + +## Document Scope & Sources *(mandatory)* + +- **Target documents**: + - `docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md` + - `docs/design/02_Detailed_Design/12_REV_Detailed.md` + - `docs/design/03_Technical_Design/03_Interface_Design.md` + - `docs/design/03_Technical_Design/01_Database_Design.md` + - `specs/008-rev004-legacy-finance-migration/spec.md` + - `specs/008-rev004-legacy-finance-migration/plan.md` + - `specs/008-rev004-legacy-finance-migration/research.md` + - `specs/008-rev004-legacy-finance-migration/data-model.md` + - `specs/008-rev004-legacy-finance-migration/quickstart.md` + - `specs/008-rev004-legacy-finance-migration/contracts/` +- **Primary source of truth**: + - `docs/design/02_Detailed_Design/12_REV_Detailed.md` + - `docs/design/03_Technical_Design/03_Interface_Design.md` + - `docs/design/03_Technical_Design/01_Database_Design.md` + - `docs/guides/BACKEND_TABLE_MAPPING.md` + - `.specify/memory/constitution.md` +- **Reference sources**: + - `docs/design/04_Appendix/Archive/05_Data_Dictionary/营收数据字典.md` + - `docs/guides/REV004_LEGACY_FINANCE_MIGRATION_PLAN_V0.md` + - `docs/design/00_Management/07_Migration_Mapping_Template.md` + - `docs/design/04_Appendix/Archive/03_Design_Docs/营业收费管理系统-概要设计说明书20250912.md` +- **Scope decision**: In scope。本轮聚焦 `REV-004` 旧账务模型迁移规划,明确迁移映射如何形成、哪些旧对象进入在线主模型、哪些仅保留历史只读、以及当前 backend 相对旧模型存在的功能缺失;本轮不直接执行数据迁移脚本,不进入 backend 代码改造。 + +## Repository Scope *(mandatory)* + +- **Target repos**: + - `water-docs`: Required + - `water-backend`: Required + - `water-frontend`: Not Required +- **Expected delivery type**: Document closure / Code evidence alignment +- **Out of scope for this round**: + - 直接开发迁移程序、ETL 脚本或数据库批处理脚本 + - 在本轮为旧账务台账逐表重建新的在线实体表族 + - 重建完整会计总账、明细账或借贷分录引擎 + - 前端迁移、前端兼容页面和前端查询适配 + +## Code Baseline *(mandatory for brownfield work)* + +- **Backend baseline**: `water-backend` `HEAD` @ `1c47b922ceca9256482b7f5d2a39040fd2ef99e2` +- **Frontend baseline**: `water-frontend` `HEAD` @ `ae65939045449894c0fccab53fee08521e538ddd`(仅用于范围排除) +- **Baseline capture rule**: 所有“已实现 / 部分实现 / 文档先行 / 历史只读”判断都必须绑定当前 backend baseline,并在研究结论中写明对应代码路径、DO/Controller/Service 或表映射证据。 + +## Evidence Scope *(mandatory)* + +- **Document evidence required**: + - `specs/008-rev004-legacy-finance-migration/spec.md` + - `specs/008-rev004-legacy-finance-migration/plan.md` + - `specs/008-rev004-legacy-finance-migration/research.md` + - `specs/008-rev004-legacy-finance-migration/data-model.md` + - `specs/008-rev004-legacy-finance-migration/contracts/rev004-legacy-mapping-contract.md` + - `specs/008-rev004-legacy-finance-migration/contracts/rev004-gap-assessment-contract.md` + - `specs/008-rev004-legacy-finance-migration/quickstart.md` +- **Backend evidence required**: + - `ChargeController.java` + - `ChargeServiceImpl.java` + - `ChargeServiceAccountingAdjustTest.java` + - `ChargeDO.java` + - `ChargeDetailDO.java` + - `OperatLogDO.java` + - `OperatLogDetailDO.java` + - `PriceCostAdjustmentDO.java` + - `PriceTierAdjustmentDO.java` + - `bk_transaction*` 相关实现与文档映射 +- **Frontend evidence required**: + - N/A +- **Verification artifacts required**: + - `research.md` + - `data-model.md` + - `contracts/*` + - `quickstart.md` + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - 形成旧到新的迁移映射方法 (Priority: P1) + +作为迁移方案设计人员,我需要先把旧账务模型中的账单、账户、收费、调整、退款、坏账和发票对象映射到新系统的承接层、映射层和历史只读层,这样后续迁移时不会陷入“旧表逐表平移”或“语义丢失”的两种极端。 + +**Why this priority**: 如果迁移映射方法不先锁定,后续迁移脚本、校验方案和实现拆解都会失去统一基线。 + +**Independent Test**: 审阅者仅通过 `research.md`、`data-model.md` 与迁移映射合同,即可判断每类旧账务对象的承接方式、映射规则和保留层次。 + +**Acceptance Scenarios**: + +1. **Given** 旧系统账务对象存在大量“汇总表 + 明细表 + 流程字段”组合, **When** 本轮规划完成, **Then** 审阅者能够明确哪些对象进入在线主模型、哪些仅作为历史只读、哪些只保留映射关系。 +2. **Given** 新系统 `REV-004` 当前采用统一账务控制模型, **When** 评审迁移方案, **Then** 不会再要求按旧表名原样重建全部在线表族。 + +--- + +### User Story 2 - 判定功能缺失与实现成熟度 (Priority: P2) + +作为技术评审人员,我需要看到旧账务模型相对于当前 backend 的功能缺失、弱映射点和已存在承接能力,这样后续才能区分“需要开发”“仅需迁移”“只需历史查询保留”三类工作。 + +**Why this priority**: 如果不区分功能缺失与仅缺表名映射,容易把迁移工程误做成无边界的功能重构。 + +**Independent Test**: 审阅者仅通过 `research.md` 和功能缺失合同,即可判断哪些 `REV-004` 相关能力已经存在、哪些属于部分实现、哪些仍然缺失。 + +**Acceptance Scenarios**: + +1. **Given** backend 已存在 `/business/charge/accounting-adjust` 与相关测试, **When** 审阅本轮结论, **Then** 能明确退款、冲正、坏账申请等核心场景已具备一定承接能力,但并未完整覆盖旧模型所有精细台账对象。 +2. **Given** 数据字典中存在退款账、特账、跨周期水量、坏账明细等旧对象, **When** 审阅缺失分析, **Then** 能明确哪些只是独立表缺失、哪些属于在线能力缺失、哪些应保留为历史只读。 + +--- + +### User Story 3 - 为后续迁移实施提供执行入口 (Priority: P3) + +作为后续实施负责人,我需要一套可以直接衔接迁移脚本开发和验收的规划工件,包括分批策略、映射矩阵、最小校验动作和差异定位入口,这样后续不会重复讨论方案框架。 + +**Why this priority**: 没有执行入口,本轮规划只能停留在概念层,无法顺利进入试迁、校验和差异修正阶段。 + +**Independent Test**: 审阅者仅通过 `plan.md` 与 `quickstart.md`,即可明确后续迁移实施的批次顺序、必做矩阵和最小校验动作。 + +**Acceptance Scenarios**: + +1. **Given** 后续需要开发迁移脚本或数据校验脚本, **When** 阅读本轮计划, **Then** 能直接知道应先产出哪些映射矩阵、按什么批次迁移、如何做最小校验。 +2. **Given** 当前阶段仍以规划为主, **When** 审阅本轮结果, **Then** 能明确本轮尚未进入实际数据迁移执行,也不会把迁移脚本视为已完成产物。 + +--- + +### Edge Cases + +- 当旧对象在数据字典中存在,但 backend 未看到同名独立表时,必须区分“语义已承接”“弱映射承接”和“功能缺失”,不得直接判定为必须原样重建。 +- 当旧对象同时携带业务结果、审批流程和页面冗余字段时,必须拆分在线承接字段、历史只读字段和追溯映射字段,避免单表平移污染新模型。 +- 当退款、冲正等场景与原交易、发票或收费结果强关联时,必须保留原交易标识与新标识映射关系,避免迁移后审计断链。 +- 当历史查询需要支持迁移验收时,不得把历史只读接口设计成状态变更接口。 + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: Specification MUST identify the exact migration-planning artifacts to be produced under `specs/008-rev004-legacy-finance-migration/`. +- **FR-002**: Specification MUST identify `12_REV_Detailed.md`、`03_Interface_Design.md`、`01_Database_Design.md`、`BACKEND_TABLE_MAPPING.md` as the main source-of-truth inputs for migration planning. +- **FR-003**: Specification MUST define the migration scope by old object categories rather than by flat table copy lists only. +- **FR-004**: Specification MUST record backend code baseline and use it to judge whether a capability is implemented, partially implemented, or document-first. +- **FR-005**: Specification MUST preserve the single-source-of-truth model and MUST NOT assume creation of new parallel formal main documents. +- **FR-006**: Specification MUST define a three-layer migration model: online main model, compatibility mapping layer, and historical readonly layer. +- **FR-007**: Specification MUST define at least one mapping contract for old object to new object, field/state mapping, and identifier traceability. +- **FR-008**: Specification MUST define how functionality gaps are judged, including distinctions between missing table, weak mapping, and missing business capability. +- **FR-009**: Specification MUST define the minimum retention set for legacy migration, including original identifiers, original bill/transaction references, before/after values, operator, timestamps, and approval traces where applicable. +- **FR-010**: Specification MUST define the migration batch order and minimum validation actions before implementation. +- **FR-011**: Specification MUST require readonly historical query capability for migration acceptance and traceability. +- **FR-012**: Specification MUST list the applicable validation commands for the planning artifacts. + +### Key Entities *(include if feature involves data)* + +- **Legacy Finance Object**: 数据字典中的旧账务对象,如营业账、预存退款、已销调整、坏账、发票关系等。 +- **Online Main Model**: 新系统中继续承接在线业务处理的标准对象。 +- **Compatibility Mapping Record**: 用于保存旧标识、新标识、状态映射、来源类型和迁移批次的映射记录。 +- **Historical Readonly Record**: 仅保留查询与审计能力、不再作为在线处理主对象的历史记录。 +- **Gap Verdict**: 对旧对象在当前 backend 中的承接状态判定,如已承接、部分承接、历史只读、功能缺失。 +- **Migration Batch**: 数据迁移执行的分批单元,用于控制顺序、校验和回滚。 + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: 审阅者可依据本轮工件明确至少 8 类旧账务对象的承接方式和迁移层次。 +- **SC-002**: 审阅者可依据本轮工件明确至少 5 类 `REV-004` 相关旧对象是否存在已实现、部分实现或功能缺失。 +- **SC-003**: 审阅者可依据本轮工件直接列出至少 4 份后续迁移实施前必须补齐的映射矩阵或校验工件。 +- **SC-004**: 本轮工件不把“旧表未原样落地”等同于“功能完全缺失”,能够区分语义承接与结构缺失。 +- **SC-005**: 本轮工件可直接作为后续迁移脚本设计、试迁和迁移验收的规划输入。