Skip to content

Commit

Permalink
dev/core#1603 fix tangental bug on form handling of long options
Browse files Browse the repository at this point in the history
This fixes the bug that derailed the fix for https://lab.civicrm.org/dev/core/-/issues/1603

On further testing I agree with Jitendra that the price field form was mis-saving the longer values (I only
tested with Euro style decimal separators but maybe on both) and it was bad data caused by this
that made the merged fix look like a regression.

I also observed that the Money functions intended to round only appeared to since it was rounding
just fine to 2 places, as tested, but it was still rounding to 2 places when we wanted more.

This fixes both the New Price field screen (when options are entered) and the edit options screen
  • Loading branch information
eileenmcnaughton committed Aug 31, 2020
1 parent 060f4f6 commit bd913db
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CRM/Price/Form/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,9 @@ public function postProcess() {
// store the submitted values in an array
$params = $this->controller->exportValues('Field');
$params['price'] = CRM_Utils_Rule::cleanMoney($params['price']);
foreach ($params['option_amount'] as $key => $amount) {
$params['option_amount'][$key] = CRM_Utils_Rule::cleanMoney($amount);
}

$params['is_display_amounts'] = CRM_Utils_Array::value('is_display_amounts', $params, FALSE);
$params['is_required'] = CRM_Utils_Array::value('is_required', $params, FALSE);
Expand Down
3 changes: 1 addition & 2 deletions CRM/Price/Form/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function setDefaultValues() {

// fix the display of the monetary value, CRM-4038
foreach ($this->_moneyFields as $field) {
$defaults[$field] = CRM_Utils_Money::format(CRM_Utils_Array::value($field, $defaults), NULL, '%a');
$defaults[$field] = CRM_Utils_Money::formatLocaleNumericRoundedByOptionalPrecision($defaults[$field], 9);
}
}

Expand Down Expand Up @@ -326,7 +326,6 @@ public function postProcess() {
return NULL;
}
else {
$params = $ids = [];
$params = $this->controller->exportValues('Option');
$fieldLabel = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $this->_fid, 'label');

Expand Down
39 changes: 37 additions & 2 deletions CRM/Utils/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ protected static function formatLocaleNumeric($amount) {
* @return string
*/
protected static function formatLocaleNumericRounded($amount, $numberOfPlaces) {
return self::formatLocaleNumeric(round($amount, $numberOfPlaces));
return self::formatNumericByFormat($amount, '%!.' . $numberOfPlaces . 'i');
}

/**
Expand All @@ -216,7 +216,42 @@ protected static function formatLocaleNumericRounded($amount, $numberOfPlaces) {
* Formatted amount.
*/
public static function formatLocaleNumericRoundedByCurrency($amount, $currency) {
$amount = self::formatLocaleNumericRounded($amount, self::getCurrencyPrecision($currency));
return self::formatLocaleNumericRoundedByPrecision($amount, self::getCurrencyPrecision($currency));
}

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

/**
* Format money for display with rounding to the supplied precision but without padding.
*
* If the string is shorter than the precision trailing zeros are not added to reach the precision
* beyond the 2 required for normally currency formatting.
*
* This handles both rounding & replacement of the currency separators for the locale.
*
* @param string $amount
* @param int $precision
*
* @return string
* Formatted amount.
*/
public static function formatLocaleNumericRoundedByOptionalPrecision($amount, $precision) {
$decimalPlaces = strlen(substr($amount, strpos($amount, '.') + 1));
$amount = self::formatLocaleNumericRounded($amount, $precision > $decimalPlaces ? $decimalPlaces : $precision);
return self::replaceCurrencySeparators($amount);
}

Expand Down
28 changes: 28 additions & 0 deletions tests/phpunit/CRM/Utils/MoneyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,34 @@ public function testFormatLocaleNumericRoundedByCurrencyEuroThousand() {
$this->setCurrencySeparators(',');
}

/**
* Test rounded by currency function with specified precision.
*
* @param string $thousandSeparator
*
* @dataProvider getThousandSeparators
*/
public function testFormatLocaleNumericRoundedByPrecision($thousandSeparator) {
$this->setCurrencySeparators($thousandSeparator);
$result = CRM_Utils_Money::formatLocaleNumericRoundedByPrecision(8950.3678, 3);
$expected = ($thousandSeparator === ',') ? '8,950.368' : '8.950,368';
$this->assertEquals($expected, $result);
}

/**
* Test rounded by currency function with specified precision but without padding to reach it.
*
* @param string $thousandSeparator
*
* @dataProvider getThousandSeparators
*/
public function testFormatLocaleNumericRoundedByOptionalPrecision($thousandSeparator) {
$this->setCurrencySeparators($thousandSeparator);
$result = CRM_Utils_Money::formatLocaleNumericRoundedByOptionalPrecision(8950.3678, 8);
$expected = ($thousandSeparator === ',') ? '8,950.3678' : '8.950,3678';
$this->assertEquals($expected, $result);
}

/**
* Test that using the space character as a currency works
*/
Expand Down

0 comments on commit bd913db

Please sign in to comment.