Files
order_site/docs/财务系统集成方案.md
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

26 KiB
Raw Permalink Blame History

财务系统集成方案

状态:现行方案(影子总账 P0 已实施,2026-10-26)。finance_accounts / journal_entries / journal_lines / periods / reconciliations 已建;总账不接管钱包余额;对账当前为手工账单导入,平台自动拉单待接。 最后校准:2026-10-26 代码基线:dev(迁移到 111,未推送、未部署生产) 说明:本文是总账/对账/关账的目标架构与分期;当前已实施 P0(销售事实凭证、手工凭证、试算平衡、期间关账、手工账单对账)与快手平台退款。初始化步骤见 财务上线初始化与验收-2026-10-26.md。 履约方式、成本模型、人工全覆盖口径以 财务与履约口径总纲-2026-10-23.md 为准;本文不重复分类设计。 目标:在不破坏现有抢单、押金、结算、寄卖、提现链路的前提下,增加可对账、可关账、可追溯的复式记账底座。 结论先说:不要直接在 worker_wallets / worker_wallet_ledgers 上继续加字段。 现有表是业务钱包与流水,不是会计总账;正确做法是新增复式记账底座,让现有钱包成为它的“余额投影”。

如果只想知道“影子总账”是什么、为什么先跑影子账:先读 影子总账说明.md。


〇、当前实施状态

能力 状态
客服备用金台账(fund_* / 备用金 manual_expenses) 已实施 P0;账户编号 FA-<用户名>;客服只能使用本人账户
商品主数据 / 渠道 SKU 映射 / 成本中心 已实施 P0(dev 分支),迁移 103/104;标准商品 745 个,只覆盖自动发货 38 + 接单平台 707
sales_daily_facts / 订单级毛利 已实施 P0(dev 分支),迁移 105;94 天收入 ¥2,650.87 万、成本 ¥950.27 万
人工成本录入(确认履约 → 扣积分/备用金 → 写快照) 已实施 P0(dev 分支),迁移 104/107;2026-10-24 人工履约页下线、入口收敛到订单页;无登记单、无审批、无报销
履约方式统一 fulfillment_mode 已实施 P0(dev 分支);迁移 105,316,585 项已回填;订单页、成本快照、销售事实统一读该字段
finance_accounts / finance_journal_entries / finance_journal_lines 已实施 P0(迁移 108)
finance_periods / finance_reconciliations / finance_reconciliation_items 已实施 P0(迁移 108)
finance_business_events / finance_settlements 未实施(当前用条目唯一键幂等)

| 现有 admin-finance-service.ts | 仍是业务事件 UNION ALL,不是总账 |

人工成本只有一条链路:订单列表/详情点「确认履约」→ 扣客服积分或备用金 → 写 cost_snapshots(subject_type='manual_case')。没有独立的人工支出登记表,也没有审批与报销环节。


一、现有财务能力盘点

1.1 已有表

表 作用 现状
worker_wallets 打手资金汇总 available_amount / frozen_deposit_amount / pending_unfreeze_amount / frozen_withdraw_amount / total_credited_amount / total_settled_amount
worker_wallet_ledgers 打手资金流水 ledger_type / amount / balance_after / frozen_after / audit_status / payload_json
worker_deposit_unfreezes 押金/报酬延迟解冻队列 到点后由调度任务入账
worker_finance_requests 充值/提现申请 request_type / status / amount / frozen_amount
worker_withdrawal_accounts 提现账户 多渠道、二维码、黑名单
worker_after_sales_cases / worker_after_sales_debts 售后追责与欠款 欠款可从后续报酬抵扣
worker_wallet_ledgers.payload_json 寄卖发布押金等扩展信息 kind / consignmentSubmissionId 等
consignment_submissions / consignment_inventories 寄卖发布押金与货款 押金冻结/释放/没收、供货货款结算

1.2 已有后台财务页

apps/backend/src/services/admin/admin-finance-service.ts 目前用一条大 UNION ALL 把订单收款、退款、打手报酬、提现、充值、售后追缴拼成“财务事件”,输出日汇总与流水。

这不是总账:

  • 没有借贷方向,无法验证每笔业务是否平衡。
  • 没有会计科目、期间、关账。
  • 没有平台侧账单与对账差异。
  • 没有订单级收入/成本/毛利。
  • 没有业务事件幂等键,重放可能重复统计。
  • 余额是可变字段,无法从流水独立重算并校验。

1.3 现有资金动作(必须全部纳入财务)

