Skip to content

Commit

Permalink
Fixes getTemplateContribution to use a more reliable way to load line…
Browse files Browse the repository at this point in the history
… items

My efforts to add testing a 'deprecate weird stuff' have identified an odd and fragile
flow for the line items in getTemplateContribution. It calls
getLineItemsByContributionID which, as it turns out, substitues the
actual entity table with 'civicrm_contribution'.

Then this line of weird handling swoops in and saves the day.

https://github.com/civicrm/civicrm-core/pull/20775/files#diff-a16d4d7449cf5f3a0616d1d282a32f27ab6d3f7d2726d076c02ad1d4d655af41R393

This switches us to something cleaner than just loads the line items (with v4 LineItem.get) and
no weird handling
  • Loading branch information
eileenmcnaughton committed Jul 6, 2021
1 parent c3013f9 commit 5b6fa91
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 15 deletions.
1 change: 0 additions & 1 deletion CRM/Contribute/BAO/Contribution.php
Original file line number Diff line number Diff line change
Expand Up @@ -2497,7 +2497,6 @@ public static function contributionCount($contactId, $includeSoftCredit = TRUE)
* The count is out on how correct related entities wind up in this case.
*/
protected static function repeatTransaction(array $input, array $contributionParams) {

$templateContribution = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution(
(int) $contributionParams['contribution_recur_id'],
array_filter([
Expand Down
4 changes: 3 additions & 1 deletion CRM/Contribute/BAO/ContributionRecur.php
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,9 @@ public static function getTemplateContribution(int $id, $overrides = []): array
}
if ($templateContributions->count()) {
$templateContribution = $templateContributions->first();
$lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($templateContribution['id']);
$order = new CRM_Financial_BAO_Order();
$order->setTemplateContributionID($templateContribution['id']);
$lineItems = $order->getLineItems();
// We only permit the financial type to be overridden for single line items.
// Otherwise we need to figure out a whole lot of extra complexity.
// It's not UI-possible to alter financial_type_id for recurring contributions
Expand Down
93 changes: 84 additions & 9 deletions CRM/Financial/BAO/Order.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
+--------------------------------------------------------------------+
*/

use Civi\Api4\LineItem;
use Civi\Api4\PriceField;
use Civi\Api4\PriceSet;

Expand Down Expand Up @@ -65,6 +66,27 @@ class CRM_Financial_BAO_Order {
*/
protected $defaultFinancialTypeID;

/**
* ID of a contribution to be used as a template.
*
* @var int
*/
protected $templateContributionID;

/**
* @return int|null
*/
public function getTemplateContributionID(): ?int {
return $this->templateContributionID;
}

/**
* @param int $templateContributionID
*/
public function setTemplateContributionID(int $templateContributionID): void {
$this->templateContributionID = $templateContributionID;
}

/**
* @return int
*/
Expand Down Expand Up @@ -283,7 +305,6 @@ public function supportsOverrideAmount(): bool {
*
* @param int $contributionPageID
*
* @throws \CiviCRM_API3_Exception
*/
public function setPriceSetIDByContributionPageID(int $contributionPageID): void {
$this->setPriceSetIDByEntity('contribution_page', $contributionPageID);
Expand Down Expand Up @@ -550,7 +571,8 @@ public function getRenewableMembershipTypes(): array {

/**
* @return array
* @throws \CiviCRM_API3_Exception
*
* @throws \API_Exception
*/
protected function calculateLineItems(): array {
$lineItems = [];
Expand All @@ -564,17 +586,26 @@ protected function calculateLineItems(): array {

// Dummy value to prevent e-notice in getLine. We calculate tax in this class.
$params['financial_type_id'] = 0;
foreach ($this->getPriceOptions() as $fieldID => $valueID) {
$this->setPriceSetIDFromSelectedField($fieldID);
$throwAwayArray = [];
// @todo - still using getLine for now but better to bring it to this class & do a better job.
$newLines = CRM_Price_BAO_PriceSet::getLine($params, $throwAwayArray, $this->getPriceSetID(), $this->getPriceFieldSpec($fieldID), $fieldID)[1];
foreach ($newLines as $newLine) {
$lineItems[$newLine['price_field_value_id']] = $newLine;
if ($this->getTemplateContributionID()) {
$lineItems = $this->getLinesFromTemplateContribution();
}
else {
foreach ($this->getPriceOptions() as $fieldID => $valueID) {
$this->setPriceSetIDFromSelectedField($fieldID);
$throwAwayArray = [];
// @todo - still using getLine for now but better to bring it to this class & do a better job.
$newLines = CRM_Price_BAO_PriceSet::getLine($params, $throwAwayArray, $this->getPriceSetID(), $this->getPriceFieldSpec($fieldID), $fieldID)[1];
foreach ($newLines as $newLine) {
$lineItems[$newLine['price_field_value_id']] = $newLine;
}
}
}

foreach ($lineItems as &$lineItem) {
// Set the price set id if not set above. Note that the above
// requires it for line retrieval but we want to fix that as it
// should not be required at that point.
$this->setPriceSetIDFromSelectedField($lineItem['price_field_id']);
// Set any pre-calculation to zero as we will calculate.
$lineItem['tax_amount'] = 0;
if ($this->getOverrideFinancialTypeID() !== FALSE) {
Expand Down Expand Up @@ -801,4 +832,48 @@ protected function addTotalsToLineBasedOnOverrideTotal(int $financialTypeID, arr
}
}

/**
* Get the line items from a template.
*
* @return \Civi\Api4\Generic\Result
*
* @throws \API_Exception
*/
protected function getLinesFromTemplateContribution(): array {
$lines = $this->getLinesForContribution();
foreach ($lines as &$line) {
// The apiv4 insists on adding id - so let it get all the details
// and we will filter out those that are not part of a template here.
unset($line['id'], $line['contribution_id']);
}
return $lines;
}

/**
* @return array
* @throws \API_Exception
* @throws \Civi\API\Exception\UnauthorizedException
*/
protected function getLinesForContribution(): array {
return (array) LineItem::get(FALSE)
->addWhere('contribution_id', '=', $this->getTemplateContributionID())
->setSelect([
'contribution_id',
'entity_id',
'entity_table',
'price_field_id',
'price_field_value_id',
'financial_type_id',
'label',
'qty',
'unit_price',
'line_total',
'tax_amount',
'non_deductible_amount',
'participant_count',
'membership_num_terms',
])
->execute();
}

}
4 changes: 2 additions & 2 deletions tests/phpunit/CRM/Core/Payment/PayPalIPNTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public function testIPNPaymentRecurSuccess(): void {
$this->assertEquals(1, $contribution1['contribution_status_id']);
$this->assertEquals('8XA571746W2698126', $contribution1['trxn_id']);
// source gets set by processor
$this->assertTrue(substr($contribution1['contribution_source'], 0, 20) === 'Online Contribution:');
$this->assertEquals('Online Contribution:', substr($contribution1['contribution_source'], 0, 20));
$contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID]);
$this->assertEquals(5, $contributionRecur['contribution_status_id']);
$paypalIPN = new CRM_Core_Payment_PayPalIPN($this->getPaypalRecurSubsequentTransaction());
Expand Down Expand Up @@ -207,7 +207,7 @@ public function testIPNPaymentMembershipRecurSuccess() {
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
public function testIPNPaymentInputMembershipRecurSuccess() {
public function testIPNPaymentInputMembershipRecurSuccess(): void {
$durationUnit = 'year';
$this->setupMembershipRecurringPaymentProcessorTransaction(['duration_unit' => $durationUnit, 'frequency_unit' => $durationUnit]);
$membershipPayment = $this->callAPISuccessGetSingle('membership_payment', []);
Expand Down
2 changes: 0 additions & 2 deletions tests/phpunit/CiviTest/CiviUnitTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2557,11 +2557,9 @@ public function setupRecurringPaymentProcessorTransaction($recurParams = [], $co
'total_amount' => '200',
'invoice_id' => $this->_invoiceID,
'financial_type_id' => 'Donation',
'contribution_status_id' => 'Pending',
'contact_id' => $this->_contactID,
'contribution_page_id' => $this->_contributionPageID,
'payment_processor_id' => $this->_paymentProcessorID,
'is_test' => 0,
'receive_date' => '2019-07-25 07:34:23',
'skipCleanMoney' => TRUE,
'amount_level' => 'expensive',
Expand Down

0 comments on commit 5b6fa91

Please sign in to comment.