按比例计费不是打折,是把没用完的时间折算成钱。
一、第十三天的那次加席
一个团队档客户在周期第 13 天加了一个席位。席位价 8 美元/月,页面显示应付 4.53 美元。他停了一下:加一个整月的席位,不是 8 美元吗?
以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。
因为计费周期按 30 天算,他只需要为剩下的 17 天付费。按比例计费(proration)只做一件事:把周期切成天,用了几天付几天,没用到的部分不计。
8 × 17 ÷ 30 = 4.53。 这不是折扣,是同一单价换了更短的时间。九笔变更的平均价差正好是 8 美元,所以 4.53 也是每笔变更的平均收款。
同一笔变更,客户看到的是两个数。 他记得自己付了 8 美元,也记得只用了一半时间;账单写 4.53,两个记忆都对,只是单位不同。
把抵扣与新增分成两行写。 账单上先列「原套餐剩余期抵扣」,再列「新套餐剩余期费用」,客户能自己加出 4.53;合成一行,看起来就像乱收费。
变更请求本身要幂等。 客户连点两次、页面超时重试,都只能产生一笔变更;否则一次升级会收两次差价,月底对账才发现。
一个人做计费,最容易错的不是不会算,而是三处口径没有写死:分母取几天、在哪一步取整、变更何时生效。
二、升级立即生效,降级期末生效
九笔变更里六笔升级、三笔降级,两条路径的账务动作完全不同。
| 项 | 升级 | 降级 |
|---|---|---|
| 生效时点 | 立即 | 当前周期结束 |
| 当期收款 | 收差价 | 0 |
| 客户体验 | 马上用上新功能 | 已付周期不缩水 |
| 账务动作 | 一张差额发票 | 一条待生效变更 |
| 常见错误 | 按新价全额重开一期 | 提前退款或提前降权 |
升级收差价,是因为客户愿意为剩余时间多付。 立即生效、立即收款,收益与付款在同一时点,争议最小。
降级不退款,是默认做法。 客户已经付过这一期,就该用完这一期;提前降权等于没收已付服务。
升级要立刻给权限,降级要等期末再收权限。 权限切换与计费切换必须同源,不能一个立即、一个期末,否则客户会用到没付钱的功能。
不要用「取消重建」实现升级。 那会生成两张账单、两次按比例退款,还会打乱续费锚点日,后面每个月对账都多一行解释。
差额发票的日期就是变更日。 不要把它并到下期续费里,否则当期收入与当期用量对不上,按比例的分母也失去依据。
降级的待生效变更要能被取消。 客户在期末前反悔,应该撤回那条变更,而不是再升一次;再升一次会多出一笔差价。
变更历史是审计的第一手材料。 谁在什么时点改了什么、按什么分母算的、由哪次请求触发,一条都不能少。
六笔升级当月产生 27.2 美元,三笔降级当月 0 收款。 前者是增量,后者只是排期,两者不能合并成一个「变更收入」。
三、分母、取整与生效时点
同一个公式,三处默认值不同,结果就会差出一笔谁都注意不到的钱。
| 易错点 | 错误写法 | 后果 | 正确做法 |
|---|---|---|---|
| 分母 | 一律用 31 天 | 30 天周期每笔少收 0.146 | 用当期实际天数 |
| 取整 | 中间步骤四舍五入 | 累计误差 0.03/月 | 全程整数分,出账截断 |
| 生效时点 | 降级立即生效 | 客户已付周期被缩水 | 期末生效,记待生效 |
分母用当期实际天数。 2 月 28 天、4 月 30 天、7 月 31 天;把 31 当常数,所有短月都少收,客户对不上自己的日历。
分母 bug 金额很小,但笔数多。 11 笔落在 30 天周期却按 31 天算,每笔少收 0.146,合计 1.61 美元;单看一笔发现不了,客户也不会为这一毛五主动来说。
周期边界用带时区的时间戳存。 只存日期,跨时区客户会在自己当地的 23:00 被算成次日,剩余天数直接差一天。
闰年与短月要单独测。 2 月 29 日开始的周期,分母是 29;用 30 会少收,用 28 会多收,两种错都不会被日常用例发现。
变更当天的天数归属只能算一次。 要么算旧套餐,要么算新套餐,不能两头都算一天;一天看起来小,一年九笔就是九天的重复。
取整只在最后一步做。 中间每一步保留整数分,生成账单行时按分截断;每步都四舍五入,误差会随步数累积。
按分截断偏向客户,这是可接受的方向。 累计误差 0.03/月,一年 0.36;比多收更容易解释,也不会触发退款流程。
取整规则要写进对外文档。 客户能预期「按分截断」,就不会为 0.01 的差额来问;不写,每一分都要人工解释。
降级必须期末生效。 立即降级会让客户已付的 17 天按低档服务交付;正确做法是记一条待生效变更,到期切换。
往返变更要能抵扣。 升级再降级一年 4 次,每次 4.53,合计 18.1;这是客户应得的抵扣,不是收入,不能记进 MRR。
四、把九笔变更算回一条账
复算:六笔升级按 17 天补差,三笔降级当期不收款;分母与取整误差单独列示,往返变更计入抵扣而非收入。
8 × 17 ÷ 30 = 4.53/笔;6 笔 = 27.18 ≈ 27.2/月
年化 6 × 12 × 4.53 = 326.2 ≈ 326,占 20,520 的 1.59%
31 分母用于 30 天周期:8 × 17 ÷ 30 − 8 × 17 ÷ 31 = 4.53 − 4.39 = 0.146/笔;11 笔 = 1.61
往返 4 × 4.53 = 18.1/年
27.2 美元/月是变更带来的增量,不是新增客户。 它在 1,710 的确认收入之内,不能和 120 个订阅的续费混在一起看。
九笔变更的合计是 27.2,不是 40.8。 只有升级产生收款,降级只是排期;把两者相加会高估一倍,进而把增长归因错。
326 美元/年占 20,520 的 1.59%。 比例小,说明按比例计费做错不会立刻显形,但会持续漏;漏到年底才发现的账最难补。
变更前后都要能复算。 半年后客户问起 4.53,你要能用当时的分母与天数重新算出来;算不出来,说明系统只存了结果、没存输入。
1.61 美元的分母误差一年不到 20 美元,但它证明分母写死了。 分母错是系统性错,不是偶发错;偶发错可以补,系统性错会跟着每一笔变更复制。
18.1 美元的往返抵扣要单独立账。 记进收入会让 MRR 虚高,记进退款会让退款率失真;它只属于「客户余额」。
把变更金额与续费金额分列。 月度账上两行分开,才能看出增长来自新客户还是老客户加购;混在一起,两种增长看起来一模一样。
五、行动清单与复算验收
- 把公式写进代码注释:剩余天数 ÷ 当期天数 × 已付金额。
- 确认分母取当期实际天数,为 2 月、30 天、31 天各写一条用例。
- 确认金额全程用整数分,只在生成账单行时截断。
- 升级走差额发票,不取消重建,续费锚点日保持不变。
- 降级记待生效变更,期末切换,当期不退款。
- 为往返变更建抵扣台账,确认它不计入 MRR。
- 取最近 9 笔变更逐笔手算,与系统金额比对到分。
- 把 27.2、326、1.61、18.1 四个数写进月度复盘模板。
验收标准:任意一笔变更,你能在 30 秒内说出剩余天数、分母、截断位置与生效时点,且手算与账单差 0 分。
使用边界与实操验收
边界一:按比例计费只适用于同一订阅内的套餐变更。 换产品、换币种、跨实体签约,都不该用这条公式硬套。
边界二:各通道的默认行为不同。 有的默认按比例、有的默认期末生效;接入前读文档,不要假设它和上一家一样。
边界三:4.53 是教学假设的平均值。 真实价差、剩余天数与周期长度各不相同,公式不变,输入必须取实际值。
边界四:税费不参与按比例计算。 差额发票的税按当地规则另算,不能把税混进 4.53,否则退款时会对不上。
边界五:试用期内的升级是另一条路径。 试用没有「已付金额」,抵扣为 0,直接按新价起算;不要套用同一个函数。
关键参考与核验范围
- Stripe 订阅按比例计费 :核对 credit 与 proration 的默认算法与生效选项。
- Stripe 升降级 :核对升级立即生效、降级期末生效的通道行为。
- Stripe 幂等请求 :核对变更请求重试时如何避免重复计费。
- RFC 3339 :核对周期边界的时间戳表示,避免时区把天数算错。
以上链接于 2026-10-26 实测可公开访问;未核验版本、价格与配额。核验日期:2026-10-26。
系列导航
- 回到本组目录:一个人的计费系统:订阅状态机、按比例计费与失败重试
- 上一篇:订阅生命周期:试用、续费、暂停、取消与五个时点
- 下一篇:按量计费与计量:一百二十九万六千条事件怎么变成一张账单
- 相关:一个人的定价与付费墙
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。