From 269274586aee844b799c4cfba6e5de6ee36edced Mon Sep 17 00:00:00 2001 From: David Andersson Date: Mon, 16 May 2022 13:12:13 +0200 Subject: [PATCH] Fixes #11 - Remove trailing zeros from formatted price (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove trailing zeros from formatted price * Add setting for how to handle trailing decimal zeros * Write tests * Fix code style * Rewrite function description * Change test name * Add empty line at end of file * rename deleteTrailingDecimalZeros to trimTrailingDecimalZeros * Fix grammar * Remove unnecessary parameter declarations * fix test name * fix comment grammar * fix docblock grammar Co-authored-by: Samuel Štancl --- src/Currency.php | 12 ++++++++++++ src/PriceFormatter.php | 8 ++++++++ tests/Currencies/SEK.php | 17 +++++++++++++++++ tests/Pest/CurrencyTest.php | 1 + tests/Pest/FormattingTest.php | 15 ++++++++++++++- 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/Currencies/SEK.php diff --git a/src/Currency.php b/src/Currency.php index adaf4cf..3f071bf 100644 --- a/src/Currency.php +++ b/src/Currency.php @@ -40,6 +40,9 @@ class Currency implements Arrayable, JsonSerializable /** How many decimals of the currency's values should get rounded. */ protected int $rounding; + /** Should trailing decimal zeros be trimmed. */ + protected bool $trimTrailingDecimalZeros; + /** Create a new Currency instance. */ public function __construct( string $code = null, @@ -52,6 +55,7 @@ class Currency implements Arrayable, JsonSerializable int $rounding = null, string $decimalSeparator = null, string $thousandsSeparator = null, + bool $trimTrailingDecimalZeros = null, ) { $this->code = $code ?? $this->code ?? ''; $this->name = $name ?? $this->name ?? ''; @@ -63,6 +67,7 @@ class Currency implements Arrayable, JsonSerializable $this->decimalSeparator = $decimalSeparator ?? $this->decimalSeparator ?? '.'; $this->thousandsSeparator = $thousandsSeparator ?? $this->thousandsSeparator ?? ','; $this->rounding = $rounding ?? $this->rounding ?? $this->mathDecimals; + $this->trimTrailingDecimalZeros = $trimTrailingDecimalZeros ?? $this->trimTrailingDecimalZeros ?? false; $this->check(); } @@ -133,6 +138,12 @@ class Currency implements Arrayable, JsonSerializable return $this->rounding; } + /** Get the currency's setting for trimming trailing decimal zeros. */ + public function trimTrailingDecimalZeros(): bool + { + return $this->trimTrailingDecimalZeros; + } + /** Convert the currency to a string (returns the code). */ public function __toString() { @@ -153,6 +164,7 @@ class Currency implements Arrayable, JsonSerializable 'rounding' => $this->rounding, 'decimalSeparator' => $this->decimalSeparator, 'thousandsSeparator' => $this->thousandsSeparator, + 'trimTrailingDecimalZeros' => $this->trimTrailingDecimalZeros, ]; } diff --git a/src/PriceFormatter.php b/src/PriceFormatter.php index b01010f..61ea4bc 100644 --- a/src/PriceFormatter.php +++ b/src/PriceFormatter.php @@ -23,6 +23,14 @@ class PriceFormatter $currency->thousandsSeparator(), ); + if ($currency->trimTrailingDecimalZeros()) { + // Remove trailing zeros from the formatted string + $decimal = rtrim($decimal, '0'); + + // Once there are no more decimal values, remove the decimal separator as well + $decimal = rtrim($decimal, $currency->decimalSeparator()); + } + return $currency->prefix() . $decimal . $currency->suffix(); } diff --git a/tests/Currencies/SEK.php b/tests/Currencies/SEK.php new file mode 100644 index 0000000..7d13337 --- /dev/null +++ b/tests/Currencies/SEK.php @@ -0,0 +1,17 @@ + 2, 'decimalSeparator' => ',', 'thousandsSeparator' => '.', + 'trimTrailingDecimalZeros' => false, ]); }); diff --git a/tests/Pest/FormattingTest.php b/tests/Pest/FormattingTest.php index fda4e03..ce390dd 100644 --- a/tests/Pest/FormattingTest.php +++ b/tests/Pest/FormattingTest.php @@ -5,8 +5,9 @@ use ArchTech\Money\Currency; use ArchTech\Money\Money; use ArchTech\Money\Tests\Currencies\CZK; use ArchTech\Money\Tests\Currencies\EUR; +use ArchTech\Money\Tests\Currencies\SEK; -beforeEach(fn () => currencies()->add([CZK::class, EUR::class])); +beforeEach(fn () => currencies()->add([CZK::class, EUR::class, SEK::class])); test('prefixes are applied', function () { expect(Money::fromDecimal(10.00, USD::class)->formatted())->toBe('$10.00'); @@ -45,3 +46,15 @@ test('the format method accepts overrides', function () { expect(Money::fromDecimal(10.45)->formatted(['decimalSeparator' => ',', 'prefix' => '$$$']))->toBe('$$$10,45'); expect(Money::fromDecimal(10.45)->formatted(decimalSeparator: ',', suffix: ' USD'))->toBe('$10,45 USD'); }); + +test('decimal zeros can be trimmed', function () { + // SEK uses decimal zero trimming + expect(Money::fromDecimal(10.00, SEK::class)->formatted())->toBe('10 kr'); + expect(Money::fromDecimal(10.10, SEK::class)->formatted())->toBe('10.1 kr'); + expect(Money::fromDecimal(10.12, SEK::class)->formatted())->toBe('10.12 kr'); + + // EUR does not use decimal zero trimming + expect(Money::fromDecimal(10.00, EUR::class)->formatted())->toBe('10.00 €'); + expect(Money::fromDecimal(10.10, EUR::class)->formatted())->toBe('10.10 €'); + expect(Money::fromDecimal(10.12, EUR::class)->formatted())->toBe('10.12 €'); +});