#brayden - subscription cancellation

1 messages · Page 1 of 1 (latest)

late hill
lone folio
#

Hi

late hill
#

@lethal ivy curious, why do you need to cancel the subscription for this?

#

But for this:

the refund is placed into a draft status for 1 hour before finalizing
assuming you mean the invoice is in draft for an hour, yes you can finalize it immediately via the API if needed:

lethal ivy
#

So since we're refunding based on past charges, we're unable to finalize the invoice since it has already previously been finalized

#

curious, why do you need to cancel the subscription for this?

We have to refund a prorated amount of money back to the customer and then re-charge the customer for a new subscription. We also need to change the start and end period of the subscription so cancelling just ended up being an easier road for us.

late hill
#

What are you referring to here, then?

the refund is placed into a draft status for 1 hour before finalizing

#

Can you provide an example?

lethal ivy
#

Yeah, can I just paste a link?

late hill
#

or an object ID like in_12345 etc

lethal ivy
#

in_1JrTmpALivADE4Jrcn7aTVEE

#

This is an example of a drafted refund invoice

#

In order to refund the full amount required when cancelling the subscription, we loop through the charges associated with the customer's account, refunding them either in full, or partially until we get a total refund amount equal to the amount due to the customer.

#

` # In order to actually refund the customer, we have to iterate through their charges and refund them until
# we've reached the prorated refund amount.
charges = Stripe::Charge.list(
customer: subscription.customer,
created: {gte: subscription.current_period_start},
limit: 100
)

refund_remaining = total_refund_amt.dup
charges.each do |charge|
  break if refund_remaining == 0

  # Check to make sure the charge was captured, i.e. not failed/voided
  next unless charge.captured

  # The refund amount for this charge is either the total remaining refund or the
  # total amount available to refund on this charge.
  refund_amt = [refund_remaining, (charge.amount - charge.amount_refunded)].min
  next if refund_amt == 0 # Nothing left to refund from this charge

  refund = Stripe::Refund.create(
    charge: charge.id,
    amount: refund_amt,
    reason: "requested_by_customer",
    metadata: {
      policy_id: policy&.id
    }
  )
  
  Stripe::Invoice.finalize_invoice(charge.invoice)

  refund_remaining -= refund_amt

  Rails.logger.debug("[SubMan] Created refund #{refund.id} (status: #{refund.status}) of $#{refund.amount / 100.0} against #{refund.charge}")
end`
#

Wish I could format that a little bit better.. but this is essentially the flow we take during the refund. The finalize_invoice call is failing due to the charge's invoice being finalized already.. which I would assume is the invoice for the initial payment.

late hill
#

OK digesting this i see what you're saying, you cancel the sub and get this prorated refund, then need to loop back through charges to refund enough to amount to that before creating the new sub. The recommended approach here would be to let the customer credit and balance handle it, but you dont want to let that happen? Or are you saying thats what you'd prefer but it doesnt work like you need it do?

lethal ivy
#

What steps, and in what order, would you recommend we perform here?

#

Our main issue is that the refund takes an hour to process and I can't figure out a way to force it.. If I could force it to finalize we'd be made in the shade.

hasty pendant
#

I'm also catching up here... my initial reaction is also "don't cancel the Subscription" but let me think about this more...

late hill
#

Yea I'd like to figure out if we can update the sub instead of cancelling and recreating to get you to the same endpoint more cleanly

lethal ivy
#

Would definitely be open to that, but there's some tricky stuff that needs to happen I think..

hasty pendant
#

Just to make sure I understand the use case, is this is the scenario you're trying to account for:

  1. Customer Subscribes and pays $100 for a year in January
  2. Six months later, in July, they move to another state so now you need to switch them to $150/year instead of $100
lethal ivy
#

We're using a schedule, because these subscriptions update annually, so not only are we having to change the amount on the sub, but we're having to change the start date, end date, and reschedule the renewal date.

hasty pendant
#

Tell me more about those date changes. Why are they changing? How much are they changing? Can you give me a detailed example scenario?

lethal ivy
#

Yup, give me one second

#

