#brayden - subscription cancellation
1 messages · Page 1 of 1 (latest)
Hi
@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:
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.
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?
Yeah, can I just paste a link?
or an object ID like in_12345 etc
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.
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?
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.
I'm also catching up here... my initial reaction is also "don't cancel the Subscription" but let me think about this more...
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
Would definitely be open to that, but there's some tricky stuff that needs to happen I think..
Just to make sure I understand the use case, is this is the scenario you're trying to account for:
- Customer Subscribes and pays $100 for a year in January
- Six months later, in July, they move to another state so now you need to switch them to $150/year instead of $100
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.
Tell me more about those date changes. Why are they changing? How much are they changing? Can you give me a detailed example scenario?
Yup, give me one second
So it would go a bit like this:
- 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
- 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 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
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?
Some questions:
- Why are you using Subscription Schedules?
- 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?
- 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.
- 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.
My recommendation would be to update the existing Subscription to the new Price and set billing_cycle_anchor to now: https://stripe.com/docs/api/subscriptions/update#update_subscription-billing_cycle_anchor
That way you keep the existing Subscription, we handle all the proration, it all ends up on a single Invoice, etc.
There more information about upgrading and downgrading Subscriptions here: https://stripe.com/docs/billing/subscriptions/upgrade-downgrade
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.
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?
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
that's usually what I recommend myself in your case
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)
Is the problem that in_1JrVPjALivADE4JrkOX4AuLN is still in draft status?
You can finalize it via the API: https://stripe.com/docs/api/invoices/finalize
I've tried doing this and the API tells me that it's already been finalized.
Can you provide a request ID showing that error?
Here's how you can find a request ID: https://support.stripe.com/questions/finding-the-id-for-an-api-request
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.
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.
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?
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.
Ahhh, this makes sense and is probably the piece I was missing. I apologize for the run around in getting to this.
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. 🙂
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!