## 2026-09-17 实施细化 ## 2026-10-06 失败回单归属与银行结果对账方案(第 3 版,待用户审阅,未实施) 第 3 版补充:区分制单导出与银行提交尝试、“从未提交银行”的单独路径(待决)、按原因冻结及误报出口、补记不生成可导出指令。第 2 版根据审阅意见修订:未付款证据须证明指令终止、按付款尝试而非附件数判断、占用与已付分开且超额按差额逐笔计算、晚到成功按冻结快照核对并覆盖“已确认失败未释放”、冻结覆盖后续指令且追回须核实到账。 ### 1. 要解决的问题(现状均已在合成测试或代码中确认) | 编号 | 现状 | 后果 | |---|---|---| | R1 | 导出制单或上传回单后状态为 `unknown`,只有匹配的失败回单能转 `confirmed_failed` 再取消 | 未付款或网银导入即失败而无回单时,占用永久不释放,且因在途拦截冻结出借人维护 | | R2 | 确认失败要求批次回单总数恰为 1(含作废) | 作废一次即永远无法确认失败;同时“附件数”本身也不能代表付款尝试次数 | | R3 | 存在同金额候选时确认失败一律拒绝 | 等额分期任一期真实失败都无法释放 | | R4 | 确认失败仍按付款前规则校验出借员工在职 | 出借员工离职后无法确认失败 | | R5 | `confirmed_failed`/`confirmed_success` 为终态,已释放/已结清分配不可改;执行状态要求 `confirmed_success` | 失败结论之后银行晚到成功无处补记;同一本金可能被再次申请并付款 | 线下对账只能查清银行事实,**不能直接解除系统占用**。任何释放、补记、追回都必须走下述有依据、有独立复核、有审计的系统流程;不提供“管理员解除占用”,不直接改库。 C(同金额回单归属确认)只防止**错误核销**,不能防止银行**实际重复付款**;本方案另设事前冻结(3.5)。 ### 2. 总体原则 1. 释放占用只能基于“银行对本批次每一次提交都已到达不再执行的终态”的正面证据;“暂时没看到付款”、对账单无支出、等待期届满都不能单独作为依据。唯一例外是 3.2a 的“人工确认未提交”:须满足全部证据与双人复核,记录和页面均标注为人工确认,与“银行确认指令终止”严格区分。 2. 每条银行事实绑定具体证据及其核验记录,由当前有资格、且不是登记人、导出人、证据上传人、批次创建人、提交人或出借员工的经理/总经理独立复核。 3. 银行事实登记属付款后环节:按**原批次冻结的收付款快照与历史审批身份**核对,不要求与出借人当前资料版本一致;只判断当前操作人的权限与独立性。 4. 历史只增不改:推翻先前结论时新增记录并标记原结论,不回写终态。 5. 无合格独立复核人时保持占用并显示业务阻塞原因,不降级为单人确认。 ### 3. 方案 #### 3.1 付款尝试与银行事实记录 - **制单导出记录**:每次导出落一条记录(序号、时间、导出人、文件摘要、制单行客户方流水号 `批次号-R00n`、金额、收付款快照摘要)。重导出沿用同一客户方流水号,所以导出次数不等于向银行提交的次数:下载两次可能只提交一次,下载一次也可能被重复提交。现有 `payment_order_export_count` 只计数,需落表。 - **银行提交尝试**:由财务登记实际向银行提交的每一次指令(提交时间、渠道、所用导出记录、银行指令号或网银批次号、客户方流水号),并附银行凭据。一次提交关联一条导出记录;一条导出记录可以对应零次、一次或多次提交。登记清单本身也要经独立复核,确认“这就是全部提交”。 - **银行事实确认**:把 `loan_receipt_attributions` 扩为银行事实确认,新增 `kind` 与可选 `attempt_id`: - `settlement`:现有归属确认,含义不变; - `failure`:某次银行提交被拒绝或失败(失败回单),须写明覆盖哪些银行指令,并绑定交易指纹与证据;存在同金额候选时必须有已复核的 `failure`(R3); - `terminated`:某次银行提交已撤销或拒绝、不再待执行(无回单时的指令终态证据,见 3.2);须写明覆盖的指令,不能以一条指令的终态推定其他提交已结束; - `not_submitted`:导出后从未提交银行(见 3.2a,是否支持待用户决定); - `late_success`:晚到成功,见 3.4。 - 以上沿用登记、独立复核、失效取代、证据绑定、历史只增不改。 #### 3.2 释放占用的证据门槛(R1、R2) 释放(`unknown` → 新终态 `confirmed_not_paid`,或沿用 `confirmed_failed` 后取消)必须同时满足: 1. **逐次提交有终态**:已复核的银行提交清单中,每一次提交都有已复核、且明确覆盖该指令的 `failure` 或 `terminated` 事实;每一条导出记录要么关联了已终止的提交,要么有已复核的 `not_submitted` 事实(3.2a)。 2. **终态证据须能唯一定位指令**:银行书面回复、网银“指令查询”的官方导出 PDF 等,须载明该尝试的客户方流水号(或银行指令号)及其终态(已拒绝、已撤销、已失败),并表明不再待执行。对账单只能作辅助核对,不能单独证明未付款。截图、口头说明、“网银查不到”一律不接受。 3. **无未解决的成功或待定事实**:作废附件只改变材料使用状态,不抹掉银行事实。曾核验为成功的回单直接阻断释放;曾为待定(处理中、受理)的,须由同一尝试后续的终态证据(失败或撤销)关闭后才不再阻断。 4. **内部等待期**:距最后一次导出满 N 个自然日(建议 3 日)。这只是内部谨慎期,不代表银行时限,也不能替代第 1、2 条。 5. **独立复核**:导出人、证据上传人、登记人不能复核。 6. 释放后系统禁止该批次再次导出;**但 OA 无法让已下载的制单文件在网银中失效**,页面仅作提示。此剩余风险由 3.4 晚到成功与 3.5 冻结兜底,不作技术保证表述。 #### 3.2a 只导出、从未提交银行(待用户决定) 这种情况下,银行可能根本没有可出具终态的指令。若本期坚持“银行终态是唯一释放依据”,这类批次将**仍然不能释放**,R1 只算部分解决。如需支持,规则单列如下,不视为满足银行终态条件: - 证据(须全部具备): - 网银“指令查询”官方导出 PDF,覆盖首次导出日至登记日,按该客户方流水号及收款账号、金额查询无结果; - 同期付款账户对账单,经逐笔核对无对应支出; - 导出人书面说明文件去向,以及未提交的原因。 - 内部等待期满。 - 双人复核:两名彼此不同、当前有资格的经理或总经理分别独立复核。两人都不能是登记人、导出人、证据上传人、批次创建人、提交人或出借员工。 - 定性:这是“查无提交”的人工谨慎结论,不是银行保证。数据上记为独立终态 `confirmed_not_submitted`(区别于银行确认终止的 `confirmed_not_paid`),页面显示“人工确认未提交”。之后若出现该流水号的成功回单,按 3.4 处理,并另记“未提交结论被推翻”。 - 实际限制: - 需要两名额外的合格复核人,且都不能是登记人、出借人、导出人等相关人员。公司人数少,是否满足尚未核实;人员不足时,这条路径不可用,额度继续占用。 - 建设银行能否出具“查询无结果”的官方导出 PDF,尚未确认;拿不到时同样继续占用。因此不能宣称“只导出未提交”的所有情况都能解决。 #### 3.3 确认失败的修正(R4) 确认失败改按付款后规则:不要求出借员工当前在职,不要求出借人当前资料版本与提交时一致,改为核对批次冻结快照;当前操作人仍按当前资格与独立性校验。 #### 3.4 晚到成功:补记与差额计算(R5) 触发:已核验的成功回单属于某个已有失败或未付款结论的批次(无论是否已取消释放),并经 `late_success` 类独立复核确认归属;核对对象是该批次冻结的收付款快照、历史审批身份与交易唯一性认领。 处理步骤: 1. **推翻原结论**:新增事实记录,标记原批次结论“已被银行事实推翻”,并写审计,不回写原终态。 2. **即时冻结**:可信晚到成功一经登记(复核前即生效),冻结该出借人,见 3.5。 3. **逐笔分配计算**:按原批次的原借款分配逐笔处理。对每笔借款 L,设晚到付款分摊到 L 的金额为 a: - 其他**已付并结清**的还款,在 L 上已结清 S;L 的未还本金为 O(已扣除 S)。 - L 上其他**未付款、仅占用**的申请属于占用冲突,不是超额。这些申请须先处理:未导出的可取消;已导出或待查证的按 3.2 举证或等待其事实。处理完毕前,L 的补记暂停。 - 冲突清除后,可补记结清额为 `min(a, O)`,差额 `a − min(a, O)` 列为对出借人的待追回款。 4. **补记方式**:由于原分配为终态(已释放)或原批次状态受限,补记生成一条关联原批次与该交易的“补记还款”,按上一步计算结果占用并立即结清。若原分配仍为占用(已确认失败但未取消),在同一事务内以“被晚到成功推翻”为原因释放,再由补记还款结清。整个过程受数据库约束“占用加结清不超过未还本金”保护。 - 数据边界:补记只记录已经发生的银行付款,**不生成付款批次、不可导出、不可再次付款**。即使整笔都是超额(可结清本金为零),也必须完整记录银行付款金额、交易指纹与待追回金额。 5. **示例**:本金 100 元,晚到成功 80 元。 - 另一笔新申请占用 70 元、尚未付款:这是占用冲突,暂停该申请的后续付款并处理该占用;处理后补记结清 80 元,剩余本金 20 元。 - 另一笔已付款并结清 60 元:剩余本金 40 元,补记结清 40 元,另 40 元列为待追回款。 #### 3.5 冻结与解冻 - **按原因冻结**:冻结以“原因记录”为单位,挂在出借人上。每条记录写明原因类型(晚到成功待确认、占用冲突、待追回款)、来源事件、状态(生效或已关闭)以及关闭依据。只要出借人仍有任一生效原因,就处于冻结状态。 - **冻结时机**:可信晚到成功登记时(复核前即生效),或产生占用冲突、待追回款时。 - **冻结范围**:该出借人的新还款申请、其他在途申请的复核与导出(含重新导出)一律拒绝。 - **不冻结**:已发生银行事实的登记、回单上传与核验、事实复核、对账与追回登记。 - **追回**:以银行到账证据(出借人退款入账回单)登记,须独立复核,支持部分追回,逐笔冲减待追回款。本期不支持冲抵后续本金。 - **原因的出口**: - 确认为真实晚到成功:完成补记后,占用冲突与待追回款作为新的原因分别处理;晚到原因在补记完成时关闭。 - 确认为误关联或重复登记(例如回单传错批次、对应的交易已在别处登记):保留原登记记录,经独立复核、附依据后关闭该原因,不补记。 - 证据仍不确定:原因保持生效,继续冻结。 - 待追回款:全额实际到账并经复核后关闭;部分追回只冲减金额,不关闭。 - **解冻**:出借人的**全部生效原因都已关闭**才解冻。不因其中一笔处理完就整体放开;仅“登记了追回结果”也不能关闭原因。 #### 3.6 权限与离职 | 环节 | 操作人 | 复核人 | |---|---|---| | 登记付款尝试、失败、终态、晚到成功、追回到账 | 当前持财务角色和 `loan.manage` 的人员 | 当前经理或总经理,且不是登记人、导出人、证据上传人、批次创建人、提交人或出借员工 | 原审批人、出借员工离职,以及法人或银行停用、出借人资料事后合法变更,都不影响上述环节(均按冻结快照核对)。人员不足时,页面显示具体环节与缺少合格复核人的原因类别。 ### 4. 页面 在还款详情的“银行结果”区,按付款尝试列出每次导出及其事实状态,只显示当前可做的动作: - 待查证:登记失败或终态证据(显示内部等待期剩余天数); - 全部尝试已终止:取消释放; - 已推翻:晚到事件、逐笔补记结果与待追回款; - 冻结中:说明原因与解冻条件,提供追回登记入口。 各表单写明证据要求:须能定位具体指令;对账单与时间吻合只能作辅助。 ### 5. 验收(实施时转为 PRD AC) 1. 只导出未付款:无指令终态证据、也不满足 3.2a 特别复核例外时,等待期满也拒绝;有能定位指令的终态证据并经独立复核后可释放;满足 3.2a 全部证据并经双人复核后,可作为“人工确认未提交”释放,记录与页面显示为人工确认;仅对账单、截图或时间依据被拒;导出人、登记人自审被拒。 2. 导出与提交分开:多次导出、一次提交,或一次导出、多次提交,都按提交清单逐条举证;一条指令的终态不能证明其他提交已结束;提交清单未经复核即不能释放。若采纳 3.2a:只导出未提交须满足全部证据并经双人复核,否则继续保持占用。 3. 作废的成功回单持续阻断;作废的待定回单在同一尝试取得终态证据后不再阻断。 4. 存在同金额候选时,失败经 `failure` 归属确认后可以释放,否则保持占用。 5. 离职或出借人资料事后合法变更后,确认失败、终态、晚到成功仍可由当前合格人员完成,并按冻结快照核对。 6. 晚到成功覆盖四种情况:已释放、已确认失败但未释放、占用冲突(先暂停后补记)、已付冲突(按差额补记加待追回);多借款合并还款逐笔计算;同一笔交易不能用于两次补记或核销。 7. 冻结按原因管理:覆盖新申请和其他在途申请的复核与导出,但不阻止事实登记;误报的晚到成功经复核关闭原因后不补记;证据不确定时继续冻结;多个原因并存时,只关闭其中一个不会解冻;部分追回不解冻。 8a. 补记不生成可导出指令;整笔超额时补记结清为零,但仍完整记录银行付款与待追回金额。 8. 全部只增不改、审计完整,不存在单人释放路径;合成全流程测试含确定性并发(终态登记与晚到回单、补记与新申请、冻结与导出),每类关键守卫都有变异测试。 ### 6. 不在本方案内 银行接口直连、对账单自动解析与 OCR、利息、冲抵后续本金、手机端专门优化(沿用共用组件)、生产存量处理(生产是否已有真实还款仍待核实)、部署。 ### 7. 需要用户确认(采纳审阅建议作为默认) | 问题 | 默认 | |---|---| | Q1 内部等待期 | 3 个自然日,仅作内部谨慎期 | | Q2 证据 | 按内容判断:须唯一定位指令并证明终态;银行官方导出 PDF 可以;对账单只能辅助 | | Q3 冻结 | 冻结新付款与未发出的后续指令,保留事实登记、对账、追回入口 | | Q4 冲抵 | 本期只支持实际退款到账 | | Q5 迁移 | 由最终数据设计决定(预计包括导出记录、银行提交尝试、事实记录扩展、补记还款、冻结原因、追回记录,以及 `confirmed_not_paid`、`confirmed_not_submitted` 两个状态);部署另行批准 | | Q6 只导出未提交(3.2a) | 用户 2026-10-06 确认支持,作为经特别复核的人工例外(全部证据加双人复核);受合格复核人数和银行能否出具查询 PDF 限制,不满足时继续占用 | `origin_reference`作为主体+出借人范围的原借入凭据唯一引用,防止更换幂等键重复登记。期初已还差额必须有adjustment证据。身份与账户分别版本控制,改账户同时撤销身份确认,旧未付快照失效。 新申请持lender→排序loan→日序号锁,只创建本事务尚未可见的新batch;所有既有batch路径先锁batch,核销沿receipt advisory→排序附件→lender/审批身份→排序loan,台账/身份维护不反向锁batch。取消保留旧申请和批次,不原位重提;一申请恰好一个保留批次。下载制单或上传回单转unknown,均不扣减本金。首期不能仅凭理由解除unknown。 借款材料沿现有PDF/图片字节检验,按种类归属借款、随机存储键、内容hash去重、授权下载理由和发送前审计;已确认材料保留,未新增物理删除接口。代账确认引用和四类材料承担本地业务证据门禁,不等同银行真伪核验。 下方“规划/尚未写schema/未运行”的文字为原方案形成时状态,当前状态以implement顶部实测回执为准。 # 本金归还最小方案(规划,未实施) ## 1. 复用边界 复用付款账户、批次制单/独立复核、回单存储/核对/交易去重及审计,不复制付款引擎。首期一张申请绑定一个活动批次、批次只有一笔付款;原借入分配保留在申请明细,不拆成两笔银行转账。付款批次复核即本次还款审批,不另接万能工作流;已有报销流程不改。 当前付款来源存在reimbursement/否则按travel_order处理的分支,新增loan_repayment必须逐消费者改为明确支持/拒绝,不能只加枚举。新来源覆盖候选/快照/权限/预检/创建/复核/导出/回单上传、job认领、匹配/人工复核/登记、列表统计和通知深链;未审消费者必须拒绝,不默认套差旅或报销。 ## 2. 最小数据合同 - 个人出借人记录:公司关系、可选OA员工关联、身份核对状态、加密收款资料及审计。非员工不虚建员工;已分配后的身份/账户变化使未付申请失去就绪资格,不能只改姓名避开自审。 - 借款记录:公司/出借人/币种、原始本金、已确认未还本金、核对截止日、历史登记标识、原入账/协议证据及确认审计。待确认不能支付,原登记与后续变动均可追溯。 - 本金还款申请与分配:一对多关联原借款、精确分配金额、事由和提交人;同公司/出借人/币种,合计与唯一付款明细一致。提交时冻结来源版本/收款信息,复核和登记时重验。 - 付款/审批状态优先由关联批次权威事实投影,不维护第二套可以独自变成已付的流程;会计交接确认单独存储,不等同银行已付。 最终表/字段名、索引与外键在实施前按Prisma现有约定确定。金额用Decimal或最小货币单位,不用浮点累加;活跃分配唯一约束、金额正数/上限及交易指纹占用必须有服务端/数据库保证。数据清理走留痕,不新增批次级联删除来源/交易证据路径。 ## 3. 并发与状态不变量 提交申请在事务中按稳定顺序锁定借款记录,重算已确认未还本金减活动占用;只有余额足够才创建分配及批次。并发同一借款只能占用可用额度,不以页面预检授权。编辑已提交申请须退回/取消原活动付款关系后重新提交,不能改已审快照。 登记路径保留既有批次→交易advisory→附件锁序;涉及多笔借款锁时按稳定ID顺序追加,核各路径不存在反向依赖后才落实现。交易claim、分配核销、付款事实和审计同事务提交;中途异常整体回滚。已付请求重试不重复减款,重复银行交易在新来源及报销来源间共用去重空间。 待复核/已复核未付仅占用本金;银行在途/未知保持占用并显示查证责任,不能为解锁重付而标失败。安全取消或有依据的确定失败才释放额度;已付纠错另审,不回写历史余额掩盖错误。 ## 4. 权限与回单 新台账沿财务全账读取与付款审查分离:财务管理台账,审批人只读其有权审批的申请及必要证据,普通员工无全账入口。制单人、提交人、出借收款人身份集合统一传给提交预检/批次复核/人工回单复核/登记重验;admin通配不能替代独立身份。 2026-10-05 修订(取代原“在职状态和业务权限不吃历史批准”):资格按环节区分。 - 付款前(新建申请、批次复核、导出制单、确认银行失败):校验当前在职、当前角色/权限、出借人就绪(身份已核实、未归档、法人与银行主数据启用)及出借员工在职。 - 付款后(回单 OCR 认领、人工回单参与人、核销登记):原审批人与出借员工的资格以审批时为准,不再复核其当前在职/角色,也不再复核法人、银行主数据当前启用状态。理由:银行已实际付出的事实不能因事后人员或主数据变化而无法登记,否则本金永久占用且未还本金多记。仍须满足:身份已核实;身份/账户版本与提交时一致(在途期间维护被 `loan.lender_in_flight` 阻止);付款快照收款资料一致;`reviewed_by/reviewed_at` 存在且审批人不是制单人、提交人或出借人关联员工(这三者之间可重合);回单的账号、金额、币种、状态与交易唯一性匹配。审批时资格的依据是复核路由当时已用当前角色校验并写入 `reviewed_by/reviewed_at`。 - 当前操作人(上传、人工复核、执行、会计交接)始终按当前权限与独立性校验。 银行备注采用短本金语义,年份不一致时不生成误导性单一年份;长事由留OA。对现有建行制单模板使用显式业务用途映射,原报销用途不变。回单识别范围只有经过新来源快照和权限校验才可扩展,不能无条件对新业务调用腾讯;真实样本/云调用另批,未验证前不宣称自动支持。 自动匹配需金额/币种/完整双方账号/成功状态/唯一交易身份满足;无OCR证据时沿既有双人手工录入复核边界,不把手工值称银行验真。人工复核不覆盖原失败或处理中状态,原件、指纹及版本证据保留;读取账号和原件继续权限/审计/脱敏。 ## 5. 页面与会计边界 财务模块新增借款台账和本金还款入口,复用列表/详情壳、金额/日期格式、附件及下一步投影,保持既有PC/手机样式;不设计新视觉体系。详情显示已确认未还、占用、可还、历史借入分配和会计交接状态,不靠颜色单独表示风险;缺资料/无人可批/银行在途给具体责任提示。 只登记代账核对结果与凭证引用,不选择或生成会计科目、不作税务判断;历史确认和实际银行付款资料由有权人员提供,测试使用合成样例。 ## 6. 验证与发布/回退 隔离DB/HTTP测完整申请→复核→回单→登记→分配核销;覆盖无独立审批人、收款人兼CEO、跨公司、余额并发、失败释放、在途不释放、重复登记、跨业务同交易、来源/账户变化及审计失败。浏览器用真实本地认证和合成数据,不把数据库直接置paid当付款流程通过。 新表和来源枚举属于迁移/权限/状态机变更,必须独立只读审查。新增枚举不保证旧镜像兼容;有新业务数据后不得直接退到仅识别两类来源的旧版,应保留兼容版本或写入隔离后另审前向修复,不删新账/claim“回退”。发布前重新核候选、备份、原密钥保管和相关敏感恢复风险,不沿用旧例外或已有一次演练授权。 ## 7. 2026-09-17 源码消费者地图与技术定稿要求 | 消费者 | 已核事实 | 新来源实施前必须证明 | | --- | --- | --- | | Prisma `PaymentBatchEntityType` / `PaymentBatch` | 现有两类来源;原有批次/回单/claim关系存在 | 增量枚举、新来源关系与索引显式约束,旧数据无回写;新增来源出现后旧镜像不作为无条件回退 | | `paymentBatchReadiness.js`、`paymentBatches.js` | readiness非报销直接冻结;路由多处报销/否则差旅分支 | loan_repayment单独资格与快照适配;未知来源一律拒绝,travel_order继续沿原冻结规则 | | `paymentReceiptVerification.js`、`paymentReceiptManualPersistence.js` | 真实核对及人工持久化明确仅报销 | 新来源独立参与人集合、同一transaction claim去重、版本与成功状态规则;不能只删除reimbursement检查 | | `paymentReceiptOcrJob.js`、`paymentReceiptMatching.js` | worker认领与匹配受业务来源限制 | 新来源eligibility与只读storage边界明确后才允许进入队列;真实云端样本未验另记 | | `client/src/api/paymentBatches.ts`、`PaymentBatchesPage.tsx` | 创建按报销,详情部分二选一标签默认差旅 | 类型/入口/详情/深链/统计显式处理本金还款,保持原报销操作与普通员工权限 | 拟以`LoanLender`、`CompanyLoan`、`LoanRepayment`、`LoanRepaymentAllocation`四类核心关系承载出借人、原借入、还款申请和分配;借款材料使用专属证据关系,付款回单继续归原批次。命名和字段尚待T1按Prisma约定定稿,不创建通用财务台账/文件中心。约束至少包括来源版本、单公司/出借人/币种、申请与借款分配唯一、金额精确且为正、证据不级联删除及历史确认可追溯。 锁序定稿必须覆盖创建、重新提交、复核、取消、失败处置、回单登记和余额确认全部写入路径:既有批次先锁batch,再沿原交易advisory/附件顺序,之后按稳定ID锁借款并更新分配;不得存在先锁借款再等待同一既有batch的反向路径。新批次创建在同一事务中的新记录不会成为绕过额度锁的理由;若当前创建器要求反向锁序,应先调整技术方案并审阅,不能边编码边隐藏差异。并发与数据库回滚以真实隔离PG测试证明,mock只覆盖路由输入与调用边界。 ## 8. T1字段与约束定稿草案(2026-09-17,仅本地设计) 本节把前述概念模型具体化为实施合同草案,尚未写Prisma/迁移或启动数据库。金额沿PaymentBatchItem的Decimal(14,2),首期currency_code固定CNY;日期@db.Date,标识UUID,snake_case列名、复数表名、created/updated及操作者沿项目约定。绝不以Number累加核额度。 | 模型/表 | 核心字段与不可变事实 | 约束/索引及删除 | | --- | --- | --- | | LoanLender / loan_lenders | id、legal_entity_id、name、employee_id可空、identity_status(unverified/verified)、identity_version、account_version、bank_account_encrypted、bank_name、account_name_encrypted、archived_at | FK主体/关联员工Restrict;(legal_entity_id,id)唯一用于复合归属;身份和账户变更递增对应版本及留审计;姓名不作唯一身份;不保存明文账号或密钥摘要 | | CompanyLoan / company_loans | id、loan_no、legal_entity_id、lender_id、currency_code、original_principal、opening_outstanding_principal、received_date、balance_as_of、historical_entry、confirmation_status、version、confirmed_by/at、accounting_confirmation_ref | loan_no唯一;主体/出借人复合FK;CHECK 0≤opening_outstanding≤original且original>0、CNY;索引(lender_id,confirmation_status,received_date);确认前不能分配;确认后本金/期初余额不可覆盖改写,纠错另审留存 | | LoanRepayment / loan_repayments | id、repayment_no、legal_entity_id、lender_id、currency_code、reason、amount、version、submitted_by/at、lender_identity_version、lender_account_version、payee_snapshot_json(仅允许加密/脱敏值)、bank_result_state、accounting_handoff_by/at/ref | repayment_no唯一;amount>0;CNY;主体/出借人复合FK;bank_result_state仅作为银行结果证据分类,不替代批次审批/付款状态;申请提交后快照不可原位改;会计交接不是银行成功 | | LoanRepaymentAllocation / loan_repayment_allocations | id、repayment_id、loan_id、amount、loan_version、reservation_state(reserved/settled/released)、settled_at、released_at、release_reason | (repayment_id,loan_id)唯一,amount>0;FK均Restrict;索引(loan_id,reservation_state);跨行总额和同主体/出借人/币种在锁内检查,不能谎称单行CHECK能保证聚合不超付 | | LoanEvidence / loan_evidences | id、loan_id、kind(agreement/incoming/accounting_confirmation/adjustment)、storage_path、mime_type、file_size、file_sha256、governance_status、uploaded_by/at、archived_at/reason | 专属材料关系;loan/uploader FK Restrict;大小/类型沿受控附件合同;同一借款同一hash/kind防重复引用;访问需权限/审计。银行付款回单继续放PaymentBatchReceiptAttachment,不复制OCR/claim体系 | | 既有PaymentBatch增量 | entity_type增加loan_repayment;loan_repayment_id可空且FK Restrict,其他来源必须为空 | SQL CHECK来源与专属FK一致;对loan_repayment_id建status≠cancelled的部分唯一索引,executed仍占唯一,failed不自动解占;每批恰好一item、entity_id=repayment.id、amount=申请与分配之和由事务及延迟约束触发器验证,迁移原型需证明;旧两来源原数据不改 | 可用本金=已确认期初未还本金−本系统settled分配−reserved分配;已确认外部历史偿还只体现在期初未还及原证据,不能再次减账。每次提交/执行在CompanyLoan行锁下重算聚合,失败回滚不能留下孤儿claim/分配/审计。发布后修正期初余额需另有可追溯调整流程,不提供直接编辑confirmed字段的API。 活动批次取消后允许同一申请重提时,新建批次并重建新版本分配;原released分配不能覆盖掉历史金额,故首期更简单规则为取消后复制成新申请编号,旧申请/分配/批次保留。禁止对executed申请重新创建批次。批次草稿删除对loan_repayment明确拒绝,使用有理由取消;不能沿原Cascade删除回单/claim链。 ## 9. T1锁图与并发验收(已对照当前源码,待数据库原型) 源码事实:paymentBatches.lockBatchWithItems锁batch;lockPaymentEntities目前reimbursement/否则travel_order;现execute先锁来源实体,再claimVerifiedReceipts;paymentReceiptVerification claim路径先交易advisory再按id锁附件,manualPersistence先batch→交易advisory→attachment。**不能直接把新借款塞入原lockPaymentEntities分支并声称满足前节锁序。** 新来源execute须显式分派,把借款锁放在现有receipt锁之后;旧两类路径保持原回归边界。 | 操作 | 固定锁序/验证 | 并发/失败退出 | | --- | --- | --- | | 创建申请和新批次 | lender→按id排序的loan→申请/分配→编号daily sequence advisory→插入本事务新batch;同请求幂等键唯一 | 在锁内重查确认/余额/版本;创建后不再等待任何已存在batch;两事务竞争同loan只能成功可用额度内的一笔 | | 复核、取消、失败处置 | 既有batch→lender→排序loan→申请/分配;不取receipt锁的路径不可调用需要它的子流程 | 重验独立身份/账户版本;只有未送银行或有确认失败证据才释放;failed状态本身不构成释放证据 | | 回单登记 | batch→全局receipt transaction advisory→按id附件→lender→排序loan→申请/分配/claim/付款事实/审计 | 所有写同事务;精确claim去重;审计失败回滚;重复成功登记返回原事实、不再减本金 | | 人工回单复核/OCR完成 | 继承原batch→advisory→attachment或原已核最小顺序;涉及额度时只能向后取lender/loan | 不得由持loan的路径回调此操作;失败/在途回单不可被人工改成成功 | | 出借人修改、余额确认 | lender→排序loan;只改来源版本/证据,不锁/更新已有batch | 未付资格在下一次预检/复核/登记重验时失效;禁止反向“来源锁→批次锁”广播更新 | 2026-09-17实施定稿:新申请先取得lender和排序loan锁,再分配编号并插入本事务的新batch;整个创建路径不等待既有batch。既有batch处理/重试不分配新编号,来源维护不反向锁batch。此顺序取代初稿序列锁优先的建议。数据库原型必须覆盖相反loan选择顺序、并行申请总额超过余额、取消与登记竞争、账户变更与复核竞争、同交易跨报销/借款竞争、最后审计抛错回滚、同幂等键重复请求。使用两条真实PG连接和barrier,不能由mock顺序调用替代。 bank_result_state分为not_sent/unknown/confirmed_failed/confirmed_success;新申请未制单可为not_sent,下载后不等于付款成功,也不允许仅凭OA记录仍未付就释放额度。无法证明是否已送银行时保持unknown并阻止重付;解除unknown需有范围的银行结果/未发送确认事实和审计。该状态仅控制风险守卫,已付仍以受核验的批次执行事实为准。 ## 10. T1权限、接口和交付门禁 沿finance.ledger.view管全账读取,新增loan.manage管登记/确认/提交,不默认授予system_admin/普通员工;实际角色种子修改列独立权限审阅。payment.batch.review既有资格加“制单/提交/出借身份集合排除”,admin通配也不免除独立性。employee_id为空且identity_status未verified不得付款,已确认外部非员工不得伪建账号;同一人的多OA身份须先完成真实身份映射,否则不能假定独立。敏感查看沿专用权限与最小投影、审计和原字段密钥。 拟接口/lenders、/company-loans、/loan-repayments分开;创建与确认分离,提交返回关联批次,只通过既有/payment-batches复核/回单/登记完成付款。GET只读无隐式确认。每个写入采用版本检查及request key,409可重读不自动重复付款。界面沿现有样式,新增来源显式标签,不采用“非报销=差旅”默认。 T1文档切片完成;T1数据库约束原型、真实并发验证及独立审阅尚未完成,不勾原8项AC。T2–T4产品实现准入仍取决于本方案审阅和相关敏感恢复风险处置。没有运行Prisma迁移、建本地库、真实OCR、秘密/资料读取或付款。