user('web'); abort_unless($actor instanceof User, 403); abort_unless($actor->hasFunctions([PurchasingRole::Admin, PurchasingRole::Finance]), 403); $filters = $request->validate(['invoice_id' => ['nullable', 'integer', 'min:1', Rule::exists('invoices', 'id')->where('tenant_id', $actor->tenant_id)], 'purchase_order_id' => ['nullable', 'integer', 'min:1', Rule::exists('purchase_orders', 'id')->where('tenant_id', $actor->tenant_id)]]); $focus = isset($filters['invoice_id']) ? (int) $filters['invoice_id'] : null; $focusOrder = isset($filters['purchase_order_id']) ? (int) $filters['purchase_order_id'] : null; Inertia::encryptHistory(); $response = Inertia::render('invoices/index', ['focusInvoiceId' => $focus, 'focusOrderId' => $focusOrder, 'stockReversals' => app(InventoryReversals::class)->financialNotices(), 'stockReturns' => app(InventoryDispositions::class)->financialNotices(), 'invoices' => Invoice::query()->whereIn('purchase_order_id', PurchaseOrder::query()->visibleTo($actor)->select('id'))->when($focus !== null, fn ($q) => $q->whereKey($focus))->when($focusOrder !== null, fn ($q) => $q->where('purchase_order_id', $focusOrder))->with('items')->latest('id')->paginate(15)->withQueryString() ->through(fn (Invoice $invoice) => [...$invoice->toArray(), 'canValidate' => app(InvoiceWorkflow::class)->reviewerEligible($actor, $invoice)]), 'orders' => PurchaseOrder::query()->visibleTo($actor)->operational()->with('items')->latest('id')->get()->map(fn ($order) => ['id' => $order->id, 'number' => $order->number, 'supplier' => $order->snapshot['supplier']['name'], 'items' => $order->items]), 'sgfDispatchAvailable' => config('sgf_invoice.workspace_enabled')===true && $actor->hasFunctions([PurchasingRole::Finance]) && ! app(OrganizationAccess::class)->maintenanceOnly($actor), 'payablesAvailable' => SupplierPayables::enabled() && app(SupplierPayables::class)->can($actor, 'view'), 'canManage' => $actor->hasFunctions([PurchasingRole::Finance]) && ! app(OrganizationAccess::class)->maintenanceOnly($actor)])->toResponse($request); $response->headers->set('Cache-Control', 'private, no-store, max-age=0'); return $response; } public function store(Request $request, PurchaseOrder $order, InvoiceWorkflow $workflow): RedirectResponse { $actor = $request->user('web'); abort_unless($actor instanceof User && $actor->hasFunctions([PurchasingRole::Finance]), 403); $decimal = ['required', 'regex:/^\d{1,12}(\.\d{1,2})?$/']; $data = $request->validate(['number' => 'required|string|max:100', 'issued_on' => 'required|date_format:Y-m-d', 'subtotal' => $decimal, 'tax' => $decimal, 'total' => $decimal, 'items' => 'required|array|min:1|max:50', 'items.*.purchase_order_item_id' => 'required|integer|distinct', 'items.*.quantity' => ['required', 'regex:/^\d{1,9}(\.\d{1,3})?$/'], 'items.*.unit' => 'sometimes|required|string|max:30', 'items.*.unit_price' => ['sometimes', ...$decimal], 'items.*.tax_rate' => ['sometimes', 'required', 'regex:/^\d{1,3}(\.\d{1,2})?$/']]); $workflow->register($actor, $order, $data); return to_route('invoices.index'); } public function validateInvoice(Request $request, Invoice $invoice, InvoiceWorkflow $workflow): RedirectResponse { $actor = $request->user('web'); abort_unless($actor instanceof User, 403); $workflow->validate($actor, $invoice); return back(); } }