We've moved discussions to Discord

Disable features from subscription when it expires

Alex Deering
Im having trouble figuring out how to handle this.  So I have a subscription that allows users to highlight recipes in searches so they show up closer to the top of the list.  This is handled super simple with them being able to select a limited number of recipes and have a boolean field for the recipes that is set to true if it is sponsored.

What I cant find with the payment stuff is how I would set up to turn the boolean field to false when their subscription ends.  Since its not immediately if they still have time left on the current months subscription  
Chris Oliver
Stripe sends a webhook when the subscription is canceled, which changes the Pay::Subscription.active? to return false. A subscription won't cancel until the end of the period unless you call cancel_now! which will do it immediately.

All you do to check the subscription status is call the following which returns a boolean.
current_team.subscribed?

Stripe CLI for forwarding webhooks is required to test any of this stuff in development of course.
Alex Deering
Sorry I got all of that and have the checking for setting the features up and showing the extras options when they have a subscription.  My problem is when the subscription ends (not when they cancel) I need to change a boolean variable on recipes that are affected by it.  Was thinking a nightly cron job but seems inefficient.
Chris Oliver
Ah, gotcha! Then I would just add a webhook listener.

We use the StripeEvent gem behind the scenes in Pay to update subscriptions, etc so you would just do the same thing. I'm pretty sure StripeEvent lets you add multiple callbacks for the same event, so you can just add your own on subscription.deleted to update the related records.

We already initialize it with API keys and everything, so you should be fine to just drop it in an initializer. https://github.com/integrallis/stripe_event

Need to go add docs to Pay & Jumpstart for how to do this.
Alex Deering
Ok Ill start looking into stripe_event and seeing about handling that.  Im using braintree, but that still uses the stripe_event gem for the webhooks right?
Chris Oliver
Negatory, Briantree and Stripe webhooks are totally different. There's a Braintree webhooks controller in Pay you can look into. Would need to extend that.

Actually, you could probably add an `after_commit` callback on the Subscription model to make your updates if the status previously changed to `canceled`. That might be easier than dealing with webhooks.
Alex Deering
Hmmm, the pay_subscription table gets updated when they cancel though and not at the end of the grace period.  Looking to make the changes when the grace period runs out. 

Doesnt look like the model gets updated again when the grace period runs out...right?

I'll have to look more into the webhooks with the pay gem then and see what I can do with that and when braintrees webhoooks are sent out for the different events. 

Also might be a bug but looking at the subscription.active? function, Im getting a false return when the subscription is cancelled but the on_grace_period? returns true.  Looking at the subscription model:
def active?
  ends_at.nil? || on_grace_period? || on_trial?
end
Shouldn't that return true if on_grace_period? is returning true?
I ran just that same check and got true, but when I use the subscription.active? it returns false
Chris Oliver
This is where Stripe + Braintree gets too tricky to make work similarly without doing a bunch of extra work. Stripe will trigger a webhook and update the status when it is canceled. Braintree doesn't have an event though I don't think.

I guess you could even schedule a job to run at the time it should end the grace period and when the job runs make sure they're still canceled (and haven't resumed) before doing the updates.

That line of code does return true if it's on grace period because it's OR between those. What's wrong?
Alex Deering
Yeah I was thinking scheduling a job to run when the grace period ends also. Or a nightly cron job that grabs any subscriptions with the same ends_at date as the day the job runs.

For the pay gem subscriptions model, the active? function is returning false even though the on_grace_period? returns true.  Running the commands in the console, here's my commands and results for reference (u is the team that the subscription is assigned to)
[6] pry(main)> u.subscription.active?
  Pay::Subscription Load (0.5ms)  SELECT "pay_subscriptions".* FROM "pay_subscriptions" WHERE "pay_subscriptions"."owner_id" = $1 AND "pay_subscriptions"."name" = $2 ORDER BY "pay_subscriptions"."id" DESC LIMIT $3  [["owner_id", 1], ["name", "default"], ["LIMIT", 1]]
=> false
[7] pry(main)> u.subscription.on_grace_period?
  Pay::Subscription Load (0.5ms)  SELECT "pay_subscriptions".* FROM "pay_subscriptions" WHERE "pay_subscriptions"."owner_id" = $1 AND "pay_subscriptions"."name" = $2 ORDER BY "pay_subscriptions"."id" DESC LIMIT $3  [["owner_id", 1], ["name", "default"], ["LIMIT", 1]]
=> true
[8] pry(main)> u.subscription.ends_at.nil?
  Pay::Subscription Load (0.4ms)  SELECT "pay_subscriptions".* FROM "pay_subscriptions" WHERE "pay_subscriptions"."owner_id" = $1 AND "pay_subscriptions"."name" = $2 ORDER BY "pay_subscriptions"."id" DESC LIMIT $3  [["owner_id", 1], ["name", "default"], ["LIMIT", 1]]
=> false
[9] pry(main)> u.subscription.on_trial?
  Pay::Subscription Load (0.4ms)  SELECT "pay_subscriptions".* FROM "pay_subscriptions" WHERE "pay_subscriptions"."owner_id" = $1 AND "pay_subscriptions"."name" = $2 ORDER BY "pay_subscriptions"."id" DESC LIMIT $3  [["owner_id", 1], ["name", "default"], ["LIMIT", 1]]
=> false
[10] pry(main)> (u.subscription.ends_at.nil? || u.subscription.on_grace_period? || u.subscription.on_trial?)
  Pay::Subscription Load (0.5ms)  SELECT "pay_subscriptions".* FROM "pay_subscriptions" WHERE "pay_subscriptions"."owner_id" = $1 AND "pay_subscriptions"."name" = $2 ORDER BY "pay_subscriptions"."id" DESC LIMIT $3  [["owner_id", 1], ["name", "default"], ["LIMIT", 1]]
  Pay::Subscription Load (0.3ms)  SELECT "pay_subscriptions".* FROM "pay_subscriptions" WHERE "pay_subscriptions"."owner_id" = $1 AND "pay_subscriptions"."name" = $2 ORDER BY "pay_subscriptions"."id" DESC LIMIT $3  [["owner_id", 1], ["name", "default"], ["LIMIT", 1]]
=> true

So the last command you can see that if I enclose all the or conditions in parenthesis it returns true...didnt think that was necessary but tried it just to see what it would return.
Chris Oliver
This stuff is always trickier than I'd like. I think either option would be good. They'd be the most reliable that way since the webhooks aren't consistent. The cron seems safer in case your background workers lost jobs if something bad happened.

And I bet the difference is that it's the Subscription status. Make sure you're browsing the SCA branch.
https://github.com/excid3/pay/blob/sca/app/models/pay/subscription.rb#L53

I still need to cut a release for v2.0 which will be all SCA.

I do believe there is a bug that the Stripe cancel should not change the status, because it's still technically active status in SCA until they cancel it.
Alex Deering
gotcha, thanks for the quick responses.  Ill start working on a cron job, as that seems the most straight forward for me and fullproof method.  

The active status doesnt effect my use very much cause all my checks use the on_grace_period? as a fallback.  Ive been testing with braintree sandbox and everything worked right out of the box with jumpstart.
Chris Oliver
Sounds good.

And yeah, I need to look at the code again and see what status Braintree is changed to on cancel. It's been a little while since I've looked at this. SCA sure made payments an absolute nightmare.
Notifications
You’re not receiving notifications from this thread.