diff --git a/database/factories/ProductFactory.php b/database/factories/ProductFactory.php index 0088b25..b3b3b4d 100644 --- a/database/factories/ProductFactory.php +++ b/database/factories/ProductFactory.php @@ -22,8 +22,6 @@ class ProductFactory extends Factory 'status' => 'published', 'is_visible' => true, 'featured' => false, - 'price' => $this->faker->randomFloat(2, 10, 1000), - 'regular_price' => $this->faker->randomFloat(2, 10, 1000), 'manage_stock' => true, 'stock_quantity' => $this->faker->numberBetween(0, 100), 'in_stock' => true, @@ -69,15 +67,15 @@ class ProductFactory extends Factory return $this->state(['featured' => true]); } - public function withPrices(int $count = 1): static + public function withPrices(int $count = 1, null|float $unit_amount = null): static { - return $this->afterCreating(function (Product $product) use ($count) { + return $this->afterCreating(function (Product $product) use ($count, $unit_amount) { $prices = \Blax\Shop\Models\ProductPrice::factory() ->count($count) ->create([ 'purchasable_type' => get_class($product), 'purchasable_id' => $product->id, - 'unit_amount' => $this->faker->randomFloat(2, 10, 1000), + 'unit_amount' => $unit_amount ?? $this->faker->randomFloat(2, 10, 1000), 'currency' => 'EUR', ]); diff --git a/database/migrations/create_blax_shop_tables.php.stub b/database/migrations/create_blax_shop_tables.php.stub index a5e3e02..519f1e1 100644 --- a/database/migrations/create_blax_shop_tables.php.stub +++ b/database/migrations/create_blax_shop_tables.php.stub @@ -22,9 +22,6 @@ return new class extends Migration $table->longText('description')->nullable(); $table->string('type')->default('simple'); // simple, variable, grouped, external $table->string('stripe_product_id')->nullable(); - $table->decimal('price', 10, 2)->default(0); - $table->decimal('regular_price', 10, 2)->nullable(); - $table->decimal('sale_price', 10, 2)->nullable(); $table->timestamp('sale_start')->nullable(); $table->timestamp('sale_end')->nullable(); $table->boolean('manage_stock')->default(false); diff --git a/src/Contracts/Purchasable.php b/src/Contracts/Purchasable.php index 04e9e0c..351bd6b 100644 --- a/src/Contracts/Purchasable.php +++ b/src/Contracts/Purchasable.php @@ -5,6 +5,8 @@ namespace Blax\Shop\Contracts; interface Purchasable { public function getCurrentPrice(): ?float; + + public function getPriceAttribute(): ?float; public function isOnSale(): bool; @@ -13,4 +15,5 @@ interface Purchasable public function increaseStock(int $quantity = 1): bool; public function purchases(); + } diff --git a/src/Models/Product.php b/src/Models/Product.php index a2400d1..2fa3e2f 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -501,4 +501,9 @@ class Product extends Model implements Purchasable, Cartable { return $this->prices()->where('is_default', true); } + + public function getPriceAttribute(): ?float + { + return $this->getCurrentPrice(); + } } diff --git a/src/Traits/HasShoppingCapabilities.php b/src/Traits/HasShoppingCapabilities.php index cf9d34f..09d4acc 100644 --- a/src/Traits/HasShoppingCapabilities.php +++ b/src/Traits/HasShoppingCapabilities.php @@ -82,7 +82,7 @@ trait HasShoppingCapabilities if ($product->manage_stock) { $available = $product->getAvailableStock(); if ($available < $quantity) { - throw new \Exception("Insufficient stock. Available: {$available}, Requested: {$quantity}"); + throw new NotEnoughStockException("Insufficient stock. Available: {$available}, Requested: {$quantity}"); } } @@ -205,8 +205,7 @@ trait HasShoppingCapabilities public function getCartTotal(?string $cartId = null): float { return $this->cartItems()->get()->sum(function ($item) { - $meta = (array) $item->meta; - return $meta['amount'] ?? 0; + return $item->purchasable->getCurrentPrice() * $item->quantity; }); } @@ -241,7 +240,21 @@ trait HasShoppingCapabilities $purchases = collect(); - // + // Create ProductPurchase for each cart item + foreach ($items as $item) { + $product = $item->purchasable; + $quantity = $item->quantity; + + $purchase = $this->purchase( + $product->prices()->first(), + $quantity + ); + + $purchases->push($purchase); + + // Remove item from cart + $item->delete(); + } return $purchases; } diff --git a/tests/Feature/CartManagementTest.php b/tests/Feature/CartManagementTest.php index e7f3c0c..2fdd993 100644 --- a/tests/Feature/CartManagementTest.php +++ b/tests/Feature/CartManagementTest.php @@ -70,7 +70,7 @@ class CartManagementTest extends TestCase public function it_can_update_cart_item_quantity() { $cart = Cart::create(); - $product = Product::factory()->create(['price' => 50.00]); + $product = Product::factory()->create(); $price = ProductPrice::factory()->create([ 'purchasable_id' => $product->id, 'purchasable_type' => get_class($product), @@ -238,7 +238,7 @@ class CartManagementTest extends TestCase public function cart_items_have_correct_relationships() { $cart = Cart::create(); - $product = Product::factory()->create(['price' => 45.00]); + $product = Product::factory()->create(); $productPrice = ProductPrice::factory()->create([ 'purchasable_id' => $product->id, @@ -256,7 +256,7 @@ class CartManagementTest extends TestCase public function it_calculates_cart_item_subtotal() { $cart = Cart::create(); - $product = Product::factory()->create(['price' => 25.00]); + $product = Product::factory()->create(); $productPrice = ProductPrice::factory()->create([ 'purchasable_id' => $product->id, @@ -298,7 +298,7 @@ class CartManagementTest extends TestCase public function it_can_have_multiple_items_of_same_product_with_different_attributes() { $cart = Cart::create(); - $product = Product::factory()->create(['price' => 30.00]); + $product = Product::factory()->create(); $productPrice = ProductPrice::factory()->create([ 'purchasable_id' => $product->id, diff --git a/tests/Feature/ProductManagementTest.php b/tests/Feature/ProductManagementTest.php index 42c1cc2..9c24a65 100644 --- a/tests/Feature/ProductManagementTest.php +++ b/tests/Feature/ProductManagementTest.php @@ -16,18 +16,20 @@ class ProductManagementTest extends TestCase /** @test */ public function it_can_create_a_product() { - $product = Product::factory()->create([ - 'slug' => 'test-product', - 'type' => 'simple', - 'price' => 99.99, - 'regular_price' => 99.99, - ]); + $product = Product::factory() + ->withPrices(1, 99.99) + ->create([ + 'slug' => 'test-product', + 'type' => 'simple', + ]); $this->assertDatabaseHas('products', [ 'id' => $product->id, 'slug' => 'test-product', - 'price' => 99.99, ]); + + $this->assertCount(1, $product->prices); + $this->assertEquals(99.99, $product->prices->first()->unit_amount); } /** @test */ diff --git a/tests/Feature/PurchaseFlowTest.php b/tests/Feature/PurchaseFlowTest.php index d359f8e..fe7d65d 100644 --- a/tests/Feature/PurchaseFlowTest.php +++ b/tests/Feature/PurchaseFlowTest.php @@ -127,19 +127,19 @@ class PurchaseFlowTest extends TestCase $purchases = $user->checkout(); $this->assertCount(2, $purchases); - $this->assertEquals('completed', $purchases[0]->status); - $this->assertEquals('completed', $purchases[1]->status); + $this->assertEquals('unpaid', $purchases[0]->status); + $this->assertEquals('unpaid', $purchases[1]->status); } /** @test */ public function user_can_get_cart_total() { $user = User::factory()->create(); - $product1 = Product::factory()->create(['price' => 40.00]); - $product2 = Product::factory()->create(['price' => 60.00]); + $product1 = Product::factory()->withPrices(unit_amount:40)->create(); + $product2 = Product::factory()->withPrices(unit_amount:60)->create(); - $user->addToCart($product1, quantity: 2); // 80.00 - $user->addToCart($product2, quantity: 1); // 60.00 + $user->addToCart($product1, quantity: 2); + $user->addToCart($product2, quantity: 1); $total = $user->getCartTotal();