Immediately charge for subscription changes

£可爱£侵袭症+ 提交于 2020-03-11 13:13:10

问题


We are using Stripe payment processing for our customer's subscriptions. When users change plans, we want them to be charged immediately for the prorated difference. Stripe does this automatically when plans have different billing intervals but when changing between plans with the same interval, Stripe defers payment till the next billing period.

The way we handle this now is to create an invoice after updating the subscription, but if the billing fails for it fails, we need to do a rollback.

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 */
  }
}

Overall, this feels wrong and convoluted. Is there an easier/cleaner way to implement this that we aren't seeing?


回答1:


You can use billing_cycle_anchor set to now when updating a subscription to force it to change the billing cycle and thus always charge the customer immediately. Personally I think this makes a lot more sense. Also this works well with prorating.

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:


To take payment for a change of quantity or subscription plan, you need to do the following:

  1. Update subscription with the new changes.
  2. Create an invoice. The thing that confused me by this is that Stripe magically knows to only invoice for the updated subscription items, and not for upcoming billing cycle items.

  3. Retrieve the newly created invoice

  4. Finalise the invoice
  5. Take payment for the invoice This assumes that your customer has a payment method stored.

Only when all of the steps have been completed, you've successfully charged for the subscription change (and charged for the change only). You can do it all of it in one go. The customer should get an invoice email from Stripe at the end of it.

As OP says, it gets particularly complicated if the payment fails. The way I see it, you have three choices:

  1. Ignore the failed payment, give the customer access to the service, and hope that they'll pay the next time payment is attempted.
  2. Roll-back the subscription upgrade, warn the customer that payment failed.
  3. Put the entire subscription on hold until the customer pays.

I'm only mentioning #3 because at times, the subscription upgrade process may be complicated. And the customer, having spent time upgrading their subscription, wouldn't want the work to be undone, for what could be a completely harmless reason (their credit card had expired for example).

It may be easier, from a development perspective, to mark a subscription as unpaid, than to roll back or to freeze (and then unfreeze) certain parts of the subscription. But you'll then run foul of barring the customer from a service that they have already paid for (their existing subscription) because they couldn't pay for the additional service.




回答3:


To immediately charge your users the prorated price difference when the user upgrades, use proration_behavior='always_invoice' option when modifying the user's subscription. Quoting from the docs:

... In order to always invoice immediately for prorations, pass always_invoice.

Example:

stripe.Subscription.modify(
    subscription_id,
    items=[{
        'id': item_id,
        'plan': plan_id,
    }],
    # Charge the prorated amount immediately.
    proration_behavior='always_invoice',
)

This immediately charges the user a prorated amount when the user changes to a more expensive plan. However, when the user changes to a cheaper plan, the user will be given a prorated credit, making the user's next bill cheaper by the prorated amount.

Scenarios

In these scenarios, suppose the billing date is on the first day of each month. Further suppose that the month has 30 days.

  1. The user is subscribed to a $5 monthly plan. The user decides to upgrade to a $30 plan on the 22th day of the month. The unused portion of the $5 plan is approximately (8 / 30) * 5 = $1.33, and the prorated amount for the $30 plan is (8 / 30) * 30 = $8.00. So the user will be charged 8.00 - 1.33 = $6.67 immediately.

  2. The user is subscribed to a $30 monthly plan. The user decides to downgrade to a $5 plan on the 22th day of the month. The unused portion of the $30 plan is approximately (8 / 30) * 30 = $8.00, and the prorated amount for the $5 plan is (8 / 30) * 5 = $1.33. In this case, the user will not be charged, but the user's next bill on the billing date will be reduced by 8.00 - 1.33 = $6.67.

The example calculations above are only approximate because Stripe prorates to the exact second, not by day.

Side notes

dearsina's answer is correct, but involves at least three API calls rather than one. To explicitly follow the steps in that answer, you could do this instead:

# 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)

But why do this when you do all the steps in one API call?




回答4:


You can use webhooks in Stripe. After creating an invoice, you can charge the invoice right away (invoice now). If the invoice payment fails, you can use a webhook to rollback to the old account.

Check this guide for more information about Stripe Subscriptions: https://www.truespotmedia.com/testing-webhooks-in-stripe-with-php/



来源:https://stackoverflow.com/questions/44417047/immediately-charge-for-subscription-changes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!