Files
compras/app/Services/WarehouseAvailability.php
2026-11-02 08:08:05 +02:00

43 lines
2.6 KiB
PHP

<?php
namespace App\Services;
use App\Models\StockItem;
use App\Models\Warehouse;
use Illuminate\Support\Facades\Schema;
class WarehouseAvailability
{
/** @return array<string,mixed> */
public function row(StockItem $item, Warehouse $warehouse, bool $planning): array
{
abort_unless($item->tenant_id === $warehouse->tenant_id && auth()->user()?->tenant_id === $item->tenant_id, 404);
$physical = app(StockWorkflow::class)->balance($item->id, $warehouse->id);
$lots = app(InventoryLots::class)->context($item->id, $warehouse->id);
$usable = $lots === null ? $physical['quantity'] : ($lots['reconciled'] ? $lots['usable_milli'] : null);
$needs = null;
$minimum = null;
if ($planning && Schema::hasTable('supply_records')) {
$needs = 0;
foreach (app(SupplyPlanning::class)->latest('reservation')->where('stock_item_id', $item->id)->where('warehouse_id', $warehouse->id)->whereIn('state', ['active', 'fulfilled'])->get() as $need) {
if (($need->snapshot['item']['unit'] ?? null) !== $item->unit) {
$needs = null;
break;
}
$needs += app(SupplyCoordination::class)->remainingReservation($need);
}
$policy = app(SupplyPlanning::class)->latest('policy')->where('stock_item_id', $item->id)->where('warehouse_id', $warehouse->id)->where('state', 'approved')->first();
if ($policy !== null && $policy->snapshot['item'] === $item->only(['id', 'code', 'name', 'unit'])) {
$minimum = $policy->data['minimum_stock_milli'] ?? null;
}
}
return ['id' => $item->id, 'code' => $item->code, 'name' => $item->name, 'unit' => $item->unit,
'physical_milli' => $physical['quantity'], 'usable_milli' => $usable, 'blocked_milli' => $lots === null || ! $lots['reconciled'] ? null : $lots['blocked_milli'],
'lot_control' => $lots !== null, 'reconciled' => $lots === null || $lots['reconciled'], 'planned_milli' => $needs,
'minimum_milli' => $minimum, 'at_minimum' => $usable !== null && $minimum !== null && $usable - app(WarehouseReservations::class)->committed($item->id, $warehouse->id) <= $minimum,
'physical_commitment_milli' => app(WarehouseReservations::class)->ready() ? app(WarehouseReservations::class)->committed($item->id, $warehouse->id) : null,
'free_milli' => $usable === null ? null : $usable - app(WarehouseReservations::class)->committed($item->id, $warehouse->id), 'ledger_version' => $physical['version']];
}
}