feat(order): throw transaction jika stok produk tidak mencukupi
This commit is contained in:
parent
464ce3df39
commit
c63245bf68
@ -115,81 +115,90 @@ public function store()
|
|||||||
|
|
||||||
// Wrap the entire operation in a database transaction
|
// Wrap the entire operation in a database transaction
|
||||||
// Ensures atomicity — if any step fails, all changes are rolled back
|
// Ensures atomicity — if any step fails, all changes are rolled back
|
||||||
DB::transaction(function () use ($invoiceNumber, $cogs, $subtotal, $discount, $total, $items, $pointsEarned) {
|
try {
|
||||||
$member = User::whereHas('customer', fn ($q) => $q->where('id', $this->member_id))
|
DB::transaction(function () use ($invoiceNumber, $cogs, $subtotal, $discount, $total, $items, $pointsEarned) {
|
||||||
->with(['membership' => fn ($q) => $q->lockForUpdate()])
|
$member = User::whereHas('customer', fn ($q) => $q->where('id', $this->member_id))
|
||||||
->first();
|
->with(['membership' => fn ($q) => $q->lockForUpdate()])
|
||||||
|
|
||||||
$order = Order::create([
|
|
||||||
'outlet_id' => $this->outlet_id,
|
|
||||||
'user_id' => auth()->id(),
|
|
||||||
'voucher_id' => $this->voucher_id == '' ? null : $this->voucher_id,
|
|
||||||
'customer_id' => $this->member_id == '' ? null : $this->member_id,
|
|
||||||
'invoice_number' => $invoiceNumber,
|
|
||||||
'cogs' => $cogs,
|
|
||||||
'subtotal' => $subtotal,
|
|
||||||
'discount' => $discount,
|
|
||||||
'total' => $total,
|
|
||||||
'channel' => $this->channel,
|
|
||||||
'status' => $this->status,
|
|
||||||
'payment_method' => $this->payment_method,
|
|
||||||
'ordered_at' => now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Attach all order items to the newly created order
|
|
||||||
$items->each(function ($item) use ($order) {
|
|
||||||
$item->order_id = $order->id;
|
|
||||||
$item->save();
|
|
||||||
|
|
||||||
// Deduct item stock from the outlet inventory
|
|
||||||
$this->decreaseOutletStock($order->outlet, $item);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Automatically record payment for the order
|
|
||||||
Payment::create([
|
|
||||||
'order_id' => $order->id,
|
|
||||||
'user_id' => auth()->id(),
|
|
||||||
'method' => $this->payment_method,
|
|
||||||
'amount' => $total,
|
|
||||||
'status' => PaymentStatus::PAID->value,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Deduct voucher quantity
|
|
||||||
if ($this->voucher_id) {
|
|
||||||
$userVoucher = DB::table('user_voucher')
|
|
||||||
->where('user_id', $member->id)
|
|
||||||
->where('voucher_id', $this->voucher_id)
|
|
||||||
->lockForUpdate()
|
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if ($userVoucher) {
|
$order = Order::create([
|
||||||
if ($userVoucher->quantity > 1) {
|
'outlet_id' => $this->outlet_id,
|
||||||
DB::table('user_voucher')
|
'user_id' => auth()->id(),
|
||||||
->where('id', $userVoucher->id)
|
'voucher_id' => $this->voucher_id == '' ? null : $this->voucher_id,
|
||||||
->update([
|
'customer_id' => $this->member_id == '' ? null : $this->member_id,
|
||||||
'quantity' => $userVoucher->quantity - 1,
|
'invoice_number' => $invoiceNumber,
|
||||||
'updated_at' => now(),
|
'cogs' => $cogs,
|
||||||
]);
|
'subtotal' => $subtotal,
|
||||||
} else {
|
'discount' => $discount,
|
||||||
DB::table('user_voucher')
|
'total' => $total,
|
||||||
->where('id', $userVoucher->id)
|
'channel' => $this->channel,
|
||||||
->delete();
|
'status' => $this->status,
|
||||||
|
'payment_method' => $this->payment_method,
|
||||||
|
'ordered_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
// Deduct item stock from the outlet inventory
|
||||||
|
$result = $this->decreaseOutletStock($order->outlet, $item);
|
||||||
|
|
||||||
|
if ($result && ! $result['status']) {
|
||||||
|
throw new \Exception($result['message']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach all order items to the newly created order
|
||||||
|
$item->order_id = $order->id;
|
||||||
|
$item->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically record payment for the order
|
||||||
|
Payment::create([
|
||||||
|
'order_id' => $order->id,
|
||||||
|
'user_id' => auth()->id(),
|
||||||
|
'method' => $this->payment_method,
|
||||||
|
'amount' => $total,
|
||||||
|
'status' => PaymentStatus::PAID->value,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Deduct voucher quantity
|
||||||
|
if ($this->voucher_id) {
|
||||||
|
$userVoucher = DB::table('user_voucher')
|
||||||
|
->where('user_id', $member->id)
|
||||||
|
->where('voucher_id', $this->voucher_id)
|
||||||
|
->lockForUpdate()
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($userVoucher) {
|
||||||
|
if ($userVoucher->quantity > 1) {
|
||||||
|
DB::table('user_voucher')
|
||||||
|
->where('id', $userVoucher->id)
|
||||||
|
->update([
|
||||||
|
'quantity' => $userVoucher->quantity - 1,
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
DB::table('user_voucher')
|
||||||
|
->where('id', $userVoucher->id)
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Update member tier points
|
// Update member tier points
|
||||||
if ($member && $member->membership) {
|
if ($member && $member->membership) {
|
||||||
$member->membership()->update([
|
$member->membership()->update([
|
||||||
'tier_points' => DB::raw("tier_points + $pointsEarned"),
|
'tier_points' => DB::raw("tier_points + $pointsEarned"),
|
||||||
'reward_points' => DB::raw("reward_points + $pointsEarned"),
|
'reward_points' => DB::raw("reward_points + $pointsEarned"),
|
||||||
'last_transaction_at' => now(),
|
'last_transaction_at' => now(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return [
|
||||||
|
'status' => false,
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return ['status' => true];
|
||||||
'status' => true,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,16 +73,28 @@ public function decreaseOutletStock($outlet, $item)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$existing = $outlet->{$relation}()->withPivot('stock')->where("{$relation}.id", $item->orderable_id)->first();
|
$existing = $outlet->{$relation}()
|
||||||
|
->withPivot('stock')
|
||||||
|
->where("{$relation}.id", $item->orderable_id)
|
||||||
|
->lockForUpdate()
|
||||||
|
->first();
|
||||||
|
|
||||||
if ($existing) {
|
if (! $existing) {
|
||||||
$currentStock = $existing->pivot->stock ?? 0;
|
return ['status' => false, 'message' => "Produk {$item->orderable->name} tidak ditemukan di {$outlet->name}."];
|
||||||
$newStock = max(0, $currentStock - $quantity);
|
|
||||||
$outlet->{$relation}()->updateExistingPivot($item->orderable_id, [
|
|
||||||
'stock' => $newStock,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$currentStock = $existing->pivot->stock ?? 0;
|
||||||
|
|
||||||
|
if ($currentStock < $quantity) {
|
||||||
|
return ['status' => false, 'message' => "Stok produk {$item->orderable->name} tidak mencukupi. Tersisa {$currentStock}, diminta {$quantity}. Silakan hubungi Administrator."];
|
||||||
|
}
|
||||||
|
|
||||||
|
$newStock = $currentStock - $quantity;
|
||||||
|
|
||||||
|
$outlet->{$relation}()->updateExistingPivot($item->orderable_id, [
|
||||||
|
'stock' => $newStock,
|
||||||
|
]);
|
||||||
|
|
||||||
activity('Order')
|
activity('Order')
|
||||||
->performedOn($item->orderable)
|
->performedOn($item->orderable)
|
||||||
->causedBy(auth()->user())
|
->causedBy(auth()->user())
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user