支持财务经办与公司代表关联方还款确认(09-17-company-loan-principal-repayment)

公司只有财务和出借收款经理两名办理人,新增限定公司、出借人和借款范围的关联方确认模式。
仅豁免指定公司代表的收款人关联;经办、自审、证据、交易归属、资金占用及 Q6 限制保留。
贯通付款、人工回单、银行对账、补证恢复、晚到补记与追回;电脑和手机显示实际确认身份。
授权版本、付款与对账停用事件及历史决定只增不改,新增迁移 20261009010000_loan_related_approval。

本地合成验证:82 迁移、HTTP 109 组、浏览器 33 组、数据库约束 9 组通过;13 个有效资金守卫变异均捕获。
已有服务端全量 4519 项通过、1 项原有跳过,后续定向 77 项通过;提示收尾另有 908 项合同测试及前端构建通过。
按用户授权提交后对干净候选运行正式 verify-candidate,不沿用旧候选回执。

限制:独立代码复核待完成(inline 模式);真实回单待验。本次仅本地提交,不推送、不部署。
生成关联决定后不能直接降回不理解该模式的旧代码;真实授权、录入、生产核实和付款仍须明确批准。
这个提交包含在:
2026-10-08 15:35:33 +08:00
父节点 4c37fceeb4
当前提交 ce11dea976
共修改 39 个文件,包含 2336 行新增和 208 行删除
+10 -6
查看文件
@@ -1,11 +1,15 @@
const ERROR_REASONS = [
{"code": "loan.bank_result_reconcile_required", "domain": "loan", "audience": "user", "defaultMessage": "银行对账事实、归属或证据尚不满足条件,请补齐材料并独立复核;占用或冻结继续保留。", "recovery": "follow_guidance"},
{"code":"loan.related_authorization_required","domain":"loan","audience":"user","defaultMessage":"本次操作没有有效的关联方公司授权,请核对授权范围和当前付款或对账权限。","recovery":"follow_guidance"},
{"code":"loan.related_scope_invalid","domain":"loan","audience":"user","defaultMessage":"关联方授权、身份、借款范围或历史决定不一致,请刷新并核对;不能转换原审批模式。","recovery":"follow_guidance"},
{"code":"loan.related_actor_conflict","domain":"loan","audience":"user","defaultMessage":"关联方确认须由指定公司有权人完成,且不能兼任本批经办、上传、录入或提案人。","recovery":"follow_guidance"},
{"code":"loan.related_q6_unavailable","domain":"loan","audience":"user","defaultMessage":"关联方模式不支持人工确认未提交;没有符合要求的银行终态证据时,额度继续占用。","recovery":"follow_guidance"},
{"code": "loan.bank_result_reconcile_required", "domain": "loan", "audience": "user", "defaultMessage": "银行对账事实、归属或证据尚不满足条件,请补齐材料并按本批次规则完成确认;占用或冻结继续保留。", "recovery": "follow_guidance"},
{"code": "loan.lender_frozen", "domain": "loan", "audience": "user", "defaultMessage": "该出借人存在尚未处理的银行对账事项,暂停新还款、复核和导出;仍可登记银行事实并对账。", "recovery": "follow_guidance"},
{"code": "loan.not_submitted_invalid", "domain": "loan", "audience": "user", "defaultMessage": "人工未提交的证据、清单或双人复核不满足要求,请补齐后重新登记复核。", "recovery": "follow_guidance"},
{"code":"loan.recovery_required","domain":"loan","audience":"user","defaultMessage":"释放依据已进入补证流程,须完成最新一轮独立复核后才能取消释放。","recovery":"follow_guidance"},
{"code":"loan.recovery_required","domain":"loan","audience":"user","defaultMessage":"释放依据已进入补证流程,须按本批次规则完成最新一轮确认后才能取消释放。","recovery":"follow_guidance"},
{"code":"loan.recovery_unavailable","domain":"loan","audience":"user","defaultMessage":"当前批次或恢复轮次不支持此操作;已释放、已核销的还款不能重新开启。","recovery":"follow_guidance"},
{"code":"loan.recovery_exists","domain":"loan","audience":"user","defaultMessage":"已有补证中或有效的恢复复核,请继续处理当前轮次。","recovery":"follow_guidance"},
{"code":"loan.recovery_stale","domain":"loan","audience":"user","defaultMessage":"补证材料、提交清单或候选批次已变化,请重新发起恢复并独立复核。","recovery":"follow_guidance"},
{"code":"loan.recovery_stale","domain":"loan","audience":"user","defaultMessage":"补证材料、提交清单或候选批次已变化,请重新发起恢复并按本批次规则完成确认。","recovery":"follow_guidance"},
{"code":"integration.erp_retired","domain":"integration","audience":"user","defaultMessage":"ERP 集成已停用,历史记录仅供查询,不能重新投递。","recovery":"follow_guidance"},
{"code":"loan.invalid_input","domain":"loan","audience":"user","defaultMessage":"借款信息不符合要求,请检查必填项、金额和日期。","recovery":"follow_guidance"},
@@ -21,17 +25,17 @@ const ERROR_REASONS = [
{"code":"loan.balance_unconfirmed","domain":"loan","audience":"user","defaultMessage":"借款余额尚未核实,不能申请归还本金。","recovery":"follow_guidance"},
{"code":"loan.allocation_invalid","domain":"loan","audience":"user","defaultMessage":"分配金额超过可还本金,或借款不属于同一公司和出借人,请重新核对。","recovery":"follow_guidance"},
{"code":"loan.reviewer_required","domain":"loan","audience":"user","defaultMessage":"没有符合独立复核要求的经理或总经理;制单人、提交人和收款人不能复核。","recovery":"follow_guidance"},
{"code":"loan.independent_review_required","domain":"loan","audience":"user","defaultMessage":"本次操作须由具备业务权限的独立人员完成,制单人、提交人或收款人不能自审。","recovery":"follow_guidance"},
{"code":"loan.independent_review_required","domain":"loan","audience":"user","defaultMessage":"当前人员不符合本批次确认规则,请核对业务权限、确认模式及经办身份冲突。","recovery":"follow_guidance"},
{"code":"loan.bank_state_unsafe","domain":"loan","audience":"user","defaultMessage":"银行付款状态尚未明确,请先查证;当前不能释放额度或再次付款。","recovery":"follow_guidance"},
{"code":"loan.handoff_not_ready","domain":"loan","audience":"user","defaultMessage":"本金付款尚未成功登记,或已完成会计交接,请核对付款状态。","recovery":"follow_guidance"},
{"code":"loan.payment_not_ready","domain":"loan","audience":"user","defaultMessage":"还款申请或付款状态已变化,请刷新核对后继续。","recovery":"follow_guidance"},
{"code":"loan.lender_in_flight","domain":"loan","audience":"user","defaultMessage":"该出借人有还款正在办理,处理完成或安全取消后才能修改身份关联和收款资料。","recovery":"follow_guidance"},
{"code":"loan.receipt_attribution_required","domain":"loan","audience":"user","defaultMessage":"该回单可能属于同一出借人的其他同金额还款,须登记归属依据并经独立复核,确认前不能核销或释放额度。","recovery":"follow_guidance"},
{"code":"loan.receipt_attribution_required","domain":"loan","audience":"user","defaultMessage":"该回单可能属于同一出借人的其他同金额还款,须登记归属依据并按本批次规则完成确认,确认前不能核销或释放额度。","recovery":"follow_guidance"},
{"code":"loan.receipt_attribution_not_required","domain":"loan","audience":"user","defaultMessage":"本还款没有同金额的其他候选批次,无需确认回单归属。","recovery":"follow_guidance"},
{"code":"loan.receipt_attribution_unavailable","domain":"loan","audience":"user","defaultMessage":"尚无可用于确认归属的已核验银行回单,请先完成回单识别或人工核对。","recovery":"follow_guidance"},
{"code":"loan.receipt_attribution_exists","domain":"loan","audience":"user","defaultMessage":"本还款已有待复核或已通过的回单归属确认,请勿重复提交。","recovery":"follow_guidance"},
{"code":"loan.submission_required","domain":"loan","audience":"user","defaultMessage":"须先登记本批次实际向银行提交的指令,才能确认提交清单。","recovery":"follow_guidance"},
{"code":"loan.submission_list_unverified","domain":"loan","audience":"user","defaultMessage":"银行提交清单尚未经独立复核,或复核后已有变化,须先完成提交清单复核。","recovery":"follow_guidance"},
{"code":"loan.submission_list_unverified","domain":"loan","audience":"user","defaultMessage":"银行提交清单尚未完成有效确认,或确认后已有变化,须按本批次规则重新确认清单。","recovery":"follow_guidance"},
{"code":"loan.submission_history_unverified","domain":"loan","audience":"user","defaultMessage":"该批次为历史批次,导出明细及与银行提交的对应关系待核实,当前不能确认失败或释放额度。","recovery":"follow_guidance"},
{"code":"loan.multiple_submissions_unresolved","domain":"loan","audience":"user","defaultMessage":"该批次有多次导出或多次银行提交,须逐次取得终态证据,当前不能确认失败。","recovery":"follow_guidance"},
{"code":"loan.voided_receipt_unresolved","domain":"loan","audience":"user","defaultMessage":"已作废的回单曾显示付款成功或处理中,须先查明该笔付款结果,当前不能确认失败。","recovery":"follow_guidance"},
@@ -19,6 +19,7 @@ const NOTIFICATION_TYPES = Object.freeze({
reimbursementPaid: 'reimbursement.paid',
paymentBatchReviewRequested: 'payment_batch.review_requested',
paymentBatchExecutionRequested: 'payment_batch.execution_requested',
paymentBatchReturned: 'payment_batch.returned',
leaveApproved: 'leave.approved',
leaveRejected: 'leave.rejected',
leaveReturned: 'leave.returned',
@@ -46,6 +47,7 @@ const IM_SUPPORTED_NOTIFICATION_TYPES = Object.freeze([
NOTIFICATION_TYPES.reimbursementPaid,
NOTIFICATION_TYPES.paymentBatchReviewRequested,
NOTIFICATION_TYPES.paymentBatchExecutionRequested,
NOTIFICATION_TYPES.paymentBatchReturned,
NOTIFICATION_TYPES.leaveApproved,
NOTIFICATION_TYPES.leaveRejected,
NOTIFICATION_TYPES.leaveReturned,
@@ -73,6 +75,7 @@ const NOTIFICATION_TYPE_TO_DOMAIN_SCOPE = Object.freeze({
[NOTIFICATION_TYPES.reimbursementPaid]: NOTIFICATION_DOMAIN_SCOPES.reimbursement,
[NOTIFICATION_TYPES.paymentBatchReviewRequested]: NOTIFICATION_DOMAIN_SCOPES.reimbursement,
[NOTIFICATION_TYPES.paymentBatchExecutionRequested]: NOTIFICATION_DOMAIN_SCOPES.reimbursement,
[NOTIFICATION_TYPES.paymentBatchReturned]: NOTIFICATION_DOMAIN_SCOPES.reimbursement,
[NOTIFICATION_TYPES.leaveApproved]: NOTIFICATION_DOMAIN_SCOPES.leave,
[NOTIFICATION_TYPES.leaveRejected]: NOTIFICATION_DOMAIN_SCOPES.leave,
[NOTIFICATION_TYPES.leaveReturned]: NOTIFICATION_DOMAIN_SCOPES.leave,