diff --git a/app/Traits/Order/WithAddItem.php b/app/Traits/Order/WithAddItem.php index c263595..2b9bb50 100644 --- a/app/Traits/Order/WithAddItem.php +++ b/app/Traits/Order/WithAddItem.php @@ -27,15 +27,7 @@ public function updatedFormBottleId(string $value) $formulas = Formula::where('size', $bottle->size)->orderBy('volume')->pluck('quality', 'id')->toArray(); - // check if there is any formula - if (empty($formulas)) { - $this->qualities = []; - $this->toast('Kualitas tidak ditemukan, silakan hubungi Administrator.', 'Gagal', 'danger'); - - return; - } - - $this->qualities = $formulas; + $this->qualities = $formulas + ['custom' => 'Custom']; } /** @@ -44,16 +36,13 @@ public function updatedFormBottleId(string $value) */ public function updatedFormBottleSize(string $value) { - $formulas = Formula::where('size', $value)->orderBy('volume')->pluck('quality', 'id')->toArray(); - - // check if there is any formula - if (empty($formulas)) { - $this->qualities = []; - - return $this->toast('Kualitas tidak ditemukan, silakan hubungi Administrator.', 'Gagal', 'danger'); + if ($this->tab !== 'refill') { + return; } - $this->qualities = $formulas; + $formulas = Formula::where('size', $value)->orderBy('volume')->pluck('quality', 'id')->toArray(); + + $this->qualities = $formulas + ['custom' => 'Custom']; } /** @@ -76,15 +65,34 @@ protected function handleNewPerfume(): void { $perfume = Perfume::find($this->form->perfume_id); $bottle = Bottle::find($this->form->bottle_id); - $quality = Formula::find($this->form->quality_id); - if (! $perfume || ! $bottle || ! $quality) { - $this->toast('Parfum, botol, atau kualitas tidak valid.', 'Gagal', 'danger'); + if (! $perfume || ! $bottle) { + $this->toast('Parfum atau botol tidak valid.', 'Gagal', 'danger'); return; } - $quantity = $quality->volume; + if ($this->form->quality_id === 'custom') { + $quantity = parseRupiahToInt($this->form->bottle_size); + $qualityName = 'Custom'; + + if ($quantity <= 0) { + $this->toast('Jumlah parfum (Custom) tidak valid.', 'Gagal', 'danger'); + + return; + } + } else { + $quality = Formula::find($this->form->quality_id); + + if (! $quality) { + $this->toast('Kualitas tidak valid.', 'Gagal', 'danger'); + + return; + } + + $quantity = $quality->volume; + $qualityName = $quality->quality; + } if ($quantity <= 0) { $this->toast('Jumlah parfum tidak valid.', 'Gagal', 'danger'); @@ -92,7 +100,7 @@ protected function handleNewPerfume(): void return; } - $this->addOrUpdateOrderItem($perfume, $quantity); + $this->addOrUpdateOrderItem($perfume, $quantity, $qualityName); $this->addOrUpdateOrderItem($bottle, 1); @@ -109,23 +117,42 @@ protected function handleNewPerfume(): void protected function handleRefillPerfume(): void { $perfume = Perfume::find($this->form->perfume_id); - $quality = Formula::find($this->form->quality_id); - if (! $perfume || ! $quality) { - $this->toast('Parfum, ukuran, atau kualitas tidak valid.', 'Gagal', 'danger'); + if (! $perfume) { + $this->toast('Parfum tidak valid.', 'Gagal', 'danger'); return; } - $quantity = $quality->volume; + if ($this->form->quality_id === 'custom') { + $quantity = parseRupiahToInt($this->form->bottle_size); + $qualityName = 'Custom'; - if (! $perfume || ! $quality || $quantity <= 0) { - $this->toast('Parfum, ukuran, atau kualitas tidak valid.', 'Gagal', 'danger'); + if ($quantity <= 0) { + $this->toast('Jumlah parfum (Custom) tidak valid.', 'Gagal', 'danger'); + + return; + } + } else { + $quality = Formula::find($this->form->quality_id); + + if (! $quality) { + $this->toast('Kualitas tidak valid.', 'Gagal', 'danger'); + + return; + } + + $quantity = $quality->volume; + $qualityName = $quality->quality; + } + + if ($quantity <= 0) { + $this->toast('Jumlah parfum tidak valid.', 'Gagal', 'danger'); return; } - $this->addOrUpdateOrderItem($perfume, $quantity); + $this->addOrUpdateOrderItem($perfume, $quantity, $qualityName); $this->toast('Parfum isi ulang ditambahkan ke keranjang.', 'Berhasil'); diff --git a/app/Traits/Order/WithManageItem.php b/app/Traits/Order/WithManageItem.php index edca4cf..f780d9d 100644 --- a/app/Traits/Order/WithManageItem.php +++ b/app/Traits/Order/WithManageItem.php @@ -11,10 +11,11 @@ trait WithManageItem * * @param mixed $model The model instance (Perfume, Bottle, or Product) * @param int $quantity The quantity to add + * @param string|null $quality The quality of the item */ - protected function addOrUpdateOrderItem($model, int $quantity): void + protected function addOrUpdateOrderItem($model, int $quantity, ?string $quality = null): void { - $existing = $this->items->firstWhere(fn ($i) => $i->orderable_type === get_class($model) && $i->orderable_id === $model->id); + $existing = $this->items->firstWhere(fn ($i) => $i->orderable_type === get_class($model) && $i->orderable_id === $model->id && $i->quality === $quality); if ($existing) { $existing->increment('quantity', $quantity); @@ -24,6 +25,7 @@ protected function addOrUpdateOrderItem($model, int $quantity): void 'user_id' => auth()->id(), 'orderable_id' => $model->id, 'orderable_type' => get_class($model), + 'quality' => $quality, 'cogs' => $model->cost_price ?? 0, 'quantity' => $quantity, 'unit_price' => $model->sale_price ?? 0, diff --git a/database/migrations/2025_10_06_135049_create_order_items_table.php b/database/migrations/2025_10_06_135049_create_order_items_table.php index c4ece66..e7dfe2e 100644 --- a/database/migrations/2025_10_06_135049_create_order_items_table.php +++ b/database/migrations/2025_10_06_135049_create_order_items_table.php @@ -16,6 +16,7 @@ public function up(): void $table->foreignId('order_id')->nullable()->constrained()->cascadeOnDelete(); $table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->morphs('orderable'); + $table->string('quality', 20)->nullable(); $table->unsignedInteger('cogs'); $table->unsignedInteger('unit_price'); $table->unsignedInteger('quantity'); diff --git a/resources/views/livewire/studio/manage/order/form.blade.php b/resources/views/livewire/studio/manage/order/form.blade.php index 19c53ce..c0ca266 100644 --- a/resources/views/livewire/studio/manage/order/form.blade.php +++ b/resources/views/livewire/studio/manage/order/form.blade.php @@ -125,6 +125,18 @@ botol... @endif + + @if ($form->quality_id === 'custom') + + Jumlah (ml) + + + ml + + + @endif @@ -227,11 +239,18 @@
-
{{ $item->orderable->name }}
- {{ formatCurrencyNumber($item->quantity, '') }} - x - {{ formatCurrencyNumber($item->unit_price, 'Rp') }} +
+ {{ $item->orderable->name }} +
+ + @if ($item->quality && $item->quality !== 'Custom') + {{ $item->quality }} + @else + {{ $item->quality === 'Custom' ? $item->quantity : formatCurrencyNumber($item->quantity, '') }} + x + {{ formatCurrencyNumber($item->unit_price, 'Rp') }} + @endif +
diff --git a/tests/Feature/Studio/Manage/Order/CreateTest.php b/tests/Feature/Studio/Manage/Order/CreateTest.php index 88a5760..54f6fec 100644 --- a/tests/Feature/Studio/Manage/Order/CreateTest.php +++ b/tests/Feature/Studio/Manage/Order/CreateTest.php @@ -91,6 +91,7 @@ 'orderable_type' => Perfume::class, 'orderable_id' => $perfume->id, 'quantity' => 30, + 'quality' => 'Premium', 'order_id' => null, ]); @@ -103,6 +104,100 @@ ]); }); +it('can add a new perfume with custom quality', function () { + $perfume = Perfume::factory()->create(['sale_price' => 1000]); + $bottle = Bottle::factory()->create(['size' => 'Custom', 'sale_price' => 5000]); + + $this->outlet->perfumes()->attach($perfume->id, ['stock' => 1000]); + $this->outlet->bottles()->attach($bottle->id, ['stock' => 50]); + + Livewire::actingAs($this->user) + ->test(Create::class) + ->set('form.outlet_id', $this->outlet->id) + ->set('tab', 'new') + ->set('form.perfume_id', $perfume->id) + ->set('form.bottle_id', $bottle->id) + ->set('form.quality_id', 'custom') + ->set('form.bottle_size', '15') + ->call('addPerfume') + ->assertHasNoErrors(); + + $this->assertDatabaseHas('order_items', [ + 'user_id' => $this->user->id, + 'orderable_type' => Perfume::class, + 'orderable_id' => $perfume->id, + 'quantity' => 15, + 'quality' => 'Custom', + 'order_id' => null, + ]); +}); + +it('can add a refill perfume with custom quality', function () { + $perfume = Perfume::factory()->create(['sale_price' => 1000]); + + $this->outlet->perfumes()->attach($perfume->id, ['stock' => 1000]); + + Livewire::actingAs($this->user) + ->test(Create::class) + ->set('form.outlet_id', $this->outlet->id) + ->set('tab', 'refill') + ->set('form.perfume_id', $perfume->id) + ->set('form.quality_id', 'custom') + ->set('form.bottle_size', '50') + ->call('addPerfume') + ->assertHasNoErrors(); + + $this->assertDatabaseHas('order_items', [ + 'user_id' => $this->user->id, + 'orderable_type' => Perfume::class, + 'orderable_id' => $perfume->id, + 'quantity' => 50, + 'quality' => 'Custom', + 'order_id' => null, + ]); +}); + +it('separates items with different qualities', function () { + $perfume = Perfume::factory()->create(['sale_price' => 1000]); + $bottle = Bottle::factory()->create(['size' => '30ml']); + $formula1 = Formula::factory()->create(['size' => '30ml', 'volume' => 30, 'quality' => 'Premium']); + $formula2 = Formula::factory()->create(['size' => '30ml', 'volume' => 30, 'quality' => 'Super']); + + $this->outlet->perfumes()->attach($perfume->id, ['stock' => 1000]); + $this->outlet->bottles()->attach($bottle->id, ['stock' => 100]); + + Livewire::actingAs($this->user) + ->test(Create::class) + ->set('form.outlet_id', $this->outlet->id) + ->set('tab', 'new') + ->set('form.perfume_id', $perfume->id) + ->set('form.bottle_id', $bottle->id) + ->set('form.quality_id', $formula1->id) + ->call('addPerfume') + ->set('form.perfume_id', $perfume->id) + ->set('form.bottle_id', $bottle->id) + ->set('form.quality_id', $formula2->id) // Switch quality + ->call('addPerfume'); + + $this->assertDatabaseHas('order_items', [ + 'orderable_id' => $perfume->id, + 'quality' => 'Premium', + 'quantity' => 30, + ]); + + $this->assertDatabaseHas('order_items', [ + 'orderable_id' => $perfume->id, + 'quality' => 'Super', + 'quantity' => 30, + ]); + + // Bottle should have aggregated to 2 (since bottle has no quality separation) + $this->assertDatabaseHas('order_items', [ + 'orderable_id' => $bottle->id, + 'quantity' => 2, + ]); +}); + it('can update item quantity in the cart', function () { $product = Product::factory()->create(['sale_price' => 50000]); $item = OrderItem::factory()->forProduct($product)->create([