借款还款同金额回单须经独立复核确认归属后方可核销(09-17-company-loan-principal-repayment)
- 同一出借人同金额的其他批次曾导出或上传回单(含确认失败后已取消的)时, 最终核销入口要求已复核的归属确认;OCR 匹配与人工回单复核均不能绕过, 证据不足保持待对账,本金与占用不变;存在候选时失败回单不能释放占用 - 新表 loan_receipt_attributions(迁移 20261006010000):绑定交易指纹、 回单核验与人工录入证据、当时候选集合;依据类型不含时间吻合;复核人须 当前有资格且独立于登记人、批次创建人、提交人、导出人、回单上传人、 人工录入人与出借员工;失效记录在重新登记时标为 superseded,历史只增不改 - 借款回单上传取出借人锁,与核销候选检查串行;串行只保证按当时已知候选 判断,核销之后才出现的新证据留待晚到结果对账流程处理 - 付款就绪检查反映归属要求;页面登记/复核/失效重登,写明同额分期每期需确认 - 测试:两个错误核销复现改为回归断言;证据绑定、确定性并发两种顺序、 PC 浏览器完整登记复核重登流程;变异测试均变红 注意:借款功能尚不具备真实还款验收条件(失败回单与对账流程、离职后确认 失败、真实回单样本、手机端弹窗、独立复核待完成);未推送、未部署。 Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -22,6 +22,18 @@ export type LoanRepayment = {
|
||||
bankResultState: string; paymentBatchId: string; status: string;
|
||||
accountingHandoffRef: string | null; accountingHandoffAt: string | null;
|
||||
allocations: Array<{ loanId: string; loanNo: string; amount: string; state: string; receivedDate: string; originReference: string; balanceAsOf: string; evidences: LoanEvidence[] }>;
|
||||
receiptAttribution?: LoanReceiptAttributionState;
|
||||
};
|
||||
export type LoanAttributionBasisKind = "customer_serial" | "bank_memo" | "bank_written_confirmation" | "competitors_resolved";
|
||||
export type LoanReceiptAttributionState = {
|
||||
required: boolean;
|
||||
competitors: Array<{ id: string; batchNo: string; status: string }>;
|
||||
receiptAvailable: boolean | null;
|
||||
current: null | {
|
||||
id: string; status: "proposed" | "approved" | "rejected" | "superseded"; basisKind: LoanAttributionBasisKind; basisNote: string; exclusionNote: string;
|
||||
proposedBy: string; proposedByName: string | null; proposedAt: string; reviewedByName: string | null; reviewedAt: string | null;
|
||||
reviewNote: string | null; coversCurrentCompetitors: boolean; stale: boolean;
|
||||
};
|
||||
};
|
||||
export function fetchCompanyLoans(page: number, lenderId?: string, signal?: AbortSignal) {
|
||||
return apiRequestData<{ items: CompanyLoan[]; total: number }>(`/api/company-loans?page=${page}&pageSize=30${lenderId ? `&lenderId=${encodeURIComponent(lenderId)}` : ""}`, { signal });
|
||||
|
||||
@@ -18,6 +18,10 @@ export const ERROR_REASON_MESSAGES: Record<string, string> = {
|
||||
"loan.handoff_not_ready": "本金付款尚未成功登记,或已完成会计交接,请核对付款状态。",
|
||||
"loan.payment_not_ready": "还款申请或付款状态已变化,请刷新核对后继续。",
|
||||
"loan.lender_in_flight": "该出借人有还款正在办理,处理完成或安全取消后才能修改身份关联和收款资料。",
|
||||
"loan.receipt_attribution_required": "该回单可能属于同一出借人的其他同金额还款,须登记归属依据并经独立复核,确认前不能核销或释放额度。",
|
||||
"loan.receipt_attribution_not_required": "本还款没有同金额的其他候选批次,无需确认回单归属。",
|
||||
"loan.receipt_attribution_unavailable": "尚无可用于确认归属的已核验银行回单,请先完成回单识别或人工核对。",
|
||||
"loan.receipt_attribution_exists": "本还款已有待复核或已通过的回单归属确认,请勿重复提交。",
|
||||
"config.enabled_query_invalid": "启用状态筛选无效,请重新选择后查询。",
|
||||
"config.document_type_invalid": "单据类型标识不符合要求,请重新选择单据类型。",
|
||||
"document_sequence.type_unsupported": "当前单据类型不支持编号,请联系管理员核对。",
|
||||
|
||||
在新工单中引用
屏蔽一个用户