/** * Check tax amount. * * @param array $params * @param bool $isLineItem * * @return mixed */ public static function checkTaxAmount($params, $isLineItem = FALSE) { $taxRates = CRM_Core_PseudoConstant::getTaxRates(); // Update contribution. if (!empty($params['id'])) { $id = $params['id']; $values = $ids = array(); $contrbutionParams = array('id' => $id); $prevContributionValue = CRM_Contribute_BAO_Contribution::getValues($contrbutionParams, $values, $ids); // To assign pervious finantial type on update of contribution if (!isset($params['financial_type_id'])) { $params['financial_type_id'] = $prevContributionValue->financial_type_id; } elseif (isset($params['financial_type_id']) && !array_key_exists($params['financial_type_id'], $taxRates)) { // Assisn tax Amount on update of contrbution if (!empty($prevContributionValue->tax_amount)) { $params['tax_amount'] = 'null'; CRM_Price_BAO_LineItem::getLineItemArray($params, array($params['id'])); foreach ($params['line_item'] as $setID => $priceField) { foreach ($priceField as $priceFieldID => $priceFieldValue) { $params['line_item'][$setID][$priceFieldID]['tax_amount'] = $params['tax_amount']; } } } } } // New Contrbution and update of contribution with tax rate financial type if (isset($params['financial_type_id']) && array_key_exists($params['financial_type_id'], $taxRates) && empty($params['skipLineItem']) && !$isLineItem) { $taxRateParams = $taxRates[$params['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($params['total_amount'], $taxRateParams); $params['tax_amount'] = round($taxAmount['tax_amount'], 2); // Get Line Item on update of contribution if (isset($params['id'])) { CRM_Price_BAO_LineItem::getLineItemArray($params, array($params['id'])); } else { CRM_Price_BAO_LineItem::getLineItemArray($params); } foreach ($params['line_item'] as $setID => $priceField) { foreach ($priceField as $priceFieldID => $priceFieldValue) { $params['line_item'][$setID][$priceFieldID]['tax_amount'] = $params['tax_amount']; } } $params['total_amount'] = $params['total_amount'] + $params['tax_amount']; } elseif (isset($params['api.line_item.create'])) { // Update total amount of contribution using lineItem $taxAmountArray = array(); foreach ($params['api.line_item.create'] as $key => $value) { if (isset($value['financial_type_id']) && array_key_exists($value['financial_type_id'], $taxRates)) { $taxRate = $taxRates[$value['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($value['line_total'], $taxRate); $taxAmountArray[] = round($taxAmount['tax_amount'], 2); } } $params['tax_amount'] = array_sum($taxAmountArray); $params['total_amount'] = $params['total_amount'] + $params['tax_amount']; } else { // update line item of contrbution if (isset($params['financial_type_id']) && array_key_exists($params['financial_type_id'], $taxRates) && $isLineItem) { $taxRate = $taxRates[$params['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($params['line_total'], $taxRate); $params['tax_amount'] = round($taxAmount['tax_amount'], 2); } } return $params; }
/** * Browse all price fields. * * @return void */ public function browse() { $customOption = array(); CRM_Price_BAO_PriceFieldValue::getValues($this->_fid, $customOption); // CRM-15378 - check if these price options are in an Event price set $isEvent = FALSE; $extendComponentId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_sid, 'extends', 'id'); $allComponents = explode(CRM_Core_DAO::VALUE_SEPARATOR, $extendComponentId); $eventComponentId = CRM_Core_Component::getComponentID('CiviEvent'); if (in_array($eventComponentId, $allComponents)) { $isEvent = TRUE; } $config = CRM_Core_Config::singleton(); $financialType = CRM_Contribute_PseudoConstant::financialType(); $taxRate = CRM_Core_PseudoConstant::getTaxRates(); // display taxTerm for priceFields $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); $getTaxDetails = FALSE; foreach ($customOption as $id => $values) { $action = array_sum(array_keys($this->actionLinks())); // Adding the required fields in the array if (isset($taxRate[$values['financial_type_id']])) { $customOption[$id]['tax_rate'] = $taxRate[$values['financial_type_id']]; if ($invoicing && isset($customOption[$id]['tax_rate'])) { $getTaxDetails = TRUE; } $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($customOption[$id]['amount'], $customOption[$id]['tax_rate']); $customOption[$id]['tax_amount'] = $taxAmount['tax_amount']; } if (!empty($values['financial_type_id'])) { $customOption[$id]['financial_type_id'] = $financialType[$values['financial_type_id']]; } // update enable/disable links depending on price_field properties. if ($this->_isSetReserved) { $action -= CRM_Core_Action::UPDATE + CRM_Core_Action::DELETE + CRM_Core_Action::DISABLE + CRM_Core_Action::ENABLE; } else { if ($values['is_active']) { $action -= CRM_Core_Action::ENABLE; } else { $action -= CRM_Core_Action::DISABLE; } } if (!empty($customOption[$id]['is_default'])) { $customOption[$id]['is_default'] = '<img src="' . $config->resourceBase . 'i/check.gif" />'; } else { $customOption[$id]['is_default'] = ''; } $customOption[$id]['order'] = $customOption[$id]['weight']; $customOption[$id]['action'] = CRM_Core_Action::formLink(self::actionLinks(), $action, array('oid' => $id, 'fid' => $this->_fid, 'sid' => $this->_sid), ts('more'), FALSE, 'priceFieldValue.row.actions', 'PriceFieldValue', $id); } // Add order changing widget to selector $returnURL = CRM_Utils_System::url('civicrm/admin/price/field/option', "action=browse&reset=1&fid={$this->_fid}&sid={$this->_sid}"); $filter = "price_field_id = {$this->_fid}"; CRM_Utils_Weight::addOrder($customOption, 'CRM_Price_DAO_PriceFieldValue', 'id', $returnURL, $filter); $this->assign('taxTerm', $taxTerm); $this->assign('getTaxDetails', $getTaxDetails); $this->assign('customOption', $customOption); $this->assign('sid', $this->_sid); $this->assign('isEvent', $isEvent); }
/** * Retrieve a list of options for the specified field. * * @param int $fieldId * Price field ID. * @param bool $inactiveNeeded * Include inactive options. * @param bool $reset * Ignore stored values\. * * @return array * array of options */ public static function getOptions($fieldId, $inactiveNeeded = FALSE, $reset = FALSE) { static $options = array(); if ($reset || empty($options[$fieldId])) { $values = array(); CRM_Price_BAO_PriceFieldValue::getValues($fieldId, $values, 'weight', !$inactiveNeeded); $options[$fieldId] = $values; $taxRates = CRM_Core_PseudoConstant::getTaxRates(); // ToDo - Code for Hook Invoke foreach ($options[$fieldId] as $priceFieldId => $priceFieldValues) { if (isset($priceFieldValues['financial_type_id']) && array_key_exists($priceFieldValues['financial_type_id'], $taxRates)) { $options[$fieldId][$priceFieldId]['tax_rate'] = $taxRates[$priceFieldValues['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($priceFieldValues['amount'], $options[$fieldId][$priceFieldId]['tax_rate']); $options[$fieldId][$priceFieldId]['tax_amount'] = round($taxAmount['tax_amount'], 2); } } } return $options[$fieldId]; }
/** * Browse all price set fields. * * @return void */ public function browse() { $resourceManager = CRM_Core_Resources::singleton(); if (!empty($_GET['new']) && $resourceManager->ajaxPopupsEnabled) { $resourceManager->addScriptFile('civicrm', 'js/crm.addNew.js', 999, 'html-header'); } $priceField = array(); $priceFieldBAO = new CRM_Price_BAO_PriceField(); // fkey is sid $priceFieldBAO->price_set_id = $this->_sid; $priceFieldBAO->orderBy('weight, label'); $priceFieldBAO->find(); // display taxTerm for priceFields $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); $getTaxDetails = FALSE; $taxRate = CRM_Core_PseudoConstant::getTaxRates(); CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes); while ($priceFieldBAO->fetch()) { $priceField[$priceFieldBAO->id] = array(); CRM_Core_DAO::storeValues($priceFieldBAO, $priceField[$priceFieldBAO->id]); // get price if it's a text field if ($priceFieldBAO->html_type == 'Text') { $optionValues = array(); $params = array('price_field_id' => $priceFieldBAO->id); CRM_Price_BAO_PriceFieldValue::retrieve($params, $optionValues); $financialTypeId = $optionValues['financial_type_id']; if (!array_key_exists($financialTypeId, $financialTypes)) { unset($priceField[$priceFieldBAO->id]); continue; } $priceField[$priceFieldBAO->id]['price'] = CRM_Utils_Array::value('amount', $optionValues); if ($invoicing && isset($taxRate[$financialTypeId])) { $priceField[$priceFieldBAO->id]['tax_rate'] = $taxRate[$financialTypeId]; $getTaxDetails = TRUE; } if (isset($priceField[$priceFieldBAO->id]['tax_rate'])) { $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($priceField[$priceFieldBAO->id]['price'], $priceField[$priceFieldBAO->id]['tax_rate']); $priceField[$priceFieldBAO->id]['tax_amount'] = $taxAmount['tax_amount']; } } $action = array_sum(array_keys(self::actionLinks())); if ($this->_isSetReserved) { $action -= CRM_Core_Action::UPDATE + CRM_Core_Action::DELETE + CRM_Core_Action::ENABLE + CRM_Core_Action::DISABLE; } else { if ($priceFieldBAO->is_active) { $action -= CRM_Core_Action::ENABLE; } else { $action -= CRM_Core_Action::DISABLE; } } if ($priceFieldBAO->active_on == '0000-00-00 00:00:00') { $priceField[$priceFieldBAO->id]['active_on'] = ''; } if ($priceFieldBAO->expire_on == '0000-00-00 00:00:00') { $priceField[$priceFieldBAO->id]['expire_on'] = ''; } // need to translate html types from the db $htmlTypes = CRM_Price_BAO_PriceField::htmlTypes(); $priceField[$priceFieldBAO->id]['html_type_display'] = $htmlTypes[$priceField[$priceFieldBAO->id]['html_type']]; $priceField[$priceFieldBAO->id]['order'] = $priceField[$priceFieldBAO->id]['weight']; $priceField[$priceFieldBAO->id]['action'] = CRM_Core_Action::formLink(self::actionLinks(), $action, array('fid' => $priceFieldBAO->id, 'sid' => $this->_sid), ts('more'), FALSE, 'priceField.row.actions', 'PriceField', $priceFieldBAO->id); $this->assign('taxTerm', $taxTerm); $this->assign('getTaxDetails', $getTaxDetails); } $returnURL = CRM_Utils_System::url('civicrm/admin/price/field', "reset=1&action=browse&sid={$this->_sid}"); $filter = "price_set_id = {$this->_sid}"; CRM_Utils_Weight::addOrder($priceField, 'CRM_Price_DAO_PriceField', 'id', $returnURL, $filter); $this->assign('priceField', $priceField); }
/** * Get line item purchase information. * * This function takes the input parameters and interprets out of it what has been purchased. * * @param $fields * This is the output of the function CRM_Price_BAO_PriceSet::getSetDetail($priceSetID, FALSE, FALSE); * And, it would make sense to introduce caching into that function and call it from here rather than * require the $fields array which is passed from pillar to post around the form in order to pass it in here. * @param array $params * Params reflecting form input e.g with fields 'price_5' => 7, 'price_8' => array(7, 8) * @param $lineItem * Line item array to be altered. * @param string $component * This parameter appears to only be relevant to determining whether memberships should be auto-renewed. * (and is effectively a boolean for 'is_membership' which could be calculated from the line items.) */ public static function processAmount($fields, &$params, &$lineItem, $component = '') { // using price set $totalPrice = $totalTax = 0; $radioLevel = $checkboxLevel = $selectLevel = $textLevel = array(); if ($component) { $autoRenew = array(); $autoRenew[0] = $autoRenew[1] = $autoRenew[2] = 0; } foreach ($fields as $id => $field) { if (empty($params["price_{$id}"]) || empty($params["price_{$id}"]) && $params["price_{$id}"] == NULL) { // skip if nothing was submitted for this field continue; } switch ($field['html_type']) { case 'Text': $firstOption = reset($field['options']); $params["price_{$id}"] = array($firstOption['id'] => $params["price_{$id}"]); CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); if (CRM_Utils_Array::value('tax_rate', $field['options'][key($field['options'])])) { $lineItem = self::setLineItem($field, $lineItem, key($field['options'])); $totalTax += $field['options'][key($field['options'])]['tax_amount'] * $lineItem[key($field['options'])]['qty']; } if (CRM_Utils_Array::value('name', $field['options'][key($field['options'])]) == 'contribution_amount') { $taxRates = CRM_Core_PseudoConstant::getTaxRates(); if (array_key_exists($params['financial_type_id'], $taxRates)) { $field['options'][key($field['options'])]['tax_rate'] = $taxRates[$params['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($field['options'][key($field['options'])]['amount'], $field['options'][key($field['options'])]['tax_rate']); $field['options'][key($field['options'])]['tax_amount'] = round($taxAmount['tax_amount'], 2); $lineItem = self::setLineItem($field, $lineItem, key($field['options'])); $totalTax += $field['options'][key($field['options'])]['tax_amount'] * $lineItem[key($field['options'])]['qty']; } } $totalPrice += $lineItem[$firstOption['id']]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[key($field['options'])]); break; case 'Radio': //special case if user select -none- if ($params["price_{$id}"] <= 0) { continue; } $params["price_{$id}"] = array($params["price_{$id}"] => 1); $optionValueId = CRM_Utils_Array::key(1, $params["price_{$id}"]); $optionLabel = CRM_Utils_Array::value('label', $field['options'][$optionValueId]); $params['amount_priceset_level_radio'] = array(); $params['amount_priceset_level_radio'][$optionValueId] = $optionLabel; if (isset($radioLevel)) { $radioLevel = array_merge($radioLevel, array_keys($params['amount_priceset_level_radio'])); } else { $radioLevel = array_keys($params['amount_priceset_level_radio']); } CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); if (CRM_Utils_Array::value('tax_rate', $field['options'][$optionValueId])) { $lineItem = self::setLineItem($field, $lineItem, $optionValueId); $totalTax += $field['options'][$optionValueId]['tax_amount']; if (CRM_Utils_Array::value('field_title', $lineItem[$optionValueId]) == 'Membership Amount') { $lineItem[$optionValueId]['line_total'] = $lineItem[$optionValueId]['unit_price'] = CRM_Utils_Rule::cleanMoney($lineItem[$optionValueId]['line_total'] - $lineItem[$optionValueId]['tax_amount']); } } $totalPrice += $lineItem[$optionValueId]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[$optionValueId]); if ($component && isset($lineItem[$optionValueId]['auto_renew']) && is_numeric($lineItem[$optionValueId]['auto_renew'])) { $autoRenew[$lineItem[$optionValueId]['auto_renew']] += $lineItem[$optionValueId]['line_total']; } break; case 'Select': $params["price_{$id}"] = array($params["price_{$id}"] => 1); $optionValueId = CRM_Utils_Array::key(1, $params["price_{$id}"]); $optionLabel = $field['options'][$optionValueId]['label']; $params['amount_priceset_level_select'] = array(); $params['amount_priceset_level_select'][CRM_Utils_Array::key(1, $params["price_{$id}"])] = $optionLabel; if (isset($selectLevel)) { $selectLevel = array_merge($selectLevel, array_keys($params['amount_priceset_level_select'])); } else { $selectLevel = array_keys($params['amount_priceset_level_select']); } CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); if (CRM_Utils_Array::value('tax_rate', $field['options'][$optionValueId])) { $lineItem = self::setLineItem($field, $lineItem, $optionValueId); $totalTax += $field['options'][$optionValueId]['tax_amount']; } $totalPrice += $lineItem[$optionValueId]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[$optionValueId]); if ($component && isset($lineItem[$optionValueId]['auto_renew']) && is_numeric($lineItem[$optionValueId]['auto_renew'])) { $autoRenew[$lineItem[$optionValueId]['auto_renew']] += $lineItem[$optionValueId]['line_total']; } break; case 'CheckBox': $params['amount_priceset_level_checkbox'] = $optionIds = array(); foreach ($params["price_{$id}"] as $optionId => $option) { $optionIds[] = $optionId; $optionLabel = $field['options'][$optionId]['label']; $params['amount_priceset_level_checkbox']["{$field['options'][$optionId]['id']}"] = $optionLabel; if (isset($checkboxLevel)) { $checkboxLevel = array_unique(array_merge($checkboxLevel, array_keys($params['amount_priceset_level_checkbox']))); } else { $checkboxLevel = array_keys($params['amount_priceset_level_checkbox']); } } CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); foreach ($optionIds as $optionId) { if (CRM_Utils_Array::value('tax_rate', $field['options'][$optionId])) { $lineItem = self::setLineItem($field, $lineItem, $optionId); $totalTax += $field['options'][$optionId]['tax_amount']; } $totalPrice += $lineItem[$optionId]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[$optionId]); if ($component && isset($lineItem[$optionId]['auto_renew']) && is_numeric($lineItem[$optionId]['auto_renew'])) { $autoRenew[$lineItem[$optionId]['auto_renew']] += $lineItem[$optionId]['line_total']; } } break; } } $amount_level = array(); $totalParticipant = 0; if (is_array($lineItem)) { foreach ($lineItem as $values) { $totalParticipant += $values['participant_count']; $amount_level[] = $values['label'] . ' - ' . (double) $values['qty']; } } $displayParticipantCount = ''; if ($totalParticipant > 0) { $displayParticipantCount = ' Participant Count -' . $totalParticipant; } $params['amount_level'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $amount_level) . $displayParticipantCount . CRM_Core_DAO::VALUE_SEPARATOR; $params['amount'] = CRM_Utils_Money::format($totalPrice, NULL, NULL, TRUE); $params['tax_amount'] = $totalTax; if ($component) { foreach ($autoRenew as $dontCare => $eachAmount) { if (!$eachAmount) { unset($autoRenew[$dontCare]); } } if (count($autoRenew) > 1) { $params['autoRenew'] = $autoRenew; } } }
/** * Implementation of hook_civicrm_buildAmount() * * If the event id of the form being loaded has a discount code, calculate the * the discount and update the price and label. Apply the initial autodiscount * based on a users membership. * * Check all priceset items and only apply the discount to the discounted items. * * @param string $pageType * @param CRM_Core_Form $form * @param $amounts */ function cividiscount_civicrm_buildAmount($pagetype, &$form, &$amounts) { if ((!$form->getVar('_action') || $form->getVar('_action') & CRM_Core_Action::PREVIEW || $form->getVar('_action') & CRM_Core_Action::ADD || $form->getVar('_action') & CRM_Core_Action::UPDATE) && !empty($amounts) && is_array($amounts) && ($pagetype == 'event' || $pagetype == 'membership')) { if (!$pagetype == 'membership' && in_array(get_class($form), array('CRM_Contribute_Form_Contribution', 'CRM_Contribute_Form_Contribution_Main'))) { return; } $contact_id = _cividiscount_get_form_contact_id($form); $autodiscount = FALSE; $eid = $form->getVar('_eventId'); $psid = $form->get('priceSetId'); $ps = $form->get('priceSet'); $v = $form->getVar('_values'); $code = trim(CRM_Utils_Request::retrieve('discountcode', 'String', $form, false, null, 'REQUEST')); if (!array_key_exists('discountcode', $form->_submitValues) && ($pid = $form->getVar('_participantId')) && $form->getVar('_action') & CRM_Core_Action::UPDATE) { $code = _cividiscount_get_item_by_track('civicrm_participant', $pid, $contact_id, TRUE); } if (!empty($v['currency'])) { $currency = $v['currency']; } elseif (!empty($v['event']['currency'])) { $currency = $v['event']['currency']; } else { $currency = CRM_Core_Config::singleton()->defaultCurrency; } // If additional participants are not allowed to receive a discount we need // to interrupt the form processing on build and POST. // This is a potential landmine if the form processing ever changes in Civi. if (!_cividiscount_allow_multiple()) { // POST from participant form to confirm page if ($form->getVar('_lastParticipant') == 1) { return; } // On build participant form $keys = array_keys($_GET); foreach ($keys as $key) { if (substr($key, 0, 16) == "_qf_Participant_") { // We can somewhat safely assume we're in the additional participant // registration form. // @todo what is the effect of this? if ($_GET[$key] == 'true') { return; } } } } $form->set('_discountInfo', NULL); $discountCalculator = new CRM_CiviDiscount_DiscountCalculator($pagetype, $eid, $contact_id, $code, FALSE); $discounts = $discountCalculator->getDiscounts(); if (!empty($code) && empty($discounts)) { $form->set('discountCodeErrorMsg', ts('The discount code you entered is invalid.')); } // here we check if discount is configured for events or for membership types. // There are two scenarios: // 1. Discount is configure for the event or membership type, in that case we should apply discount only // if default fee / membership type is configured. ( i.e price set with quick config true ) // 2. Discount is configure at price field level, in this case discount should be applied only for // that particular price set field. $keys = array_keys($discounts); $key = array_shift($keys); // in this case discount is specified for event id or membership type id, so we need to get info of // associated price set fields. For events discount we already have the list, but for memberships we // need to filter at membership type level //retrieve price set field associated with this priceset $priceSetInfo = CRM_CiviDiscount_Utils::getPriceSetsInfo($psid); $originalAmounts = $amounts; //$discount = array_shift($discounts); foreach ($discounts as $done_care => $discount) { if (!empty($discountCalculator->autoDiscounts) && array_key_exists($done_care, $discountCalculator->autoDiscounts)) { $autodiscount = TRUE; } else { $autodiscount = FALSE; } $priceFields = isset($discount['pricesets']) ? $discount['pricesets'] : array(); if (empty($priceFields) && (!empty($code) || $autodiscount)) { // apply discount to all the price fields if no price set set if ($pagetype == 'event') { $applyToAllLineItems = TRUE; if (!empty($key)) { $discounts[$key]['pricesets'] = array_keys($priceSetInfo); } } else { // filter only valid membership types that have discount foreach ($priceSetInfo as $pfID => $priceFieldValues) { if (!empty($priceFieldValues['membership_type_id']) && in_array($priceFieldValues['membership_type_id'], CRM_Utils_Array::value('memberships', $discount, array()))) { $priceFields[$pfID] = $pfID; } } } } // we should check for MultParticipant AND set Error Messages only if // this $discount is autodiscount or used discount if ($autodiscount || !empty($code) && $code == $discount['code']) { $apcount = _cividiscount_checkEventDiscountMultipleParticipants($pagetype, $form, $discount); } else { // silently set FALSE $apcount = FALSE; } if (empty($apcount)) { //this was set to return but that doesn't make sense as there might be another discount continue; } $discountApplied = FALSE; if (!empty($autodiscount) || !empty($code)) { foreach ($amounts as $fee_id => &$fee) { if (!is_array($fee['options'])) { continue; } foreach ($fee['options'] as $option_id => &$option) { if (!empty($applyToAllLineItems) || CRM_Utils_Array::value($option['id'], $priceFields)) { $originalLabel = $originalAmounts[$fee_id]['options'][$option_id]['label']; $originalAmount = CRM_Utils_Rule::cleanMoney($originalAmounts[$fee_id]['options'][$option_id]['amount']); list($amount, $label) = _cividiscount_calc_discount($originalAmount, $originalLabel, $discount, $autodiscount, $currency); $discountAmount = $originalAmounts[$fee_id]['options'][$option_id]['amount'] - $amount; if ($discountAmount > CRM_Utils_Array::value('discount_applied', $option)) { $option['amount'] = $amount; $option['label'] = $label; $option['discount_applied'] = $discountAmount; /* * Priyanka Karan @ Veda NFP Consulting Ltd * Re-calculate VAT/Sales TAX on discounted amount. */ $recalculateTaxAmount = array(); if (array_key_exists('tax_amount', $originalAmounts[$fee_id]['options'][$option_id]) && array_key_exists('tax_rate', $originalAmounts[$fee_id]['options'][$option_id])) { $recalculateTaxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($amount, $originalAmounts[$fee_id]['options'][$option_id]['tax_rate']); if (!empty($recalculateTaxAmount)) { $option['tax_amount'] = round($recalculateTaxAmount['tax_amount'], 2); } } } $discountApplied = TRUE; } } } } } // Display discount message if one is available if ($pagetype == 'event') { foreach ($discounts as $code => $discount) { if (isset($discount['events']) && array_key_exists($eid, $discount['events']) && $discount['discount_msg_enabled'] && (!isset($discountApplied) || !$discountApplied) && !empty($discount['autodiscount'])) { CRM_Core_Session::setStatus(html_entity_decode($discount['discount_msg']), '', 'no-popup'); } } } // this seems to incorrectly set to only the last discount but it seems not to matter in the way it is used if (isset($discountApplied) && $discountApplied) { if (!empty($ps['fields'])) { $ps['fields'] = $amounts; $form->setVar('_priceSet', $ps); } $form->set('_discountInfo', array('discount' => $discount, 'autodiscount' => $autodiscount, 'contact_id' => $contact_id)); } } }
/** * Get the tax amount (misnamed function). * * @param array $params * @param bool $isLineItem * * @return array */ public static function checkTaxAmount($params, $isLineItem = FALSE) { $taxRates = CRM_Core_PseudoConstant::getTaxRates(); // Update contribution. if (!empty($params['id'])) { // CRM-19126 and CRM-19152 If neither total or financial_type_id are set on an update // there are no tax implications - early return. if (!isset($params['total_amount']) && !isset($params['financial_type_id'])) { return $params; } if (empty($params['prevContribution'])) { $params['prevContribution'] = self::getOriginalContribution($params['id']); } foreach (array('total_amount', 'financial_type_id', 'fee_amount') as $field) { if (!isset($params[$field])) { if ($field == 'total_amount' && $params['prevContribution']->tax_amount) { // Tax amount gets added back on later.... $params['total_amount'] = $params['prevContribution']->total_amount - $params['prevContribution']->tax_amount; } else { $params[$field] = $params['prevContribution']->{$field}; if ($params[$field] != $params['prevContribution']->{$field}) { } } } } self::calculateMissingAmountParams($params, $params['id']); if (!array_key_exists($params['financial_type_id'], $taxRates)) { // Assign tax Amount on update of contribution if (!empty($params['prevContribution']->tax_amount)) { $params['tax_amount'] = 'null'; CRM_Price_BAO_LineItem::getLineItemArray($params, array($params['id'])); foreach ($params['line_item'] as $setID => $priceField) { foreach ($priceField as $priceFieldID => $priceFieldValue) { $params['line_item'][$setID][$priceFieldID]['tax_amount'] = $params['tax_amount']; } } } } } // New Contribution and update of contribution with tax rate financial type if (isset($params['financial_type_id']) && array_key_exists($params['financial_type_id'], $taxRates) && empty($params['skipLineItem']) && !$isLineItem) { $taxRateParams = $taxRates[$params['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount(CRM_Utils_Array::value('total_amount', $params), $taxRateParams); $params['tax_amount'] = round($taxAmount['tax_amount'], 2); // Get Line Item on update of contribution if (isset($params['id'])) { CRM_Price_BAO_LineItem::getLineItemArray($params, array($params['id'])); } else { CRM_Price_BAO_LineItem::getLineItemArray($params); } foreach ($params['line_item'] as $setID => $priceField) { foreach ($priceField as $priceFieldID => $priceFieldValue) { $params['line_item'][$setID][$priceFieldID]['tax_amount'] = $params['tax_amount']; } } $params['total_amount'] = CRM_Utils_Array::value('total_amount', $params) + $params['tax_amount']; } elseif (isset($params['api.line_item.create'])) { // Update total amount of contribution using lineItem $taxAmountArray = array(); foreach ($params['api.line_item.create'] as $key => $value) { if (isset($value['financial_type_id']) && array_key_exists($value['financial_type_id'], $taxRates)) { $taxRate = $taxRates[$value['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($value['line_total'], $taxRate); $taxAmountArray[] = round($taxAmount['tax_amount'], 2); } } $params['tax_amount'] = array_sum($taxAmountArray); $params['total_amount'] = $params['total_amount'] + $params['tax_amount']; } else { // update line item of contrbution if (isset($params['financial_type_id']) && array_key_exists($params['financial_type_id'], $taxRates) && $isLineItem) { $taxRate = $taxRates[$params['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($params['line_total'], $taxRate); $params['tax_amount'] = round($taxAmount['tax_amount'], 2); } } return $params; }
/** * Get line item purchase information. * * This function takes the input parameters and interprets out of it what has been purchased. * * @param $fields * This is the output of the function CRM_Price_BAO_PriceSet::getSetDetail($priceSetID, FALSE, FALSE); * And, it would make sense to introduce caching into that function and call it from here rather than * require the $fields array which is passed from pillar to post around the form in order to pass it in here. * @param array $params * Params reflecting form input e.g with fields 'price_5' => 7, 'price_8' => array(7, 8) * @param $lineItem * Line item array to be altered. * @param string $component * This parameter appears to only be relevant to determining whether memberships should be auto-renewed. * (and is effectively a boolean for 'is_membership' which could be calculated from the line items.) */ public static function processAmount($fields, &$params, &$lineItem, $component = '') { // using price set $totalPrice = $totalTax = 0; $radioLevel = $checkboxLevel = $selectLevel = $textLevel = array(); if ($component) { $autoRenew = array(); $autoRenew[0] = $autoRenew[1] = $autoRenew[2] = 0; } foreach ($fields as $id => $field) { if (empty($params["price_{$id}"]) || empty($params["price_{$id}"]) && $params["price_{$id}"] == NULL) { // skip if nothing was submitted for this field continue; } switch ($field['html_type']) { case 'Text': $firstOption = reset($field['options']); $params["price_{$id}"] = array($firstOption['id'] => $params["price_{$id}"]); CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); if (CRM_Utils_Array::value('tax_rate', $field['options'][key($field['options'])])) { $lineItem = self::setLineItem($field, $lineItem, key($field['options'])); $totalTax += $field['options'][key($field['options'])]['tax_amount'] * $lineItem[key($field['options'])]['qty']; } if (CRM_Utils_Array::value('name', $field['options'][key($field['options'])]) == 'contribution_amount') { $taxRates = CRM_Core_PseudoConstant::getTaxRates(); if (array_key_exists($params['financial_type_id'], $taxRates)) { $field['options'][key($field['options'])]['tax_rate'] = $taxRates[$params['financial_type_id']]; $taxAmount = CRM_Contribute_BAO_Contribution_Utils::calculateTaxAmount($field['options'][key($field['options'])]['amount'], $field['options'][key($field['options'])]['tax_rate']); $field['options'][key($field['options'])]['tax_amount'] = round($taxAmount['tax_amount'], 2); $lineItem = self::setLineItem($field, $lineItem, key($field['options'])); $totalTax += $field['options'][key($field['options'])]['tax_amount'] * $lineItem[key($field['options'])]['qty']; } } $totalPrice += $lineItem[$firstOption['id']]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[key($field['options'])]); break; case 'Radio': //special case if user select -none- if ($params["price_{$id}"] <= 0) { continue; } $params["price_{$id}"] = array($params["price_{$id}"] => 1); $optionValueId = CRM_Utils_Array::key(1, $params["price_{$id}"]); $optionLabel = CRM_Utils_Array::value('label', $field['options'][$optionValueId]); $params['amount_priceset_level_radio'] = array(); $params['amount_priceset_level_radio'][$optionValueId] = $optionLabel; if (isset($radioLevel)) { $radioLevel = array_merge($radioLevel, array_keys($params['amount_priceset_level_radio'])); } else { $radioLevel = array_keys($params['amount_priceset_level_radio']); } CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); if (CRM_Utils_Array::value('tax_rate', $field['options'][$optionValueId])) { $lineItem = self::setLineItem($field, $lineItem, $optionValueId); $totalTax += $field['options'][$optionValueId]['tax_amount']; if (CRM_Utils_Array::value('field_title', $lineItem[$optionValueId]) == 'Membership Amount') { $lineItem[$optionValueId]['line_total'] = $lineItem[$optionValueId]['unit_price'] = CRM_Utils_Rule::cleanMoney($lineItem[$optionValueId]['line_total'] - $lineItem[$optionValueId]['tax_amount']); } } $totalPrice += $lineItem[$optionValueId]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[$optionValueId]); if ($component && isset($lineItem[$optionValueId]['auto_renew']) && is_numeric($lineItem[$optionValueId]['auto_renew'])) { $autoRenew[$lineItem[$optionValueId]['auto_renew']] += $lineItem[$optionValueId]['line_total']; } break; case 'Select': $params["price_{$id}"] = array($params["price_{$id}"] => 1); $optionValueId = CRM_Utils_Array::key(1, $params["price_{$id}"]); $optionLabel = $field['options'][$optionValueId]['label']; $params['amount_priceset_level_select'] = array(); $params['amount_priceset_level_select'][CRM_Utils_Array::key(1, $params["price_{$id}"])] = $optionLabel; if (isset($selectLevel)) { $selectLevel = array_merge($selectLevel, array_keys($params['amount_priceset_level_select'])); } else { $selectLevel = array_keys($params['amount_priceset_level_select']); } CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); if (CRM_Utils_Array::value('tax_rate', $field['options'][$optionValueId])) { $lineItem = self::setLineItem($field, $lineItem, $optionValueId); $totalTax += $field['options'][$optionValueId]['tax_amount']; } $totalPrice += $lineItem[$optionValueId]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[$optionValueId]); if ($component && isset($lineItem[$optionValueId]['auto_renew']) && is_numeric($lineItem[$optionValueId]['auto_renew'])) { $autoRenew[$lineItem[$optionValueId]['auto_renew']] += $lineItem[$optionValueId]['line_total']; } break; case 'CheckBox': $params['amount_priceset_level_checkbox'] = $optionIds = array(); foreach ($params["price_{$id}"] as $optionId => $option) { $optionIds[] = $optionId; $optionLabel = $field['options'][$optionId]['label']; $params['amount_priceset_level_checkbox']["{$field['options'][$optionId]['id']}"] = $optionLabel; if (isset($checkboxLevel)) { $checkboxLevel = array_unique(array_merge($checkboxLevel, array_keys($params['amount_priceset_level_checkbox']))); } else { $checkboxLevel = array_keys($params['amount_priceset_level_checkbox']); } } CRM_Price_BAO_LineItem::format($id, $params, $field, $lineItem); foreach ($optionIds as $optionId) { if (CRM_Utils_Array::value('tax_rate', $field['options'][$optionId])) { $lineItem = self::setLineItem($field, $lineItem, $optionId); $totalTax += $field['options'][$optionId]['tax_amount']; } $totalPrice += $lineItem[$optionId]['line_total'] + CRM_Utils_Array::value('tax_amount', $lineItem[$optionId]); if ($component && isset($lineItem[$optionId]['auto_renew']) && is_numeric($lineItem[$optionId]['auto_renew'])) { $autoRenew[$lineItem[$optionId]['auto_renew']] += $lineItem[$optionId]['line_total']; } } break; } } $amount_level = array(); $totalParticipant = 0; if (is_array($lineItem)) { foreach ($lineItem as $values) { $totalParticipant += $values['participant_count']; // This is a bit nasty. The logic of 'quick config' was because price set configuration was // (and still is) too difficult to replace the 'quick config' price set configuration on the contribution // page. // // However, because the quick config concept existed all sorts of logic was hung off it // and function behaviour sometimes depends on whether 'price set' is set - although actually it // is always set at the functional level. In this case we are dealing with the default 'quick config' // price set having a label of 'Contribution Amount' which could wind up creating a 'funny looking' label. // The correct answer is probably for it to have an empty label in the DB - the label is never shown so it is a // place holder. // // But, in the interests of being careful when capacity is low - avoiding the known default value // will get us by. // Crucially a test has been added so a better solution can be implemented later with some comfort. // @todo - stop setting amount level in this function & call the getAmountLevel function to retrieve it. if ($values['label'] != ts('Contribution Amount')) { $amount_level[] = $values['label'] . ' - ' . (double) $values['qty']; } } } $displayParticipantCount = ''; if ($totalParticipant > 0) { $displayParticipantCount = ' Participant Count -' . $totalParticipant; } // @todo - stop setting amount level in this function & call the getAmountLevel function to retrieve it. if (!empty($amount_level)) { $params['amount_level'] = CRM_Utils_Array::implodePadded($amount_level); if (!empty($displayParticipantCount)) { $params['amount_level'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $amount_level) . $displayParticipantCount . CRM_Core_DAO::VALUE_SEPARATOR; } } $params['amount'] = CRM_Utils_Money::format($totalPrice, NULL, NULL, TRUE); $params['tax_amount'] = $totalTax; if ($component) { foreach ($autoRenew as $dontCare => $eachAmount) { if (!$eachAmount) { unset($autoRenew[$dontCare]); } } if (count($autoRenew) > 1) { $params['autoRenew'] = $autoRenew; } } }