PayMill subscription 的月度扣款周期如何计算?
支付老李
结论
在问题所指的早期 PAYMILL Subscription API 中,1 MONTH 表示固定的 30 天周期,不是按自然月的对应日期扣款。
因此:
- 订阅创建于 2014-04-15,下一次扣款时间约为 2014-05-15。
- 订阅创建于 2014-01-31,按 30 天计算,下一次扣款时间约为 2014-03-02,不会自动调整到 2 月的最后一天。
- 后续扣款仍按固定周期递增,不会在某个月没有 31 日时自动改为月末扣款。
原因
PAYMILL 使用 MONTH 表示固定时长的订阅间隔,并非“下一个自然月”。从 15 日开始的订阅,首次扣款可能恰好落在下月 15 日,但遇到有 28、29 或 31 天的月份,扣款日期就可能偏移。
下一次计划扣款时间可以理解为:
next_capture_at = previous_capture_at + 30 days
实际扣款时间还可能受时区、队列执行时间和支付失败重试等因素影响。
实现方式
创建订阅后,业务系统不应自行假定扣款会发生在“每月同一天”。应读取 PAYMILL 返回的 next_capture_at,以此确定下一次扣款时间。
示意请求:
POST /v2/subscriptions
Content-Type: application/x-www-form-urlencoded
client=client_xxx
offer=offer_xxx
payment=pay_xxx
示意处理逻辑:
const subscription = await createPaymillSubscription({
client: "client_xxx",
offer: "offer_xxx",
payment: "pay_xxx"
});
const nextCaptureAt = new Date(
subscription.next_capture_at * 1000
);
console.log(nextCaptureAt.toISOString());
next_capture_at 通常是 Unix timestamp。它是否以秒为单位,应以实际接口响应和所用 SDK 的字段定义为准。
如果业务要求每月固定日期
如果产品规则要求在“每月 15 日”或“月末”扣款,就不能只依赖 1 MONTH。可以由业务系统计算日历日期,并在目标日期发起单次支付,也可以改用支持自然月锚点和月末规则的订阅系统。
月末策略需要提前约定,例如:
目标日存在:使用目标日
目标日不存在:使用该月最后一天
JavaScript 示例:
function billingDate(year, monthIndex, preferredDay) {
const lastDay = new Date(year, monthIndex + 1, 0).getDate();
return new Date(year, monthIndex, Math.min(preferredDay, lastDay));
}
const februaryBillingDate = billingDate(2014, 1, 31);
// 2014-02-28(本地时区)
在生产环境中,还需要固定业务时区,避免服务器时区或夏令时造成日期偏移。
注意事项
PAYMILL 已是历史支付服务,以上结论针对问题所述时期的 Subscription API。维护遗留系统时,应先检查实际订阅对象中的 next_capture_at、已有交易记录和当时所用 SDK 的行为,不要只根据当前日期重新推算。
固定 30 天也不意味着一年扣款 12 次后仍会落在原始周年日。如果账单、合同或用户界面写的是“每个自然月”,实际计费规则应与对外说明保持一致。
备注:内容仅供参考。
