Files
order_site/docs/客服备用金台账实施方案-2026-10-18.md
T

16 KiB
Raw Blame History

客服备用金台账实施方案(2026-10-18)

状态:已实施 P0(迁移 100/101,前端/后端已上线到代码库;未部署生产)。 最后校准:2026-10-18 代码基线:main @ 7542d547 背景:两位主管向客服发放备用金,客服用于充值、采购、赔偿等;目前全部走人工,无法监控每笔资金用途和每个客服余额。 结论:这不是报销系统,而是客服备用金(周转金)台账。P0 已完成“账户 + 流水 + 支出 + 对账”,不做复杂审批和总账。


〇、实际落地结果

项 实际实现
数据库 100_fund_accounts.sql:fund_accounts / fund_entries / manual_expenses / fund_reconciliations
显示名 101_admin_display_name.sql:admin_users.display_name,备用金 owner_name 由触发器同步
后端 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 })
测试 后端 738 通过 / 3 跳过;前端 143 通过;两端 typecheck、lint、build 通过

与本文原方案的差异:

  1. 实际表名 manual_expenses 是客服备用金支出明细,不是后来财务方案里的公司人工支出表 manual_expense_records。
  2. P0 未实现异常队列、批量发放/对账、导出、低余额提醒、大额支出主管确认;这些仍在 P1。
  3. 客服账户姓名使用 owner_name 快照 + admin_users.display_name 触发器同步;历史审计 payload 不重写。
  4. 支出凭证目前只校验数组非空,未校验对象存储 key 是否真实存在。

后续衔接:

  • 财务侧公司人工支出登记应新建 manual_expense_records,通过 fund_expense_id 关联本表的 manual_expenses.id,不要复用或改名。
  • 备用金支出可作为“钱从客服备用金出”的来源证据;公司直付、垫付报销仍走公司人工支出登记。

一、目标与非目标

1.1 目标

系统必须能回答四个问题:

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

1.2 非目标(P0 不做)

  • 不做垫付/直付的复杂资金性质区分;
  • 不做多级审批流;
  • 不做成本中心、订单毛利、复式总账;
  • 不做平台账户独立钱包(当前口径:充值后立即用于订单/消耗,直接记支出);
  • 不做多币种、发票、税务。

二、业务模型

flowchart LR
  C["公司资金"] -->|拨付| S["主管资金池<br/>2 位主管"]
  S -->|发放| A["客服备用金账户<br/>每人一个余额"]
  A -->|支出| P["平台 / 供应商 / 客户"]
  A -->|缴回| S
  P -->|付款截图| E["支出记录"]

2.1 五类流水,缺一不可

流水类型 钱的方向 对客服余额 是否算支出 关键字段
期初 上线初始化 增加 否 金额、主管确认
发放 主管 → 客服 增加 否 金额、主管、客服、时间、凭证
支出 客服 → 平台/供应商/客户 减少 是 金额、用途、收款方、平台账号、订单号(可选)、付款截图
缴回 客服 → 主管 减少 否 金额、主管、客服、时间、凭证
调整 主管/财务 → 客服 增加或减少 视原因 差异金额、原因、审批人、凭证

只有“支出”没有“发放/缴回/期初”,余额永远算不出来。

2.2 余额公式

客服余额 = 期初 + 累计发放 + 累计调整 - 累计支出 - 累计缴回
主管池余额 = 期初 + 公司拨付 + 客服缴回 - 发放给客服 - 调整

余额只能由流水产生,不允许直接手工修改。


三、账户设计

3.1 主管资金池

  • 两位主管各一个账户;
  • 公司给主管拨付、主管发给客服、客服缴回,都记入主管池;
  • 每个客服指定一个责任主管;
  • 发放可以两位主管都操作,但每笔必须记录发放人;
  • 对账由责任主管确认,避免“两个人都以为对方对过了”。

