From 7727463693fcbf6eb2e35ed2df0327b42b6cb54f Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Tue, 6 Jul 2021 13:26:33 +1200 Subject: [PATCH] Clean up code to determine line items for batch entry This removes a chunk of weird code & further consolidates on the internal BAO_Order helper. Note the test cover is in CRM_Batch_Form_EntryTest, which has validateFinancials enabled --- CRM/Batch/Form/Entry.php | 60 +++++----------------- CRM/Financial/BAO/Order.php | 99 ++++++++++++++++++++++++++----------- 2 files changed, 82 insertions(+), 77 deletions(-) diff --git a/CRM/Batch/Form/Entry.php b/CRM/Batch/Form/Entry.php index 821d8afdd8..ff306545cf 100644 --- a/CRM/Batch/Form/Entry.php +++ b/CRM/Batch/Form/Entry.php @@ -717,6 +717,7 @@ class CRM_Batch_Form_Entry extends CRM_Core_Form { * * @throws \CRM_Core_Exception * @throws \CiviCRM_API3_Exception + * @throws \API_Exception */ private function processMembership(array $params) { $batchTotal = 0; @@ -737,7 +738,6 @@ class CRM_Batch_Form_Entry extends CRM_Core_Form { $value[$fieldKey] = CRM_Utils_Rule::cleanMoney($fieldValue); } } - $membershipOrganizationID = $value['membership_type'][0]; $value = $this->standardiseRow($value); // update contact information @@ -764,57 +764,21 @@ class CRM_Batch_Form_Entry extends CRM_Core_Form { $value['soft_credit'][$key]['soft_credit_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_ContributionSoft', 'soft_credit_type_id', 'Gift'); } } - $batchTotal += $value['total_amount']; - $value['batch_id'] = $this->_batchId; $value['skipRecentView'] = TRUE; - // make entry in line item for contribution - - $editedFieldParams = [ - 'price_set_id' => $priceSetId, - 'name' => $membershipOrganizationID, - ]; - - $editedResults = []; - CRM_Price_BAO_PriceField::retrieve($editedFieldParams, $editedResults); - - if (!empty($editedResults)) { - unset($this->_priceSet['fields']); - $this->_priceSet['fields'][$editedResults['id']] = $priceSets['fields'][$editedResults['id']]; - unset($this->_priceSet['fields'][$editedResults['id']]['options']); - $fid = $editedResults['id']; - $editedFieldParams = [ - 'price_field_id' => $editedResults['id'], - 'membership_type_id' => $value['membership_type_id'], - ]; - - $editedResults = []; - CRM_Price_BAO_PriceFieldValue::retrieve($editedFieldParams, $editedResults); - $this->_priceSet['fields'][$fid]['options'][$editedResults['id']] = $priceSets['fields'][$fid]['options'][$editedResults['id']]; - if (!empty($value['total_amount'])) { - $this->_priceSet['fields'][$fid]['options'][$editedResults['id']]['amount'] = $value['total_amount']; - } - - $fieldID = key($this->_priceSet['fields']); - $value['price_' . $fieldID] = $editedResults['id']; - - $lineItem = []; - CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], - $value, $lineItem[$priceSetId] - ); - - //CRM-11529 for backoffice transactions - //when financial_type_id is passed in form, update the - //lineitems with the financial type selected in form - if (!empty($value['financial_type_id']) && !empty($lineItem[$priceSetId])) { - foreach ($lineItem[$priceSetId] as &$values) { - $values['financial_type_id'] = $value['financial_type_id']; - } - } - - $value['lineItems'] = $lineItem; + $order = new CRM_Financial_BAO_Order(); + // We use the override total amount because we are dealing with a + // possibly tax_inclusive total, which is assumed for the override total. + $order->setOverrideTotalAmount($value['total_amount']); + $order->setLineItem([ + 'membership_type_id' => $value['membership_type_id'], + 'financial_type_id' => $value['financial_type_id'], + ], $key); + + if (!empty($order->getLineItems())) { + $value['lineItems'] = [$order->getPriceSetID() => $order->getPriceFieldIndexedLineItems()]; $value['processPriceSet'] = TRUE; } // end of contribution related section diff --git a/CRM/Financial/BAO/Order.php b/CRM/Financial/BAO/Order.php index 5e7e4417f4..2388c44526 100644 --- a/CRM/Financial/BAO/Order.php +++ b/CRM/Financial/BAO/Order.php @@ -177,10 +177,12 @@ class CRM_Financial_BAO_Order { * @return float|false */ public function getOverrideTotalAmount() { - if (count($this->getPriceOptions()) !== 1) { + // The override amount is only valid for quick config price sets where more + // than one field has not been selected. + if (!$this->overrideTotalAmount || !$this->supportsOverrideAmount() || count($this->getPriceOptions()) > 1) { return FALSE; } - return $this->overrideTotalAmount ?? FALSE; + return $this->overrideTotalAmount; } /** @@ -191,9 +193,7 @@ class CRM_Financial_BAO_Order { * @param float $overrideTotalAmount */ public function setOverrideTotalAmount(float $overrideTotalAmount): void { - if ($this->supportsOverrideAmount()) { - $this->overrideTotalAmount = $overrideTotalAmount; - } + $this->overrideTotalAmount = $overrideTotalAmount; } /** @@ -217,7 +217,7 @@ class CRM_Financial_BAO_Order { * * @param int $overrideFinancialTypeID */ - public function setOverrideFinancialTypeID(int $overrideFinancialTypeID) { + public function setOverrideFinancialTypeID(int $overrideFinancialTypeID): void { $this->overrideFinancialTypeID = $overrideFinancialTypeID; } @@ -479,6 +479,22 @@ class CRM_Financial_BAO_Order { return $this->lineItems; } + /** + * Get line items in a 'traditional' indexing format. + * + * This ensures the line items are indexed by + * price field id - as required by the contribution BAO. + * + * @throws \CiviCRM_API3_Exception + */ + public function getPriceFieldIndexedLineItems(): array { + $lines = []; + foreach ($this->getLineItems() as $item) { + $lines[$item['price_field_id']] = $item; + } + return $lines; + } + /** * Get line items that specifically relate to memberships. * @@ -566,14 +582,7 @@ class CRM_Financial_BAO_Order { } $taxRate = $this->getTaxRate((int) $lineItem['financial_type_id']); if ($this->getOverrideTotalAmount() !== FALSE) { - if ($taxRate) { - // Total is tax inclusive. - $lineItem['tax_amount'] = ($taxRate / 100) * $this->getOverrideTotalAmount() / (1 + ($taxRate / 100)); - $lineItem['line_total'] = $lineItem['unit_price'] = $this->getOverrideTotalAmount() - $lineItem['tax_amount']; - } - else { - $lineItem['line_total'] = $lineItem['unit_price'] = $this->getOverrideTotalAmount(); - } + $this->addTotalsToLineBasedOnOverrideTotal((int) $lineItem['financial_type_id'], $lineItem); } elseif ($taxRate) { $lineItem['tax_amount'] = ($taxRate / 100) * $lineItem['line_total']; @@ -674,8 +683,16 @@ class CRM_Financial_BAO_Order { * */ public function setLineItem(array $lineItem, $index): void { - if (!empty($lineItem['price_field_id']) && !isset($this->priceSetID)) { - $this->setPriceSetIDFromSelectedField($lineItem['price_field_id']); + if (!isset($this->priceSetID)) { + if (!empty($lineItem['price_field_id'])) { + $this->setPriceSetIDFromSelectedField($lineItem['price_field_id']); + } + else { + // we are using either the default membership or default contribution + // If membership type is passed in we use the default price field. + $component = !empty($lineItem['membership_type_id']) ? 'membership' : 'contribution'; + $this->setPriceSetToDefault($component); + } } if (!isset($lineItem['financial_type_id'])) { $lineItem['financial_type_id'] = $this->getDefaultFinancialTypeID(); @@ -683,14 +700,15 @@ class CRM_Financial_BAO_Order { if (!is_numeric($lineItem['financial_type_id'])) { $lineItem['financial_type_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'financial_type_id', $lineItem['financial_type_id']); } - $lineItem['tax_amount'] = ($this->getTaxRate($lineItem['financial_type_id']) / 100) * $lineItem['line_total']; + if ($this->getOverrideTotalAmount()) { + $this->addTotalsToLineBasedOnOverrideTotal((int) $lineItem['financial_type_id'], $lineItem); + } + else { + $lineItem['tax_amount'] = ($this->getTaxRate($lineItem['financial_type_id']) / 100) * $lineItem['line_total']; + } if (!empty($lineItem['membership_type_id'])) { $lineItem['entity_table'] = 'civicrm_membership'; if (empty($lineItem['price_field_id']) && empty($lineItem['price_field_value_id'])) { - // If only the membership type is passed in we use the default price field. - if (!isset($this->priceSetID)) { - $this->setPriceSetToDefault('membership'); - } $lineItem = $this->fillMembershipLine($lineItem); } } @@ -742,17 +760,20 @@ class CRM_Financial_BAO_Order { */ protected function fillMembershipLine(array $lineItem): array { $fields = $this->getPriceFieldsMetadata(); - $field = reset($fields); - if (!isset($lineItem['price_field_value_id'])) { - foreach ($field['options'] as $option) { - if ((int) $option['membership_type_id'] === (int) $lineItem['membership_type_id']) { - $lineItem['price_field_id'] = $field['id']; - $lineItem['price_field_value_id'] = $option['id']; - $lineItem['qty'] = 1; + foreach ($fields as $field) { + if (!isset($lineItem['price_field_value_id'])) { + foreach ($field['options'] as $option) { + if ((int) $option['membership_type_id'] === (int) $lineItem['membership_type_id']) { + $lineItem['price_field_id'] = $field['id']; + $lineItem['price_field_value_id'] = $option['id']; + $lineItem['qty'] = 1; + } } } + if (isset($lineItem['price_field_value_id'], $field['options'][$lineItem['price_field_value_id']])) { + $option = $field['options'][$lineItem['price_field_value_id']]; + } } - $option = $field['options'][$lineItem['price_field_value_id']]; $lineItem['unit_price'] = $lineItem['line_total'] ?? $option['amount']; $lineItem['label'] = $lineItem['label'] ?? $option['label']; $lineItem['field_title'] = $lineItem['field_title'] ?? $option['label']; @@ -760,4 +781,24 @@ class CRM_Financial_BAO_Order { return $lineItem; } + /** + * Add total_amount and tax_amount to the line from the override total. + * + * @param int $financialTypeID + * @param array $lineItem + * + * @return void + */ + protected function addTotalsToLineBasedOnOverrideTotal(int $financialTypeID, array &$lineItem): void { + $taxRate = $this->getTaxRate($financialTypeID); + if ($taxRate) { + // Total is tax inclusive. + $lineItem['tax_amount'] = ($taxRate / 100) * $this->getOverrideTotalAmount() / (1 + ($taxRate / 100)); + $lineItem['line_total'] = $lineItem['unit_price'] = $this->getOverrideTotalAmount() - $lineItem['tax_amount']; + } + else { + $lineItem['line_total'] = $lineItem['unit_price'] = $this->getOverrideTotalAmount(); + } + } + } -- 2.25.1