|
- <?php
-
- namespace App\Http\Controllers\Items;
-
- use App\Models\Item;
- use App\Models\Location;
- use App\Models\Stock;
- use App\Models\StockMovement;
- use Framework\Routing\Router;
-
- class AdjustStockController
- {
- public function handle(Router $router)
- {
- if (!session()->has('user_id')) {
- return redirect($router->route('show-register-form'));
- }
-
- secure();
-
- $parameters = $router->current()->parameters();
-
- $item = Item::find((int) $parameters['item']);
-
- if (!$item) {
- return redirect($router->route('show-items'));
- }
-
- $data = validate($_POST, [
- 'location_id' => ['required'],
- // not ['required'] - PHP's empty("0") is true, which would reject
- // a legitimate "set this to zero" adjustment before it reaches
- // the ctype_digit check below (which does allow zero).
- 'quantity' => [],
- 'notes' => [],
- ], 'adjust_errors');
-
- if (!isset($data['quantity']) || !ctype_digit((string) $data['quantity'])) {
- session()->put('adjust_errors', [
- 'quantity' => ['quantity must be a whole number, 0 or greater'],
- ]);
-
- return redirect($router->route('show-adjust-stock-form', ['item' => $item->id]));
- }
-
- $location = Location::find((int) $data['location_id']);
-
- if (!$location) {
- return redirect($router->route('show-adjust-stock-form', ['item' => $item->id]));
- }
-
- $stock = Stock::forItemAtLocation($item->id, $location->id);
- $newQuantity = (int) $data['quantity'];
- $change = $newQuantity - $stock->quantity;
-
- $stock->quantity = $newQuantity;
- $stock->save();
-
- $movement = new StockMovement();
- $movement->item_id = $item->id;
- $movement->location_id = $location->id;
- $movement->type = 'adjustment';
- $movement->quantity_change = $change;
- $movement->quantity_after = $newQuantity;
- $movement->notes = $data['notes'] ?? '';
- $movement->user_id = session('user_id');
- $movement->save();
-
- $this->alertIfLowStock($item);
-
- return redirect($router->route('view-item', ['item' => $item->id]));
- }
-
- private function alertIfLowStock(Item $item): void
- {
- if ($item->reorder_level <= 0) {
- return;
- }
-
- $total = array_sum(array_map(
- fn($row) => $row->quantity,
- Stock::where('item_id', $item->id)->all(),
- ));
-
- if ($total > $item->reorder_level) {
- return;
- }
-
- app('queue')->push(function ($itemName, $total, $reorderLevel) {
- app('email')
- ->to(config('warehouse.alert_email'))
- ->subject("Low stock: {$itemName}")
- ->text("{$itemName} is at {$total} units, at or below its reorder level of {$reorderLevel}.")
- ->send();
- }, $item->name, $total, $item->reorder_level);
- }
- }
|