From 1cb095188284d6bf62367e29f2c5923c03ac8693 Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 8 Feb 2018 12:03:22 +1300 Subject: [PATCH] Fix unit test to not rely on hacking the DB to have ids for price sets & associated values --- CRM/Price/BAO/LineItem.php | 97 +++++++++++++++++ .../CRM/Event/BAO/ChangeFeeSelectionTest.php | 100 +++++++++--------- 2 files changed, 147 insertions(+), 50 deletions(-) diff --git a/CRM/Price/BAO/LineItem.php b/CRM/Price/BAO/LineItem.php index 66792a6f30..8296e38470 100644 --- a/CRM/Price/BAO/LineItem.php +++ b/CRM/Price/BAO/LineItem.php @@ -602,6 +602,56 @@ WHERE li.contribution_id = %1"; } } + /** + * Build the line items for the submitted price field. + * + * This is when first building them - not an update where an entityId is already present + * as this is intended as a subfunction of that. Ideally getLineItemArray would call this + * (resolving to the same format regardless of what type of price set is being used first). + * + * @param array $priceParams + * These are per the way the form processes them - ie + * ['price_1' => 1, 'price_2' => 8] + * This would mean price field id 1, option 1 (or 1 unit if using is_enter_qty). + * @param float|NULL $overrideAmount + * Optional override of the amount. + * + * @param int|NULL $financialTypeID + * Financial type ID is the type should be overridden. + * + * @return array + * Line items formatted for processing. These will look like + * [4] => ['price_field_id' => 4, 'price_field_value_id' => x, 'label....qty...unit_price...line_total...financial_type_id] + * [5] => ['price_field_id' => 5, 'price_field_value_id' => x, 'label....qty...unit_price...line_total...financial_type_id] + * + */ + public static function buildLineItemsForSubmittedPriceField($priceParams, $overrideAmount = NULL, $financialTypeID = NULL) { + $lineItems = array(); + foreach ($priceParams as $key => $value) { + $priceField = self::getPriceFieldMetaData($key); + + if ($priceField['html_type'] === 'Text') { + $valueSpec = reset($priceField['values']); + } + else { + $valueSpec = $priceField['values'][$value]; + } + $qty = $priceField['is_enter_qty'] ? $value : 1; + $lineItems[$priceField['id']] = [ + 'price_field_id' => $priceField['id'], + 'price_field_value_id' => $valueSpec['id'], + 'label' => $valueSpec['label'], + 'qty' => $qty, + 'unit_price' => $overrideAmount ?: $valueSpec['amount'], + 'line_total' => $qty * ($overrideAmount ?: $valueSpec['amount']), + 'financial_type_id' => $financialTypeID ?: $valueSpec['financial_type_id'], + 'membership_type_id' => $valueSpec['membership_type_id'], + 'price_set_id' => $priceField['price_set_id'], + ]; + } + return $lineItems; + } + /** * Function to update related contribution of a entity and * add/update/cancel financial records @@ -1023,6 +1073,53 @@ WHERE li.contribution_id = %1"; } } + /** + * Get the metadata for a price field. + * + * @param string|int $key + * Price field id. Either as an integer or as 'price_4' where 4 is the id + * + * @return array + * Metadata for the price field with a values key for option values. + */ + protected static function getPriceFieldMetaData($key) { + $priceFieldID = str_replace('price_', '', $key); + if (!isset(Civi::$statics[__CLASS__]['price_fields'][$priceFieldID])) { + $values = civicrm_api3('PriceFieldValue', 'get', [ + 'price_field_id' => $priceFieldID, + 'return' => [ + 'id', + 'amount', + 'financial_type_id', + 'membership_type_id', + 'label', + 'price_field_id', + 'price_field_id.price_set_id', + 'price_field_id.html_type', + 'is_enter_qty', + ], + ]); + $firstValue = reset($values['values']); + $values = $values['values']; + foreach ($values as $index => $value) { + // Let's be nice to calling functions & ensure membership_type_id is set + // so they don't have to handle notices on it. Handle one place not many. + if (!isset($value['membership_type_id'])) { + $values[$index]['membership_type_id'] = NULL; + } + } + + Civi::$statics[__CLASS__]['price_fields'][$priceFieldID] = [ + 'price_set_id' => $firstValue['price_field_id.price_set_id'], + 'id' => $firstValue['price_field_id'], + 'html_type' => $firstValue['price_field_id.html_type'], + 'is_enter_qty' => !empty($firstValue['is_enter_qty']), + 'values' => $values, + ]; + } + return Civi::$statics[__CLASS__]['price_fields'][$priceFieldID]; + } + /** * Helper function to retrieve financial trxn parameters to reverse * for given financial item identified by $financialItemID diff --git a/tests/phpunit/CRM/Event/BAO/ChangeFeeSelectionTest.php b/tests/phpunit/CRM/Event/BAO/ChangeFeeSelectionTest.php index e26832f390..d1bb547361 100644 --- a/tests/phpunit/CRM/Event/BAO/ChangeFeeSelectionTest.php +++ b/tests/phpunit/CRM/Event/BAO/ChangeFeeSelectionTest.php @@ -9,6 +9,9 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { protected $_cheapFee = 80; protected $_expensiveFee = 100; protected $_veryExpensive = 120; + protected $expensiveFeeValueID; + protected $cheapFeeValueID; + protected $veryExpensiveFeeValueID; /** * @var int @@ -32,7 +35,6 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { */ public function setUp() { parent::setUp(); - $this->cleanup(); $this->_contactId = $this->individualCreate(); $event = $this->eventCreate(array('is_monetary' => 1)); $this->_eventId = $event['id']; @@ -41,7 +43,6 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->_priceSetID, TRUE, FALSE); $priceSet = CRM_Utils_Array::value($this->_priceSetID, $priceSet); $this->_feeBlock = CRM_Utils_Array::value('fields', $priceSet); - $this->registerParticipantAndPay(); } /** @@ -52,24 +53,6 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { $this->quickCleanUpFinancialEntities(); } - /** - * Remove default price field stuff. - * - * This is not actually good. However resolving this requires - * a lot more fixes & we have a bit of work to do on event tests. - * - * @throws \Exception - */ - protected function cleanup() { - $this->quickCleanup( - array( - 'civicrm_price_field_value', - 'civicrm_price_field', - 'civicrm_price_set', - ) - ); - } - /** * Create an event with a price set. * @@ -129,6 +112,26 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { ); } $field = CRM_Price_BAO_PriceField::create($paramsField); + $values = $this->callAPISuccess('PriceFieldValue', 'get', [ + 'price_field_id' => $field->id, + 'return' => ['id', 'label'] + ]); + foreach ($values['values'] as $value) { + switch ($value['label']) { + case 'Expensive Room': + $this->expensiveFeeValueID = $value['id']; + break; + + case 'Cheap Room': + $this->cheapFeeValueID = $value['id']; + break; + + case 'Very Expensive': + $this->veryExpensiveFeeValueID = $value['id']; + break; + } + } + $this->priceSetFieldID = $field->id; return $priceSet->id; } @@ -224,28 +227,31 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { 'contribution_id' => $this->_contributionId, )); - $priceSetParams['price_1'] = 1; // 1 is the option of the expensive room - $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); - CRM_Price_BAO_PriceSet::processAmount($this->_feeBlock, $priceSetParams, $lineItem); - $lineItemVal[$this->_priceSetID] = $lineItem; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID; + + $lineItems = CRM_Price_BAO_LineItem::buildLineItemsForSubmittedPriceField($priceSetParams); + CRM_Price_BAO_PriceSet::processAmount($this->_feeBlock, $priceSetParams, $lineItems); + $lineItemVal[$this->_priceSetID] = $lineItems; CRM_Price_BAO_LineItem::processPriceSet($participant['id'], $lineItemVal, $this->getContributionObject($contribution['id']), 'civicrm_participant'); $this->balanceCheck($this->_expensiveFee); } public function testCRM19273() { - $priceSetParams['price_1'] = 2; + $this->registerParticipantAndPay(); + + $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee); $this->balanceCheck($this->_cheapFee); - $priceSetParams['price_1'] = 1; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee); $this->balanceCheck($this->_expensiveFee); - $priceSetParams['price_1'] = 3; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee); $this->balanceCheck($this->_veryExpensive); @@ -259,7 +265,7 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { $partiallyPaidContribuitonStatus = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Partially paid'); $this->assertEquals($this->callAPISuccessGetValue('Contribution', array('id' => $this->_contributionId, 'return' => 'contribution_status_id')), $partiallyPaidContribuitonStatus); - $priceSetParams['price_1'] = 3; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem); $this->assertEquals($this->callAPISuccessGetValue('Contribution', array('id' => $this->_contributionId, 'return' => 'contribution_status_id')), $partiallyPaidContribuitonStatus); @@ -269,12 +275,13 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { * Test that proper financial items are recorded for cancelled line items */ public function testCRM20611() { - $priceSetParams['price_1'] = 1; + $this->registerParticipantAndPay(); + $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem); $this->balanceCheck($this->_expensiveFee); - $priceSetParams['price_1'] = 2; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem); $this->balanceCheck($this->_cheapFee); @@ -313,16 +320,6 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { * Test to ensure that correct financial records are entered on text price field fee change on event registration */ public function testCRM21513() { - $this->quickCleanup( - array( - 'civicrm_price_field_value', - 'civicrm_price_field', - 'civicrm_price_set', - 'civicrm_line_item', - 'civicrm_financial_item', - ) - ); - $this->_priceSetID = $this->priceSetCreate('Text'); CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $this->_priceSetID); $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->_priceSetID, TRUE, FALSE); @@ -341,6 +338,7 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { 'contact_id' => $this->_contactId, ); $participant = $this->callAPISuccess('Participant', 'create', $params); + $this->_participantId = $participant['id']; $contributionParams = array( 'total_amount' => 10, 'source' => 'Testset with information', @@ -363,21 +361,21 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { )); // CASE 1: Choose text price qty 1 (x$10 = $10 amount) - $priceSetParams['price_1'] = 1; + $priceSetParams['price_' . $this->priceSetFieldID] = 1; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_PriceSet::processAmount($this->_feeBlock, $priceSetParams, $lineItem); $lineItemVal[$this->_priceSetID] = $lineItem; CRM_Price_BAO_LineItem::processPriceSet($this->_participantId, $lineItemVal, $this->getContributionObject($contribution['id']), 'civicrm_participant'); // CASE 2: Choose text price qty 3 (x$10 = $30 amount) - $priceSetParams['price_1'] = 3; - $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); - CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, 0); + $priceSetParams['price_' . $this->priceSetFieldID] = 3; + $lineItem = CRM_Price_BAO_LineItem::getLineItems($participant['id'], 'participant'); + CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $participant['id'], 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, 0); // CASE 3: Choose text price qty 2 (x$10 = $20 amount) - $priceSetParams['price_1'] = 2; - $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); - CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, 0); + $priceSetParams['price_' . $this->priceSetFieldID] = 2; + $lineItem = CRM_Price_BAO_LineItem::getLineItems($participant['id'], 'participant'); + CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $participant['id'], 'participant', $this->_contributionId, $this->_feeBlock, $lineItem, 0); $financialItems = $this->callAPISuccess('FinancialItem', 'Get', array( 'entity_table' => 'civicrm_line_item', @@ -421,20 +419,22 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase { * CRM-17151: Test that Contribution status change to 'Completed' if balance is zero. */ public function testCRM17151() { + $this->registerParticipantAndPay(); + $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); $partiallyPaidStatusId = array_search('Partially paid', $contributionStatuses); $pendingRefundStatusId = array_search('Pending refund', $contributionStatuses); $completedStatusId = array_search('Completed', $contributionStatuses); $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $completedStatusId, 'Payment t be completed'); - $priceSetParams['price_1'] = 2; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem); $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $pendingRefundStatusId, 'Contribution must be refunding'); - $priceSetParams['price_1'] = 1; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem); $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $completedStatusId, 'Contribution must, after complete payment be in state completed'); - $priceSetParams['price_1'] = 3; + $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID; $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant'); CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem); $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $partiallyPaidStatusId, 'Partial Paid'); -- 2.25.1