feat: Add custom perfume quality option and display quality in order items.
This commit is contained in:
parent
1eb43643d2
commit
9a1bd66eba
@ -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');
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -125,6 +125,18 @@
|
||||
botol...</span>
|
||||
</flux:field>
|
||||
@endif
|
||||
|
||||
@if ($form->quality_id === 'custom')
|
||||
<flux:field class="mt-4">
|
||||
<flux:label>Jumlah (ml)</flux:label>
|
||||
<flux:input.group>
|
||||
<flux:input placeholder="Masukkan jumlah (ml)"
|
||||
x-mask:dynamic="$money($input, ',')"
|
||||
wire:model="form.bottle_size" autocomplete="off" />
|
||||
<flux:input.group.suffix>ml</flux:input.group.suffix>
|
||||
</flux:input.group>
|
||||
</flux:field>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</flux:tab.panel>
|
||||
@ -227,11 +239,18 @@
|
||||
<flux:table.cell>
|
||||
<flux:heading>
|
||||
<div>
|
||||
<div>{{ $item->orderable->name }}</div>
|
||||
<span
|
||||
class="text-xs text-gray-400">{{ formatCurrencyNumber($item->quantity, '') }}
|
||||
x
|
||||
{{ formatCurrencyNumber($item->unit_price, 'Rp') }}</span>
|
||||
<div>
|
||||
{{ $item->orderable->name }}
|
||||
</div>
|
||||
<span class="text-xs text-gray-400">
|
||||
@if ($item->quality && $item->quality !== 'Custom')
|
||||
{{ $item->quality }}
|
||||
@else
|
||||
{{ $item->quality === 'Custom' ? $item->quantity : formatCurrencyNumber($item->quantity, '') }}
|
||||
x
|
||||
{{ formatCurrencyNumber($item->unit_price, 'Rp') }}
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
</flux:heading>
|
||||
</flux:table.cell>
|
||||
|
||||
@ -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([
|
||||
|
||||
Loading…
Reference in New Issue
Block a user