3.2 客服备用金账户

  • 每个客服一个账户;
  • 客服只能看到自己的余额和流水;
  • 主管能看到自己名下客服的余额和流水;
  • 财务/管理员能看到全部;
  • 余额不足时不能继续支出,先由主管补拨。

3.3 平台账户

当前口径为 A:充值后立即用于订单/消耗,因此不单独建平台钱包。支出记录中保留“平台名称 + 平台账号”,用于追溯钱充到了哪里。

如果以后出现“充值后平台还有余额、以后继续用”的情况,再增加平台账户层,不混入客服余额。


四、数据模型

P0 四张表即可。

4.1 fund_accounts 资金账户

字段 说明
id 主键
account_no 账户编号,唯一
account_type supervisor / agent
owner_admin_user_id 主管或客服的后台用户 ID
owner_name 姓名快照
responsible_supervisor_id 客服的责任主管;主管账户为空
balance_fen 当前余额,分
status active / frozen / closed
created_at / updated_at 时间

约束:

  • 同一用户同一类型只能有一个账户;
  • 余额不得为负;
  • 冻结账户不能发放、不能支出,但允许缴回和调整。

4.2 fund_entries 资金流水

字段 说明
id 主键
entry_no 流水号,唯一
account_id 所属账户
entry_type opening / funding / issue / expense / return / adjustment
amount_fen 有符号金额,正数流入、负数流出
balance_after_fen 记账后余额快照
transfer_no 转账批次号;发放/缴回的两条流水共用
counterparty_account_id 对方账户;支出时为空
expense_id 支出明细 ID;仅 expense 使用
reconciliation_id 对账调整关联
occurred_at 资金实际发生时间
created_by_admin_user_id 操作人
evidence_json 凭证文件 key、备注
note 说明
created_at 创建时间

约束:

  • amount_fen <> 0;
  • 余额只能通过流水变化;
  • 发放、缴回必须同时写两条流水:主管负数、客服正数,或反过来;
  • 支出必须同时写一条客服负数流水和一条 manual_expenses;
  • 已记账流水不可修改、不可删除;更正走调整或反向流水。

4.3 manual_expenses 支出明细

字段 说明
id 主键
expense_no 支出编号,唯一
account_id 客服备用金账户
amount_fen 支出金额,分
category platform_recharge / purchase / compensation / freight / other
payee_type platform / supplier / customer / other
payee_name 收款方名称
payee_account 收款账号
platform_name 充值平台名称
platform_account 平台账号
order_id 关联订单,可空
order_item_id 关联订单项,可空
paid_at 付款时间
evidence_json 付款截图、凭证
note 用途/原因
fund_entry_id 对应资金流水,唯一
created_by_admin_user_id 登记人
created_at / updated_at 时间

约束:

  • 金额 > 0;
  • 用途、收款方、付款时间、凭证必填;
  • 订单号可选;赔偿类建议关联订单;
  • 同一客服 + 同金额 + 同收款方 24 小时内重复,提示疑似重复;
  • 付款时间不能晚于当前时间;超过 24 小时补记标记“迟登记”。

4.4 fund_reconciliations 对账

字段 说明
id 主键
account_id 客服或主管账户
period_start / period_end 对账区间
system_balance_fen 系统余额
actual_balance_fen 实际余额
difference_fen 差异
status pending / confirmed / discrepancy
reason 差异原因
evidence_json 盘点/截图
confirmed_by_admin_user_id 确认人
confirmed_at 确认时间
created_at 创建时间

规则:

  • 差异为 0 才能直接确认;
  • 差异不为 0 必须填写原因,并走调整流水;
  • 调整必须由主管/财务/管理员操作,不能由客服自行改余额。

五、业务流程

5.1 上线初始化

  1. 建立两位主管账户;
  2. 建立每个客服账户,指定责任主管;
  3. 主管确认每个客服的期初余额;
  4. 期初余额写 opening 流水,备注“上线期初余额”;
  5. 期初确认后,所有余额变化必须走流水。

