Skip to content

Commit

Permalink
Merge pull request civicrm#9711 from KarinG/master
Browse files Browse the repository at this point in the history
CRM-19908 - Fundamental Fixes for TaxMath Calculations 4.7
  • Loading branch information
colemanw authored Feb 3, 2017
2 parents d6005d8 + fa46cc8 commit 5519e0a
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 27 deletions.
3 changes: 2 additions & 1 deletion CRM/Contribute/BAO/Contribution/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,8 @@ public static function getFirstLastDetails($contactID) {
*/
public static function calculateTaxAmount($amount, $taxRate) {
$taxAmount = array();
$taxAmount['tax_amount'] = round(($taxRate / 100) * CRM_Utils_Rule::cleanMoney($amount), 2);
// There can not be any rounding at this stage - as this is prior to quantity multiplication
$taxAmount['tax_amount'] = ($taxRate / 100) * CRM_Utils_Rule::cleanMoney($amount);

return $taxAmount;
}
Expand Down
32 changes: 9 additions & 23 deletions CRM/Price/BAO/LineItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,15 @@ public static function getLineItems($entityId, $entity = 'participant', $isQuick
'tax_amount' => $dao->tax_amount,
'price_set_id' => $dao->price_set_id,
);
$lineItems[$dao->id]['tax_rate'] = CRM_Price_BAO_LineItem::calculateTaxRate($lineItems[$dao->id]);
$taxRates = CRM_Core_PseudoConstant::getTaxRates();
if (isset($lineItems[$dao->id]['financial_type_id']) && array_key_exists($lineItems[$dao->id]['financial_type_id'], $taxRates)) {
// We are close to output/display here - so apply some rounding at output/display level - to not show Tax Rate in all 8 decimals
$lineItems[$dao->id]['tax_rate'] = round($taxRates[$lineItems[$dao->id]['financial_type_id']], 3);
}
else {
// There is no Tax Rate associated with this Financial Type
$lineItems[$dao->id]['tax_rate'] = FALSE;
}
$lineItems[$dao->id]['subTotal'] = $lineItems[$dao->id]['qty'] * $lineItems[$dao->id]['unit_price'];
if ($lineItems[$dao->id]['tax_amount'] != '') {
$getTaxDetails = TRUE;
Expand Down Expand Up @@ -597,26 +605,4 @@ public static function getLineItemArray(&$params, $entityId = NULL, $entityTable
}
}

/**
* Calculate tax rate in percentage.
*
* @param array $lineItemId
* An assoc array of lineItem.
*
* @return int|void
* tax rate
*/
public static function calculateTaxRate($lineItemId) {
if ($lineItemId['unit_price'] == 0 || $lineItemId['qty'] == 0) {
return FALSE;
}
if ($lineItemId['html_type'] == 'Text') {
$tax = round($lineItemId['tax_amount'] / ($lineItemId['unit_price'] * $lineItemId['qty']) * 100, 2);
}
else {
$tax = round(($lineItemId['tax_amount'] / $lineItemId['unit_price']) * 100, 2);
}
return $tax;
}

}
5 changes: 3 additions & 2 deletions CRM/Price/BAO/PriceSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -1590,11 +1590,12 @@ public static function copyPriceSet($baoName, $id, $newId) {
* @return array
*/
public static function setLineItem($field, $lineItem, $optionValueId, &$totalTax) {
// Here we round - i.e. after multiplying by quantity
if ($field['html_type'] == 'Text') {
$taxAmount = $field['options'][$optionValueId]['tax_amount'] * $lineItem[$optionValueId]['qty'];
$taxAmount = round($field['options'][$optionValueId]['tax_amount'] * $lineItem[$optionValueId]['qty'], 2);
}
else {
$taxAmount = $field['options'][$optionValueId]['tax_amount'];
$taxAmount = round($field['options'][$optionValueId]['tax_amount'], 2);
}
$taxRate = $field['options'][$optionValueId]['tax_rate'];
$lineItem[$optionValueId]['tax_amount'] = $taxAmount;
Expand Down
2 changes: 1 addition & 1 deletion templates/CRM/Price/Page/LineItem.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
{if $getTaxDetails}
<td class="right">{$line.line_total|crmMoney}</td>
{if $line.tax_rate != "" || $line.tax_amount != ""}
<td class="right">{$taxTerm} ({$line.tax_rate|string_format:"%.2f"}%)</td>
<td class="right">{$taxTerm} ({$line.tax_rate|string_format:"%.3f"}%)</td>
<td class="right">{$line.tax_amount|crmMoney}</td>
{else}
<td></td>
Expand Down
62 changes: 62 additions & 0 deletions tests/phpunit/api/v3/ContributionPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1416,4 +1416,66 @@ public function addPriceFields(&$params) {
);
}

/**
* Test Tax Amount is calculated properly when using PriceSet with Field Type = Text/Numeric Quantity
*/
public function testSubmitContributionPageWithPriceSetQuantity() {
$this->_priceSetParams['is_quick_config'] = 0;
$this->enableTaxAndInvoicing();
$financialType = $this->createFinancialType();
$financialTypeId = $financialType['id'];
// This function sets the Tax Rate at 10% - it currently has no way to pass Tax Rate into it - so let's work with 10%
$financialAccount = $this->relationForFinancialTypeWithFinancialAccount($financialType['id'], 5);

$this->setUpContributionPage();
$submitParams = array(
'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
'id' => (int) $this->_ids['contribution_page'],
'first_name' => 'J',
'last_name' => 'T',
'email' => 'JT@ohcanada.ca',
'is_pay_later' => TRUE,
);

// Create PriceSet/PriceField
$priceSetID = reset($this->_ids['price_set']);
$priceField = $this->callAPISuccess('price_field', 'create', array(
'price_set_id' => $priceSetID,
'label' => 'Printing Rights',
'html_type' => 'Text',
));
$priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
'price_set_id' => $priceSetID,
'price_field_id' => $priceField['id'],
'label' => 'Printing Rights',
'financial_type_id' => $financialTypeId,
'amount' => '16.95',
));
$priceFieldId = $priceField['id'];

// Set quantity for our test
$submitParams['price_' . $priceFieldId] = 180;

// contribution_page submit requires amount and tax_amount - and that's ok we're not testing that - we're testing at the LineItem level
$submitParams['amount'] = 180 * 16.95;
// This is the correct Tax Amount - use it later to compare to what the CiviCRM Core came up with at the LineItem level
$submitParams['tax_amount'] = 180 * 16.95 * 0.10;

$this->callAPISuccess('contribution_page', 'submit', $submitParams);
$contribution = $this->callAPISuccessGetSingle('contribution', array(
'contribution_page_id' => $this->_ids['contribution_page'],
));

// Retrieve the lineItem that belongs to the Printing Rights and check the tax_amount CiviCRM Core calculated for it
$lineItem = $this->callAPISuccess('LineItem', 'get', array(
'contribution_id' => $contribution['id'],
'label' => 'Printing Rights',
));
$lineItemId = $lineItem['id'];
$lineItem_TaxAmount = round($lineItem['values'][$lineItemId]['tax_amount'], 2);

// Compare this to what it should be!
$this->assertEquals($lineItem_TaxAmount, round($submitParams['tax_amount'], 2), 'Wrong Sales Tax Amount is calculated and stored.');
}

}

0 comments on commit 5519e0a

Please sign in to comment.