支持财务经办与公司代表关联方还款确认(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 行删除
+77
查看文件
@@ -1951,6 +1951,9 @@ model EntityRiskFlag {
}
model PaymentBatch {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
loan_repayment_id String? @db.Uuid
loan_repayment LoanRepayment? @relation(fields: [loan_repayment_id], references: [id], onDelete: Restrict)
id String @id @default(uuid()) @db.Uuid
@@ -2097,6 +2100,9 @@ model PaymentReceiptVerification {
}
model PaymentReceiptManualProposal {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
attachment_id String @db.Uuid
original_verification_id String @db.Uuid
@@ -3879,6 +3885,56 @@ model ApprovalTransfer {
}
// Scoped company authority for related-party loan repayment. Content and events
// are immutable; a newer confirmed version supersedes earlier scope, never
// falling back to an older version after stopping either permission.
model LoanRelatedAuthorization {
id String @id @default(uuid()) @db.Uuid
legal_entity_id String @db.Uuid
lender_id String @db.Uuid
approver_id String @db.Uuid
identity_version Int
version Int
basis String @db.VarChar(1000)
proposed_by String @db.Uuid
proposed_at DateTime @default(now())
request_key String @db.Uuid
loans LoanRelatedAuthorizationLoan[]
events LoanRelatedAuthorizationEvent[]
@@unique([lender_id, version])
@@unique([proposed_by, request_key])
@@map("loan_related_authorizations")
}
model LoanRelatedAuthorizationLoan {
authorization_id String @db.Uuid
loan_id String @db.Uuid
authorization LoanRelatedAuthorization @relation(fields: [authorization_id], references: [id], onDelete: Restrict)
@@id([authorization_id, loan_id])
@@map("loan_related_authorization_loans")
}
model LoanRelatedAuthorizationEvent {
id String @id @default(uuid()) @db.Uuid
authorization_id String @db.Uuid
sequence Int
action String @db.VarChar(24)
payment_enabled Boolean
reconcile_enabled Boolean
actor_id String @db.Uuid
reason String @db.VarChar(500)
created_at DateTime @default(now())
authorization LoanRelatedAuthorization @relation(fields: [authorization_id], references: [id], onDelete: Restrict)
@@unique([authorization_id, sequence])
@@map("loan_related_authorization_events")
}
model LoanLender {
id String @id @default(uuid()) @db.Uuid
legal_entity_id String @db.Uuid
@@ -3950,6 +4006,12 @@ model CompanyLoan {
}
model LoanRepayment {
approval_mode String @default("independent") @db.VarChar(16)
authorization_id String? @db.Uuid
approval_context Json?
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
repayment_no String @unique @db.VarChar(64)
legal_entity_id String @db.Uuid
@@ -4025,6 +4087,9 @@ model LoanEvidence {
// Partial unique index (one proposed/approved per batch) and history trigger
// live in migration 20261006010000_loan_receipt_attribution.
model LoanReceiptAttribution {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
payment_batch_id String @db.Uuid
fingerprint String @db.VarChar(64)
@@ -4113,6 +4178,9 @@ model LoanBankSubmission {
}
model LoanBankSubmissionAttestation {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
payment_batch_id String @db.Uuid
submission_ids Json
@@ -4162,6 +4230,9 @@ model LoanBankTerminalEvidence {
}
model LoanBankTerminalFact {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
payment_batch_id String @db.Uuid
submission_id String @db.Uuid
@@ -4207,6 +4278,9 @@ model LoanFailureEvidenceUse {
// SR: original bank conclusions remain immutable; recovery controls release only.
model LoanReleaseRecovery {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
payment_batch_id String @db.Uuid
sequence Int
@@ -4311,6 +4385,9 @@ model LoanFreezeReason {
}
model LoanBankResultEvent {
loan_approval_mode String @default("independent") @db.VarChar(16)
loan_authorization_id String? @db.Uuid
loan_approval_context Json?
id String @id @default(uuid()) @db.Uuid
payment_batch_id String @db.Uuid
kind String @db.VarChar(16)