quantity; switch ($item->purchasable_type) { case Perfume::class: $relation = 'perfumes'; break; case Product::class: $relation = 'products'; break; case Bottle::class: $relation = 'bottles'; break; default: return; } // Lock the row to prevent race conditions $existing = $warehouse->{$relation}() ->where("{$relation}.id", $item->purchasable_id) ->lockForUpdate() ->withPivot('stock') ->first(); if ($existing) { $previousStock = $existing->pivot->stock ?? 0; $warehouse->{$relation}()->updateExistingPivot($item->purchasable_id, [ 'stock' => $previousStock + $quantity, ]); } else { $previousStock = 0; $warehouse->{$relation}()->attach($item->purchasable_id, [ 'stock' => $quantity, ]); } StockActivityLogService::logWarehouse( logName: 'Belanja', event: 'Menambah', description: 'Stok '.$item->purchasable->name.' di '.$warehouse->name.' bertambah '.formatCurrencyNumber($quantity), performedOn: $item->purchasable, warehouse: $warehouse, quantityChange: $quantity, previousStock: $previousStock, newStock: $previousStock + $quantity, extraProperties: [ 'purchasable_id' => $item->purchasable_id, 'purchasable_type' => $item->purchasable_type, 'purchase_id' => $item->purchase_id ?? null, ] ); } public function decreaseWarehouseStock($warehouse, $item): void { $quantity = $item->quantity; switch ($item->purchasable_type) { case Perfume::class: $relation = 'perfumes'; break; case Product::class: $relation = 'products'; break; case Bottle::class: $relation = 'bottles'; break; default: return; } $existing = $warehouse->{$relation}() ->where("{$relation}.id", $item->purchasable_id) ->lockForUpdate() ->withPivot('stock') ->first(); $currentStock = $existing?->pivot->stock ?? 0; $newStock = max(0, $currentStock - $quantity); if ($existing) { if ($newStock === 0) { $warehouse->{$relation}()->detach($item->purchasable_id); } else { $warehouse->{$relation}()->updateExistingPivot( $item->purchasable_id, ['stock' => $newStock] ); } } StockActivityLogService::logWarehouse( logName: 'Belanja', event: 'Mengurangi', description: 'Stok '.$item->purchasable->name.' di '.$warehouse->name.' berkurang '.$quantity, performedOn: $item->purchasable, warehouse: $warehouse, quantityChange: $quantity, previousStock: $currentStock, newStock: $newStock, extraProperties: [ 'purchasable_id' => $item->purchasable_id, 'purchasable_type' => $item->purchasable_type, 'purchase_id' => $item->purchase_id, ] ); } }