From 30a35c50de0b143c22fe3501f721a3291660b304 Mon Sep 17 00:00:00 2001 From: Michel Bade Date: Mon, 21 Sep 2026 09:19:13 +0200 Subject: [PATCH] fix: wrong tax summing --- src/Context/Cart/CalculatedTax.php | 14 ++--- tests/Context/Cart/CalculatedTaxTest.php | 69 ++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/Context/Cart/CalculatedTax.php b/src/Context/Cart/CalculatedTax.php index e8410d3..0788f7c 100644 --- a/src/Context/Cart/CalculatedTax.php +++ b/src/Context/Cart/CalculatedTax.php @@ -42,18 +42,20 @@ public static function sum(Collection $calculatedTaxes): Collection $new = []; foreach ($calculatedTaxes as $calculatedTax) { - $exists = isset($new[$calculatedTax->getTaxRate()]); + $key = (string) $calculatedTax->getTaxRate(); + + $exists = isset($new[$key]); if (!$exists) { - $new[$calculatedTax->getTaxRate()] = $calculatedTax; + $new[$key] = $calculatedTax; continue; } - $new[$calculatedTax->getTaxRate()] = new CalculatedTax([ + $new[$key] = new CalculatedTax([ 'taxRate' => $calculatedTax->getTaxRate(), - 'price' => $new[$calculatedTax->getTaxRate()]->getPrice() + $calculatedTax->getPrice(), - 'tax' => $new[$calculatedTax->getTaxRate()]->getTax() + $calculatedTax->getTax(), - 'label' => implode(' + ', array_filter([$new[$calculatedTax->getTaxRate()]->getLabel(), $calculatedTax->getLabel()])) ?: null, + 'price' => $new[$key]->getPrice() + $calculatedTax->getPrice(), + 'tax' => $new[$key]->getTax() + $calculatedTax->getTax(), + 'label' => implode(' + ', array_filter([$new[$key]->getLabel(), $calculatedTax->getLabel()])) ?: null, ]); } diff --git a/tests/Context/Cart/CalculatedTaxTest.php b/tests/Context/Cart/CalculatedTaxTest.php index 74d6644..8f5e65c 100644 --- a/tests/Context/Cart/CalculatedTaxTest.php +++ b/tests/Context/Cart/CalculatedTaxTest.php @@ -66,4 +66,73 @@ public function testSum(): void static::assertSame(0.7, $tax7->getTax()); static::assertNull($tax7->getLabel()); } + + /** + * Tax rates are grouped by a string key. A float key would be truncated to an int + * by PHP, so 7.0 and 7.7 would collide and be summed into a single wrong rate. + */ + public function testSumKeepsTaxRatesWithTheSameIntegerPartApart(): void + { + $calculatedTaxes = new Collection([ + new CalculatedTax([ + 'taxRate' => 7.0, + 'price' => 10.0, + 'tax' => 0.7, + 'label' => 'reduced', + ]), + new CalculatedTax([ + 'taxRate' => 7.7, + 'price' => 20.0, + 'tax' => 1.54, + 'label' => 'standard', + ]), + ]); + + $sum = CalculatedTax::sum($calculatedTaxes); + + static::assertCount(2, $sum); + + $tax7 = $sum->get('7'); + static::assertNotNull($tax7); + static::assertSame(7.0, $tax7->getTaxRate()); + static::assertSame(10.0, $tax7->getPrice()); + static::assertSame(0.7, $tax7->getTax()); + static::assertSame('reduced', $tax7->getLabel()); + + $tax77 = $sum->get('7.7'); + static::assertNotNull($tax77); + static::assertSame(7.7, $tax77->getTaxRate()); + static::assertSame(20.0, $tax77->getPrice()); + static::assertSame(1.54, $tax77->getTax()); + static::assertSame('standard', $tax77->getLabel()); + } + + public function testSumMergesIdenticalFractionalTaxRates(): void + { + $calculatedTaxes = new Collection([ + new CalculatedTax([ + 'taxRate' => 7.7, + 'price' => 10.0, + 'tax' => 0.77, + 'label' => 'label 1', + ]), + new CalculatedTax([ + 'taxRate' => 7.7, + 'price' => 20.0, + 'tax' => 1.54, + 'label' => 'label 2', + ]), + ]); + + $sum = CalculatedTax::sum($calculatedTaxes); + + static::assertCount(1, $sum); + + $tax77 = $sum->get('7.7'); + static::assertNotNull($tax77); + static::assertSame(7.7, $tax77->getTaxRate()); + static::assertSame(30.0, $tax77->getPrice()); + static::assertSame(2.31, $tax77->getTax()); + static::assertSame('label 1 + label 2', $tax77->getLabel()); + } }