From 7a2c41e02d9f795cc9919e59f9fc1c9aaa2c11fb Mon Sep 17 00:00:00 2001 From: Joel Male Date: Sun, 8 Sep 2024 08:32:51 +1000 Subject: [PATCH] add better livewire support - and reset collection indexes properly --- README.md | 24 ++- src/Cart.php | 14 +- src/CartCondition.php | 10 +- tests/Unit/CartConditionsTest.php | 282 +++++++++++++++++++++--------- 4 files changed, 240 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 62d7279..25a99c5 100644 --- a/README.md +++ b/README.md @@ -368,8 +368,30 @@ #### Getting conditions on the cart: **Cart::getConditions()** $condition->getMaximum(); // the maximum dollar amount of the target, needed to keep the condition active $condition->getAttributes(); // the attributes of the condition, returns an empty [] if no attributes added } +``` -// You can also get a condition that has been applied on the cart by using its name: +#### Getting conditions on the cart as an array: **Cart::getConditions(array: true)** + +You can get all cart conditions in array format by passing "array: true". This is useful if you want to store the carts conditions on a Livewire component since by default we have collections inside collections for conditions which Livewire does not support. + +```php +$cartConditions = Cart::getConditions(true); +$cartConditions = Cart::getConditions(active: true); + +foreach ($cartConditions as $condition) { + $condition['name']; // the name of the condition + $condition['type']; // the type + $condition['value']; // the value of the condition + $condition['order']; // the order of the condition + $condition['minimum']; // the minimum dollar amount of the target, needed to activate the condition + $condition['maximum']; // the maximum dollar amount of the target, needed to keep the condition active + $condition['attributes']; // the attributes of the condition, returns an empty [] if no attributes added +} +``` + +#### Getting conditions by name: **Cart::getCondition($conditionName)** + +```php $condition = Cart::getCondition('GST'); $condition->getTarget(); // the target of which the condition was applied diff --git a/src/Cart.php b/src/Cart.php index 0361cb6..7b88520 100644 --- a/src/Cart.php +++ b/src/Cart.php @@ -340,7 +340,7 @@ public function condition(array|CartCondition $condition): self * * @param bool $active - If true, only conditions actually applied on the cart are returned */ - public function getConditions(bool $active = false): CartConditionCollection + public function getConditions(bool $array = false, bool $active = false): CartConditionCollection|array { $conditions = new CartConditionCollection( $this->session->get($this->sessionKeyCartConditions) @@ -358,7 +358,9 @@ public function getConditions(bool $active = false): CartConditionCollection }); } - return $conditions; + return $array ? $conditions->map(function (CartCondition $condition) { + return $condition->toArray(); + })->toArray() : $conditions; } /** @@ -404,6 +406,9 @@ public function removeCartCondition($conditionName) $conditions->pull($conditionName); + // reset indexes + $conditions = $conditions->values(); + $this->saveConditions($conditions); } @@ -456,6 +461,9 @@ public function removeItemCondition($itemId, $conditionName) } } + // reset indexes + $item['conditions'] = array_values($item['conditions']); + $this->update($itemId, [ 'conditions' => $item['conditions'], ]); @@ -728,7 +736,7 @@ protected function addItem($id, $item) /** * save the cart * - * @param $cart CartCollection + * @param $cart CartCollection */ protected function save($cart) { diff --git a/src/CartCondition.php b/src/CartCondition.php index 4e9106b..0908655 100644 --- a/src/CartCondition.php +++ b/src/CartCondition.php @@ -8,15 +8,12 @@ class CartCondition { - /** - * @var array - */ private $args; /** * the parsed raw value of the condition */ - public $parsedRawValue = 0; + private $parsedRawValue = 0; /** * @param array $args (name, type, target, value) @@ -269,4 +266,9 @@ protected function validate($args) throw new InvalidConditionException($validator->messages()->first()); } } + + public function toArray(): array + { + return $this->args; + } } diff --git a/tests/Unit/CartConditionsTest.php b/tests/Unit/CartConditionsTest.php index 26e01b9..cb1d766 100644 --- a/tests/Unit/CartConditionsTest.php +++ b/tests/Unit/CartConditionsTest.php @@ -2,6 +2,7 @@ use Wearepixel\Cart\Cart; use Wearepixel\Cart\CartCondition; +use Wearepixel\Cart\CartConditionCollection; use Wearepixel\Cart\Tests\Helpers\SessionMock; beforeEach(function () { @@ -9,11 +10,11 @@ $events->shouldReceive('dispatch'); $this->cart = new Cart( - new SessionMock, + new SessionMock(), $events, 'cart', 'SAMPLESESSIONKEY', - require (__DIR__ . '/../Helpers/ConfigConditionsMock.php') + require(__DIR__ . '/../Helpers/ConfigConditionsMock.php') ); }); @@ -21,7 +22,168 @@ Mockery::close(); }); +describe('conditions', function () { + test('can be completely cleared', function () { + $siteWideDiscount = new CartCondition([ + 'name' => 'Site Wide Discount', + 'type' => 'discount', + 'target' => 'total', + 'value' => '-5%', + ]); + + $giftCard = new CartCondition([ + 'name' => 'Gift Card', + 'type' => 'gift_card', + 'target' => 'total', + 'value' => '-25', + ]); + + $itemCondition = new CartCondition([ + 'name' => 'Item Discount', + 'type' => 'discount', + 'value' => '-5%', + ]); + + $item = [ + 'id' => 1, + 'name' => 'Backpack', + 'price' => 168.72, + 'quantity' => 1, + 'attributes' => [], + 'conditions' => [$itemCondition], + ]; + + $this->cart->add($item); + + $this->cart->condition([$siteWideDiscount, $giftCard]); + + expect($this->cart->getConditions()->count())->toEqual(2, 'Cart should have two conditions'); + expect($this->cart->get(1)['conditions'])->toHaveCount(1, 'Cart should have one condition'); + + $this->cart->clearAllConditions(); + + expect($this->cart->getConditions()->count())->toEqual(0, 'Cart should have no conditions now'); + expect($this->cart->get(1)['conditions'])->toHaveCount(0, 'Cart items should have no conditions now'); + }); + + test('can be converted to array', function () { + $condition = new CartCondition([ + 'name' => 'Site Wide Discount', + 'type' => 'discount', + 'target' => 'total', + 'value' => '-5%', + ]); + + $this->cart->condition($condition); + + $conditions = $this->cart->getConditions(true); + + expect($conditions)->toHaveCount(1, 'Cart should have one condition'); + expect($conditions['Site Wide Discount'])->toEqual([ + 'name' => 'Site Wide Discount', + 'type' => 'discount', + 'target' => 'total', + 'value' => '-5%', + 'order' => 1, + ]); + }); + + test('can be removed by name', function () { + $conditionOne = new CartCondition([ + 'name' => '5% Site Wide Sale', + 'type' => 'sale', + 'value' => '-5%', + ]); + + $conditionTwo = new CartCondition([ + 'name' => 'Mother\'s Day Gift Pack', + 'type' => 'promo', + 'value' => '-25', + ]); + + $this->cart->add([ + 'id' => 1, + 'name' => 'Body Scrub Kit', + 'price' => 100, + 'quantity' => 1, + 'attributes' => [], + ]); + + $this->cart->condition([$conditionOne, $conditionTwo]); + + // let's very first the item has 2 conditions in it + expect($this->cart->getConditions())->toHaveCount(2, 'The item should have two conditions'); + + // now let's remove a condition on that item using the condition name + $this->cart->removeCartCondition('5% Site Wide Sale'); + + // now we should have only 1 condition left on that item + expect($this->cart->getConditions())->toHaveCount(1, 'Item should have one condition left'); + expect($this->cart->getConditions()[0]->getName())->toEqual('Mother\'s Day Gift Pack'); + }); +}); + describe('cart level conditions', function () { + test('can get conditions', function () { + $this->cart->add([ + 'id' => 456, + 'name' => 'Leather Shoes', + 'price' => 129.99, + 'quantity' => 1, + ]); + + $condition = new CartCondition([ + 'name' => '$5 Discount', + 'type' => 'tax', + 'target' => 'subtotal', + 'value' => '-5', + ]); + + $this->cart->condition($condition); + + $conditions = $this->cart->getConditions(); + + expect($conditions)->toHaveCount(1, 'Cart should have one condition'); + expect($conditions)->toBeInstanceOf(CartConditionCollection::class); + }); + + test('can get conditions by name', function () { + $this->cart->add([ + 'id' => 456, + 'name' => 'Leather Shoes', + 'price' => 129.99, + 'quantity' => 1, + ]); + + $conditionOne = new CartCondition([ + 'name' => '$5 Discount', + 'type' => 'tax', + 'target' => 'subtotal', + 'value' => '-5', + ]); + + $conditionTwo = new CartCondition([ + 'name' => '5% Off', + 'type' => 'tax', + 'target' => 'subtotal', + 'value' => '-5%', + ]); + + $this->cart->condition($conditionOne); + $this->cart->condition($conditionTwo); + + $conditions = $this->cart->getConditions(); + + expect($conditions)->toHaveCount(2, 'Cart should have two conditions'); + expect($conditions)->toBeInstanceOf(CartConditionCollection::class); + + $condition = $this->cart->getCondition('5% Off'); + + expect($condition)->toBeInstanceOf(CartCondition::class); + expect($condition->getName())->toEqual('5% Off'); + expect($condition->getValue())->toEqual('-5%'); + }); + test('can discount the subtotal by dollar amount', function () { $this->cart->add([ 'id' => 456, @@ -1092,7 +1254,7 @@ }); describe('item level conditions', function () { - test('can add an item with a condition', function () { + test('can be added to an item', function () { $saleCondition = new CartCondition([ 'name' => '5% Discount', 'type' => 'sale', @@ -1116,6 +1278,41 @@ expect($this->cart->getTotal())->toEqual(18, 'Cart should have total of 18'); }); + test('can be removed by name', function () { + $itemCondition1 = new CartCondition([ + 'name' => '5% Site Wide Sale', + 'type' => 'sale', + 'value' => '-5%', + ]); + + $itemCondition2 = new CartCondition([ + 'name' => 'Mother\'s Day Gift Pack', + 'type' => 'promo', + 'value' => '-25', + ]); + + $item = [ + 'id' => 1, + 'name' => 'Body Scrub Kit', + 'price' => 100, + 'quantity' => 1, + 'attributes' => [], + 'conditions' => [$itemCondition1, $itemCondition2], + ]; + + $this->cart->add($item); + + // let's very first the item has 2 conditions in it + expect($this->cart->get(1)['conditions'])->toHaveCount(2, 'The item should have two conditions'); + + // now let's remove a condition on that item using the condition name + $this->cart->removeItemCondition(1, '5% Site Wide Sale'); + + // now we should have only 1 condition left on that item + expect($this->cart->get(1)['conditions'])->toHaveCount(1, 'Item should have one condition left'); + expect($this->cart->get(1)['conditions'][0]->getName())->toEqual('Mother\'s Day Gift Pack'); + }); + test('can add item with multiple negative item conditions', function () { $saleCondition = new CartCondition([ 'name' => '5% Sale', @@ -1656,83 +1853,4 @@ // expect($this->cart->getConditions()->first()->getName())->toEqual('Item Gift Pack 20'); // expect($this->cart->getConditions()->last()->getName())->toEqual('TAX'); // }); - -}); - -describe('conditions', function () { - test('can be completely cleared', function () { - $siteWideDiscount = new CartCondition([ - 'name' => 'Site Wide Discount', - 'type' => 'discount', - 'target' => 'total', - 'value' => '-5%', - ]); - - $giftCard = new CartCondition([ - 'name' => 'Gift Card', - 'type' => 'gift_card', - 'target' => 'total', - 'value' => '-25', - ]); - - $itemCondition = new CartCondition([ - 'name' => 'Item Discount', - 'type' => 'discount', - 'value' => '-5%', - ]); - - $item = [ - 'id' => 1, - 'name' => 'Backpack', - 'price' => 168.72, - 'quantity' => 1, - 'attributes' => [], - 'conditions' => [$itemCondition], - ]; - - $this->cart->add($item); - - $this->cart->condition([$siteWideDiscount, $giftCard]); - - expect($this->cart->getConditions()->count())->toEqual(2, 'Cart should have two conditions'); - expect($this->cart->get(1)['conditions'])->toHaveCount(1, 'Cart should have one condition'); - - $this->cart->clearAllConditions(); - - expect($this->cart->getConditions()->count())->toEqual(0, 'Cart should have no conditions now'); - expect($this->cart->get(1)['conditions'])->toHaveCount(0, 'Cart items should have no conditions now'); - }); - - // test('remove item condition by condition name', function () { - // $itemCondition1 = new CartCondition([ - // 'name' => 'SALE 5%', - // 'type' => 'sale', - // 'value' => '-5%', - // ]); - // $itemCondition2 = new CartCondition([ - // 'name' => 'Item Gift Pack 25.00', - // 'type' => 'promo', - // 'value' => '-25', - // ]); - - // $item = [ - // 'id' => 456, - // 'name' => 'Sample Item 1', - // 'price' => 100, - // 'quantity' => 1, - // 'attributes' => [], - // 'conditions' => [$itemCondition1, $itemCondition2], - // ]; - - // $this->cart->add($item); - - // // let's very first the item has 2 conditions in it - // expect($this->cart->get(456)['conditions'])->toHaveCount(2, 'Item should have two conditions'); - - // // now let's remove a condition on that item using the condition name - // $this->cart->removeItemCondition(456, 'SALE 5%'); - - // // now we should have only 1 condition left on that item - // expect($this->cart->get(456)['conditions'])->toHaveCount(1, 'Item should have one condition left'); - // }); });