diff --git a/scripts/admin-test-env-modules/finance-settlement-full-contract.test.mjs b/scripts/admin-test-env-modules/finance-settlement-full-contract.test.mjs index 79b0525ae..63665eb17 100644 --- a/scripts/admin-test-env-modules/finance-settlement-full-contract.test.mjs +++ b/scripts/admin-test-env-modules/finance-settlement-full-contract.test.mjs @@ -37,6 +37,7 @@ function fakeContext(overrides = {}) { ...overrides } const calls = []; const assertions = []; const gaps = []; const steps = [] return { marker: 'T1', token: 'token', createdResources: { financeFullFixtures: fixture }, calls, assertions, gaps, steps, + financeState: { balances, paidAmounts, statuses, versions }, addStep(module, name, response, passed, evidence, options) { steps.push({ module, name, passed, evidence, options }) }, addCoverageGap(...args) { gaps.push(args) }, assert(module, name, res, condition) { assertions.push({ name, condition }); assert.equal(condition, true, name) }, async request(method, path, body, token, headers) { @@ -113,6 +114,17 @@ test('正式结算动作仅使用本轮 fixture,覆盖 VOID/REOPEN、重放、 } }) +test('结算动作按实时详情跳过已被前置幂等场景部分收款的陈旧 fixture', async () => { + const context = fakeContext() + context.financeState.balances.set('101', 99.99) + context.financeState.paidAmounts.set('101', 0.01) + context.financeState.statuses.set('101', 'PARTIALLY_PAID') + await run(context) + const firstAction = context.calls.find((call) => call.path.endsWith('/actions')) + assert.match(firstAction.path, /\/settlements\/102\/actions$/) + assert.equal(context.gaps.length, 0) +}) + test('冻结共享输入使用 4 条 statements、3 条 AR 和 payableSettlements 数组', async () => { const context = fakeContext() assert.equal(context.createdResources.financeFullFixtures.statements.length, 4) diff --git a/scripts/admin-test-env-modules/finance-settlement-full.mjs b/scripts/admin-test-env-modules/finance-settlement-full.mjs index 226e98d76..73b672522 100644 --- a/scripts/admin-test-env-modules/finance-settlement-full.mjs +++ b/scripts/admin-test-env-modules/finance-settlement-full.mjs @@ -36,6 +36,15 @@ async function detail(context, targetId) { return { response, value: data(response) } } +async function findActionTarget(context, items) { + for (const item of items) { + const current = await detail(context, settlementId(item)) + if (ok(current.response) && status(current.value) === 'ISSUED' + && outstanding(current.value) > 0 && paid(current.value) === 0) return item + } + return null +} + async function verifyVoidReopen(context, item) { const targetId = settlementId(item) const before = await detail(context, targetId) @@ -152,8 +161,7 @@ export async function run(context) { manualIds.length > 0 && manualIds.every((feeId) => usedIds.has(feeId)), `manual=${manualIds.length}, settled=${manualIds.filter((feeId) => usedIds.has(feeId)).length}`, OPTIONS) - const actionTarget = validReceivables.find((item) => item.status === 'ISSUED') - ?? validPayables.find((item) => item.status === 'ISSUED') + const actionTarget = await findActionTarget(context, [...validReceivables, ...validPayables]) if (!actionTarget) gap(context, '取得结算单动作 Fixture', 'settlement VOID/REOPEN', '本轮没有未收付款且状态 ISSUED 的 AR/AP,禁止借历史单据') else await verifyVoidReopen(context, actionTarget)