From 6ec4ec67305705d816ffbbe6154c897f68359361 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Tue, 13 Oct 2026 14:50:41 +0800 Subject: [PATCH] feat(web-admin): sync lump-sum deadline to last due date Add applyLumpSumDeadlineToLastDueDate for dj payment schedules, skipping locked or void rows. Co-authored-by: Cursor --- .../src/utils/protocol-sample-payment.test.ts | 46 ++++++++++++++++++- .../src/utils/protocol-sample-payment.ts | 19 ++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/web-admin/src/utils/protocol-sample-payment.test.ts b/web-admin/src/utils/protocol-sample-payment.test.ts index 66065e0b..139e680e 100644 --- a/web-admin/src/utils/protocol-sample-payment.test.ts +++ b/web-admin/src/utils/protocol-sample-payment.test.ts @@ -17,7 +17,8 @@ import { availableSamplePayModes, samplePaymentHasConfirmedTransfer, calcLastPeriodDueAmount, - shouldAutoFillLastPeriodDue + shouldAutoFillLastPeriodDue, + applyLumpSumDeadlineToLastDueDate } from './protocol-sample-payment' describe('parsePreferentialPrice', () => { @@ -372,3 +373,46 @@ describe('shouldAutoFillLastPeriodDue', () => { ) }) }) + +describe('applyLumpSumDeadlineToLastDueDate', () => { + it('writes deadline to last unlocked schedule', () => { + const next = applyLumpSumDeadlineToLastDueDate( + [ + { scheduleNo: 1, dueDate: '', scheduleStatus: 'open' }, + { scheduleNo: 2, dueDate: '20260101', scheduleStatus: 'open' } + ], + '20261231', + (s) => false + ) + assert.equal(next[0].dueDate, '') + assert.equal(next[1].dueDate, '20261231') + }) + it('clears dueDate when deadline empty', () => { + const next = applyLumpSumDeadlineToLastDueDate( + [{ scheduleNo: 1, dueDate: '20261231', scheduleStatus: 'open' }], + '', + () => false + ) + assert.equal(next[0].dueDate, '') + }) + it('skips when last schedule locked', () => { + const next = applyLumpSumDeadlineToLastDueDate( + [{ scheduleNo: 1, dueDate: '20260101', scheduleStatus: 'open' }], + '20261231', + () => true + ) + assert.equal(next[0].dueDate, '20260101') + }) + it('ignores void schedules when picking last', () => { + const next = applyLumpSumDeadlineToLastDueDate( + [ + { scheduleNo: 1, dueDate: '', scheduleStatus: 'open' }, + { scheduleNo: 2, dueDate: 'old', scheduleStatus: 'void' } + ], + '20261231', + () => false + ) + assert.equal(next[0].dueDate, '20261231') + assert.equal(next[1].dueDate, 'old') + }) +}) diff --git a/web-admin/src/utils/protocol-sample-payment.ts b/web-admin/src/utils/protocol-sample-payment.ts index d715963c..545abdf2 100644 --- a/web-admin/src/utils/protocol-sample-payment.ts +++ b/web-admin/src/utils/protocol-sample-payment.ts @@ -440,3 +440,22 @@ export function shouldAutoFillLastPeriodDue(opts: { }): boolean { return !opts.lastManualOverride && !opts.lastLocked } + +/** 趸交:将截止时间写入未作废批次中的最后一期 dueDate;锁定则跳过 */ +export function applyLumpSumDeadlineToLastDueDate( + schedules: T[], + deadline: string | null | undefined, + isLocked: (sch: T) => boolean +): T[] { + const due = String(deadline || '').trim() + const activeIdx: number[] = [] + schedules.forEach((s, i) => { + if (String(s.scheduleStatus || 'open') !== 'void') activeIdx.push(i) + }) + if (!activeIdx.length) return schedules.map((s) => ({ ...s })) + const lastIdx = activeIdx[activeIdx.length - 1] + if (isLocked(schedules[lastIdx])) { + return schedules.map((s) => ({ ...s })) + } + return schedules.map((s, i) => (i === lastIdx ? { ...s, dueDate: due } : { ...s })) +}