Skip to content

Commit

Permalink
Merge pull request #12626 from eileenmcnaughton/money_fn
Browse files Browse the repository at this point in the history
dev/core/#119 Fix mishandling of non decimal currency on additional payment form.
  • Loading branch information
eileenmcnaughton authored Aug 19, 2018
2 parents 59add83 + 28c249a commit 4a741fb
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 17 deletions.
2 changes: 1 addition & 1 deletion CRM/Contribute/Form/AdditionalPayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function setDefaultValues() {
$defaults['total_amount'] = CRM_Utils_Money::format(abs($this->_refund), NULL, NULL, TRUE);
}
elseif ($this->_owed) {
$defaults['total_amount'] = number_format($this->_owed, 2);
$defaults['total_amount'] = CRM_Utils_Money::formatLocaleNumericRoundedForDefaultCurrency($this->_owed);
}

// Set $newCredit variable in template to control whether link to credit card mode is included
Expand Down
120 changes: 104 additions & 16 deletions CRM/Utils/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,26 +95,13 @@ public static function format($amount, $currency = NULL, $format = NULL, $onlyNu
if (!$currency) {
$currency = $config->defaultCurrency;
}

// money_format() exists only in certain PHP install (CRM-650)
// setlocale() affects native gettext (CRM-11054, CRM-9976)
if (is_numeric($amount) && function_exists('money_format')) {
$lc = setlocale(LC_MONETARY, 0);
setlocale(LC_MONETARY, 'en_US.utf8', 'en_US', 'en_US.utf8', 'en_US', 'C');
$amount = money_format($valueFormat, $amount);
setlocale(LC_MONETARY, $lc);
}

$rep = array(
',' => $config->monetaryThousandSeparator,
'.' => $config->monetaryDecimalPoint,
);

$amount = self::formatNumericByFormat($amount, $valueFormat);
// If it contains tags, means that HTML was passed and the
// amount is already converted properly,
// so don't mess with it again.
// @todo deprecate handling for the html tags because .... WTF
if (strpos($amount, '<') === FALSE) {
$amount = strtr($amount, $rep);
$amount = self::replaceCurrencySeparators($amount);
}

$replacements = array(
Expand Down Expand Up @@ -186,4 +173,105 @@ public static function equals($value1, $value2, $currency) {
return TRUE;
}

/**
* Format money for display (just numeric part) according to the current locale.
*
* This calls the underlying system function but does not handle currency separators.
*
* It's not totally clear when it changes the $amount value but has historical usage.
*
* @param $amount
*
* @return string
*/
protected static function formatLocaleNumeric($amount) {
return self::formatNumericByFormat($amount, CRM_Core_Config::singleton()->moneyvalueformat);
}

/**
* Format money for display (just numeric part) according to the current locale with rounding.
*
* At this stage this is conceived as an internal function with the currency wrapper
* functions determining the number of places.
*
* This calls the underlying system function but does not handle currency separators.
*
* It's not totally clear when it changes the $amount value but has historical usage.
*
* @param string $amount
* @param int $numberOfPlaces
*
* @return string
*/
protected static function formatLocaleNumericRounded($amount, $numberOfPlaces) {
return self::formatLocaleNumeric(round($amount, $numberOfPlaces));
}

/**
* Format money for display (just numeric part) according to the current locale with rounding.
*
* This handles both rounding & replacement of the currency separators for the locale.
*
* @param string $amount
* @param string $currency
*
* @return string
* Formatted amount.
*/
public static function formatLocaleNumericRoundedByCurrency($amount, $currency) {
$amount = self::formatLocaleNumericRounded($amount, self::getCurrencyPrecision($currency));
return self::replaceCurrencySeparators($amount);
}

/**
* Format money for display (just numeric part) according to the current locale with rounding based on the
* default currency for the site.
*
* @param $amount
* @return mixed
*/
public static function formatLocaleNumericRoundedForDefaultCurrency($amount) {
return self::formatLocaleNumericRoundedByCurrency($amount, self::getCurrencyPrecision(CRM_Core_Config::singleton()->defaultCurrency));
}

/**
* Replace currency separators.
*
* @param string $amount
*
* @return string
*/
protected static function replaceCurrencySeparators($amount) {
$config = CRM_Core_Config::singleton();
$rep = array(
',' => $config->monetaryThousandSeparator,
'.' => $config->monetaryDecimalPoint,
);
return strtr($amount, $rep);
}

/**
* Format numeric part of currency by the passed in format.
*
* This is envisaged as an internal function, with wrapper functions defining valueFormat
* into easily understood functions / variables and handling separator conversions and
* rounding.
*
* @param string $amount
* @param string $valueFormat
*
* @return string
*/
protected static function formatNumericByFormat($amount, $valueFormat) {
// money_format() exists only in certain PHP install (CRM-650)
// setlocale() affects native gettext (CRM-11054, CRM-9976)
if (is_numeric($amount) && function_exists('money_format')) {
$lc = setlocale(LC_MONETARY, 0);
setlocale(LC_MONETARY, 'en_US.utf8', 'en_US', 'en_US.utf8', 'en_US', 'C');
$amount = money_format($valueFormat, $amount);
setlocale(LC_MONETARY, $lc);
}
return $amount;
}

}

0 comments on commit 4a741fb

Please sign in to comment.