So it would go a bit like this:

  1. You start a sub on January 1, 2021 at $100/yr
    • We create a schedule and set your sub up to renew automatically on January 1, 2022 at $100/yr
  2. You move on July 1, 2021 to a new state where your coverage should be $200/yr
    • We need to now have the schedule changed so that you renew on July 1, 2022 and not Jan 1, 2022 anymore. So we need the start
      and end dates of the sub to be in July, and not in January anymore.
#

We are choosing to cancel and create a new subscription, because we just have a lot of logic built around creating new subs, since this is the primary way our customers interact with our product and it appears to be the easiest way for us to get our automatic renewals scheduled for the new billing period.

#

and I should mention, there are business reasons why we want to start a new annual sub when changing address, as opposed to just continuing on the current schedule, just with a higher rate for the sub. Does that make sense?

hasty pendant
#

Some questions:

  1. Why are you using Subscription Schedules?
  2. On July 1st what do you want to happen? Does the Customer get $50 back from the unused half of the year they paid $100 for, then they're billed $200?
lethal ivy
#
  1. Schedules make it easy for us to use webhooks to automatically perform some business logic on our end. Basically, the subscription is an insurance premium on items that customer owns. After a year of coverage (the subscription), we add inflation to the value of the items and then charge the customer a new rate for next year's subscription.
#
  1. Yes, and then a new sub is started on that day, not continued from the original $100 sub
#

Because keeping the same sub would have us calculating inflation on Jan 1, when we need to calculate it on July 1.

hasty pendant
#

That way you keep the existing Subscription, we handle all the proration, it all ends up on a single Invoice, etc.

lethal ivy
#

I don't really think this is going to be feasible for us right now.. While it sounds like it might be a good thing for us to look at in the future, it requires a significant rewrite of some really core services and the risk there doesn't currently justify the means for us.

#

Is there truly not a way to finalize the refund invoice that is created by our current workflow?

#

Because this would solve our current issues if we could figure out a way to do that.

hasty pendant
#

Sorry, I'm not sure what "finalize the refund invoice" means.

#

There's no such thing a a "refund invoice" in Stripe. Are you talking about an Invoice you're creating that contains a credit note or something like that?

lethal ivy
#

No, I can get another one spun up and share it here if you'd like.

#

The current process we follow is we cancel the current sub, determine the prorated amount to refund the customer based on the remaining time on the cancelled sub, then loop through the customer's charges, refunding until we reach the full refund amount

hot island
#

that's usually what I recommend myself in your case

lethal ivy
#

If you take a look at this invoice and the following one, you'll kind of see the full picture here..

#

This invoice was for the original sub and was $650. $649.87 is being refunded from it (the prorated amount from cancellation)

hasty pendant
#

Is the problem that in_1JrVPjALivADE4JrkOX4AuLN is still in draft status?

lethal ivy
#

Yup

#

Takes an hour for it to finalize

hasty pendant
lethal ivy
#

I've tried doing this and the API tells me that it's already been finalized.

hasty pendant
#

Can you provide a request ID showing that error?

lethal ivy
#

Yeah, I guess perhaps I'm not getting the correct invoice though.. which may be my main issue. I'm using the invoice attached to the charge being refunded.

hasty pendant
#

Yeah, I'm not seeing a finalize API request for that Invoice.

#

I'm seeing requests failing for other Invoices, but not that one.

#

I'm using the invoice attached to the charge being refunded.
If an Invoice has a Charge associated with it is is by definition already finalized.

#

An Invoice will not generate a Charge until after it's finalized.

lethal ivy
#

So when I create the refund, I've basically got the charge object and the refund object that I create using the charge ID. Is there a way to get this invoice ID from either of those objects? What's the best way to get this invoice ID?

hasty pendant
#

You would get the Invoice ID in the response to your request to cancel the existing Subscription. It will be the latest_invoice on the Subscription object returned when you cancel.

#

It's the Invoice generated to handle proration when the Invoice is canceled.

lethal ivy
#

Ahhh, this makes sense and is probably the piece I was missing. I apologize for the run around in getting to this.

hasty pendant
#

No worries! I think we were thrown by the unusual approach of canceling and creating a new Subscription instead of updating the existing one, but I do think this is the core issue. 🙂

lethal ivy
#

Yes, I know it's not the greatest approach lol but we're married to it for the time being as I stated earlier. Really appreciate the help here, I'll hop back in here another day should that not fully solve my issues. Have a good one!