Compare commits

...
6 Commits
Author SHA1 Message Date
Joel Male 9a4b5382bd 1.0.2 2024-08-16 16:55:10 +10:00
Joel Male 95054f41a4 feature: quantities now support decimals
Merge pull request #4 from wearepixel/feature/quantities-now-support-decimals
2024-08-16 16:52:13 +10:00
Joel Male 0a9bcc2832 quantities now support decimals (so adding 1.1, or setting it to 1.1) 2024-08-16 16:49:59 +10:00
Joel Male 8c8c90c170 Feature: Cart item orders never change
Merge pull request #2 from wearepixel/feature/cart-item-orders-never-change
2024-08-16 16:33:26 +10:00
Pixel Tech 18c753f39b Apply Laravel Pint
Signed-off-by: Pixel Tech <tech@wearepixel.com.au>
2024-08-16 06:33:03 +00:00
Joel Male d12a566366 cart item orders never change 2024-08-16 16:29:46 +10:00
6 changed files with 219 additions and 98 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "wearepixel/laravel-cart", "name": "wearepixel/laravel-cart",
"version": "1.0.1", "version": "1.0.2",
"description": "A cart implementation for Laravel", "description": "A cart implementation for Laravel",
"keywords": [ "keywords": [
"laravel", "laravel",
+9 -18
View File
@@ -196,11 +196,9 @@ public function add($id, $name = null, $price = null, $quantity = null, $attribu
// if the item is already in the cart we will just update it // if the item is already in the cart we will just update it
if ($cart->has($id)) { if ($cart->has($id)) {
$this->update($id, $item); $this->update($id, $item);
} else { } else {
$this->addItem($id, $item);
$this->addRow($id, $item);
} }
$this->currentItemId = $id; $this->currentItemId = $id;
@@ -225,21 +223,13 @@ public function update($id, $data)
$cart = $this->getContent(); $cart = $this->getContent();
$item = $cart->pull($id); $item = $cart->get($id);
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
// if the key is currently "quantity" we will need to check if an arithmetic
// symbol is present so we can decide if the update of quantity is being added
// or being reduced.
if ($key == 'quantity') { if ($key == 'quantity') {
// we will check if quantity value provided is array,
// if it is, we will need to check if a key "relative" is set
// and we will evaluate its value if true or false,
// this tells us how to treat the quantity value if it should be updated
// relatively to its current quantity value or just totally replace the value
if (is_array($value)) { if (is_array($value)) {
if (isset($value['relative'])) { if (isset($value['relative'])) {
if ((bool) $value['relative']) { if (isset($value['relative']) && $value['relative'] === true) {
$item = $this->updateQuantityRelative($item, $key, $value['value']); $item = $this->updateQuantityRelative($item, $key, $value['value']);
} else { } else {
$item = $this->updateQuantityNotRelative($item, $key, $value['value']); $item = $this->updateQuantityNotRelative($item, $key, $value['value']);
@@ -255,6 +245,7 @@ public function update($id, $data)
} }
} }
// update the item in the cart
$cart->put($id, $item); $cart->put($id, $item);
$this->save($cart); $this->save($cart);
@@ -725,7 +716,7 @@ protected function validate($item)
* *
* @return bool * @return bool
*/ */
protected function addRow($id, $item) protected function addItem($id, $item)
{ {
if ($this->fireEvent('adding', $item) === false) { if ($this->fireEvent('adding', $item) === false) {
return false; return false;
@@ -792,7 +783,7 @@ protected function itemHasConditions($item)
protected function updateQuantityRelative($item, $key, $value) protected function updateQuantityRelative($item, $key, $value)
{ {
if (preg_match('/\-/', $value) == 1) { if (preg_match('/\-/', $value) == 1) {
$value = (int) str_replace('-', '', $value); $value = (float) str_replace('-', '', $value);
// we will not allowed to reduced quantity to 0, so if the given value // we will not allowed to reduced quantity to 0, so if the given value
// would result to item quantity of 0, we will not do it. // would result to item quantity of 0, we will not do it.
@@ -800,9 +791,9 @@ protected function updateQuantityRelative($item, $key, $value)
$item[$key] -= $value; $item[$key] -= $value;
} }
} elseif (preg_match('/\+/', $value) == 1) { } elseif (preg_match('/\+/', $value) == 1) {
$item[$key] += (int) str_replace('+', '', $value); $item[$key] += (float) str_replace('+', '', $value);
} else { } else {
$item[$key] += (int) $value; $item[$key] += (float) $value;
} }
return $item; return $item;
@@ -815,7 +806,7 @@ protected function updateQuantityRelative($item, $key, $value)
*/ */
protected function updateQuantityNotRelative($item, $key, $value) protected function updateQuantityNotRelative($item, $key, $value)
{ {
$item[$key] = (int) $value; $item[$key] = (float) $value;
return $item; return $item;
} }
+1 -3
View File
@@ -4,6 +4,4 @@
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
class CartCollection extends Collection class CartCollection extends Collection {}
{
}
+1 -3
View File
@@ -2,6 +2,4 @@
namespace Wearepixel\Cart\Exceptions; namespace Wearepixel\Cart\Exceptions;
class UnknownModelException extends \Exception class UnknownModelException extends \Exception {}
{
}
+2 -3
View File
@@ -1,8 +1,7 @@
<?php <?php
return [ return [
'format_numbers' => false, 'format_numbers' => true,
'decimals' => 2, 'decimals' => 2,
'dec_point' => '.', 'round_mode' => 'up',
'thousands_sep' => ',',
]; ];
+205 -70
View File
@@ -49,6 +49,21 @@
expect($this->cart->getTotal())->toEqual(0, 'Total should be 0'); expect($this->cart->getTotal())->toEqual(0, 'Total should be 0');
}); });
test('can add an item without attributes', function () {
$item = [
'id' => 1,
'name' => 'Pocket Shorts',
'price' => 67.99,
'quantity' => 2,
];
$this->cart->add($item);
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
expect($this->cart->getContent()->count())->toEqual(1, 'Cart content should be 1');
expect($this->cart->getTotal())->toEqual(135.98, 'Cart total should be 135.98');
});
test('can add items as array', function () { test('can add items as array', function () {
$item = [ $item = [
'id' => 456, 'id' => 456,
@@ -65,82 +80,209 @@
expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456'); expect($this->cart->getContent()->first()['id'])->toEqual(456, 'The first content must have ID of 456');
expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"'); expect($this->cart->getContent()->first()['name'])->toEqual('Sample Item', 'The first content must have name of "Sample Item"');
}); });
});
test('cart can add items with multidimensional array', function () { test('can add multiple items with an array', function () {
$items = [ $items = [
[ [
'id' => 456, 'id' => 1,
'name' => 'Sample Item 1', 'name' => 'Half Button Open Collar',
'price' => 71.99,
'quantity' => 1,
'attributes' => [],
],
[
'id' => 2,
'name' => 'Oli Crew Neck',
'price' => 59.99,
'quantity' => 1,
'attributes' => [],
],
[
'id' => 3,
'name' => 'Denim Shorts',
'price' => 69.99,
'quantity' => 3,
'attributes' => [],
],
];
$this->cart->add($items);
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty');
expect($this->cart->getContent()->toArray())->toHaveCount(3, 'Cart should have 3 items');
expect($this->cart->getTotal())->toEqual(341.95, 'Cart should have a total of 341.95');
});
test('cart item prices should be normalized when added to cart', function () {
// add a price in a string format should be converted to float
$this->cart->add(1, 'Book of Languages Item', '100.99', 2, []);
expect($this->cart->getContent()->first()['price'])->toBeFloat('Cart price should be a float');
});
test('can update a cart item with new attributes and it should be still instance of item attribute collection', function () {
$item = [
'id' => 1,
'name' => 'Leather Shows',
'price' => 67.99, 'price' => 67.99,
'quantity' => 4, 'quantity' => 4,
'attributes' => [], 'attributes' => [
], 'product_id' => '145',
[ 'color' => 'red',
'id' => 568, ],
'name' => 'Sample Item 2', ];
'price' => 69.25,
'quantity' => 4,
'attributes' => [],
],
[
'id' => 856,
'name' => 'Sample Item 3',
'price' => 50.25,
'quantity' => 4,
'attributes' => [],
],
];
$this->cart->add($items); $this->cart->add($item);
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty'); $item = $this->cart->get(1);
expect($this->cart->getContent()->toArray())->toHaveCount(3, 'Cart should have 3 items');
});
test('cart can add item without attributes', function () { expect($item->attributes)->toBeInstanceOf('Wearepixel\\Cart\\ItemAttributeCollection');
$item = [
'id' => 456,
'name' => 'Sample Item 1',
'price' => 67.99,
'quantity' => 4,
];
$this->cart->add($item); // now lets update the item with its new attributes
// when we get that item from cart, it should still be an instance of ItemAttributeCollection
$updatedItem = [
'attributes' => [
'product_id' => '145',
'color' => 'red',
],
];
expect($this->cart->isEmpty())->toBeFalse('Cart should not be empty'); $this->cart->update(1, $updatedItem);
});
test('cart update with attribute then attributes should be still instance of item attribute collection', function () { expect($item->attributes)->toBeInstanceOf('Wearepixel\\Cart\\ItemAttributeCollection');
$item = [ });
'id' => 456,
'name' => 'Sample Item 1',
'price' => 67.99,
'quantity' => 4,
'attributes' => [
'product_id' => '145',
'color' => 'red',
],
];
$this->cart->add($item);
// lets get the attribute and prove first its an instance of test('item orders are preserved by the order they are added', function () {
// ItemAttributeCollection $items = [
$item = $this->cart->get(456); [
'id' => 50,
'name' => 'Leather Shows',
'price' => 67.99,
'quantity' => 4,
'attributes' => [
'product_id' => '145',
'color' => 'red',
],
],
[
'id' => 2,
'name' => 'Oli Crew Neck',
'price' => 59.99,
'quantity' => 1,
'attributes' => [],
],
];
expect($item->attributes)->toBeInstanceOf('Wearepixel\Cart\ItemAttributeCollection'); $this->cart->add($items);
// now lets update the item with its new attributes $items = $this->cart->getContent();
// when we get that item from cart, it should still be an instance of ItemAttributeCollection
$updatedItem = [
'attributes' => [
'product_id' => '145',
'color' => 'red',
],
];
$this->cart->update(456, $updatedItem);
expect($item->attributes)->toBeInstanceOf('Wearepixel\Cart\ItemAttributeCollection'); expect($items->toArray())->toHaveCount(2, 'Cart should have 2 items');
expect($items->first()->id)->toEqual(50, 'First item should have ID of 1');
expect($items->last()->id)->toEqual(2, 'Last item should have ID of 2');
});
test('item orders are preserved by the order they are added even when items are updated', function () {
$items = [
[
'id' => 50,
'name' => 'Leather Shows',
'price' => 67.99,
'quantity' => 4,
'attributes' => [
'product_id' => '145',
'color' => 'red',
],
],
[
'id' => 2,
'name' => 'Oli Crew Neck',
'price' => 59.99,
'quantity' => 1,
'attributes' => [],
],
];
$this->cart->add($items);
$this->cart->update(50, ['name' => 'Updated Name']);
$items = $this->cart->getContent();
expect($items->toArray())->toHaveCount(2, 'Cart should have 2 items');
expect($items->first()->id)->toEqual(50, 'First item should have ID of 1');
expect($items->last()->id)->toEqual(2, 'Last item should have ID of 2');
});
test('can update existing items', function () {
$items = [
[
'id' => 1,
'name' => 'Magic The Gathering Card Pack',
'price' => 12.99,
'quantity' => 3,
'attributes' => [],
],
[
'id' => 2,
'name' => 'Magic The Gathering Card Case',
'price' => 39.99,
'quantity' => 1,
'attributes' => [],
],
];
$this->cart->add($items);
$item = $this->cart->get(1);
expect($item['name'])->toEqual('Magic The Gathering Card Pack', 'Item name should be "Magic The Gathering Card Pack"');
expect($item['price'])->toEqual(12.99, 'Item price should be "12.99"');
expect($item['quantity'])->toEqual(3, 'Item quantity should be 3');
// when cart's item quantity is updated, the subtotal should be updated as well
$this->cart->update(1, [
'name' => 'Magic The Gathering Card Packs',
'quantity' => 2,
'price' => 10.20,
]);
$item = $this->cart->get(1);
expect($item['name'])->toEqual('Magic The Gathering Card Packs', 'Item name should be "Magic The Gathering Card Packs"');
expect($item['price'])->toEqual(10.20, 'Item price should be 10.20');
expect($item['quantity'])->toEqual(5, 'Item quantity should be 2');
});
test('can update existing item quanties with decimals', function () {
$items = [
'id' => 1,
'name' => 'Fertilizer',
'price' => 30,
'quantity' => 7.8,
'attributes' => [
'unit' => 'kilogram',
],
];
$this->cart->add($items);
$item = $this->cart->get(1);
expect($item['quantity'])->toEqual(7.8, 'Item quantity should be 7.8');
// when cart's item quantity is updated, the subtotal should be updated as well
$this->cart->update(1, [
'quantity' => [
'relative' => true,
'value' => 2.1,
],
]);
$item = $this->cart->get(1);
expect($item['quantity'])->toEqual(9.9, 'Item quantity should be 9.9');
});
}); });
test('cart items attributes', function () { test('cart items attributes', function () {
@@ -233,13 +375,6 @@
expect($item['quantity'])->toEqual(5, 'Item quantity should be 5'); expect($item['quantity'])->toEqual(5, 'Item quantity should be 5');
}); });
test('item price should be normalized when added to cart', function () {
// add a price in a string format should be converted to float
$this->cart->add(455, 'Sample Item', '100.99', 2, []);
expect($this->cart->getContent()->first()['price'])->toBeFloat('Cart price should be a float');
});
test('it removes an item on cart by item id', function () { test('it removes an item on cart by item id', function () {
$items = [ $items = [
[ [