formSharedData(), [ 'values' => $this->stockEntryRepository->listForIndex(), ])); } public function create(Request $request): View|RedirectResponse { if (! auth()->user()->isAdmin()) { return redirect()->route('home'); } $model = new StockEntry([ 'ordered_at' => now()->toDateString(), 'entry_type' => 'ingredient', ]); $ingredientId = (int) $request->query('ingredient_id'); if ($ingredientId > 0) { $ingredient = Ingredient::query()->find($ingredientId); if ($ingredient) { $model->entry_type = 'ingredient'; $model->ingredient_id = $ingredient->id; $model->setRelation('ingredient', $ingredient); } } return view('admin.inventory.stock-entries.create', array_merge($this->formSharedData(), [ 'model' => $model, ])); } public function store(StoreStockEntryRequest $request): RedirectResponse { if (! $request->user()->isAdmin()) { return redirect()->route('home'); } $data = $request->validatedPayload(); $data['ordered_by'] = (int) auth()->id(); $this->stockEntryRepository->create($data); \Session::flash('alert-save', '1'); return redirect()->route('admin.inventory.stock-entries.index'); } public function show(StockEntry $stockEntry): View { $stockEntry->load([ 'ingredient', 'packagingItem.packagingMaterial', 'supplier', 'location', 'quality', 'orderedByUser.account', 'receivedByUser.account', ]); return view('admin.inventory.stock-entries.show', array_merge($this->formSharedData(), [ 'model' => $stockEntry, 'materialQualities' => MaterialQuality::query()->orderBy('pos')->orderBy('name')->get(), ])); } public function edit(StockEntry $stockEntry): View|RedirectResponse { if (! auth()->user()->isAdmin()) { return redirect()->route('home'); } if (! $stockEntry->isPending()) { \Session::flash('alert-error', __('Nur offene Bestellungen können bearbeitet werden.')); return redirect()->route('admin.inventory.stock-entries.show', $stockEntry); } $stockEntry->load(['ingredient', 'packagingItem']); return view('admin.inventory.stock-entries.edit', array_merge($this->formSharedData(), [ 'model' => $stockEntry, ])); } public function update(UpdateStockEntryRequest $request, StockEntry $stockEntry): RedirectResponse { if (! $request->user()->isAdmin()) { return redirect()->route('home'); } if (! $stockEntry->isPending()) { \Session::flash('alert-error', __('Nur offene Bestellungen können bearbeitet werden.')); return redirect()->route('admin.inventory.stock-entries.show', $stockEntry); } $this->stockEntryRepository->update($stockEntry, $request->validatedPayload()); \Session::flash('alert-save', '1'); return redirect()->route('admin.inventory.stock-entries.index'); } public function copy(StockEntry $stockEntry): RedirectResponse { if (! auth()->user()->isAdmin()) { return redirect()->route('home'); } $data = $stockEntry->only([ 'entry_type', 'ingredient_id', 'packaging_item_id', 'supplier_id', 'location_id', 'ordered_quantity', 'price_per_kg', 'price_per_kg_gross', 'price_total', 'tax_rate_id', 'tax_rate_percent', 'quality_id', ]); $data['ordered_at'] = now()->toDateString(); $data['ordered_by'] = (int) auth()->id(); $data['status'] = 'pending'; $copy = $this->stockEntryRepository->create($data); \Session::flash('alert-warning', __('Kopie angelegt – bitte Menge/Charge prüfen und speichern.')); return redirect()->route('admin.inventory.stock-entries.edit', $copy); } public function destroy(StockEntry $stockEntry): RedirectResponse { if (! auth()->user()->isAdmin()) { return redirect()->route('home'); } if (! $stockEntry->isPending()) { \Session::flash('alert-error', __('Nur offene Bestellungen können gelöscht werden.')); return redirect()->route('admin.inventory.stock-entries.index'); } $stockEntry->delete(); \Session::flash('alert-success', __('Eintrag gelöscht')); return redirect()->route('admin.inventory.stock-entries.index'); } public function receive(ReceiveStockEntryRequest $request, StockEntry $stockEntry): RedirectResponse { if (! $stockEntry->isPending()) { \Session::flash('alert-error', __('Eintrag nicht mehr offen.')); return redirect()->route('admin.inventory.stock-entries.show', $stockEntry); } $data = $request->validated(); if ($stockEntry->entry_type !== 'ingredient') { $data['quality_id'] = null; $data['best_before'] = null; } $this->stockEntryRepository->receive($stockEntry, $data); \Session::flash('alert-save', '1'); return redirect()->route('admin.inventory.stock-entries.show', $stockEntry->fresh()); } public function searchIngredients(Request $request): JsonResponse { $term = trim((string) $request->query('q', '')); if (mb_strlen($term) < 1) { return response()->json(['results' => []]); } $rows = Ingredient::query() ->where('active', true) ->where(function ($query) use ($term) { $query->where('name', 'like', '%'.$term.'%') ->orWhere('inci', 'like', '%'.$term.'%'); }) ->orderBy('name') ->limit(30) ->get(['id', 'name', 'inci']); $results = $rows->map(function (Ingredient $i) { $text = $i->name; if ($i->inci) { $text .= ' ('.$i->inci.')'; } return ['id' => $i->id, 'text' => $text]; })->values()->all(); return response()->json(['results' => $results]); } public function searchPackagingItems(Request $request): JsonResponse { $term = trim((string) $request->query('q', '')); $entryType = $request->query('entry_type'); $categoryMap = [ 'packaging' => 'packaging', 'shipping' => 'shipping', ]; $query = PackagingItem::query() ->where('active', true); if ($entryType && isset($categoryMap[$entryType])) { $query->where('category', $categoryMap[$entryType]); } if (mb_strlen($term) >= 1) { $query->where('name', 'like', '%'.$term.'%'); } $rows = $query->orderBy('name')->limit(30)->get(['id', 'name']); $results = $rows->map(fn (PackagingItem $p) => [ 'id' => $p->id, 'text' => $p->name, ])->values()->all(); return response()->json(['results' => $results]); } /** * @return array */ protected function formSharedData(): array { return [ 'suppliers' => Supplier::query()->where('active', true)->orderBy('name')->get(), 'locations' => Location::query()->where('active', true)->orderBy('name')->get(), 'materialQualities' => MaterialQuality::query()->orderBy('pos')->orderBy('name')->get(), 'taxRates' => TaxRate::query()->active()->orderBy('pos')->orderBy('name')->get(), 'entryTypeLabels' => [ 'ingredient' => __('Rohstoff'), 'packaging' => __('Produktverpackung'), 'shipping' => __('Versandverpackung'), ], ]; } }