This commit is contained in:
2026-11-02 08:08:05 +02:00
parent 13a6cb9922
commit 504b01b244
246 changed files with 24499 additions and 185 deletions
@@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers;
use App\Models\GoodsReceipt;
use App\Models\GoodsReceiptItem;
use App\Models\StockOperation;
use App\Models\SupplyRecord;
use App\Models\User;
use App\Services\InventoryDispositions;
use App\Services\InventoryReversals;
use App\Services\SupplyPlanning;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Inertia\Inertia;
use Inertia\Response;
class InventoryReversalController extends Controller
{
public function index(Request $request, InventoryReversals $workflow): Response
{
$actor = $request->user('web');
abort_unless($actor instanceof User, 403);
$capabilities = [];
foreach (['read', 'prepare', 'review', 'execute'] as $capability) {
$capabilities[$capability] = $workflow->allows($actor, $capability);
}
abort_unless(collect($capabilities)->contains(fn (bool $allow) => $allow), 403);
$ready = Schema::hasTable('supply_records');
$records = $ready ? app(SupplyPlanning::class)->latest('stock_reversal')->latest('id')->limit(100)->get() : collect();
$operations = [];
$receipts = [];
if ($ready && $capabilities['prepare']) {
$corrected = $workflow->corrections('operation');
$operations = StockOperation::query()->whereIn('kind', ['issue', 'transfer', 'adjustment', 'supplier_return', 'write_off'])->latest('id')->limit(200)->get()
->reject(fn ($op) => isset($corrected[$op->id]))->map(fn ($op) => ['id' => $op->id, 'label' => $op->reference.' · '.$op->snapshot['stock_item']['name'].' · '.$op->snapshot['warehouse']['name']])->values()->all();
$correctedReceipts = $workflow->corrections('receipt');
foreach (GoodsReceiptItem::query()->whereNotNull('stock_item_id')->where('accepted_milli', '>', 0)->latest('id')->limit(200)->get() as $line) {
if (isset($correctedReceipts[$line->id])) {
continue;
}
$receipt = GoodsReceipt::query()->whereKey($line->goods_receipt_id)->firstOrFail();
$receipts[] = ['id' => $line->id, 'label' => $receipt->number.' · '.$line->snapshot['stock_item']['name'].' · '.$line->snapshot['warehouse']['name']];
}
}
$other = app(InventoryDispositions::class);
return Inertia::render('stock/reversals', ['ready' => $ready, 'actorId' => $actor->id, 'today' => today()->toDateString(), 'capabilities' => $capabilities,
'canViewDispositions' => collect(['read', 'prepare', 'review', 'execute'])->contains(fn ($a) => $other->allows($actor, $a)),
'records' => $records, 'operations' => $operations, 'receipts' => $receipts,
'history' => $ready ? SupplyRecord::query()->where('kind', 'stock_reversal')->whereIn('record_key', $records->pluck('record_key'))->latest('id')->get()->groupBy('record_key') : []]);
}
public function save(Request $request, InventoryReversals $workflow): RedirectResponse
{
$actor = $request->user('web');
abort_unless($actor instanceof User, 403);
abort_unless(Schema::hasTable('supply_records'), 503, 'Instalação do diário pendente.');
$workflow->save($actor, $request->all());
return back()->with('success', 'Estorno registado com a origem preservada.');
}
}