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();
|
$formulas = Formula::where('size', $bottle->size)->orderBy('volume')->pluck('quality', 'id')->toArray();
|
||||||
|
|
||||||
// check if there is any formula
|
$this->qualities = $formulas + ['custom' => 'Custom'];
|
||||||
if (empty($formulas)) {
|
|
||||||
$this->qualities = [];
|
|
||||||
$this->toast('Kualitas tidak ditemukan, silakan hubungi Administrator.', 'Gagal', 'danger');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->qualities = $formulas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,16 +36,13 @@ public function updatedFormBottleId(string $value)
|
|||||||
*/
|
*/
|
||||||
public function updatedFormBottleSize(string $value)
|
public function updatedFormBottleSize(string $value)
|
||||||
{
|
{
|
||||||
$formulas = Formula::where('size', $value)->orderBy('volume')->pluck('quality', 'id')->toArray();
|
if ($this->tab !== 'refill') {
|
||||||
|
return;
|
||||||
// check if there is any formula
|
|
||||||
if (empty($formulas)) {
|
|
||||||
$this->qualities = [];
|
|
||||||
|
|
||||||
return $this->toast('Kualitas tidak ditemukan, silakan hubungi Administrator.', 'Gagal', 'danger');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$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);
|
$perfume = Perfume::find($this->form->perfume_id);
|
||||||
$bottle = Bottle::find($this->form->bottle_id);
|
$bottle = Bottle::find($this->form->bottle_id);
|
||||||
$quality = Formula::find($this->form->quality_id);
|
|
||||||
|
|
||||||
if (! $perfume || ! $bottle || ! $quality) {
|
if (! $perfume || ! $bottle) {
|
||||||
$this->toast('Parfum, botol, atau kualitas tidak valid.', 'Gagal', 'danger');
|
$this->toast('Parfum atau botol tidak valid.', 'Gagal', 'danger');
|
||||||
|
|
||||||
return;
|
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) {
|
if ($quantity <= 0) {
|
||||||
$this->toast('Jumlah parfum tidak valid.', 'Gagal', 'danger');
|
$this->toast('Jumlah parfum tidak valid.', 'Gagal', 'danger');
|
||||||
@ -92,7 +100,7 @@ protected function handleNewPerfume(): void
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addOrUpdateOrderItem($perfume, $quantity);
|
$this->addOrUpdateOrderItem($perfume, $quantity, $qualityName);
|
||||||
|
|
||||||
$this->addOrUpdateOrderItem($bottle, 1);
|
$this->addOrUpdateOrderItem($bottle, 1);
|
||||||
|
|
||||||
@ -109,23 +117,42 @@ protected function handleNewPerfume(): void
|
|||||||
protected function handleRefillPerfume(): void
|
protected function handleRefillPerfume(): void
|
||||||
{
|
{
|
||||||
$perfume = Perfume::find($this->form->perfume_id);
|
$perfume = Perfume::find($this->form->perfume_id);
|
||||||
$quality = Formula::find($this->form->quality_id);
|
|
||||||
|
|
||||||
if (! $perfume || ! $quality) {
|
if (! $perfume) {
|
||||||
$this->toast('Parfum, ukuran, atau kualitas tidak valid.', 'Gagal', 'danger');
|
$this->toast('Parfum tidak valid.', 'Gagal', 'danger');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$quantity = $quality->volume;
|
if ($this->form->quality_id === 'custom') {
|
||||||
|
$quantity = parseRupiahToInt($this->form->bottle_size);
|
||||||
|
$qualityName = 'Custom';
|
||||||
|
|
||||||
if (! $perfume || ! $quality || $quantity <= 0) {
|
if ($quantity <= 0) {
|
||||||
$this->toast('Parfum, ukuran, atau kualitas tidak valid.', 'Gagal', 'danger');
|
$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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->addOrUpdateOrderItem($perfume, $quantity);
|
$this->addOrUpdateOrderItem($perfume, $quantity, $qualityName);
|
||||||
|
|
||||||
$this->toast('Parfum isi ulang ditambahkan ke keranjang.', 'Berhasil');
|
$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 mixed $model The model instance (Perfume, Bottle, or Product)
|
||||||
* @param int $quantity The quantity to add
|
* @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) {
|
if ($existing) {
|
||||||
$existing->increment('quantity', $quantity);
|
$existing->increment('quantity', $quantity);
|
||||||
@ -24,6 +25,7 @@ protected function addOrUpdateOrderItem($model, int $quantity): void
|
|||||||
'user_id' => auth()->id(),
|
'user_id' => auth()->id(),
|
||||||
'orderable_id' => $model->id,
|
'orderable_id' => $model->id,
|
||||||
'orderable_type' => get_class($model),
|
'orderable_type' => get_class($model),
|
||||||
|
'quality' => $quality,
|
||||||
'cogs' => $model->cost_price ?? 0,
|
'cogs' => $model->cost_price ?? 0,
|
||||||
'quantity' => $quantity,
|
'quantity' => $quantity,
|
||||||
'unit_price' => $model->sale_price ?? 0,
|
'unit_price' => $model->sale_price ?? 0,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ public function up(): void
|
|||||||
$table->foreignId('order_id')->nullable()->constrained()->cascadeOnDelete();
|
$table->foreignId('order_id')->nullable()->constrained()->cascadeOnDelete();
|
||||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||||
$table->morphs('orderable');
|
$table->morphs('orderable');
|
||||||
|
$table->string('quality', 20)->nullable();
|
||||||
$table->unsignedInteger('cogs');
|
$table->unsignedInteger('cogs');
|
||||||
$table->unsignedInteger('unit_price');
|
$table->unsignedInteger('unit_price');
|
||||||
$table->unsignedInteger('quantity');
|
$table->unsignedInteger('quantity');
|
||||||
|
|||||||
@ -125,6 +125,18 @@
|
|||||||
botol...</span>
|
botol...</span>
|
||||||
</flux:field>
|
</flux:field>
|
||||||
@endif
|
@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>
|
||||||
</div>
|
</div>
|
||||||
</flux:tab.panel>
|
</flux:tab.panel>
|
||||||
@ -227,11 +239,18 @@
|
|||||||
<flux:table.cell>
|
<flux:table.cell>
|
||||||
<flux:heading>
|
<flux:heading>
|
||||||
<div>
|
<div>
|
||||||
<div>{{ $item->orderable->name }}</div>
|
<div>
|
||||||
<span
|
{{ $item->orderable->name }}
|
||||||
class="text-xs text-gray-400">{{ formatCurrencyNumber($item->quantity, '') }}
|
</div>
|
||||||
x
|
<span class="text-xs text-gray-400">
|
||||||
{{ formatCurrencyNumber($item->unit_price, 'Rp') }}</span>
|
@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>
|
</div>
|
||||||
</flux:heading>
|
</flux:heading>
|
||||||
</flux:table.cell>
|
</flux:table.cell>
|
||||||
|
|||||||
@ -91,6 +91,7 @@
|
|||||||
'orderable_type' => Perfume::class,
|
'orderable_type' => Perfume::class,
|
||||||
'orderable_id' => $perfume->id,
|
'orderable_id' => $perfume->id,
|
||||||
'quantity' => 30,
|
'quantity' => 30,
|
||||||
|
'quality' => 'Premium',
|
||||||
'order_id' => null,
|
'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 () {
|
it('can update item quantity in the cart', function () {
|
||||||
$product = Product::factory()->create(['sale_price' => 50000]);
|
$product = Product::factory()->create(['sale_price' => 50000]);
|
||||||
$item = OrderItem::factory()->forProduct($product)->create([
|
$item = OrderItem::factory()->forProduct($product)->create([
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user