Fix unit test to not rely on hacking the DB to have ids for price sets & associated...
authoreileen <emcnaughton@wikimedia.org>
Wed, 7 Feb 2018 23:03:22 +0000 (12:03 +1300)
committereileen <emcnaughton@wikimedia.org>
Thu, 8 Feb 2018 00:25:13 +0000 (13:25 +1300)
CRM/Price/BAO/LineItem.php
tests/phpunit/CRM/Event/BAO/ChangeFeeSelectionTest.php

index 66792a6f30f03c68a0418cdaa133a336c21bc2e0..8296e384703d79ada9740966a05792765f33d325 100644 (file)
@@ -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
index e26832f39094ac2cda8f34ebff7e83bc2c5091d0..d1bb54736189cea313b8729efc9f2354f4832de7 100644 (file)
@@ -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');