汇总已落盘的借款本金与还款、兼容历史编号的周期化编号、付款责任与回单核验、报销进度和排序、PWA/采购事务、错误原因与日期校验及ERP退役。 统一共享预算池锁序和锁后判断,恢复差旅原预算选择,补原因码固定夹具及反向完整性检查。 纳入配套迁移、测试、受管QA、分层验收合同、规约及任务记录;原始证据留在ignored artifacts。 关联任务:09-17-company-loan-principal-repayment、09-17-erp-exclusive-retirement、09-18-reimbursement-periodic-numbering、09-08-reimbursement-payment-closeout、09-18-local-concurrency-product-fixes、09-19-budget-pool-concurrency、09-05-error-explainability-payment-readiness。 预算补审由Claude定向验证2文件928项通过,原4446/28及r6结果仍仅对应各自历史输入;本轮未重跑测试。 完整新候选门禁、R1真实入口接入与12项公网义务仍开放。生产编号未启用、差旅仍冻结;不推送、不部署,不宣称发布资格。
17 KiB
2026-09-17 实施细化
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通配不能替代独立身份。
银行备注采用短本金语义,年份不一致时不生成误导性单一年份;长事由留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、秘密/资料读取或付款。