# 人工支出与客服备用金 > 状态:**现行(P0 已实施,待部署生产)**。 > 最后校准:2026-10-26(人工确认改单事务、subject_id 归一、配置自动匹配、人工缺成本入队列) > **2026-10-24 变更**:独立「人工履约」页面已下线,订单列表/详情里的「人工录单」改为「确认履约」;`/finance/manual-order-cost*` 接口已删除。资金链路不变(扣积分/备用金 → 写 `manual_case` 快照)。 > 代码基线:`dev @ 43f402cf + 迁移 100/101/104/107`(已合并到 `dev`,**未推送、未部署生产**) > **业务口径以 [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) 为准**;本文只负责人工录单的字段、流程、权限与备用金台账。 > 本文合并自原《人工支出登记落地方案-2026-10-17.md》与《客服备用金台账实施方案-2026-10-18.md》。 --- ## 〇、只有一条链路:确认履约(原人工录单) 2026-10-23 口径调整:**公司人工支出登记单与审批报销状态机整链下线**。人工成本现在只有一条路径。 ```text 订单列表/详情「确认履约」 → 扣客服积分或备用金余额(写 fund_entries / platform_credit_entries) → 写 cost_snapshots(subject_type='manual_case',subject_id=order_item_id) ``` | 表 | 业务含义 | 状态 | 关键字段 | | --- | --- | --- | --- | | `manual_expenses` | **客服备用金支出**:客服从自己的备用金账户里充值/采购/赔偿 | 已实施(迁移 `100`) | `account_id` / `fund_entry_id` / `category` / `payee_*` / `order_item_id` / `evidence_json` | | `cost_snapshots` | **人工成本的唯一落点** | 已实施(迁移 `104` + 完整性兜底 `111`) | `subject_type='manual_case'` / `subject_id=order_item_id` / `total_amount_fen` / `snapshot_stage='actual'`;资金来源写 `metadata_json.fundExpenseId / creditEntryId` | 结论: 1. **没有单独的登记单表**。`manual_expense_records` 与 `manual_expense_events` 已随迁移 `104` 归并下线。 2. **没有审批、没有报销**。订单页「人工录单」一次操作完成"扣钱 + 记成本",录入即计入毛利。 3. 客服侧收口的是"备用金余额与用途":钱从谁的备用金出、付给谁、有没有凭证,全在 `manual_expenses` + `fund_entries`。 4. 客服角色只能用本人备用金账户(后端越权直接 403);管理员/财务可代录到指定客服账户。 5. 余额不足直接拒绝,**不允许负余额**。 6. 历史人工支出找不回来,**直接放弃**:不补录、不做样本回填、不做均价估算。 --- ## 一、核心口径 1. **人工成本逐单、按实际金额。** 不按小时、不按固定单量、不按固定单价。 2. **人工支出从客服备用金账户扣款。** 余额不足直接拒绝,不允许负余额。 3. **客服角色只能使用自己的备用金账户。** 后端越权直接 403;管理员/财务可代录到指定客服账户。 4. **历史人工支出找不回来,直接放弃。** 不补录、不做样本校准;历史缺口只计入 `cost_missing_count`,不阻塞上线。 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_cost_missing`:**首次创建人工履约配置之后**的订单项,只要还没有人工成本快照就进入队列;确认履约写入快照后自动 `resolved`。历史人工单不进入该队列。 --- ## 三、确认履约 ### 3.1 落点 - 服务:`apps/backend/src/services/finance/manual-fulfillment-service.ts` - 接口:`apps/backend/src/routes/admin/finance.ts` 的 `POST /finance/manual-fulfillment/confirm`;待办 `GET /finance/manual-fulfillment/pending` - 组件:`apps/frontend/src/components/admin/ManualFulfillmentConfirmModal.tsx` - 订单入口:订单列表/详情「确认履约」 - 权限:`admin / operator / support`;客服只能使用本人备用金/积分账户;管理员/财务/运营可在确认时通过 `fundAccountId` / `creditOwnerAdminUserId` 指定客服账户代录 - 配置前置:商品与成本 → 人工 SKU 配置(`manual_fulfillment_configs`) ### 3.2 资金流与成本流(同一事务) ```text BEGIN 锁定 order_items 行(FOR UPDATE OF oi) → 复查是否已有 manual_case 快照(有则 409,不扣款) → 按 SKU 自动匹配人工履约配置(配置晚于下单也能挂上) → 解析成本项/成本版本(版本缺失在扣款前失败) → 扣积分(platform_credit_entries)或扣备用金(fund_entries + manual_expenses) → 写 cost_snapshots(actual,subject_id = order_item_id) COMMIT -- 任一步失败整体回滚 ``` - 余额不足直接拒绝,**不允许负余额**; - 重复点击/并发请求:订单项行锁 + `uq_cost_snapshots_manual_order_item` 唯一索引双重兜底,只有一个请求能成功扣款; - 同一个订单项最多一条有效人工成本快照;不同订单项(包括现金与积分两条链路)不会因为 id 撞车互相覆盖。 ### 3.3 成本快照 - `subject_type='manual_case'`、`subject_id=order_item_id`、`order_item_id` 同值; - 金额:固定成本 = `credit_quantity × 平台换算率`;成本不固定 = 客服填写的实际金额; - `metadata_json` 记录 `fundExpenseId / creditEntryId / subjectSource / platformKey / creditQuantity / costFen / paidBy` 等; - `uq_cost_snapshots_manual_order_item` 保证一个订单项只有一条有效快照(迁移 `111`)。 ### 3.4 录入字段 ```text order_item_id -- 订单项(必填;弹窗内锁定) costFen -- 仅成本不固定的 SKU 必填,> 0(分) payeeName -- 收款方(选填,默认「人工履约」) note -- 备注(选填) ``` 平台、消耗积分与固定成本都来自人工 SKU 配置;客服不选账户、不改平台。管理员/财务/运营代录时额外传 `fundAccountId`(现金)或 `creditOwnerAdminUserId`(积分),未指定则回退本人账户。 ### 3.5 配置与监控 - 人工 SKU 的匹配键:`spec_json.skuNick → spec_json.outSkuSn → sku_code → sku_name`;没有前两级的历史单也能按后两级配置。 - 保存配置后立即回填该 SKU 最近 30 天的订单项;定时任务每 5 分钟对最近窗口内未匹配项兜底;更早历史需显式「重新匹配」。 - 未配置 SKU 的订单项进入 `manual_cost_missing`(`detail.configMissing=true`),配置后自动匹配;确认履约后异常自动收口。 --- ## 四、订单页「确认履约」 - 弹窗只展示已配置履约渠道的人工项;固定成本零输入,成本不固定才要求填金额; - 锁定订单与订单项,不允许改平台/账户; - 确认即扣钱并写成本,没有审核/报销步骤; - 若 SKU 还没配置,弹窗会提示先去「商品与成本 → 人工 SKU 配置」补配置; - 重复确认会被拒绝,不会重复扣款。 --- ## 五、每日必查与关账门槛 | 指标 | 目标 | | --- | ---: | | 人工订单项无资金流水(现金备用金支出 / 积分消耗流水) | 0 | | 人工订单项无有效成本快照 | 0 | | 现金人工成本金额与 manual_expenses 不一致 | 0 | | `manual_cost_missing` open(上线后) | 0(历史人工单不计入) | 关账门槛: - 存在上线后人工单无成本记录:**不允许关账**; - 存在上线后人工单没有对应资金流水(现金或积分):**不允许关账**; - 存在现金人工支出与备用金流水金额不一致:**不允许关账**。 核对 SQL 见 [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) §八。 --- ## 六、异常处理 - 发现人工单无成本:确认履约;扣款与写成本同事务,失败整体回滚,不会出现「扣了钱没记成本」。 - 备用金/积分不足:拒绝确认,由主管补拨/充值后再确认;不允许负余额。 - 人工 SKU 未配置:进入 `manual_cost_missing` 队列,配置后自动回填订单项,再确认即可。 - 确认后需要更正:当前不提供反审核;只能通过后续冲销/调整处理(P1),不要直接改库。 - 历史人工单:找不回来、**直接放弃**,不补录、不计入上线后监控缺口。 --- ## 七、历史人工:直接放弃 历史人工支出找不回来,口径明确为**放弃**: - 不补录、不回填 `cost_snapshots`; - 不做样本抽取与均价估算; - 不阻塞上线,历史缺口计入销售事实的 `cost_missing_count`; - 只保证**上线后**的新单不丢:人工单必须有备用金支出与成本快照。 历史平台 53,901 项同理,只有拿到旧平台结算数据才允许按历史成本入账。 --- ## 八、关联文档 - 业务口径: [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) - 数据模型: [成本中心与履约模型.md](成本中心与履约模型.md) - 影子总账: [财务系统集成方案.md](财务系统集成方案.md) - 订单读取与履约展示: [成本中心与履约模型.md](成本中心与履约模型.md) §六