Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed dev/core#2505 fix formatting of numbers in civireport #20123

Merged
merged 1 commit into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CRM/Core/BAO/CustomField.php
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,13 @@ private static function formatDisplayValue($value, $field, $entityId = NULL) {
}
$display = implode(', ', $disp);
}
elseif ($field['data_type'] == 'Float' && isset($value)) {
// $value can also be an array(while using IN operator from search builder or api).
foreach ((array) $value as $val) {
$disp[] = CRM_Utils_Number::formatLocaleNumeric($val);
}
$display = implode(', ', $disp);
}
break;
}
return $display;
Expand Down
19 changes: 19 additions & 0 deletions CRM/Utils/Number.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,23 @@ public static function formatUnitSize($size, $checkForPostMax = FALSE) {
}
}

/**
* Format number for display according to the current or supplied locale.
*
* Note this should not be used in conjunction with any calls to
* replaceCurrencySeparators as this function already does that.
*
* @param string $amount
* @param string $locale
*
* @return string
* @throws \Brick\Money\Exception\UnknownCurrencyException
*/
public static function formatLocaleNumeric(string $amount, $locale = NULL): string {
$formatter = new \NumberFormatter($locale ?? CRM_Core_I18n::getLocale(), NumberFormatter::DECIMAL);
$formatter->setSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL, CRM_Core_Config::singleton()->monetaryDecimalPoint);
$formatter->setSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL, CRM_Core_Config::singleton()->monetaryThousandSeparator);
return $formatter->format($amount);
}

}
133 changes: 133 additions & 0 deletions tests/phpunit/CRM/Core/BAO/CustomQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,58 @@ public function testSearchCustomDataFromTo() {
}
}

/**
* Test filtering by relative custom data.
*
* @throws \CRM_Core_Exception
*/
public function testLocalizedSearchCustomDataFromTo() {
$this->setMonetaryDecimalPoint(',');
$this->setMonetaryThousandSeparator('.');
$ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest');
$datas = [
'Int' => ['value' => 2, 'formatted_from' => '1', 'formatted_to' => '2'],
'Float' => ['value' => 12.123, 'formatted_from' => '11,123', 'formatted_to' => '12,123'],
'Float' => ['value' => 3412.123, 'formatted_from' => '3.411,123', 'formatted_to' => '3.412,123'],
'Money' => ['value' => 91.21, 'formatted_from' => '90,21', 'formatted_to' => '91,21'],
'Money' => ['value' => 7891.22, 'formatted_from' => '7.890,22', 'formatted_to' => '7.891,22'],
];
foreach ($datas as $type => $data) {
$customField = $this->customFieldCreate(
[
'custom_group_id' => $ids['custom_group_id'],
'label' => "$type field",
'data_type' => $type,
'html_type' => 'Text',
'default_value' => NULL,
]
);
$customFieldName = 'custom_' . $customField['id'];
// Assigning the relevant form value to be within a custom key is normally done in
// build field params. It would be better if it were all done in convertFormValues
// but for now we just imitate it.
$from = $data['value'] - 1;
$to = $data['value'];
$formatted_from = $data['formatted_from'];
$formatted_to = $data['formatted_to'];
$formValues = [
$customFieldName . '_from' => $from,
$customFieldName . '_to' => $to,
];

$params = CRM_Contact_BAO_Query::convertFormValues($formValues);
$queryObj = new CRM_Contact_BAO_Query($params);
$queryObj->query();
$this->assertEquals(
'civicrm_value_testlocalized_1.' . strtolower($type) . "_field_{$customField['id']} BETWEEN \"$from\" AND \"$to\"",
$queryObj->_where[0][0]
);
$this->assertEquals($queryObj->_qill[0][0], "$type field BETWEEN $formatted_from, $formatted_to");
}
$this->setMonetaryDecimalPoint('.');
$this->setMonetaryThousandSeparator(',');
}

/**
* Test filtering by relative custom data.
*
Expand Down Expand Up @@ -319,6 +371,87 @@ public function testSearchCustomDataFromAndTo() {
}
}

/**
* Test filtering by relative custom data.
*
* @throws \CRM_Core_Exception
*/
public function testLocalizedSearchCustomDataFromAndTo() {
$this->setMonetaryDecimalPoint(',');
$this->setMonetaryThousandSeparator('.');
$ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest');
$dataSet = [
'Date' => ['value' => '2015-06-06', 'sql_string' => '"20150606235959"', 'qill_string' => "'June 6th, 2015 11:59 PM'", 'qill_string_greater' => "'June 6th, 2015 12:00 AM'"],
// @todo - investigate the impact of using quotes on what should be an integer field.
'Int' => ['value' => 2, 'sql_string' => '"2"'],
'Float' => ['value' => 12.123, 'sql_string' => '"12,123"'],
'Float' => ['value' => 3412.123, 'sql_string' => '"3412.123"', 'qill_string' => '3.412,123'],
'Money' => ['value' => 91.21],
'Money' => ['value' => 7891.21, 'qill_string' => '7.891,21'],
];
foreach ($dataSet as $type => $values) {
$data = $values['value'];
$isDate = ($type === 'Date');
$customField = $this->customFieldCreate(
[
'custom_group_id' => $ids['custom_group_id'],
'label' => "$type field",
'data_type' => $type,
'html_type' => ($isDate) ? 'Select Date' : 'Text',
'default_value' => NULL,
]
);
$customFieldName = 'custom_' . $customField['id'];

$expectedValue = $values['sql_string'] ?? $data;
$expectedQillValue = $values['qill_string'] ?? $data;
$toQillValue = chr(226) . chr(137) . chr(164) . ' ' . $expectedQillValue;
$fromQillValue = chr(226) . chr(137) . chr(165) . ' ' . ($values['qill_string_greater'] ?? $expectedQillValue);

// Assigning the relevant form value to be within a custom key is normally done in
// build field params. It would be better if it were all done in convertFormValues
// but for now we just imitate it.

//Scenario 2 : TO date filter
$formValues = [
$customFieldName . '_to' => $data,
];

$params = CRM_Contact_BAO_Query::convertFormValues($formValues);
$queryObj = new CRM_Contact_BAO_Query($params);
$queryObj->query();

$this->assertEquals(
'civicrm_value_testlocalized_1.' . strtolower($type) . "_field_{$customField['id']} <= $expectedValue",
$queryObj->_where[0][0]
);
$this->assertEquals($queryObj->_qill[0][0],
"$type field $toQillValue"
);

//Scenario 2 : FROM date filter
$formValues = [
$customFieldName . '_from' => $values['value'],
];

$params = CRM_Contact_BAO_Query::convertFormValues($formValues);
$queryObj = new CRM_Contact_BAO_Query($params);
$queryObj->query();

$expectedValue = ($isDate) ? '"20150606000000"' : $expectedValue;
$this->assertEquals(
'civicrm_value_testlocalized_1.' . strtolower($type) . "_field_{$customField['id']} >= $expectedValue",
$queryObj->_where[0][0]
);
$this->assertEquals(
"$type field $fromQillValue",
$queryObj->_qill[0][0]
);
}
$this->setMonetaryDecimalPoint('.');
$this->setMonetaryThousandSeparator(',');
}

/**
* Test filtering by relative custom data dates.
*
Expand Down