Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow to cancel subscription through CiviCRM #241

Open
wants to merge 3 commits into
base: 4.7-dev
Choose a base branch
from

Conversation

sunilpawar
Copy link

#240 allow to cancel subscription through CiviCRM

@h-c-c
Copy link
Collaborator

h-c-c commented Oct 24, 2017

Interesting! So does this get called when the cancel button is clicked on a Recurring Contribution?

@sunilpawar
Copy link
Author

yes, on clicking on 'cancel' link , pop will open , it has options (e.g notify user) like other payment processor have.

@h-c-c
Copy link
Collaborator

h-c-c commented Oct 24, 2017

I haven't tested this, but I feel like we'd be causing an error once the webhook receives the 'customer.subscription.deleted' event because that code currently cancels the recurring contribution.

In this case the recurring contribution would already be canceled.

Have you tested this and/or are you seeing such an error?

Thanks

@sunilpawar
Copy link
Author

@sunilpawar
Copy link
Author

Hi, what's your opinion on my last comment.?

@drastik
Copy link
Owner

drastik commented Nov 21, 2017

Is this something that currently does not work with the current codebase?
(cancelling a recurring contribution in Civi UI)

@h-c-c
Copy link
Collaborator

h-c-c commented Nov 21, 2017

@sunilpawar I was having difficulty understanding your sentence. But I think I have it now.

recurring cancel api check status is not cancelled before going further. so there would not be any issue.

With the API explorer, I just tried canceling an already-canceled recurring contribution with seemingly no ill effects.

@sunilpawar Have you have a chance to test your code?

@drastik currently the way we're doing it is cancel in the Stripe UI and the event triggers the Recurring Contribution cancelation in Civi.

@sunilpawar
Copy link
Author

@h-c-c , yes i have tested this on live and test mode.

\Stripe\Stripe::setApiKey($this->_paymentProcessor['user_name']);
$subscription = \Stripe\Subscription::retrieve($params['subscriptionId']);
$subscription->cancel();
return TRUE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks correct.

@@ -817,6 +817,10 @@ public function doRecurPayment(&$params, $amount, $stripe_customer) {
VALUES (%1, %2, %3, %4, %5, '{$this->_islive}')", $query_params);
}

