A removeFromCart cart method

This commit is contained in:
Fabian @ Blax Software 2025-12-09 10:30:53 +01:00
parent 6fede41426
commit d60724d2ad
2 changed files with 240 additions and 0 deletions

View File

@ -198,6 +198,41 @@ class Cart extends Model
return $cartItem->fresh();
}
public function removeFromCart(
Model $cartable,
int $quantity = 1,
array $parameters = []
): CartItem|true {
$item = $this->items()
->where('purchasable_id', $cartable->getKey())
->where('purchasable_type', get_class($cartable))
->get()
->first(function ($item) use ($parameters) {
$existingParams = is_array($item->parameters)
? $item->parameters
: (array) $item->parameters;
ksort($existingParams);
ksort($parameters);
return $existingParams === $parameters;
});
if ($item) {
if ($item->quantity > $quantity) {
// Decrease quantity
$newQuantity = $item->quantity - $quantity;
$item->update([
'quantity' => $newQuantity,
'subtotal' => ($cartable->getCurrentPrice()) * $newQuantity,
]);
} else {
// Remove item from cart
$item->delete();
}
}
return $item ?? true;
}
public function checkout(): static
{
$items = $this->items()

View File

@ -396,4 +396,209 @@ class CartManagementTest extends TestCase
$this->assertEquals(4, $cartWithProduct->getTotalItems());
$this->assertEquals((150.00 * 2) + (120 * 2), $cartWithProduct->getTotal());
}
/** @test */
public function it_can_remove_item_from_cart_completely()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 50.00,
]);
$cartItem = $cart->addToCart($price, quantity: 2);
$this->assertCount(1, $cart->items);
$result = $cart->removeFromCart($price, quantity: 2);
$this->assertCount(0, $cart->refresh()->items);
$this->assertTrue(true); // Item was deleted
}
/** @test */
public function it_can_decrease_cart_item_quantity()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 75.00,
]);
$cartItem = $cart->addToCart($price, quantity: 5);
$this->assertEquals(5, $cartItem->quantity);
$result = $cart->removeFromCart($price, quantity: 2);
$updatedItem = $cart->items->first();
$this->assertEquals(3, $updatedItem->quantity);
$this->assertEquals(75.00 * 3, $updatedItem->subtotal);
}
/** @test */
public function it_updates_subtotal_correctly_when_decreasing_quantity()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 100.00,
]);
$cart->addToCart($price, quantity: 4);
$cart->removeFromCart($price, quantity: 1);
$cartItem = $cart->items->first();
$this->assertEquals(3, $cartItem->quantity);
$this->assertEquals(300.00, $cartItem->subtotal);
}
/** @test */
public function it_respects_parameters_when_removing_from_cart()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 50.00,
]);
// Add same product with different parameters
$cartItem1 = $cart->addToCart(
$price,
quantity: 2,
parameters: ['color' => 'blue']
);
$cartItem2 = $cart->addToCart(
$price,
quantity: 3,
parameters: ['color' => 'red']
);
$this->assertCount(2, $cart->items);
// Remove only the blue item
$cart->removeFromCart($price, quantity: 2, parameters: ['color' => 'blue']);
$this->assertCount(1, $cart->refresh()->items);
$this->assertEquals('red', $cart->items->first()->parameters['color']);
$this->assertEquals(3, $cart->items->first()->quantity);
}
/** @test */
public function it_decreases_only_matching_parameters_when_removing()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 50.00,
]);
$cart->addToCart(
$price,
quantity: 5,
parameters: ['size' => 'large']
);
$cart->removeFromCart($price, quantity: 2, parameters: ['size' => 'large']);
$cartItem = $cart->items->first();
$this->assertEquals(3, $cartItem->quantity);
$this->assertEquals('large', $cartItem->parameters['size']);
}
/** @test */
public function it_returns_cart_item_when_quantity_is_decreased()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 50.00,
]);
$cart->addToCart($price, quantity: 5);
$result = $cart->removeFromCart($price, quantity: 2);
$this->assertInstanceOf(CartItem::class, $result);
$this->assertEquals(3, $result->quantity);
}
/** @test */
public function it_handles_removing_nonexistent_item_gracefully()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 50.00,
]);
$result = $cart->removeFromCart($price, quantity: 1);
// Should return true when item doesn't exist
$this->assertTrue($result);
$this->assertCount(0, $cart->items);
}
/** @test */
public function it_updates_cart_total_after_removing_items()
{
$cart = Cart::create();
$product = Product::factory()->create();
$price = ProductPrice::factory()->create([
'purchasable_id' => $product->id,
'purchasable_type' => get_class($product),
'unit_amount' => 50.00,
]);
$cart->addToCart($price, quantity: 5);
$this->assertEquals(250.00, $cart->getTotal());
$cart->removeFromCart($price, quantity: 2);
$this->assertEquals(150.00, $cart->refresh()->getTotal());
}
/** @test */
public function it_can_remove_from_cart_with_multiple_items()
{
$cart = Cart::create();
$product1 = Product::factory()->create();
$product2 = Product::factory()->create();
$price1 = ProductPrice::factory()->create([
'purchasable_id' => $product1->id,
'purchasable_type' => get_class($product1),
'unit_amount' => 50.00,
]);
$price2 = ProductPrice::factory()->create([
'purchasable_id' => $product2->id,
'purchasable_type' => get_class($product2),
'unit_amount' => 75.00,
]);
$cart->addToCart($price1, quantity: 2);
$cart->addToCart($price2, quantity: 3);
$this->assertCount(2, $cart->items);
$cart->removeFromCart($price1, quantity: 2);
$this->assertCount(1, $cart->refresh()->items);
$this->assertEquals($price2->id, $cart->items->first()->purchasable_id);
$this->assertEquals(225.00, $cart->getTotal());
}
}