Commit Graph
15 Commits
Author SHA1 Message Date
yml2213 dc78dc92d1 feat(cost-center): 接单模板商品全量同步,改价默认立即生效 2026-10-29 21:44:29 +08:00
yml2213 9d5af359fa feat(finance): 完成财务控制、L1 钱包硬化与迁移收敛
- P0/P1:影子总账追加调整、关账/退款/资金/积分幂等、成本版本追溯、对账订单项维度
- 迁移收敛:原 103–114 合并为 103_finance_foundation、104_finance_controls、105_work_order_consignment
- 数据:L1 钱包 BIGINT/CHECK/奖励幂等;重复奖励审计口径修正与人工核对清单
- 报表:销售毛利缺失成本收入提示,旧收支页明确现金流口径
- 文档:同步迁移基线、合并评估、代码复核与上线说明
2026-10-27 16:08:16 +08:00
yml2213 0de0fd7b58 chore(db): 将 108–115 补丁迁移收敛为 108–111
- 原 108/111/112/113/114 合并为 108_finance_cost_integrity:
  成本异常归档、人工成本完整性、影子总账、商品页/模板查询索引
- 原 115 注释迁移改为 111_work_order_share_cancel_reason_comment
- 新增 reconcile-migration-history.sql,用于已跑旧 112–115 的库
  重建 schema_migrations 顺序,不重复执行 DDL
- 已验证:001→111、101→111 两条升级路径;
  旧 115 与新 111 的 pg_dump schema 完全一致
- 测试/文档迁移编号同步到 103–111

验证:backend check 853(849 pass / 4 skip);frontend check 172 + build。
2026-10-27 12:37:21 +08:00
yml2213 2b967ddd4c feat(cost-center): 商品初始化/回填增加时间范围,默认最近 30 天
- 接单模板初始化预览/执行支持 dateFrom/dateTo,只使用范围内工单证据;
  范围外模板不再先建商品
- 按工单回填商品支持时间范围;人工商品归一 UI 传时间范围
- 模板初始化重置只清理范围内导入映射/订单项,避免误伤范围外数据
- 初始化/回填默认最近 30 天,自动发货仍固定 30 天
- 文档更新初始化口径与页面操作
2026-10-26 16:26:48 +08:00
yml2213 6dc1e7e727 fix(scheduler): 成本财务同步默认回退最近 7 天,避免小库语句超时 2026-10-26 15:49:51 +08:00
yml2213 62763ddf0c feat(finance): 支持代录指定客服账户,并上线影子总账/对账/关账/快手平台退款
- 人工确认履约:管理员/财务/运营可传 fundAccountId / creditOwnerAdminUserId
  指定客服备用金/积分账户;客服仍强制本人账户
- 新增迁移 112:finance_accounts / journal_entries / journal_lines /
  periods / reconciliations / reconciliation_items,种子 11 个科目
- 影子总账:销售事实按日生成收入/退款/成本凭证,支持手工凭证、试算平衡;
  不接管钱包余额;总账同步接入定时任务与退款重算
- 期间关账/反关账:关账先补凭证并校验试算平衡,closed 期间禁止新增凭证
- 平台对账:JSON 账单导入,按 provider + platform_order_id 匹配订单/退款,
  标记 matched/amount_mismatch/missing_order/missing_refund/duplicate
- 平台退款:快手行业(91)同意退款 API 接入,成功后落 source=platform;
  抖音/拼多多返回 501,保留手工退款
- 新增后台「财务 → 总账与对账」页面(总账/期间/对账三个 Tab)
- 集成测试扩展到代录、总账平衡、关账阻断、手工凭证、对账匹配

验证:backend check 844(840 pass / 4 skip);frontend check 172 + build;
迁移 112 在 scratch 库全量执行并重跑幂等;本地生产副本已升级到 112,
销售事实同步 56 条凭证,借贷合计 1,885,351,864 = 1,885,351,864。
2026-10-26 13:32:47 +08:00
yml2213 a3e2bdb7c4 feat(finance): 人工成本单事务/幂等 + 配置自动匹配 + 缺成本监控
- 确认履约改为单事务:锁订单项 → 复查快照 → 扣积分/备用金 → 写成本快照;
  快照失败整体回滚,不再出现「钱扣了、成本没记」
- manual_case 的 subject_id 统一为 order_item_id,新增订单项级唯一索引(迁移 111),
  消除 manual_expenses.id / platform_credit_entries.id 跨表撞车
- 人工 SKU 匹配增加 sku_code / sku_name 兜底;保存配置立即回填最近 30 天,
  定时任务按窗口 rematch,确认时再按 SKU 兜底匹配
