[WIP] dev/core/issues/860: discount not applied to line item: don't overwrite _priceSet if populated. #14994
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview
Fix for dev/core/issues/860 Incorrect line item created for back-end membership sign-up using price set and CiviDiscount.
Before
When doing a back-end membership sign-up using a price set, with an additional item e.g. donation and with a CiviDiscount code applying to the membership, the line item created for the membership does not reflect the discount but the contribution total does. The problem does not occur without the additional item.
Steps to replicate
Expected result
Contribution created with total amount $80 and 2 line items:
Actual result
Contribution created with total amount $80 and 2 line items:
Note that the membership line item has the wrong amount and the sum of the line items is not equal to the contribution amount.
After
Actual result = Expected result
Technical Details
I traced the misbehaviour in a debugger and found that the price set was being instantiated twice, once with the discount, once without, causing the line items to be calculated without the discount. However if there was only one line item, a different route through the code kicked in, overriding the line item amount. I have some detailed notes from debugger sessions if those would be of interest.
I tried a couple of different approaches to fixing. The one in this PR avoids instantiating the price set twice by checking, in CRM_Member_Form_Membership, whether $this->_priceSet is already set: if it is, we skip the call to $this->setPriceSetParameters(). This is simple and it works, in my testing. It begs the question why the existing code instantiates the price set twice and I didn't find a convincing rationale for that. If there's someone who understands this rationale, they may be able to suggest a more satisfying fix. However the fix presented here is simple, fairly contained and, in my testing, leads to correct line items where previously they were incorrect. Incorrect line items are a Bad Thing, so I'm hoping a simple, contained fix will be acceptable even if it doesn't answer the bigger question of "but why is it trying to instantiate the price set twice?"
The other approach I tried was to insert a call to the buildAmount hook when instantiating the price set for the second time. This also works but
(a) required duplicating some code for setting up the fee block, including checking isACLFinancialTypeStatus() and
(b) retains the second instantiation of the price set, which seems unnecessary.
So I preferred the first approach.