From 2078f119ec5d0ead3c0a6fa94137c77d9acd4e32 Mon Sep 17 00:00:00 2001 From: sartoric <> Date: Wed, 12 Feb 2020 22:42:41 +0100 Subject: [PATCH] Enable gross price as base price --- src/CartItem.php | 87 ++++++++++++++++++++++++++++++++------------- src/Config/cart.php | 12 +++++++ tests/CartTest.php | 38 ++++++++++++++++++++ 3 files changed, 113 insertions(+), 24 deletions(-) diff --git a/src/CartItem.php b/src/CartItem.php index c2d9724..63589b5 100644 --- a/src/CartItem.php +++ b/src/CartItem.php @@ -7,6 +7,18 @@ use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Support\Arr; +/** + * @property-read mixed discount + * @property-read float discountTotal + * @property-read float priceTarget + * @property-read float priceNet + * @property-read float priceTotal + * @property-read float subtotal + * @property-read float taxTotal + * @property-read float tax + * @property-read float total + * @property-read float priceTax + */ class CartItem implements Arrayable, Jsonable { /** @@ -371,39 +383,66 @@ class CartItem implements Arrayable, Jsonable $decimals = config('cart.format.decimals', 2); switch ($attribute) { - case 'discount': - return $this->price * ($this->discountRate / 100); - case 'tax': - return round($this->priceTarget * ($this->taxRate / 100), $decimals); - case 'priceTax': - return round($this->priceTarget + $this->tax, $decimals); - case 'discountTotal': - return round($this->discount * $this->qty, $decimals); - case 'weightTotal': - return round($this->weight * $this->qty, $decimals); - case 'priceTotal': - return round($this->price * $this->qty, $decimals); - case 'subtotal': - return round($this->priceTotal - $this->discountTotal, $decimals); - case 'priceTarget': - return round(($this->priceTotal - $this->discountTotal) / $this->qty, $decimals); - case 'taxTotal': - return round($this->subtotal * ($this->taxRate / 100), $decimals); - case 'total': - return round($this->subtotal + $this->taxTotal, $decimals); - case 'model': if (isset($this->associatedModel)) { return with(new $this->associatedModel())->find($this->id); } - case 'modelFQCN': if (isset($this->associatedModel)) { return $this->associatedModel; } + case 'weightTotal': + return round($this->weight * $this->qty, $decimals); + } - default: - return; + if (config('cart.gross_price')) { + switch ($attribute) { + case 'priceNet': + return round($this->price / (1 + ($this->taxRate / 100)), $decimals); + case 'discount': + return $this->priceNet * ($this->discountRate / 100); + case 'tax': + return round($this->priceTarget * ($this->taxRate / 100), $decimals); + case 'priceTax': + return round($this->priceTarget + $this->tax, $decimals); + case 'discountTotal': + return round($this->discount * $this->qty, $decimals); + case 'priceTotal': + return round($this->priceNet * $this->qty, $decimals); + case 'subtotal': + return round($this->priceTotal - $this->discountTotal, $decimals); + case 'priceTarget': + return round(($this->priceTotal - $this->discountTotal) / $this->qty, $decimals); + case 'taxTotal': + return round($this->subtotal * ($this->taxRate / 100), $decimals); + case 'total': + return round($this->subtotal + $this->taxTotal, $decimals); + default: + return; + } + } else { + switch ($attribute) { + case 'discount': + return $this->price * ($this->discountRate / 100); + case 'tax': + return round($this->priceTarget * ($this->taxRate / 100), $decimals); + case 'priceTax': + return round($this->priceTarget + $this->tax, $decimals); + case 'discountTotal': + return round($this->discount * $this->qty, $decimals); + case 'priceTotal': + return round($this->price * $this->qty, $decimals); + case 'subtotal': + return round($this->priceTotal - $this->discountTotal, $decimals); + case 'priceTarget': + return round(($this->priceTotal - $this->discountTotal) / $this->qty, $decimals); + case 'taxTotal': + return round($this->subtotal * ($this->taxRate / 100), $decimals); + case 'total': + return round($this->subtotal + $this->taxTotal, $decimals); + default: + return; + } } } diff --git a/src/Config/cart.php b/src/Config/cart.php index a437d69..739265e 100644 --- a/src/Config/cart.php +++ b/src/Config/cart.php @@ -2,6 +2,18 @@ return [ + /* + |-------------------------------------------------------------------------- + | Gross price as base price + |-------------------------------------------------------------------------- + | + | This default value is used to select the method to calculate prices and taxes + | If true the item price is managed as a gross price, so taxes will be calculated by separation/exclusion + | + */ + + 'gross_price' => false, + /* |-------------------------------------------------------------------------- | Default tax rate diff --git a/tests/CartTest.php b/tests/CartTest.php index e5624dc..d530599 100644 --- a/tests/CartTest.php +++ b/tests/CartTest.php @@ -1329,6 +1329,44 @@ class CartTest extends TestCase $this->assertEquals($cart->totalFloat(), $cart->subtotalFloat() + $cart->taxFloat()); } + /** @test */ + public function it_use_gross_price_as_base_price() + { + $cart = $this->getCartDiscount(0); + config(['cart.gross_price' => true]); + + $cartItem = $cart->add(new BuyableProduct(1, 'First item', 100), 2); + + $cart->setGlobalTax(22); + + // check net price + $this->assertEquals(81.97, round($cartItem->priceNet,2)); + } + + /** @test */ + public function it_use_gross_price_and_it_use_correctly_rounded_values_for_totals_and_cart_summary() + { + $this->setConfigFormat(2, ',', ''); + config(['cart.gross_price' => true]); + + $cart = $this->getCartDiscount(6); + + $cartItem = $cart->add(new BuyableProduct(1, 'First item', 0.23093), 1000); + $cart->add(new BuyableProduct(2, 'Second item', 5.38791), 5); + $cart->add(new BuyableProduct(3, 'Third item', 0.46354), 25); + + $cart->setGlobalTax(22); + + // check total + $this->assertEquals('254,12', $cart->total()); + + // check item price total + $this->assertEquals(190, $cartItem->priceTotal); + // check that the sum of cart subvalues matches the total (in order to avoid cart summary to looks wrong) + $this->assertEquals($cart->totalFloat(), $cart->subtotalFloat() + $cart->taxFloat()); + } + + /** * Get an instance of the cart. *