业务动作 代码入口 财务性质
订单支付 services/order/order-service.ts 收入/预收 + 平台应收
订单退款 订单状态回流、售后 冲减收入/应收
工单验收结算 repositories/worker-platform/work-order-settlement-repo.ts 履约成本 + 应付打手
抢单冻结押金 work-order-grab-repo.ts 打手余额 → 押金负债
验收释放押金 work-order-settlement-repo.ts 押金负债 → 打手余额
取消/超时没收押金 work-order-cancel-repo.ts 押金负债 → 违约金收入
拼单份额结算 work-order-settlement-repo.ts 按份额拆分成本/押金
售后扣款/欠款抵扣 after-sales-repo.ts 冲减应付打手 / 其他应收
充值审核通过 worker-finance-request-service.ts 银行存款 → 打手余额
提现申请/审核 同上 打手余额 → 银行存款
寄卖发布押金 consignment-deposit-repo.ts 打手余额 → 押金负债
寄卖货款结算 consignment-deposit-repo.ts 采购成本/存货 → 应付卖家
平台服务费/通道费 目前未单独建模 销售费用/财务费用

1.4 履约方式与成本中心的前置关系

财务总账需要先知道“这笔钱属于哪个商品、哪个店铺、哪种履约方式、用了哪个成本版本”:

履约方式 实现 成本模型 财务侧
自动发货 affiliate_dash 上游固定成本 → cost_versions 采购成本
接单平台 work_orders 模板规则版本 / 工单实际报酬 履约成本 + 押金负债
历史平台 ct_assisted / feifei(已下线) 历史成本未采集则单列 仅历史报表
人工 无工单、无自动发货任务、无历史平台任务 逐单实际金额,确认履约直接扣积分/备用金 人工成本 + 备用金

电子凭证只是核销码,不进入上述分类。

因此建议顺序是:

统一履约事实(fulfillment_mode + 成本模型)
  -> 商品主数据 + 渠道SKU映射
  -> 成本中心(cost_items / cost_versions / cost_snapshots)
  -> 销售事实(sales_daily_facts)
  -> 影子总账(finance_*)
  -> 对账 / 转正

详细设计见 财务与履约口径总纲-2026-10-23.md 与 成本中心与履约模型.md。


二、建设原则

  1. 复式记账:每笔业务至少两行分录,借方合计 = 贷方合计;不平不允许提交。
  2. 不可变:已过账分录禁止 UPDATE / DELETE;冲正用反向分录。
  3. 业务事件幂等:每个业务动作有唯一 business_event_id,重复投递只入账一次。
  4. 金额只用整数分:数据库 BIGINT,禁止浮点。
  5. 钱包是投影:worker_wallets 的余额必须能由总账分录重算出来;差异告警。
  6. 同一事务:业务状态变更与会计分录在同一数据库事务内提交,避免“货发了、账没记”。
  7. 期间可关账:关账后禁止补记;必须用调整分录并留原因。
  8. 对账优先:先做影子账 + 对账,再切换钱包读模型,不做一次性大爆炸迁移。

三、目标架构

flowchart LR
  BIZ["业务动作<br/>订单/工单/寄卖/提现/售后"] --> OUTBOX["finance_business_events<br/>幂等事件"]
  OUTBOX --> POST["finance-posting-service<br/>借贷规则"]
  POST --> JE["finance_journal_entries"]
  JE --> JL["finance_journal_lines"]
  JL --> ACC["finance_accounts<br/>科目表"]
  JL --> PROJ["余额投影<br/>worker_wallets / 平台应收应付"]
  EXT["平台账单 / 支付流水"] --> REC["finance_reconciliations"]
  PROJ --> REC
  REC --> REPORT["试算平衡 / 利润表 / 订单损益"]

3.1 科目表(建议)

编码 科目 类型 正常方向
1001 银行存款 资产 借
1002 支付通道待结算 资产 借
1101 应收账款-平台 资产 借
1201 预付账款-供货平台 资产 借
1301 其他应收-打手欠款 资产 借
2001 应付打手报酬 负债 贷
2002 应付卖家货款 负债 贷
2003 打手押金 负债 贷
2004 打手可提现余额 负债 贷
2005 其他应付-垫付人 负债 贷
2101 应付平台服务费 负债 贷
2201 预收账款 负债 贷
3001 本年利润 权益 贷
4001 商品销售收入 收入 贷
4101 平台服务费收入 收入 贷
4201 违约金/没收押金收入 收入 贷
5001 商品采购成本 成本 借
5101 履约成本-打手报酬 成本 借
5102 履约成本-人工客服 成本 借
5201 支付通道费 费用 借
5301 售后损失 费用 借
5401 平台服务费 费用 借

