文件
hyb-oa/scripts/qa/company-loan-freeze-fixture.cjs
wangsli 431c36eae3 借款对账 S4–S8:人工未提交、晚到补记、追回与界面收口(09-17-company-loan-principal-repayment)
新增三类证据与双人复核的人工未提交、逐原因冻结、晚到付款逐借款补记和实际退款追回;补齐对账与补证恢复界面,保护已消费依据、最终归属重验及全局交易唯一性。

验证:81 迁移、HTTP 95 组、浏览器 13 组、数据库约束 9 组;13 项有效变异被捕获,部分由下游或数据库保护检出。构建、类型、合同和治理检查通过;修复后同模型只读静态复核通过。

真实回单待验、整体业务验收未通过;S0 存量、人员、银行材料与业务独立验收未完成。3 个新增迁移须纳入获批发布清单。本次仅本地提交,不推送、不部署。
2026-10-07 21:58:03 +08:00

32 行
2.6 KiB
JavaScript

const assert = require('node:assert/strict');
const { randomUUID } = require('node:crypto');
module.exports = async function freezeFixture(h) {
const { prisma, call, req, finance, manager, verifiedLender, confirmedLoan, repay, exportOrder, uploadEvidence } = h;
const freezes = req('./src/services/loanFreezes');
const lender = await verifiedLender('合成冻结出借人', null, '4');
const loan = await confirmedLoan(lender.id, '1000.00', '合成冻结借款');
const first = await repay(lender.id, loan.id, '10.00');
await call(manager, 'POST', `/payment-batches/${first.id}/review`, {}); await exportOrder(first.id);
const draft = await repay(lender.id, loan.id, '20.00');
const request = { employee: { id: finance.id }, headers: {}, id: randomUUID(), ip: "127.0.0.1" };
const batch = await prisma.paymentBatch.findUniqueOrThrow({ where: { id: first.id }, include: { items: true } });
const open = (kind, key) => prisma.$transaction((tx) => freezes.openReason(tx, batch, request, kind, key));
const close = (kind, key) => prisma.$transaction((tx) => freezes.closeReason(tx, batch, request, kind, key, { action: 'synthetic_source_resolved', recordId: randomUUID() }));
const key = randomUUID(); const other = randomUUID();
const reason = await open('late_success', key); await open('receivable', other);
assert.equal((await open('late_success', key)).id, reason.id);
await call(manager, 'POST', `/payment-batches/${draft.id}/review`, {}, 409, 'loan.lender_frozen');
await call(finance, 'POST', `/payment-batches/${first.id}/payment-order`, {}, 409, 'loan.lender_frozen');
await call(finance, 'POST', '/loan-repayments', { lenderId: lender.id, reason: '合成冻结后新付款', requestKey: randomUUID(), allocations: [{ loanId: loan.id, amount: '1.00' }] }, 409, 'loan.lender_frozen');
await uploadEvidence(first.id); // Facts remain recordable.
await close('late_success', key);
assert.equal((await freezes.state(prisma, lender.id)).frozen, true);
await call(manager, 'POST', `/payment-batches/${draft.id}/review`, {}, 409, 'loan.lender_frozen');
await close('receivable', other);
assert.equal((await freezes.state(prisma, lender.id)).frozen, false);
await call(manager, 'POST', `/payment-batches/${draft.id}/review`, {});
await assert.rejects(prisma.loanFreezeReason.delete({ where: { id: reason.id } }));
await assert.rejects(prisma.loanFreezeReason.update({ where: { id: reason.id }, data: { status: 'active' } }));
return ['s5_all_active_causes_block_new_payment_review_export_but_allow_facts', 's5_individual_closure_never_unfreezes_other_causes_and_history_immutable'];
};