5.2 公司 → 主管

管理员记录“拨付”,主管池增加。若公司层暂不管理,至少给主管池录期初余额。

5.3 主管 → 客服

主管选择客服、填写金额、付款方式、时间、凭证,提交后:

  • 主管池减少;
  • 客服余额增加;
  • 生成两条 issue 流水,共用一个 transfer_no。

5.4 客服支出

客服填写金额、用途、收款方/平台、平台账号、订单号(可选)、付款时间、截图、备注,提交后:

  • 客服余额减少;
  • 生成一条 expense 流水;
  • 生成一条 manual_expenses 明细。

5.5 客服缴回

客服或主管发起缴回,主管确认后:

  • 客服余额减少;
  • 主管池增加;
  • 生成两条 return 流水。

5.6 对账

  1. 系统显示当前余额;
  2. 主管/客服盘点实际现金、微信、支付宝等余额;
  3. 输入实际余额,系统计算差异;
  4. 差异为 0 直接确认;不为 0 填写原因并走调整;
  5. 调整后重新对平。

建议频率:每笔流水当天记,每天生成余额快照,每周主管与客服对一次账。


六、权限设计

新增权限点:

  • fund.view:查看账户和流水;
  • fund.issue:发放/缴回;
  • fund.expense:登记支出;
  • fund.reconcile:发起/确认对账;
  • fund.adjust:调整余额;
  • fund.export:导出。

角色建议:

角色 权限
管理员 全部
财务 查看全部、对账、调整、导出
主管(operator 或新增 fund_manager) 查看名下客服、发放、缴回、对账
客服(support) 登记自己的支出、查看自己的余额和流水

服务层还要做归属校验:

  • 客服只能操作自己的账户;
  • 主管只能操作自己名下客服;
  • 发放人不能给自己发放;
  • 调整必须由主管/财务/管理员操作;
  • 所有写操作写审计日志。

七、页面设计

7.1 管理端“备用金”页

建议五个页签:

  1. 总览:公司总备用金、主管池合计、客服余额合计、本月支出、待对账人数、异常笔数。
  2. 客服余额:客服、责任主管、当前余额、本月发放、本月支出、本月缴回、最后交易、最后对账、状态。
  3. 主管资金池:主管、池余额、本月拨入、本月发放、本月收回、名下客服数、差异。
  4. 支出明细:时间、客服、金额、用途、收款方/平台、订单号、凭证、状态;支持筛选。
  5. 对账与异常:负余额、无凭证、长期未动、疑似重复、对账差异、超限额。

7.2 客服端“我的备用金”

  • 当前余额;
  • 发放/支出/缴回流水;
  • “登记支出”按钮;
  • “申请补拨”按钮;
  • “申请缴回”按钮;
  • 对账状态。

7.3 订单详情(可选)

订单详情增加“本单相关支出”小卡片,展示已关联的支出合计和明细。订单号不是必填,所以这个卡片只对已关联订单的支出生效。


八、接口设计

方法 路径 用途
GET /admin/fund/overview 总览
GET /admin/fund/accounts 账户列表
GET /admin/fund/accounts/:id 账户详情 + 流水
POST /admin/fund/accounts/:id/funding 公司 → 主管拨付
POST /admin/fund/accounts/:id/issue 主管 → 客服发放
POST /admin/fund/accounts/:id/return 客服 → 主管缴回
POST /admin/fund/accounts/:id/expenses 登记支出
GET /admin/fund/expenses 支出明细
GET /admin/fund/expenses/:id 支出详情
POST /admin/fund/reconciliations 发起对账
POST /admin/fund/reconciliations/:id/confirm 确认对账
POST /admin/fund/reconciliations/:id/adjust 差异调整

实现要求:

  • 所有金额用“分”存储,前端按元展示;
  • 发放、缴回、支出必须在数据库事务中完成;
  • 账户行使用 SELECT ... FOR UPDATE,避免并发导致余额错乱;
  • 所有写接口使用现有 createJsonHandler({ audit }) 写审计日志;
  • 所有写接口做权限点和归属校验。