- 新增 manual_cost_missing 异常队列:从首次人工配置起算,确认履约立即收口
- 补单元测试与真实 PostgreSQL 集成测试(并发、重复、强制快照失败回滚、双资金链路)
- 校准财务文档并新增上线初始化/验收手册(历史人工不补录,只保证配置后的新单)

验证:backend typecheck/lint/format/check:sql/test 843(839 pass / 4 skip);
frontend typecheck/lint/test 172;迁移 111 在 scratch 库全量执行 + 重跑幂等。
2026-10-26 13:04:51 +08:00
yml2213 39fe448b48 feat(cost-exceptions): 支持 --days=0 一次性归档
一次性清理需要「不按时间过滤」的语义,但 CLI 把 days 下限钳在 1:
本地库的 15.2 万条 resolved 异常是 17 小时前重建生成的,
--days=1 一条都命中不了,只能手写 SQL。

- --days=0 表示不过滤时间,归档全部已处理行(open 仍不归档);
- 执行时打印一次性清理提示,避免日常误用;
- 记录 2026-10-25 的实际清理结果:151,939 行 / 152 批 / 3.9 秒,
  热表 260,253 → 108,314(全为 open),VACUUM FULL 后 155 MB → 51 MB,
  归档表 61 MB,主键重叠 0 条。

验证:--days=0 --dry-run 返回 retentionDays=0、archivableRows=0(已清空)。
2026-10-25 13:34:09 +08:00
yml2213 d90c066888 feat(cost-center): 成本异常 60 天归档
cost_exceptions 只增不减:本地快照 260,253 行(resolved 151,939 / open 108,314),
已处理的行只是审计痕迹,留在热表会拖慢「状态 + 时间」分页,并让唯一索引持续膨胀。

- 迁移 108:新增 cost_exceptions_archive(保留原 id 与时间字段,加 archived_at),
  热表补部分索引 idx_cost_exceptions_archivable
  (COALESCE(resolved_at, created_at)) WHERE status <> 'open',让每日任务不扫全表;
- cost-exception-archive-service:只归档 status <> 'open' 且超期的行,每批 1000 行,
  DELETE ... RETURNING + INSERT 在同一语句内完成,单批原子,不存在「删了没归档」;
- data-retention 每日任务接入;保留期走 COST_EXCEPTION_RETENTION_DAYS(默认 60);
- 新增 npm run cost-exceptions:archive(--dry-run / --days / --batch-size)。

为什么 open 行不归档:open 是待办队列,超期不等于已解决,归档等于把问题藏起来。

验证:
- 3 条 resolved 回拨到 90 天前 → 归档 3 条,热表 resolved 151,939 → 151,936;
- 1 条 open 回拨到 90 天前 → 仍在热表,未被归档;
- 归档表保留原 id 与时间,archived_at 记录归档时刻;
- 恢复测试数据后计数回到 151,939 / 108,314。
2026-10-25 12:09:20 +08:00
yml2213 ad1e1bc884 perf(db): 收入口径回填改为分批脚本
迁移 104 里对 order_items 的全表 UPDATE 实测 34.4 秒(375,447 行),
远超默认语句超时 15s,单事务迁移会拖住启动甚至直接失败。

- 104 只保留 DDL 与索引/约束,删除全表 UPDATE;
- 新增 scripts/backfill-revenue-basis.ts:按 id 分批、幂等、支持
  --dry-run / --batch-size / --max-batches(kebab 与 camel 两种写法);
- package.json 增加 revenue:backfill;
- migrate.ts 启动时做一次带索引计数,仍有 unknown 时打印告警并给出命令,
  不阻塞启动;
- 文档补充回填步骤与「不执行的后果」。

验证:
- 实测 37.5 万行全表更新 34.4s → 脚本按批执行,单批 5000 行;
- 功能验证:单条订单项置 unknown → 脚本回填 → 金额与 basis 恢复正确;
- 启动告警验证:保留 1 条 unknown 重启 → 日志出现告警;回填后计数归零;
- 全新库从 102 迁移到 107 仍成功(2s)。
2026-10-25 12:02:26 +08:00
yml2213 0099597b0d docs: 迁移编号同步为 103–107 并校准分支状态
- 全量替换文档里的旧迁移编号:106→107、107→105、108/109/111→104、112→106、110→107;
- 删除 113/114 的残留引用(这两个编号从未落地);
- 分支状态校准为 `dev @ 465a9f65 + 迁移收敛`,本地库按「清 103–112 记录后重跑」对齐;
- 成本中心与履约模型 §一 重写迁移基线表,§八 改为迁移基线与本地库同步;
- 归档原地改造脚本的索引补登记。
2026-10-25 11:38:18 +08:00
yml2213 7824170d3c fix(finance): 支持生产快照升级并修复成本回填
修复生产 101 到 112 的迁移兼容问题;接单商品回填改为分批执行;修正未验收工单成本快照的 order_id/order_item_id 映射;更新本地生产快照数据基线。
2026-10-25 11:10:33 +08:00
yml2213 790de676c6 feat(admin): 收口人工履约入口并修复履约筛选 2026-10-24 17:42:07 +08:00
yml2213andClaude Opus 4.5 fb679d76f6 refactor(finance): 人工成本收敛为「人工录单 → 扣备用金 → 写快照」
公司人工支出登记单与审批报销状态机整链下线,人工成本只留一条链路。

