feat: Ensure order totals are non-negative, improve voucher deduction validation, and add pessimistic locking for stock updates.
This commit is contained in:
parent
4b1566c1a2
commit
2978d34e9e
@ -109,7 +109,7 @@ public function store(): array
|
||||
$discount = $voucherDiscount + $manualDiscount;
|
||||
|
||||
// Calculate total (subtotal - manual discount - voucher discount)
|
||||
$total = $afterManual - $voucherDiscount;
|
||||
$total = max(0, $afterManual - $voucherDiscount);
|
||||
|
||||
$pointsEarned = (int) floor($total / 5000);
|
||||
|
||||
@ -141,7 +141,7 @@ public function store(): array
|
||||
// Deduct item stock from the outlet inventory
|
||||
$result = $this->decreaseOutletStock($order->outlet, $item);
|
||||
|
||||
if ($result && ! $result['status']) {
|
||||
if (! $result['status']) {
|
||||
throw new \Exception($result['message']);
|
||||
}
|
||||
|
||||
@ -161,27 +161,35 @@ public function store(): array
|
||||
|
||||
// Deduct voucher quantity
|
||||
if ($this->voucher_id) {
|
||||
if (! $member) {
|
||||
throw new \Exception('Data member tidak valid.');
|
||||
}
|
||||
|
||||
$userVoucher = DB::table('user_voucher')
|
||||
->where('user_id', $member->id)
|
||||
->where('voucher_id', $this->voucher_id)
|
||||
->lockForUpdate()
|
||||
->first();
|
||||
|
||||
if ($userVoucher) {
|
||||
if (! $userVoucher->quantity) {
|
||||
return;
|
||||
} elseif ($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();
|
||||
}
|
||||
if (! $userVoucher) {
|
||||
throw new \Exception('Member tidak memiliki voucher ini.');
|
||||
}
|
||||
|
||||
if ($userVoucher->quantity < 1) {
|
||||
throw new \Exception('Voucher sudah habis terpakai.');
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@ public function getSubTotal(): int
|
||||
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->items->sum(fn ($item) => $item->unit_price * $item->quantity - parseRupiahToInt($this->form->discount) - $this->voucherDiscount);
|
||||
$subtotal = $this->items->sum(fn ($item) => $item->unit_price * $item->quantity);
|
||||
|
||||
return max(0, $subtotal - parseRupiahToInt($this->form->discount) - $this->voucherDiscount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,11 @@ public function increaseOutletStock($outlet, $item): void
|
||||
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) {
|
||||
$currentStock = $existing->pivot->stock ?? 0;
|
||||
@ -112,5 +116,7 @@ public function decreaseOutletStock($outlet, $item)
|
||||
'purchase_id' => $item->purchase_id ?? null,
|
||||
]
|
||||
);
|
||||
|
||||
return ['status' => true];
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user