From 0efcd6a6e5b176dae7c9fd5019ba39804e54354d Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Tue, 13 Oct 2026 14:43:07 +0800 Subject: [PATCH] docs: add protocol payment last-period autofill design Document confirmed rules for fq last-period due amount auto-fill and dj lump-sum deadline to due date sync in SamplePaymentPanel. Co-authored-by: Cursor --- ...col-payment-last-period-autofill-design.md | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/superpowers/specs/2026-10-13-protocol-payment-last-period-autofill-design.md diff --git a/docs/superpowers/specs/2026-10-13-protocol-payment-last-period-autofill-design.md b/docs/superpowers/specs/2026-10-13-protocol-payment-last-period-autofill-design.md new file mode 100644 index 00000000..c53ab9f0 --- /dev/null +++ b/docs/superpowers/specs/2026-10-13-protocol-payment-last-period-autofill-design.md @@ -0,0 +1,93 @@ +# 采集协议单 · 分期尾期金额与趸交应缴日自动填入 + +**日期:** 2026-10-13 +**范围:** `web-admin` 采集协议单新增/编辑弹窗(`SamplePaymentPanel`,payment_model_version ≥ 2) +**状态:** 已确认设计,待写实现计划 + +## 1. 背景与目标 + +采集协议单按样本配置缴费时: + +1. **分期(`fq`)**:用户手填各期应缴费金额;希望前几期填完后,**最后一期自动 = 合同金额 − 前 N−1 期之和**,减少合计对不齐。 +2. **趸交(`dj`)**:填写「趸交截止时间」后,**最后一期(通常第 1 期)应缴费时间**自动填入该截止时间。 + +## 2. 已确认决策 + +| 项 | 决策 | +|----|------| +| 分期尾期交互 | 方案 B:自动重算;尾期仍可手改;手改后不再自动覆盖,直到前几期再变 | +| 分改趸截止时间 | **不做**:不新增「趸交截止时间」字段,不做截止日 → 应缴日联动 | +| 实现路径 | 方案 1:`SamplePaymentPanel` 联动 + `protocol-sample-payment.ts` 纯函数 + 单测 | +| v1 整单缴费 | **不改** | +| 后端 API | **不改** | + +## 3. 行为规则 + +### 3.1 分期 · 最后一期应缴费金额 + +- **适用:** `payMode === 'fq'`,且存在 ≥ 2 个未作废应缴批次。 +- **公式:** + `lastDue = round((contractAmount − Σ priorDueAmounts) * 100) / 100` + 用「分」为单位累加前 N−1 期,尾差落在最后一期。 +- **触发:** 用户修改**前 N−1 期**任一 `dueAmount` 时,若允许自动填入,则写入最后一期并同步 `installmentRatios`。 +- **用户覆盖:** + - 用户直接修改最后一期 `dueAmount` → 标记该样本「尾期用户覆盖」; + - 覆盖期间不自动改写尾期; + - 前几期任一金额再次变化 → **清除覆盖标记**并按公式重算写入。 +- **不自动写入的情况:** + - 最后一期已锁定(存在 `payStatus === 'yjf'` 的转账); + - 合同金额为空 / 非有限数; + - 前 N−1 期金额均未有效填写(无法形成有意义的补尾); + - 当前为分改趸 `fgd`(本需求不要求对 `fgd` 做尾期自动补齐;若实现时复用同一路径,须在计划中显式写明「仅 `fq`」)。 +- **负数:** 公式结果 < 0 时写入 `0`;保存时仍由现有「各期合计 = 合同」校验拦截。 + +### 3.2 趸交 · 趸交截止时间 → 应缴费时间 + +- **适用:** `payMode === 'dj'`。 +- **行为:** + - 截止时间有值 → 写入该样本**最后一期**未锁定批次的 `dueDate`; + - 截止时间清空 → 同步清空该未锁定最后一期的 `dueDate`。 +- **跳过:** 最后一期已锁定(存在 `yjf` 转账)。 +- **与重建一致性:** `rebuildSchedules` 在趸交重建时已用 `lumpSumDeadline` 填 `dueDate`;须补齐「仅改截止时间、不 rebuild」路径,使行为与重建一致。 + +### 3.3 分改趸 + +- 不新增 UI 字段;不因本需求改应缴日联动。 + +## 4. 代码落点 + +### 4.1 纯函数(`web-admin/src/utils/protocol-sample-payment.ts`) + +| 函数 | 职责 | +|------|------| +| `calcLastPeriodDueAmount(contractAmount, priorAmounts[])` | 返回尾期金额;无法计算时返回 `null` | +| `shouldAutoFillLastPeriodDue({ lastManualOverride, lastLocked })` | 是否允许自动写入尾期 | +| `applyLumpSumDeadlineToLastDueDate(schedules, deadline, isLocked)` | 返回更新后的 schedules(只改未锁定最后一期的 `dueDate`) | + +覆盖状态由组件内存维护(如按样本 key 的 `Map` 或临时字段),**不落库**。 + +### 4.2 组件(`SamplePaymentPanel.vue`) + +- `patchSchedule`:处理 `dueAmount` 变更时的尾期自动填入 / 覆盖标记。 +- 趸交截止时间变更:在写入 `lumpSumDeadline` 后调用 `applyLumpSumDeadlineToLastDueDate`(无需整表 rebuild)。 + +### 4.3 测试(扩展 `protocol-sample-payment.test.ts`) + +1. 前几期填齐 → 尾期 = 合同 − 之和;尾差落在尾期。 +2. 尾期手改后前几期未变 → 不覆盖;前几期再变 → 再覆盖。 +3. 尾期锁定 → 不自动改。 +4. 趸交:填/清截止时间 → 最后一期应缴日同步/清空;锁定则跳过。 + +## 5. 非目标 + +- 分改趸截止时间 UI 与联动 +- v1 `ProtocolFormDialog` 整单缴费联动 +- 后端 schema / API 变更 +- 强制尾期只读 + +## 6. 验收要点 + +1. 新建/编辑协议单,样本缴费模式为分期:填前 N−1 期金额后,最后一期自动等于合同尾差;手改尾期后不被立刻覆盖;再改前几期则重新自动。 +2. 趸交:改「趸交截止时间」后,应缴费时间同步;清空截止时间后应缴费时间清空;已确认转账锁定的批次不被改。 +3. 分改趸界面仍无「趸交截止时间」字段,行为与改前一致。 +4. 相关纯函数单测通过。