口径调整(2026-10-23 确认):
- 历史人工支出找不回来,直接放弃:不补录、不做样本校准、不做均价估算,
  只保证上线后的新单不丢。
- 人工成本逐单按实际金额,从客服备用金扣款,客服只能用本人账户;
  没有登记单、没有审批、没有报销,录入即计入毛利。

后端:
- 新增 services/finance/manual-order-cost-service.ts:扣备用金 + 写 actual
  成本快照,同一事务,余额不足直接拒绝不允许负余额。
- 成本快照主体从「人工支出登记单 id」改为「客服备用金支出单 id」
  (subject_type='manual_case',subject_id=manual_expenses.id)。
- 删除 services/finance/manual-expense-service.ts(1263 行)与
  routes/admin/finance.ts 下 /finance/manual-expenses* 全套接口。

前端:
- 删除 AdminManualExpensePage.tsx(778 行)与 /admin/manual-expenses 菜单页。
- ManualOrderCostModal 去掉「提交审核 / 立即计入成本」开关,录入即生效。
- 新增 services/admin/manual-order-cost.ts。

迁移:
- 106_manual_expense_records.sql → 106_fund_account_no_readable.sql,
  只保留备用金账户编号可读化。
- 108_drop_manual_expense_records.sql:删除 manual_expense_records 与
  manual_expense_events 两张表。
- 109_isolate_legacy_manual_snapshots.sql:把来源为旧登记链的历史孤儿快照
  subject_id 改为负数,与 manual_expenses.id 彻底隔离。

踩坑修复(E2E 实测发现):主体 id 换空间后与历史孤儿快照撞唯一索引
uq_cost_snapshots_active_subject_item,INSERT ... ON CONFLICT DO NOTHING
静默跳过,导致「钱从备用金扣了、成本快照却没写成」。修法是迁移 109 隔离
legacy 主体 + 后端快照写失败必须抛错回滚(409),杜绝账实不符。

文档:现行 5 篇 + README 基线校准为 dev @ 43f402cf + 迁移 103–109,
修正已删除的旧迁移号,删除「人工支出登记 + 审批 + 报销」口径,
已作废 DDL 草案移入 docs/archive/2026-10-23/。

校验:后端 765 项 / 0 失败(含 check:sql 迁移护栏),前端 143 项全通过;
E2E 实测两笔同订单项各自独立主体、余额扣减与快照金额一一对应;
本地库迁移 108/109 执行后数据量与改造前完全一致。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
2026-10-24 11:31:29 +08:00
yml2213 43f402cf72 docs(finance): 现行财务文档收敛为 5 篇,履约口径只定义一次
原 9 篇 3,647 行,履约分类口径在总纲、模型文档、交接总结里重复三遍,
且仍留着"三块履约""按小时人工成本"等已作废表述。本次收敛为 5 篇
1,778 行:

- 财务与履约口径总纲-2026-10-23.md(300 行):唯一口径来源
  七条硬口径、三个正交维度、真实履约构成、成本模型规则、人工全覆盖、
  实施顺序、进度、验收 SQL、防回归清单
- 成本中心与履约模型.md(471 行):数据模型、迁移 103–107、履约回填、
  销售事实、本地库原地改造、索引与性能
- 成本中心API契约.md(270 行):字段替换总表、枚举、前后端模块边界
- 人工支出与备用金.md(218 行):人工支出登记字段/状态机/权限 +
  客服备用金台账
- 财务系统集成方案.md:复式总账层(未实施)

旧的 4 篇(成本中心与三块履约模型、人工支出登记落地方案、
客服备用金台账实施方案、财务履约改造交接总结)移入
docs/archive/2026-10-23/ 并加归档提示。

履约分类判定 SQL 只在总纲保留一份,其它文档改为链接。
2026-10-23 16:06:40 +08:00