科目可按实际业务裁剪,但“资产/负债/权益/收入/成本费用”五类与借贷方向必须先定死。

3.2 核心表

-- 科目
CREATE TABLE finance_accounts (
  id BIGSERIAL PRIMARY KEY,
  account_code TEXT NOT NULL UNIQUE,
  account_name TEXT NOT NULL,
  account_type TEXT NOT NULL CHECK (account_type IN ('asset','liability','equity','revenue','expense')),
  normal_side TEXT NOT NULL CHECK (normal_side IN ('debit','credit')),
  parent_id BIGINT REFERENCES finance_accounts(id),
  status TEXT NOT NULL DEFAULT 'active',
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

-- 业务事件收件箱:幂等闸门
CREATE TABLE finance_business_events (
  id BIGSERIAL PRIMARY KEY,
  business_event_id TEXT NOT NULL UNIQUE,
  event_type TEXT NOT NULL,
  source_type TEXT NOT NULL,
  source_id TEXT NOT NULL,
  occurred_at TIMESTAMPTZ NOT NULL,
  payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  status TEXT NOT NULL DEFAULT 'received'
    CHECK (status IN ('received','posted','failed','ignored')),
  attempts INTEGER NOT NULL DEFAULT 0,
  last_error TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL,
  processed_at TIMESTAMPTZ
);

-- 结算单(打手报酬 / 卖家货款 / 平台服务费)
CREATE TABLE finance_settlements (
  id BIGSERIAL PRIMARY KEY,
  settlement_no TEXT NOT NULL UNIQUE,
  counterparty_type TEXT NOT NULL CHECK (counterparty_type IN ('worker','supplier','platform','other')),
  counterparty_id TEXT NOT NULL DEFAULT '',
  period_key TEXT NOT NULL,
  amount_fen BIGINT NOT NULL DEFAULT 0,
  status TEXT NOT NULL DEFAULT 'pending'
    CHECK (status IN ('pending','approved','paid','cancelled')),
  approved_at TIMESTAMPTZ,
  paid_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE TABLE finance_settlement_items (
  id BIGSERIAL PRIMARY KEY,
  settlement_id BIGINT NOT NULL REFERENCES finance_settlements(id) ON DELETE CASCADE,
  source_type TEXT NOT NULL,
  source_id TEXT NOT NULL,
  amount_fen BIGINT NOT NULL DEFAULT 0,
  created_at TIMESTAMPTZ NOT NULL
);

-- 凭证头
CREATE TABLE finance_journal_entries (
  id BIGSERIAL PRIMARY KEY,
  entry_no TEXT NOT NULL UNIQUE,
  business_event_id TEXT NOT NULL UNIQUE REFERENCES finance_business_events(business_event_id),
  entry_type TEXT NOT NULL,
  occurred_at TIMESTAMPTZ NOT NULL,
  posted_at TIMESTAMPTZ NOT NULL,
  period_key TEXT NOT NULL,
  currency TEXT NOT NULL DEFAULT 'CNY',
  memo TEXT NOT NULL DEFAULT '',
  status TEXT NOT NULL DEFAULT 'posted' CHECK (status IN ('draft','posted','reversed')),
  reversal_of_id BIGINT REFERENCES finance_journal_entries(id),
  created_by TEXT NOT NULL DEFAULT 'system',
  created_at TIMESTAMPTZ NOT NULL
);

-- 凭证行
CREATE TABLE finance_journal_lines (
  id BIGSERIAL PRIMARY KEY,
  entry_id BIGINT NOT NULL REFERENCES finance_journal_entries(id) ON DELETE RESTRICT,
  line_no INTEGER NOT NULL,
  account_id BIGINT NOT NULL REFERENCES finance_accounts(id),
  debit_fen BIGINT NOT NULL DEFAULT 0,
  credit_fen BIGINT NOT NULL DEFAULT 0,
  order_id BIGINT,
  work_order_id BIGINT,
  worker_id BIGINT,
  shop_id TEXT NOT NULL DEFAULT '',
  provider TEXT NOT NULL DEFAULT '',
  settlement_id BIGINT REFERENCES finance_settlements(id),
  memo TEXT NOT NULL DEFAULT '',
  dimensions_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  CHECK (debit_fen >= 0 AND credit_fen >= 0),
  CHECK ((debit_fen > 0) <> (credit_fen > 0)),
  UNIQUE (entry_id, line_no)
);

-- 会计期间
CREATE TABLE finance_periods (
  period_key TEXT PRIMARY KEY,          -- 2026-10
  starts_at TIMESTAMPTZ NOT NULL,
  ends_at TIMESTAMPTZ NOT NULL,
  status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open','closed')),
  closed_at TIMESTAMPTZ,
  closed_by TEXT NOT NULL DEFAULT ''
);

-- 对账批次 / 明细
CREATE TABLE finance_reconciliations (
  id BIGSERIAL PRIMARY KEY,
  channel TEXT NOT NULL,                -- 91 / kuaishou / pdd / douyin / affiliate_dash / alipay
  period_key TEXT NOT NULL,
  expected_fen BIGINT NOT NULL DEFAULT 0,
  actual_fen BIGINT NOT NULL DEFAULT 0,
  diff_fen BIGINT NOT NULL DEFAULT 0,
  status TEXT NOT NULL DEFAULT 'pending'
    CHECK (status IN ('pending','matched','diff','resolved')),
  created_at TIMESTAMPTZ NOT NULL,
  resolved_at TIMESTAMPTZ
);

CREATE TABLE finance_reconciliation_items (
  id BIGSERIAL PRIMARY KEY,
  reconciliation_id BIGINT NOT NULL REFERENCES finance_reconciliations(id) ON DELETE CASCADE,
  source_type TEXT NOT NULL,
  source_id TEXT NOT NULL,
  external_no TEXT NOT NULL DEFAULT '',
  expected_fen BIGINT NOT NULL DEFAULT 0,
  actual_fen BIGINT NOT NULL DEFAULT 0,
  diff_fen BIGINT NOT NULL DEFAULT 0,
  resolution TEXT NOT NULL DEFAULT '',
  created_at TIMESTAMPTZ NOT NULL
);

3.3 业务事件 → 分录规则(建议)

冲正不修改原凭证:新建一条 business_event_id = <原ID>:reverse 的反向凭证,并让 reversal_of_id 指向原凭证;原凭证保持 posted 不变。

事件 借方 贷方 备注
订单支付 1002 支付通道待结算 / 1101 应收平台 2201 预收账款 金额 = 用户实付(已确认);确认时点待拍板
履约完成/验收 2201 预收账款 4001 商品销售收入 或按交付时点确认
工单验收结算 5101 履约成本 2001 应付打手报酬 按份额逐笔
打手报酬转可提现 2001 应付打手报酬 2004 打手可提现余额 与现有 reward_settlement 对齐
抢单冻结押金 2004 打手可提现余额 2003 打手押金 不产生损益
释放押金 2003 打手押金 2004 打手可提现余额 不产生损益
没收押金 2003 打手押金 4201 违约金收入 需原因与审计
提现审核通过 2004 打手可提现余额 1001 银行存款 先冻结后扣减
充值审核通过 1001 银行存款 2004 打手可提现余额 需支付流水号
售后扣款 2001/2004 1301 其他应收-打手欠款 欠款不足转 worker_after_sales_debts
寄卖发布押金 2004 打手可提现余额 2003 打手押金 与普通押金分维度
寄卖验收货款 5001 商品采购成本 2002 应付卖家货款 货款金额取 `cost_price_fen
支付卖家货款 2002 应付卖家货款 1001 银行存款 需结算单
平台服务费 5401 平台服务费 2101 应付平台服务费 从平台账单导入
确认履约(客服垫付) 5102 履约成本-人工客服(按 cost_item_id 映射科目) 2005 其他应付-垫付人 扣客服积分/备用金时同步发生;不需要单独审批
客服备用金发放 1001 银行存款 2005 其他应付-垫付人 主管发放时发生
退款冲正(预留) 反向凭证 reversal_of_id 指向原凭证 — 退款/仲裁暂未接入,先预留不实现

已确认(2026-10-17):收入金额口径 = 用户实付;打手报酬 = 支出(总额法);退款/仲裁先预留;人工支出以登记表为入口。 仍待拍板:收入确认时点(付款 / 发货 / 验收 / 售后期结束),它直接影响利润表与预收账款。


四、与现有代码的接入方式

4.1 唯一记账入口

新增 apps/backend/src/services/finance/finance-posting-service.ts:

postBusinessEvent({
  businessEventId,   // 业务唯一键,如 work_order:123:settle
  eventType,         // work_order_settled
  sourceType,        // work_order
  sourceId,          // 123
  occurredAt,
  lines: [...],      // 借贷行
})

约束:

  • 在业务事务内调用;使用同一个 PoolClient。
  • finance_business_events 先 INSERT ... ON CONFLICT DO NOTHING。
  • 已存在则直接返回,不重复入账。
  • 校验借贷平衡;不平抛错并回滚业务事务。
  • 写入 finance_journal_entries / finance_journal_lines。
  • 更新钱包投影(或由投影任务异步更新,但同一事务更安全)。

4.2 需要改造的写入点

位置 改造
services/order/order-service.ts 订单支付/退款发事件
repositories/worker-platform/work-order-settlement-repo.ts 验收结算、押金释放、报酬入账发事件
work-order-grab-repo.ts 抢单冻结押金发事件
work-order-cancel-repo.ts 取消/超时没收押金发事件
after-sales-repo.ts 售后扣款/欠款抵扣发事件
worker-finance-request-service.ts 充值/提现审核发事件
consignment-deposit-repo.ts 发布押金、货款结算发事件
services/finance/manual-fulfillment-service.ts(已实施) 确认履约成功时发事件;主体是积分流水 / 备用金支出
admin-finance-service.ts 改为读总账/试算平衡,不再用 UNION ALL 拼报表

4.3 钱包投影一致性

第一阶段保留现有钱包更新逻辑,同时写总账;第二阶段再切换:

  1. 影子期:业务照旧改钱包,同时写总账;每日比较“钱包余额”与“总账重算余额”。
  2. 校验期:差异为 0 连续 N 天后,后台展示“总账余额”为准。
  3. 切换期:钱包读接口改为读投影;旧字段保留一个版本用于回滚。
  4. 清理期:删除重复的余额更新代码,只保留总账 + 投影。

五、后台页面与 API

5.1 页面

页面 内容
财务总览 收入、成本、毛利、押金负债、可提现余额、待结算
凭证簿 按期间/事件/科目/订单筛选;查看借贷行
科目表 科目树、启用/停用、期初余额
结算中心 打手报酬、卖家货款、平台服务费结算单
对账中心 平台账单导入、差异明细、处理状态
期间关账 月末检查、关账、反关账(需高权限)
订单损益 单笔订单收入、采购成本、打手报酬、退款、毛利
试算平衡 / 利润表 按期间导出

5.2 API

已实现(P0,销售事实、成本快照与人工支出):

GET  /api/v1/admin/finance/sales-profit/overview
GET  /api/v1/admin/finance/sales-facts
POST /api/v1/admin/finance/sales-facts/rebuild
POST /api/v1/admin/cost-center/snapshots/sync
GET  /api/v1/admin/orders/:orderId/refunds
POST /api/v1/admin/orders/:orderId/refunds
POST /api/v1/admin/orders/:orderId/refunds/:refundId/void

2026-10-23 下线了 /finance/manual-expenses* 全套接口(登记/审批/报销)。 2026-10-24 下线 /finance/manual-order-cost*(人工录单),改为 GET /finance/manual-fulfillment/pending + POST /finance/manual-fulfillment/confirm。 2026-10-24 上线手动退款登记(order_refunds):整单退款按订单项拆条、共享 batch_no,销售事实按有效退款冲减;后续平台退款 API 只需写 source='api'/'platform' + external_ref,其余聚合与冲减逻辑复用。

总账层建议新增前缀 /api/v1/admin/finance:

GET  /accounts
POST /accounts
GET  /journal?period=&eventType=&orderId=&workOrderId=
GET  /journal/:id
GET  /trial-balance?period=
GET  /profit-loss?period=
GET  /order-profit/:orderId
GET  /settlements
POST /settlements/:id/approve
GET  /reconciliations
POST /reconciliations/import
POST /reconciliations/:id/resolve
GET  /periods
POST /periods/:key/close

权限建议新增:

  • finance.post:手工分录
  • finance.close:关账
  • finance.reconcile:对账处理
  • 现有 finance.view / review / config / export 继续使用

所有写操作必须写 admin_audit_logs;关账、手工分录、冲正必须填原因。


六、总账层分期

项目级顺序以 README.md §三 为准;本节只描述“总账层”内部阶段。 进入 P0 前应已完成:统一履约事实、商品主数据、渠道 SKU 映射、成本中心、销售事实、确认履约(manual-fulfillment-service)。

P0:影子总账(1–2 周)

前置:先完成统一履约事实、商品主数据、渠道 SKU 映射、成本中心与销售事实(见 财务与履约口径总纲-2026-10-23.md)。否则影子总账只能记“总额”,无法按店铺/皮肤/成本版本出毛利。

  • 建 finance_accounts / business_events / journal_entries / journal_lines / periods。
  • 先接高频且核心的事件:订单支付、工单结算、押金冻结/释放/没收、提现,以及确认履约。
  • 写总账但不改现有钱包逻辑。
  • 每日对账:钱包余额 vs 总账余额。
  • 补金额守恒与幂等测试。

P1:寄卖、售后、充值与结算(1–2 周)

  • 接寄卖发布押金、货款结算、售后欠款/抵扣、打手充值。
  • 建 finance_settlements / finance_settlement_items。
  • 后台增加凭证簿与试算平衡。

P2:平台对账(2–3 周)

  • 接 91 / 快手 / PDD / 抖音 / affiliate-dash 账单或导出。
  • 建 finance_reconciliations / finance_reconciliation_items。
  • 差异必须能定位到订单/工单/提现单。
  • 对账差异不自动改账,必须人工确认后生成调整分录。

P3:报表与关账(2 周)

  • 利润表、订单损益、现金流量简表。
  • 期间关账、反关账、期初余额。
  • 导出与权限审计。

P4:钱包切换(1 周,需灰度)

  • 钱包读模型切到总账投影。
  • 旧字段保留一个版本;差异告警。
  • 回滚方案:关闭投影读开关,回到旧钱包字段。

七、必须补的测试

  1. 每笔凭证借方合计 = 贷方合计。
  2. 同一 business_event_id 重复投递只入账一次。
  3. 冲正后原凭证 + 反向凭证净额为 0。
  4. 钱包余额 = 总账重算余额。
  5. 抢单冻结 / 验收释放 / 取消没收的押金守恒。
  6. 拼单多份额:份额报酬 + 押金 + 欠款抵扣 = 钱包变化。
  7. 提现:申请冻结、审核通过、拒绝解冻三条路径。
  8. 寄卖:发布押金、驳回释放、验收货款、撤销处置。
  9. 售后:扣款、欠款、后续报酬抵扣。
  10. 关账后禁止补记;调整分录必须留原因。
  11. 对账:平台金额、订单金额、钱包金额三方差异可定位。

八、需要业务拍板的问题

2026-10-17 已确认 4 条口径,2026-10-22/23 追加确认收入时点、人工支出与电子凭证口径;明细见 财务与履约口径总纲-2026-10-23.md。

# 问题 状态 影响
1 收入金额口径 ✅ 已确认:收入 = 用户实付(orders.total_amount),与快手 paymentFen 数据核验 100% 一致 收入基数
2 收入确认时点:付款 / 发货 / 验收 / 售后期结束? ✅ 先按 paid_at 归属销售日;成本快照生成后回填到同一销售日 决定利润表与预收账款
3 平台结算周期与账单口径(91、快手、PDD、抖音、affiliate-dash) ⏳ 待定 决定对账与应收
4 打手报酬是“成本”还是“代收代付”? ✅ 已确认:支出/成本(最终提现打款),按总额法 收入总额法/净额法
5 寄卖货款的采购成本确认时点 ⏳ 待定 决定存货/成本
6 提现通道费、平台服务费由谁承担 ⏳ 待定 决定费用科目与结算
7 退款、拒付、仲裁的冲减规则 ✅ 已确认:暂未接入,先预留(字段 + reversal_of_id + 事件类型,不实现逻辑) 决定售后与收入冲回
8 人工支出如何入账 ✅ 已确认:逐单实际金额,确认履约直接扣积分/备用金并写成本快照;无登记单/审批/报销;历史人工支出找不回来、直接放弃 决定人工成本与备用金
9 电子凭证是否作为履约/成本分类 ✅ 不参与分类;电子凭证只是快手核销码 决定报表口径
10 历史人工支出 ✅ 不补录,只取少量样本校准;上线后人工单必须 100% 有成本记录 决定上线范围
11 是否需要发票/税务 ⏳ 待定 决定发票表与税额
12 是否多币种 ⏳ 待定(当前 CNY) 若否则需汇率与汇兑损益

九、一句话结论

财务系统应作为“总账层”接入,而不是继续扩展业务钱包。 先把商品主数据、成本中心、人工 case 与销售事实补齐,再以影子总账 + 幂等业务事件 + 每日对账落地;确认钱包与总账长期一致后,再切换余额读模型。这样既能保护现有抢单/押金/寄卖链路,也能为平台结算、订单损益和关账留出正确底座。