From e438393e7ad60974ae6e55eaec28ae9b87b5b048 Mon Sep 17 00:00:00 2001 From: Roland Rusch Date: Tue, 29 Aug 2023 10:57:31 +0200 Subject: [PATCH] RETROTEC-AG/OpenXE#18 Number parser implementieren --- .../I18n/Formatter/CurrencyFormatter.php | 21 ++++++++ .../I18n/Formatter/FloatFormatter.php | 48 ++++++++++++++++++- classes/Components/I18n/FormatterService.php | 25 ++++++++-- www/lib/class.erpapi.php | 35 ++++++++++++-- 4 files changed, 119 insertions(+), 10 deletions(-) diff --git a/classes/Components/I18n/Formatter/CurrencyFormatter.php b/classes/Components/I18n/Formatter/CurrencyFormatter.php index 7cba2254..82c3a042 100644 --- a/classes/Components/I18n/Formatter/CurrencyFormatter.php +++ b/classes/Components/I18n/Formatter/CurrencyFormatter.php @@ -100,6 +100,27 @@ class CurrencyFormatter extends FloatFormatter + /** + * Return a string that can be used in an SQL query to format the value for presentation to a User. + * Should return the same string as if it was formatted by FormatterInterface::formatForUser(), but directly from + * the database. + * This function does not need a native PHP value, but a table column is needed. + * + * @TODO This function is not complete. It does not add a currency symbol. + * + * @param string $col + * + * @return string + * @deprecated + * + */ + public function formatForUserWithSqlStatement(string $col): string + { + return parent::formatForUserWithSqlStatement($col); + } + + + protected function parse(string $input, ?\NumberFormatter $numberFormatter = null): false|float|int { if (!$this->showCcy) { diff --git a/classes/Components/I18n/Formatter/FloatFormatter.php b/classes/Components/I18n/Formatter/FloatFormatter.php index 501ba423..dbcea5cd 100644 --- a/classes/Components/I18n/Formatter/FloatFormatter.php +++ b/classes/Components/I18n/Formatter/FloatFormatter.php @@ -120,7 +120,13 @@ class FloatFormatter extends AbstractFormatter implements FormatterInterface { $min_decimals = $this->getNumberFormatter()->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS); $max_decimals = $this->getNumberFormatter()->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS); - return ("FORMAT({$col},LEAST('{$max_decimals}',GREATEST('{$min_decimals}',LENGTH(TRIM(TRAILING '0' FROM SUBSTRING_INDEX(CAST({$col} AS CHAR),'.',-1))))),'{$this->getLocale()}')"); + + $sql = "FORMAT({$col},LEAST('{$max_decimals}',GREATEST('{$min_decimals}',LENGTH(TRIM(TRAILING '0' FROM SUBSTRING_INDEX(CAST({$col} AS CHAR),'.',-1))))),'{$this->getLocale()}')"; + + if (!$this->getNumberFormatter()->getAttribute(\NumberFormatter::GROUPING_USED)) { + $sql = "REPLACE({$sql}, '{$this->getNumberFormatter()->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL)}', '')"; + } + return $sql; } @@ -215,6 +221,46 @@ class FloatFormatter extends AbstractFormatter implements FormatterInterface + /** + * Return the locale defined decimal symbol. + * + * @return string + */ + public function getDecimalSymbol(): string + { + return $this->getNumberFormatter()->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); + } + + + + /** + * Overwrite the locale defined decimal symbol. + * + * @param string $symbol + * + * @return $this + */ + public function setDecimalSymbol(string $symbol): self + { + $this->getNumberFormatter()->setSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL, $symbol); + return $this; + } + + + + /** + * Disable grouping (thousands). + * + * @return $this + */ + public function hideGrouping(): self + { + $this->getNumberFormatter()->setAttribute(\NumberFormatter::GROUPING_USED, 0); + return $this; + } + + + /** * Return a \NumberFormatter object from cache. If the object does not exist, it is created first. * diff --git a/classes/Components/I18n/FormatterService.php b/classes/Components/I18n/FormatterService.php index d6fecb79..b927002d 100644 --- a/classes/Components/I18n/FormatterService.php +++ b/classes/Components/I18n/FormatterService.php @@ -37,6 +37,18 @@ class FormatterService + /** + * Return the currently set locale. + * + * @return string + */ + public function getLocale(): string + { + return $this->locale; + } + + + /** * Factory for FormatterInterface objects. There will be a FormatterInterface object for every data type * necessary. @@ -61,8 +73,10 @@ class FormatterService * * @return FloatFormatter */ - public function floatFromUserInput(string $input, FormatterMode $strictness=FormatterMode::MODE_NULL): FloatFormatter - { + public function floatFromUserInput( + string $input, + FormatterMode $strictness = FormatterMode::MODE_NULL + ): FloatFormatter { $formatter = new FloatFormatter($this->locale, $strictness); $formatter->parseUserInput($input); return $formatter; @@ -78,8 +92,10 @@ class FormatterService * * @return FloatFormatter */ - public function floatFromPhpVal(string|null|float $input, FormatterMode $strictness=FormatterMode::MODE_NULL): FloatFormatter - { + public function floatFromPhpVal( + string|null|float $input, + FormatterMode $strictness = FormatterMode::MODE_NULL + ): FloatFormatter { $formatter = $this->factory(FloatFormatter::class, $strictness); $formatter->setPhpVal($input); return $formatter; @@ -284,6 +300,7 @@ class FormatterService } + /** * Format a price value for output. * diff --git a/www/lib/class.erpapi.php b/www/lib/class.erpapi.php index e764b32b..91a1d09d 100644 --- a/www/lib/class.erpapi.php +++ b/www/lib/class.erpapi.php @@ -1445,12 +1445,38 @@ public function NavigationHooks(&$menu) { return 'concat('.$spalte.",' ".$this->GetGewichtbezeichnung()."')"; } - - // @refactor DbHelper Komponente + + + + /** + * Erstelle die lokalisierten Formatierungsanweisungen für das SQL-Query. + * + * @deprecated Es wäre besser, die Formatierung in PHP zu machen + */ function FormatPreis($spalte, $stellen = null, $punkt = false) { - if(is_null($stellen))return "if(trim(round( $spalte *100))+0 <> trim($spalte*100)+0, format($spalte, length( trim($spalte)+0)-length(round($spalte))-1 ".($punkt?"":" ,'de_DE'")."),format($spalte,2".($punkt?"":" ,'de_DE'")."))"; - return "format($spalte,$stellen".($punkt?"":" ,'de_DE'").")"; + if (is_null($stellen)) { + return "if(trim(round( $spalte *100))+0 <> trim($spalte*100)+0, format($spalte, length( trim($spalte)+0)-length(round($spalte))-1 " . ($punkt ? "" : " ,'de_DE'") . "),format($spalte,2" . ($punkt ? "" : " ,'de_DE'") . "))"; + } + return "format($spalte,$stellen" . ($punkt ? "" : " ,'de_DE'") . ")"; + // Wenn die Zahlen umformatiert werden, funktioniert in den Tabellen die in Javascript implementierte Summierung nicht mehr! + /** @var \Xentral\Components\I18n\FormatterService $fs */ + $fs = $this->app->Container->get('FormatterService'); + $currencyFormatter = new \Xentral\Components\I18n\Formatter\CurrencyFormatter( + $punkt ? 'en_US' : $fs->getLocale(), + \Xentral\Components\I18n\Formatter\FormatterMode::MODE_NULL + ); + if ($punkt) { + $currencyFormatter->hideGrouping(); + } + $currencyFormatter->hideCurrency(); + if ($stellen !== null) { + $currencyFormatter->setMinDigits($stellen); + } + return $currencyFormatter->formatForUserWithSqlStatement($spalte); + +// if(is_null($stellen))return "if(trim(round( $spalte *100))+0 <> trim($spalte*100)+0, format($spalte, length( trim($spalte)+0)-length(round($spalte))-1 ".($punkt?"":" ,'de_DE'")."),format($spalte,2".($punkt?"":" ,'de_DE'")."))"; +// return "format($spalte,$stellen".($punkt?"":" ,'de_DE'").")"; } @@ -1517,7 +1543,6 @@ public function NavigationHooks(&$menu) * @deprecated Es wäre besser, die Formatierung in PHP zu machen * */ - function FormatMenge($spalte, $decimals = 0) { /** @var \Xentral\Components\I18n\FormatterService $fn */