longshotlabs / meteor-plans-stripe

Stripe service add-on for aldeed:plans package
https://atmospherejs.com/aldeed/plans-stripe
MIT License
18 stars 11 forks source link

How to handle case if you cancel right after you first payment, and your plan is still active for one month? #3

Closed sferoze closed 7 years ago

sferoze commented 8 years ago

I just tested this package out and it is very easy to get working. Great instructions thanks!

But I am not sure how to handle this case. I tried signing up for the pro plan I created, and then cancelling it by downgrading to the free plan. Then I signed up for the pro plan again and I noticed it charged me again.

Has it been thought of how to approach this situation? Where the user still has certain amount of time left on the plan even though they cancelled?

aldeed commented 7 years ago

Thanks @sferoze. In 0.0.5 release, cancelation now works a bit differently and should resolve the problem you describe. See https://github.com/aldeed/meteor-plans-stripe#cancelation

sferoze commented 7 years ago

Hi @aldeed thanks a lot. I read the docs and still have a quick question about the update.

"When you remove a plan that is linked with a Stripe subscription, the subscription will be set to cancel at the end of the current billing period."

By "removing a plan that is linked with a stripe subscription" does this mean using AppPlans.set to change the users plan from one associated with stripe subscription, to a free plan that has no payment associated with it?

Before when I called AppPlans.set to switch a user from paid to free plan, it immediately downgraded then and deleted the stripe customer id.

With this new update, if I call AppPlans.set and go from paid to free, it won't immediately downgrade them anymore?

Or

Is are you talking about actually deleting the plan in stripe?

sferoze commented 7 years ago

It seems like your referring to deleting a plan in stripe.

Then downgrading a user from paid to free plan will still be an issue, since it downgrades them right away and they can't use the paid plan until the end of month or till whenever the period ends for what they paid for.

aldeed commented 7 years ago

@sferoze When you AppPlans.remove the Stripe-connected plan, it will set it to cancel in Stripe but won't actually remove it from the user yet in your app. The way you'll know it worked is that AppPlans.endDate would now return a date. And then if you perform a sync after that date, at that time the plan will actually be removed from the user.

If you .set, that should work, too. The problem is that the plan isn't removed immediately so .get would not necessarily work correctly because there will actually be two plans in the array, one of which is pending cancelation.

So it's probably best to stick to add/remove the pro plan and assume free if has/hasAccess is false. If you have multiple paid plans, this pkg might not be best for you yet. Technically it should do things differently if going from one stripe plan to another. In that case it should just update the current subscription with a new plan name and then Stripe will automatically prorate and such. That isn't yet implemented.

sferoze commented 7 years ago

@aldeed

What if you do not want to remove the plan, but the user just wants to downgrade. This is the more common scenario. Right now I am not concerned about deleting Stripe plans after I created them.

Here is the workflow of a very common situation that I don't think is resolved yet.

  1. Setup plans in stripe.
  2. Customer subscribes to a paid plan and pays for one month.
  3. A week later the customer decides to cancel the subscription. Since the customer paid for the month, they should be able to use paid services for the time frame they paid for. But they should also be allowed to cancel the subscription so they won't be charged anymore.
  4. So once the subscription has been cancelled, it should show them the date the paid plan will expire on. After that date when the customer logs in they will be using the free plan.

So basically, we need a way for the customer to cancel a subscription so they are not charged again but still be allowed to stay on the plan for the time they paid for. This is different than actually deleting the plan from Stripe.

Please advise and on how handle this scenario with your package. Thanks so much!!!

aldeed commented 7 years ago

@sferoze It should be currently working exactly as you described.

Let's say you have a monthly Stripe-linked plan called "pro".

User subscribes and is charged for 1 month when you do: AppPlans.add('pro') User clicks Cancel in your app a week later and you do: AppPlans.remove('pro')

At this point AppPlans.has('pro') still returns true until the end of the month. The package has set an end date for the plan in Stripe at the end of this month, so they won't be charged for the next month. AppPlans.endDate('pro') will return the date at which the plan will be lost.

sferoze commented 7 years ago

@aldeed but I don't want to delete the entire plan!

The user justs wants to cancel the plan for themselves.

If I delete the entire pro plan in stripe... then how would other users subscribe to that plan?

sferoze commented 7 years ago

I might be misunderstanding.... AppPlans.remove('pro') doesn't delete the plan and just removes the user from the plan?

aldeed commented 7 years ago

@sferoze Correct. https://github.com/aldeed/meteor-plans/tree/master#remove-a-plan-for-a-user

sferoze commented 7 years ago

@aldeed a few follow up questions if you have a chance....

Background info: I just have 2 plans .... free and pro... Any user not on pro... should be on the free plan.

1) Say I remove the pro plan for a user. And it set for an end date lets say a week later. When the end date arrives what will happen when this code runs on onLogin? Will it set the user back to the free plan? Or should I add code here to manually add the free plan back to the user?

Accounts.onLogin(function (info) {
  AppPlans.sync({userId: info.user._id});
});

2) If they cancel before the end date.... but then they subscribe again before the end date.... how would this work? It should not charge them again, but accept a credit card if they previously deleted it. Then just resume the subscription.

aldeed commented 7 years ago

@sferoze

  1. As far as I remember, it only removes the expired plan when you sync, so you'd want to do this:
Accounts.onLogin(function (info) {
  var userId = info.user._id;

  // Sync plan with Stripe
  AppPlans.sync({
    userId: userId
  });

  // Default plan is "free" for new users
  var plan = AppPlans.get({userId: userId});
  if (!plan) {
    AppPlans.set('free', {userId: userId});
  }
});
  1. If they resubscribe it just removes the end date from their Stripe subscription and reactivates it, assuming their credit card is still on file. I'm not sure I tested the case where their credit card was removed. I assume it would prompt them to enter it again, but you should test that to be sure.
sferoze commented 7 years ago

@aldeed

I was working on implementing this today and ran into one issue.

If a customer wants to delete their billing information, the only way to do it with Stripe is to delete the customer from Stripe.

So the user will no longer has a stripe customer #.

Thus it always sets the user back to the free plan when it syncs since the customer is no longer in Stripe.

But was wondering if a customer is deleted from Stripe, but before deleting I did AppPlans.remove('pro') which set an end date.

Is it possible when syncing... to not automatically remove the plan if no stripe customer exists and an pro plan end date has been set?

sferoze commented 7 years ago

currently I do something like this to get it to work

Accounts.onLogin (info) ->
  userId = info.user._id

  syncAndSet = ->
    AppPlans.sync userId: userId
    plan = AppPlans.get(userId: userId)
    if !plan
      AppPlans.set 'lite', userId: userId

  if !!AppPlans.endDate('pro', userId: userId)
    if moment().isAfter(AppPlans.endDate('pro', userId: userId))
      syncAndSet()
  else
    syncAndSet()

But I don't think this is very reliable...

aldeed commented 7 years ago

@sferoze I don't have time to look closely at this right now, but don't want to lose it. Can you paste your last two comments into a new issue?

sferoze commented 7 years ago

yup will do