// update recur processor_id with subscriptionId
if ($subscription_id && $recuring_contribution_id) {
CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_ContributionRecur', $recuring_contribution_id, 'processor_id', $subscription_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use the Contributionrecur.create API here instead of accessing the DAO object directly? It's less likely to break in the future if we use the API.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattwire , used api instead of DAO function

@h-c-c
Copy link
Collaborator

h-c-c commented Nov 25, 2017

@sunilpawar I just gave this a spin. When I attempt to cancel a subscription that is already canceled through the Stripe UI, it throughly locks up my civi session. Maybe we should check to see if the subscription is active before canceling it, and maybe give feedback that it doesn't exist if that's the case, and just cancel the recurring contribution.

If we proceed like this, then there's probably no need for the "Send cancellation request to Stripe?" option.

240

What do you think?

Thanks!

@sunilpawar
Copy link
Author

@h-c-c
added try catch block to handled any exception.
Tested for cancelling already cancelled subscription.

is there way to check subscription is active, because retrieve cancelled subscription using api throwing error message 'No such subscription: sub_xxxxxxx'

@drastik
Copy link
Owner

drastik commented Nov 26, 2017

We should init Stripe once in a constructor, that way we don't call these require_once() 's within functions/methods.

@h-c-c
Copy link
Collaborator

h-c-c commented Dec 9, 2017

@sunilpawar I'm against this radio button choice for "Send cancellation request to Stripe?". I'm trying to think of a valid use case for letting the user get their systems out of sync and I really can't think of good reason.

Am I missing something? Seems like we should always cancel the subscription in Stripe and simply delete the recurring contribution if it's somehow already gone.

whydothis

What do you think? Thanks!

@MegaphoneJon
Copy link

The "send cancellation request" is part of core CiviCRM.

The use case is that you can cancel recurring payments on the payment processor side, which doesn't update CiviCRM. It's not uncommon for folks to do so, not realizing there's a more correct way. I see this a lot when people switch from having a PayPal "Donate" button to using Civi - their staff are used to cancelling recurring contributions from within PayPal itself. I don't think this should block a merge.

@h-c-c
Copy link
Collaborator

h-c-c commented Jan 24, 2018

Thanks @MegaphoneJon, good to know! I understand the scenario, but not the use case. I think a better approach would be to always try to cancel on the payprocessor side and catch silently, with the assumption that we never want an active subscription without a a matching active recurring contribution. My feeling is, if we don't have to give users a way to shoot themselves in the foot, then let's not.

I guess I was more specifically asking, is there a valid use case for having a canceled recurring contribution and active subscription. I see none at this time. Leaving the radio buttons seems like a potential pitfall, much less so if "yes" was set as the default option. It's a little detail, but ultimately a kindness I feel.

@sunilpawar what if we take this approach?

-break up the initialization and cancel in to two different try statements.
-Catch hard on the initialization
-Then catch soft for the retrieve and cancel...don't do anything for the exception.

That should hand the already-canceled situation I think.

@MegaphoneJon
Copy link

Hi @h-c-c - the use cases I've encountered are:

  • Someone erroneously canceled the payment on the payment processor side;
  • The payment processor account is no longer valid.

There's also "testing", but I think that can be handled more elegantly in other ways.

@sunilpawar
Copy link
Author

@h-c-c This is back-end option for Admin/Support team who perform these operation and its safe (not every have access to payment processor site to cancel recurring payment if requested by end user). That's why these feature available through API.

CiviCRM have similar feature for other Payment processor (AuthorizeNet, PayPal Pro)

@h-c-c
Copy link
Collaborator

h-c-c commented Jan 26, 2018

ha! I'm pretty sure that means it's not safe. That is after all, the point of @MegaphoneJon 's use case....that admin people make errors.

What do think about the proposed solution to your question?

is there way to check subscription is active, because retrieve cancelled subscription using api throwing error message 'No such subscription: sub_xxxxxxx'

@jmcclelland
Copy link
Contributor

I think this is an important feature and I would really like to see it added. It seems like the only outstanding issue is h-c-c's suggestion about how to handle the already canceled subscription.

I would only add one more thing... the civicrm_contribution_recur table does not have the subscription id (aka processor_id) in it. That means any attempt to cancel a recurring contribution that was made before this patch will fail.

I would suggest two steps:

  1. Alter the cancelSubscription function to check for the presence of the subscription id in params and fail gracefully if it's not there.
  2. I think we would need an upgrade script that populates this field from the civicrm_stripe_subscription table. Something like:

UPDATE civicrm_contribution_recur cr JOIN civicrm_stripe_subscriptions ss ON cr.id = ss.contribution_recur_id SET cr.processor_id = ss.subscription_id WHERE cr.processor_id IS NULL;

@MegaphoneJon
Copy link

I'd only add that the extension should gracefully handle the situation where a subscription is already canceled from within Stripe. With the PayPal processor, pressing the "Cancel Recurring Contribution" button hangs CiviCRM, and leaves a message in the CiviCRM log.

@h-c-c
Copy link
Collaborator

h-c-c commented Apr 19, 2018

@sunilpawar To deal with the already canceled situation, apparently we can see if $subscription->ended_at is set. Found here:
stripe/stripe-php#368

Probably a good idea to keep the try/catches in there anyway.

@sunilpawar
Copy link
Author

I will add this, Thank @h-c-c for link.

@petzsch
Copy link

petzsch commented Aug 31, 2018

Is this PR still moving forward?The feature would be highly appreciated. 👍

scardinius pushed a commit to WeMoveEU/com.drastikbydesign.stripe that referenced this pull request Nov 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants