From 69e15d738b11889008e5a2590fdaa40b2fadcc68 Mon Sep 17 00:00:00 2001 From: Jaap Jansma Date: Thu, 22 Apr 2021 15:05:39 +0200 Subject: [PATCH] Fixed dev/core#2505 Fixed failing test Fixed issue with wrong parameters in comment section Improved settings of NumberFormatter removed unused function --- CRM/Core/BAO/CustomField.php | 7 + CRM/Utils/Number.php | 19 +++ .../phpunit/CRM/Core/BAO/CustomQueryTest.php | 133 ++++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index ab42c14cc520..323b9ce9cdc7 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -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; diff --git a/CRM/Utils/Number.php b/CRM/Utils/Number.php index 3dae925661ef..790fdd1278e2 100644 --- a/CRM/Utils/Number.php +++ b/CRM/Utils/Number.php @@ -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); + } + } diff --git a/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php b/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php index 783d89a38a84..6888defc0407 100644 --- a/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php +++ b/tests/phpunit/CRM/Core/BAO/CustomQueryTest.php @@ -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. * @@ -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. *