九、校验与异常

规则 处理
金额 <= 0 拒绝
余额不足 拒绝,提示先补拨
账户冻结 禁止发放/支出,允许缴回/调整
支出无凭证 拒绝
发放/缴回无凭证 允许备注+交接说明,但标记待补
收款方为空 拒绝
付款时间晚于当前 拒绝
付款时间早于当天 允许,标记迟登记
同客服+同金额+同收款方 24h 内重复 提示,需备注原因
对账差异未填原因 拒绝确认
调整无审批人 拒绝

异常队列:

  • 负余额;
  • 无凭证;
  • 超过 7 天未对账;
  • 余额长期不动;
  • 单笔/单日支出异常;
  • 同一凭证被多笔复用;
  • 对账差异。

十、分期落地

P0(先能记、能看、能对)

  • 四张表 + 索引;
  • 主管池、客服账户;
  • 期初、发放、支出、缴回、调整五类流水;
  • 支出明细 + 凭证上传;
  • 总览、客服余额、主管池、支出明细、对账页面;
  • 权限点 + 审计;
  • 上线期初余额;
  • 每周对账。

P1(更好用)

  • 异常队列和提醒;
  • 余额上限、低余额提醒;
  • 批量发放/批量对账;
  • 导出;
  • 大额支出主管确认;
  • 移动端快速登记。

P2(算得更清)

  • 订单关联支出汇总;
  • 支出分类与成本中心打通;
  • 单均人工成本、店铺/客服维度报表。

P3(财务总账)

  • 复式记账;
  • 与订单、钱包、提现、人工支出统一对账;
  • 期间关账。

十一、上线步骤

  1. 业务确认:两位主管、客服名单、责任主管、支出分类、期初余额截止时间。
  2. 开发:迁移、后端台账服务、接口、前端页面、权限。
  3. 初始化:建立账户,录入期初余额,主管逐人确认。
  4. 试点:选 2 位主管 + 2~3 位客服,跑 1 周。
  5. 校准:根据试点调整字段、分类、对账频率。
  6. 全量:全部客服上线,关闭线下 Excel/微信群记账。
  7. 运营:每周对账,每月复盘余额和支出异常。

十二、测试与验收

12.1 必测

  • 发放:主管池减少、客服余额增加,两条流水金额相反;
  • 支出:客服余额减少,支出明细与流水一一对应;
  • 缴回:客服余额减少、主管池增加;
  • 余额不足:拒绝支出;
  • 并发发放/支出:余额不超扣、不出现负数;
  • 权限:客服不能看别人,主管不能看非名下客服,客服不能调整;
  • 对账差异:必须填原因并生成调整流水;
  • 审计:所有写操作有日志。

12.2 验收标准

  • 每个客服的当前余额可查;
  • 每笔支出可追溯到人、金额、用途、收款方、时间、凭证;
  • 主管池余额与发放/缴回流水对得上;
  • 系统余额与客服实际余额的差异有记录、有原因、有审批;
  • 不存在无流水导致的余额变化;
  • 不存在负余额(除非明确开启允许负余额)。

十三、待确认

  1. 两位主管的钱是公司资金,还是主管个人先垫?P0 先按公司资金池记,个人垫资在备注中说明。
  2. 客服账号是否都是现有 admin_users 的 support 角色?如果是,直接绑定 owner_admin_user_id。
  3. 客服余额是“一个总余额”,还是需要分微信/支付宝/现金多个钱包?P0 建议一个总余额 + 流水记付款方式。
  4. 期初余额的截止时间和确认人。
  5. 支出分类是否就用:平台充值、采购/拿货、客户赔偿、运费、其他。
  6. 对账频率:每周一次是否足够,是否需要每日快照。
  7. 大额支出是否需要主管事前确认;阈值多少。