Files
order_site/docs/人工支出与备用金.md
T
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

12 KiB
Raw Blame History

人工支出与客服备用金

状态:现行(P0 已实施,未部署生产)。 最后校准:2026-10-24 2026-10-24 变更:独立「人工履约」页面已下线,订单列表/详情里的「人工录单」改为「确认履约」;/finance/manual-order-cost* 接口已删除。资金链路不变(扣积分/备用金 → 写 manual_case 快照)。 代码基线:dev @ 43f402cf + 迁移 100/101/104/107(已合并到 dev,未推送、未部署生产) 业务口径以 财务与履约口径总纲-2026-10-23.md 为准;本文只负责人工录单的字段、流程、权限与备用金台账。 本文合并自原《人工支出登记落地方案-2026-10-17.md》与《客服备用金台账实施方案-2026-10-18.md》。


〇、只有一条链路:确认履约(原人工录单)

2026-10-23 口径调整:公司人工支出登记单与审批报销状态机整链下线。人工成本现在只有一条路径。

订单列表/详情「确认履约」
  → 扣客服积分或备用金余额(写 fund_entries / platform_credit_entries)
  → 写 cost_snapshots(subject_type='manual_case',subject_id=manual_expenses.id)
表 业务含义 状态 关键字段
manual_expenses 客服备用金支出:客服从自己的备用金账户里充值/采购/赔偿 已实施(迁移 100) account_id / fund_entry_id / category / payee_* / order_item_id / evidence_json
cost_snapshots 人工成本的唯一落点 已实施(迁移 104) subject_type='manual_case' / subject_id=manual_expenses.id / total_amount_fen / snapshot_stage='actual'

结论:

  1. 没有单独的登记单表。manual_expense_records 与 manual_expense_events 已随迁移 104 归并下线。
  2. 没有审批、没有报销。订单页「人工录单」一次操作完成"扣钱 + 记成本",录入即计入毛利。
  3. 客服侧收口的是"备用金余额与用途":钱从谁的备用金出、付给谁、有没有凭证,全在 manual_expenses + fund_entries。
  4. 客服角色只能用本人备用金账户(后端越权直接 403);管理员/财务可代录到指定客服账户。
  5. 余额不足直接拒绝,不允许负余额。
  6. 历史人工支出找不回来,直接放弃:不补录、不做样本回填、不做均价估算。

一、核心口径

  1. 人工成本逐单、按实际金额。 不按小时、不按固定单量、不按固定单价。
  2. 人工支出从客服备用金账户扣款。 余额不足直接拒绝,不允许负余额。
  3. 客服角色只能使用自己的备用金账户。 后端越权直接 403;管理员/财务可代录到指定客服账户。
  4. 历史人工支出找不回来,直接放弃。 不补录、不做样本校准;历史缺口标记 historical_missing,不阻塞上线。
  5. 上线后每一笔人工单必须 100% 有成本记录,否则不允许关账。
  6. 录入必须"发生在垫付当天"才有监管价值;事后补记只能算账,不能算监管。
  7. 客服备用金是周转金台账,不是报销系统。 P0 只做"账户 + 流水 + 支出 + 对账",不做复杂审批和总账。
  8. 人工录单一录到底:没有登记单、没有审批、没有报销。钱与成本在同一次操作里落地。

二、客服备用金台账

2.1 落地结果

项 实际实现
数据库 迁移 100_fund_accounts.sql:fund_accounts / fund_entries / manual_expenses / fund_reconciliations
显示名 迁移 101_admin_display_name.sql:admin_users.display_name,备用金 owner_name 由触发器同步
账户编号 迁移 107_manual_fulfillment.sql:FA-<大写用户名>(如 FA-KF_1、FA-JIAJIALI),重名追加 -2、-3
后端 admin-fund-service.ts、routes/admin/fund.ts;金额全部用分,写操作使用事务与行锁
前端 AdminFundPage.tsx、FundManagementView.tsx、FundSupportView.tsx;管理端与客服端分流
权限 fund.view / fund.issue / fund.expense / fund.reconcile / fund.adjust / fund.export
审计 所有写接口接入 createJsonHandler({ audit })

2.2 系统要回答的四个问题

  1. 公司现在有多少钱在主管和客服手里?
  2. 每个客服当前余额是多少?
  3. 每一笔钱花到哪、为什么花、有没有凭证?
  4. 系统余额和客服实际余额对不对得上?

2.3 账户

fund_accounts 一行 = 一个备用金账户,归属一个管理员(客服或主管)。account_no 必须是 FA-<大写用户名>,重名时按 id 顺序追加 -2、-3。

2.4 流水

fund_entries 是只追加的账户流水。每笔备用金变动写一行,正数=入账,负数=出账,带 entry_type(issue 发放 / expense 支出 / reconcile 对账调整 / adjust 人工调整)与 balance_after 快照。

2.5 支出

manual_expenses 记录一次具体支出:账户、金额(分)、分类(purchase 采购 / compensation 赔偿 / freight 运费 / platform_recharge 平台充值 / other)、收款方信息、凭证、关联的 fund_entry_id。

2.6 对账

fund_reconciliations 记录期初/期末账面余额、实际盘点余额与差异说明。差异必须由主管确认并留痕。

2.7 P0 未实现(仍在 P1)

