立即收取订阅更改费用
Posted
技术标签:
【中文标题】立即收取订阅更改费用【英文标题】:Immediately charge for subscription changes 【发布时间】:2017-11-09 01:35:48 【问题描述】:我们正在为客户的订阅使用 Stripe 付款处理。当用户更改计划时,我们希望他们立即为按比例分配的差额付费。当计划具有不同的计费间隔时,Stripe 会自动执行此操作,但在具有相同间隔的计划之间进行更改时,Stripe 会将付款推迟到下一个计费周期。
我们现在的处理方式是在更新订阅后创建发票,但是如果因为失败而导致计费失败,我们需要进行回滚。
stripe.subscriptions.update(/* change plan */);
if (plans_have_different_billing_intervals)
try
stripe.invoices.create(/* for all pending charges */);
catch (err)
/* rollback subscription to old plan */
总的来说,这感觉是错误的和令人费解的。是否有一种我们没有看到的更简单/更清洁的方法来实现这一点?
【问题讨论】:
唯一的其他解决方案是使用stripe.com/docs/subscriptions/… 知道要向他们收取多少费用,然后预先向他们收取费用,然后才在禁用按比例分配的情况下升级。 【参考方案1】:您可以在更新订阅时将billing_cycle_anchor
设置为now
,以强制其更改计费周期,从而始终立即向客户收费。我个人认为这更有意义。这也适用于按比例分配。
await stripe.subscriptions.update(subscription.id,
billing_cycle_anchor: 'now',
items: [ id: itemId, plan: planId ]
);
https://stripe.com/docs/billing/subscriptions/billing-cycle#changing
【讨论】:
我认为这是最简单的方法。谢谢,它就像一个魅力。【参考方案2】:要在用户升级时立即向用户收取按比例分配的差价,请在修改用户订阅时使用proration_behavior='always_invoice'
选项。引用文档:
...为了始终立即为按比例开具发票,请传递 always_invoice。
Python 示例:
stripe.Subscription.modify(
subscription_id,
items=[
'id': item_id,
'plan': plan_id,
],
# Charge the prorated amount immediately.
proration_behavior='always_invoice',
)
当用户更改为更昂贵的计划时,这会立即按比例向用户收取费用。但是,当用户更改为更便宜的计划时,用户将获得按比例分配的信用额度,从而使用户的下一个账单更便宜。
场景
在这些情况下,假设结算日期是每个月的第一天。进一步假设该月有 30 天。
场景 1:用户订阅了 5 美元的月度计划。用户决定在每月 22 日升级到 30 美元的计划。当月还剩 8 天时,5 美元计划的未使用部分约为(8 / 30) * 5 = $1.33
,30 美元计划的按比例分配的金额为(8 / 30) * 30 = $8.00
。因此用户将立即被收取8.00 - 1.33 = $6.67
的费用。
场景 2:用户订阅了 30 美元的月度计划。用户决定在每月 22 日降级到 5 美元的计划。当月还剩 8 天时,30 美元计划的未使用部分约为(8 / 30) * 30 = $8.00
,5 美元计划的按比例分配的金额为(8 / 30) * 5 = $1.33
。在这种情况下,不会向用户收费,但用户的下一个账单(在下一个账单日期)将减少8.00 - 1.33 = $6.67
。
上面的示例计算只是近似值,因为 Stripe 会按比例精确到秒,而不是按天。
旁注
dearsina's answer 是正确的,但至少涉及三个 API 调用,而不是一个。要明确遵循该答案中的步骤,您可以这样做:
# Step 1 in dearsina's answer: Modify the subscription.
modified_subscription = stripe.Subscription.modify(
subscription_id,
items=[
'id': item_id,
'plan': plan_id,
],
)
# Steps 2 and 3: Create and retrieve invoice.
invoice = stripe.Invoice.create(customer=modified_subscription.customer)
# Steps 4 and 5: Finalize and pay invoice.
stripe.Invoice.pay(invoice.id)
但是,既然您可以在一个 API 调用中完成所有步骤,为什么还要这样做呢?
【讨论】:
这似乎是 2020 年的最佳选择。它将升级计划,按比例时间立即计费,无需取消订阅或手动生成发票。跨度> 【参考方案3】:要收取更改数量或订阅计划的费用,您需要执行以下操作:
-
Update subscription 有新的变化。
Create an invoice。 让我感到困惑的是,Stripe 神奇地知道只为更新的订阅项目开具发票,而不是为即将到来的计费周期项目开具发票。
Retrieve the newly created invoice
Finalise the invoice Take payment for the invoice 这假设您的客户存储了一种付款方式。只有在完成所有步骤后,您才能成功为订阅更改收费(并且仅针对更改收费)。您可以一口气完成所有操作。客户应在邮件末尾收到来自 Stripe 的发票电子邮件。
正如 OP 所说,如果付款失败,情况会变得特别复杂。在我看来,你有三个选择:
-
忽略失败的付款,让客户访问服务,并希望他们在下次尝试付款时付款。
回滚订阅升级,警告客户付款失败。
暂停整个订阅,直到客户付款。
我只提到#3,因为有时订阅升级过程可能很复杂。客户在花费时间升级他们的订阅后,不希望工作被撤消,这可能是一个完全无害的原因(例如他们的信用卡已过期)。
从开发的角度来看,将订阅标记为unpaid
可能比回滚或冻结(然后解冻)订阅的某些部分更容易。但是,您将违反禁止客户使用他们已经支付的服务(他们现有的订阅),因为他们无法支付额外的服务。
【讨论】:
嗨,我怎样才能实现你所描述的#2 选择?我想将订阅回滚到最新的活动状态。 您需要(再次)将他们的订阅更新回尝试付款(会失败)之前的状态。 是的,但是我该怎么做呢,我怎么才能取回之前的订阅信息(比如订阅项目、数量……) 不能,需要自己存储“之前”,更新,尝试支付,如果不行,更新回“之前”。 问题是:为什么 Stripe 不简单地为我们做这一切?为什么不引入一个更改订阅的标志,比如force_payment: true
,让我们免去手动向客户收费的麻烦?想要直接向您的客户收取升级费用,而不是等到他们的结算周期结束(可能要将近一年),这当然并不少见?【参考方案4】:
您可以在 Stripe 中使用 webhooks。创建发票后,您可以立即收取发票费用(立即开票)。如果发票付款失败,您可以使用 webhook 回滚到旧帐户。
查看本指南以获取有关 Stripe 订阅的更多信息:https://www.truespotmedia.com/testing-webhooks-in-stripe-with-php/
【讨论】:
以上是关于立即收取订阅更改费用的主要内容,如果未能解决你的问题,请参考以下文章