Details
-
Type: Bug
-
Status: Done/Fixed
-
Priority: Major
-
Resolution: Fixed/Completed
-
Affects Version/s: 4.4.19, 4.6.15, 4.7.6
-
Component/s: CiviContribute, CiviMember
-
Labels:None
-
Documentation Required?:None
-
Funding Source:Contributed Code
Description
This bug has existed for years - but I finally tracked down the circumstances.
If:
- a contact has multiple recurring contributions tied to the same membership (e.g. renewing a recurring membership at a different rate, or replacing card info that will soon expire);
- The payment processor supports reporting the cancellation;
- You try to cancel the older of the two recurring contributions;
The result is that the NEWER of the two recurring contributions is canceled.
The heart of the reason is in two places:
- CRM_Contribute_Form_CancelSubscription::preProcess calls a function CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails. It passes through a record ID' and the entity of that record (Contribution, ContributionRecur, Membership).
- getSubscriptionDetails executes a SQL query and returns a single row from the results.
The problem is that a membership can have multiple subscription details, but getSubscriptionDetails only returns one, the newest. So canceling subscription A can lead to subscription B being canceled.
A subsidiary issue is that we throw a fatal error if someone tries canceling a recurring contribution for a membership that's already been canceled. If someone has two recurring contributions, we have to allow them to cancel both, so I'm removing this error check.
Right now, CRM_Contribute_Form_CancelSubscription::preProcess calls getSubscriptionDetails twice if a record has both a crid and mid. I don't understand what code path would allow you to have an mid without a crid - but assuming there is one I'm unaware of, I'm going to submit a PR so that if you have both, we use the crid subscription details, not the mid's.
It's arguable that it shouldn't be allowed to renew an auto-renewing membership, and instead it's treated as an "Update Billing Details" request. However, this disallows renewing at a different rate, so I think this is the best option for now.