user('web'); abort_unless($actor instanceof User, 403); $capabilities = []; foreach (['read', 'prepare', 'review', 'execute'] as $capability) { $capabilities[$capability] = $workflow->allows($actor, $capability); } $canViewReversals = collect(['read', 'prepare', 'review', 'execute'])->contains(fn ($a) => app(InventoryReversals::class)->allows($actor, $a)); if (! collect($capabilities)->contains(fn (bool $allow) => $allow) && $canViewReversals) { return redirect('/stock/estornos'); } abort_unless(collect($capabilities)->contains(fn (bool $allow) => $allow), 403); return DB::transaction(function () use ($request, $workflow, $actor, $capabilities, $canViewReversals) { if (DB::getDriverName() === 'pgsql' && DB::transactionLevel() === 1) { DB::statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY'); } return $this->page($request, $workflow, $actor, $capabilities, $canViewReversals); }); } /** @param array $capabilities */ private function page(Request $request, InventoryDispositions $workflow, User $actor, array $capabilities, bool $canViewReversals): Response { $page = app(InventoryCorrectionPage::class)->read($request, $actor, 'stock_event'); ['ready' => $ready, 'focus' => $focus, 'records' => $records] = $page; $receipts = []; $lots = []; if ($ready && $capabilities['prepare']) { foreach (app(InventoryCorrectionPage::class)->receipts($records->pluck('data.receipt_item_id')->push($page['lookup']['receipt']), $page['lookup']['search']) as $line) { $receipt = GoodsReceipt::query()->whereKey($line->goods_receipt_id)->firstOrFail(); $receipts[] = ['id' => $line->id, 'stock_item_id' => $line->stock_item_id, 'warehouse_id' => $receipt->warehouse_id, 'accepted_milli' => $line->accepted_milli, 'returned_milli' => $workflow->returnedForReceipt($line->id), 'label' => $receipt->number.' · '.$receipt->snapshot['supplier']['name'].' · '.$line->snapshot['stock_item']['name']]; } foreach (app(InventoryLots::class)->activeSetups()->get() as $setup) { $context = app(InventoryLots::class)->context($setup->stock_item_id, $setup->warehouse_id); foreach ($context['lots'] ?? [] as $lot) { if ($lot['quantity_milli'] > 0) { $lots[] = ['id' => $lot['id'], 'stock_item_id' => $setup->stock_item_id, 'warehouse_id' => $setup->warehouse_id, 'code' => $lot['data']['code'], 'quantity_milli' => $lot['quantity_milli'], 'receipt_item_id' => $lot['origin']['receipt_item_id'] ?? null, 'reconciled' => $context['reconciled']]; } } } } Inertia::encryptHistory(); $response = Inertia::render('stock/dispositions', ['ready' => $ready, 'actorId' => $actor->id, 'today' => today()->toDateString(), 'capabilities' => $capabilities, 'recordPagination' => $page['pagination'], 'filters' => $page['filters'], 'sourceSearch' => $page['lookup']['search'], 'sourceFormKey' => $page['lookup']['form'], 'focusRecordId' => $focus->id ?? null, 'focusChanged' => $focus !== null && $records->first()?->id !== $focus->id, 'records' => $records->map(fn (SupplyRecord $record) => [...$record->toArray(), 'canApprove' => $workflow->canAct($actor, $record, 'approve'), 'canReturn' => $workflow->canAct($actor, $record, 'return'), 'canExecute' => $workflow->canAct($actor, $record, 'execute'), 'executionSourceCurrent' => $record->state === 'approved' ? $workflow->executionSourceCurrent($record) : null]), 'canViewOperations' => $actor->hasFunctions(['admin', 'warehouse', 'procurement', 'finance', 'inventory_adjust_review']), 'canViewReversals' => $canViewReversals, 'correctedOperations' => collect(app(InventoryReversals::class)->corrections('operation'))->only($records->pluck('data.stock_operation_id')->filter()->all())->map(fn ($r) => $r->data['reference']), 'items' => $capabilities['prepare'] ? StockItem::query()->orderBy('code')->get(['id', 'code', 'name', 'unit']) : [], 'warehouses' => $capabilities['prepare'] ? Warehouse::query()->orderBy('code')->get(['id', 'code', 'name']) : [], 'receipts' => $receipts, 'lots' => $lots, 'history' => $ready ? SupplyRecord::query()->where('kind', 'stock_event')->whereIn('record_key', $records->pluck('record_key'))->latest('id')->get()->groupBy('record_key') : []])->toResponse($request); $response->headers->set('Cache-Control', 'private, no-store, max-age=0'); return $response; } public function save(Request $request, InventoryDispositions $workflow): RedirectResponse { $actor = $request->user('web'); abort_unless($actor instanceof User, 403); abort_unless(Schema::hasTable('supply_records'), 503, 'Instalação do diário de stock pendente.'); $workflow->save($actor, $request->all()); return back()->with('success', 'Processo de stock registado.'); } }