修复授权分页并补齐追回到账诊断验证(09-17-company-loan-principal-repayment)
这个提交包含在:
@@ -1155,6 +1155,7 @@ await canReadReimbursementBusinessFact(prisma, reimbursement, employee.id);
|
||||
- Same-company employee association includes archived/history rows in duplicate checks, including the old identity-confirmation entry. Reuse a unique matching lender; reject ambiguous links and require explicit refresh for different data. Existing-lender actions lock lender before sorted employees. New creation never locks an existing lender after employees: finish and reacquire in the correct order if a link appeared. Use employee `FOR NO KEY UPDATE` to serialize association/source edits while allowing audit/actor FK `KEY SHARE`; `FOR UPDATE` can deadlock against another employee's refresh/audit. Persist and serialize each actor's request-key binding for both creation and reuse, with audit in the same transaction.
|
||||
- Explicit employee refresh rejects reserved repayments, checks source/identity/account versions and advances both lender versions with renewed finance identity confirmation. This invalidates old company-representative grants without changing principal or historical payment snapshots. Employee-linked lenders cannot use the manual account PATCH; employee-master edits alone never rewrite the loan copy. Verify the actual audit-FK interleaving, duplicate/legacy races, refresh versus repayment creation, audit rollback and reverse mutations using `RUN_ISOLATED_LOAN_EMPLOYEE_ONLY=1` and optional `RUN_ISOLATED_LOAN_EMPLOYEE_MUTATIONS=1` on the isolated loan runner; retain the original full-loan regression.
|
||||
- Related-party loans use the explicit `loanApprovalPolicy` branch, not a global reviewer exception. Finance proposes `LoanRelatedAuthorization` for one company/lender, its verified employee identity and specific confirmed loans; that designated active manager/CEO confirms it. Grants, scope and lifecycle events are append-only. Resolve the latest confirmed version without falling back to an older grant when the new scope is narrower or stopped; a superseded version cannot receive stop events.
|
||||
- The authorization selector calls `GET /loan-lenders?eligible=related_authority` under the existing finance/`loan.manage` gate. Filter verified, employee-linked, non-self lenders before both pagination and count; this selector filter does not replace final representative-role/scope checks. Omitted `eligible` preserves the ordinary list, unsupported values reject, and opening the dialog resets to page 1. Browser pagination waits for a loaded, changed option list and checks the intended IDs, including cache hits; a network response alone is insufficient. After evidence upload, select the exact returned evidence ID when its option is attached, never the last option or placeholder. Verify genuine page 3 with desktop/mobile scope registration and designated confirmation, an unchanged-page counterexample, and distinct synthetic payer/payee accounts for direction refusals. Set `RUN_ISOLATED_LOAN_BROWSER_DIAGNOSTIC` to `authorization-pagination` or `refund` with the existing isolated DB/browser switches; diagnostic checks do not confer release eligibility.
|
||||
- Freeze `LoanRepayment.approval_mode`, `authorization_id` and `approval_context` at creation. Only `related_party` waives the designated payee-conflict reason. Keep maker/submitter/exporter/uploader/manual-entry/proposer conflicts as a separate union of all history, including voided and superseded materials; do not remove the payee employee from that union. Reject designated-reviewer participation at maker entry points as well as decision/final-consumer checks. Old independent loans and shared reimbursement/travel rules do not switch modes.
|
||||
- New payment creation/approval/export checks current payment authority; new reconciliation decisions and final reservation release check current reconciliation authority. `decisionFields()` stores purpose, actual actor, target, scope, authorization version/event and conflict identities. `assertDecision()` validates immutable historical provenance at receipt reconstruction, settlement, terminal/recovery consumption and bank-event booking; it does not require the old reviewer to remain active or the old grant to remain enabled. Stopping payment and stopping reconciliation are separate events. Previously approved bank facts remain usable if their evidence and all money/transaction checks still hold.
|
||||
- Related payment review may return an application with `decision=reject` and a reason. This records an immutable decision without releasing reservations; it cannot later be approved, exported or paid. Finance uses safe never-sent cancellation and creates a corrected application. The UI, responsibility and notification consumers must distinguish this from an approved payment or an independent review.
|
||||
|
||||
在新工单中引用
屏蔽一个用户