批量发放/对账、导出、低余额提醒、大额支出主管确认;支出凭证目前只校验数组非空,未校验对象存储 key 是否真实存在。

原「异常队列」指人工支出登记单的审批异常队列,随登记链下线而取消。现在的人工异常只有一类:人工录单匹配不到有效成本版本时写 manual_expense_cost_missing,由成本中心的异常面板统一处理。


三、人工录单

3.1 落点

  • 服务:apps/backend/src/services/finance/manual-order-cost-service.ts;备用金扣款唯一写入口 admin-fund-service.ts 的 writeFundExpense
  • 接口:apps/backend/src/routes/admin/finance.ts 的 POST /finance/manual-order-costs;成本项选项 GET /finance/manual-order-cost-items
  • 组件:apps/frontend/src/components/admin/ManualOrderCostModal.tsx
  • 订单入口:订单列表/详情「人工录单」打开弹窗,锁定订单号、选择订单项与备用金账户、填写本单实际金额;支持深链 /admin/orders/:orderId?manualCost=1
  • 权限:登记 fund.expense / finance.config;客服角色自动锁定本人账户
  • 已删除:迁移 106_manual_expense_records.sql 建的登记单表(迁移 104 归并下线)、manual-expense-service.ts、AdminManualExpensePage.tsx、/admin/manual-expenses 页面与菜单

3.2 资金流与成本流(同一事务)

锁定 fund_accounts 行
  → 校验余额
  → 扣减余额
  → 写 fund_entries
  → 写 manual_expenses(order_id / order_item_id 已带上)
  → 解析成本版本
  → 写 cost_snapshots(actual)

余额不足直接拒绝,不允许负余额。扣钱与记成本在同一个事务里,要么都成功要么都回滚。

3.3 成本快照

以 subject_type='manual_case'、subject_id=manual_expenses.id 写 actual 快照,金额 = 录入的实际金额。

同一订单项多笔支出可累加,不会互相覆盖(唯一键是 subject_type + subject_id + cost_item_id,每笔支出单一个主体)。快照 metadata_json 里记录处理人、收款方、付款方式、费用类型、凭证、履约方式。

没有匹配到有效成本版本时,写 manual_expense_cost_missing 异常(status='open'),不允许静默记 0;此时备用金已经扣了,界面会提示"已扣备用金,但未匹配到有效成本版本,已进入异常队列"。

3.4 录入字段

order_id, order_item_id   -- 订单与订单项(锁定订单号,不允许改)
fund_account_id           -- 备用金账户;客服只能本人
amount_fen                -- 实际金额(分),> 0
expense_category          -- goods_purchase / compensation / refund_advance /
                           -- service_fee / freight / recharge / other
payee_type, payee_name, payee_account
payment_method            -- wechat / alipay / bank / cash / platform_balance / other
note                      -- 备注兼凭证(无附件时)
evidenceJson              -- 凭证(对象存储 key / 流水号 / 聊天记录 key)

费用类型到备用金分类的映射:goods_purchase→purchase、compensation→compensation、freight→freight、recharge→platform_recharge,其余 → other。

3.5 凭证

凭证至少留一项可追溯信息(对象存储 key、流水号、聊天记录 key,或备注文字),否则后端拒绝。


四、订单页「确认履约」

订单里的数据足够预填 90%:店铺、商品、规格、数量、用户实付、支付时间、平台单号、履约标签、状态,后台订单列表/详情已经全部具备。客服实际只需要补 4 件事:渠道/项目、金额、收款方、凭证(外加默认带出的「谁、什么时候」)。

弹窗规则:

  • 锁定订单号,不允许改;
  • 必须选择备用金账户(客服角色自动带入本人账户且不可改);
  • 金额按本单实际金额填写,没有小时单价或固定单量;
  • 录入即生效:扣备用金与写成本快照一次完成,不再有"提交审核"步骤。

五、每日必查与关账门槛

指标 目标
人工订单项无备用金支出单 0
人工订单项无成本快照 0
人工支出金额与备用金流水不一致 0
成本异常 open 中人工项 0(历史标记除外)

关账门槛:

  • 存在人工单无成本记录:不允许关账;
  • 存在人工单未扣备用金:不允许关账;
  • 存在人工支出与备用金流水金额不一致:不允许关账。

核对 SQL 见 财务与履约口径总纲-2026-10-23.md §八。


六、异常处理

  • 发现人工单无成本:当天补录;补录走人工录单,仍然从备用金扣款,不允许直接改余额。
  • 备用金余额不足:拒绝录入,由主管补拨后再录;不允许负余额。
  • 人工录单匹配不到成本版本:备用金已扣,成本异常进队列;补齐 sys_manual_service 的有效版本后重新解析。
  • 同一订单项多笔支出:允许累加(渠道费、加急费、补差价),但每笔都必须有独立备用金流水。
  • 历史人工单:标记 historical_missing,找不回来、直接放弃,不补录、不计入上线后缺口。

七、历史人工:直接放弃

历史人工支出找不回来,口径明确为放弃:

  • 不补录、不回填 cost_snapshots;
  • 不做样本抽取与均价估算;
  • 不阻塞上线,历史缺口在销售事实里标记 historical_missing;
  • 只保证上线后的新单不丢:人工单必须有备用金支出与成本快照。

历史平台 53,901 项同理,只有拿到旧平台结算数据才允许按历史成本入账。


八、关联文档