立即收取订阅更改费用

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/

【讨论】:

以上是关于立即收取订阅更改费用的主要内容,如果未能解决你的问题,请参考以下文章

条纹:在保存的卡上创建 30 天试用订阅费用,但允许用户升级并立即开始收费?

Paypal 经常性:立即收取试用金额?

首次订阅 Stripe 的用户如何收取额外费用?

初次成功付款后,条带计费订阅不收取“后续费用”

Paypal 通过定期付款收取费用?

Authorize.net - 延迟付款和重复