This commit is contained in:
2026-11-03 11:51:44 +02:00
parent badaada043
commit e753f7a0a4
309 changed files with 14537 additions and 529 deletions
@@ -3,24 +3,24 @@
namespace App\Http\Controllers;
use App\Models\GoodsReceipt;
use App\Models\GoodsReceiptItem;
use App\Models\StockItem;
use App\Models\SupplyRecord;
use App\Models\User;
use App\Models\Warehouse;
use App\Services\InventoryCorrectionPage;
use App\Services\InventoryDispositions;
use App\Services\InventoryLots;
use App\Services\InventoryReversals;
use App\Services\SupplyPlanning;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\Response;
class InventoryDispositionController extends Controller
{
public function index(Request $request, InventoryDispositions $workflow): Response|RedirectResponse
public function index(Request $request, InventoryDispositions $workflow): Response
{
$actor = $request->user('web');
abort_unless($actor instanceof User, 403);
@@ -33,12 +33,25 @@ class InventoryDispositionController extends Controller
return redirect('/stock/estornos');
}
abort_unless(collect($capabilities)->contains(fn (bool $allow) => $allow), 403);
$ready = Schema::hasTable('supply_records');
$records = $ready ? app(SupplyPlanning::class)->latest('stock_event')->latest('id')->limit(100)->get() : collect();
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<string,bool> $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 (GoodsReceiptItem::query()->whereNotNull('stock_item_id')->where('accepted_milli', '>', 0)->latest('id')->limit(200)->get() as $line) {
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']];
@@ -54,13 +67,23 @@ class InventoryDispositionController extends Controller
}
}
return Inertia::render('stock/dispositions', ['ready' => $ready, 'actorId' => $actor->id, 'today' => today()->toDateString(), 'capabilities' => $capabilities, 'records' => $records,
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') : []]);
'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