钱怎么流
- 1你的后端每发生一次计量动作,就 POST 一条 usage event。
- 2月度 cron 按 (客户, 合同) 聚合事件、锁定一份 FX snapshot。
- 3Cron 生成 invoice——标价币种小计、CNY 收款金额。
- 4商户或终端用户调收银台接口,我们在微信 / 支付宝侧建一个 payment order。
- 5消费者付款。渠道回调到达。我们把 CNY 收款 + FX 换算写入 append-only ledger。
- 6月底,财务关闭结算 batch——两位管理员审批后,按结算币种 FX 清算打到你银行。
对象一览
Usage event
一次计量动作——token、agent 调用、图片、GB·天。携带 metric、quantity、customerExternalId、idempotencyKey、occurredAt。
Customer
你的终端用户。我们不处理身份信息,只用你给的 externalId 引用。
Product + rate card
Product 是你卖的东西。Rate card 把 metric → 单位大小 → 单价 minor 绑定。版本化、锁定到 invoice。
Contract
把 (客户, 产品, rate card) 用账期绑起来。Usage events 通过 customer 自动归属合同。
FX snapshot
Invoice 生成时锁定的汇率。同一份 snapshot 用来算 CNY 收款 + USD 净结算。
Invoice
标价币种小计、CNY 收款、平台费、净结算。状态机:draft → finalized → paid(或 void / refunded)。
Payment order
每次 checkout 尝试一条。住在微信或支付宝侧。渠道回调把状态翻成 paid / failed / refunded。
Ledger entry
Append-only 双式记账。每笔交易(收款、平台费、FX、出款)都有匹配的借贷两行。
Settlement batch
按结算币种月度关账。两位管理员审批后,FX 清算电汇到你银行。
不变量
- 每条业务行都带 merchantId——数据层多租户隔离。
- 所有金额是 bigint 以字符串序列化,单位是 minor。
- FX 汇率是 decimal 字符串,不用 JS float。
- Ledger 分录 append-only;余额 = SUM(credit) − SUM(debit),不 patch。
- Usage events 用 idempotency key 去重;(merchantId, idempotencyKey) 唯一。