*/ public array $results = []; public function mount(): void { $this->form->fill(); } public function form(Schema $form): Schema { return $form ->schema([ Select::make('supplier') ->label('Beszállító:') ->options(function (Get $get) { $selectedIds = $this->data['supplier'] ?? []; $query = Supplier::query(); $productQuery = $this->buildProductQuery($get, exclude: 'supplier'); if ($productQuery) { $query->where(function ($q) use ($productQuery, $selectedIds) { $q->whereIn('id', (clone $productQuery)->whereNotNull('supplier_id')->distinct()->pluck('supplier_id')) ->orWhereIn('id', $selectedIds); }); } return $query->orderBy('name')->pluck('name', 'id'); }) ->multiple() ->searchable() ->live() ->placeholder('Válasszon beszállítót...'), Select::make('productGroup') ->label('Termékcsoport:') ->options(function (Get $get) { $selectedIds = $this->data['productGroup'] ?? []; $query = ProductGroup::query(); $productQuery = $this->buildProductQuery($get, exclude: 'productGroup'); if ($productQuery) { $query->where(function ($q) use ($productQuery, $selectedIds) { $q->whereIn('id', (clone $productQuery)->whereNotNull('product_group_id')->distinct()->pluck('product_group_id')) ->orWhereIn('id', $selectedIds); }); } return $query->orderBy('name')->pluck('name', 'id'); }) ->multiple() ->searchable() ->live() ->placeholder('Válasszon termékcsoportot...'), Select::make('product') ->label('Termék:') ->multiple() ->searchable() ->live() ->getSearchResultsUsing(function (string $search, Get $get) { $query = $this->buildProductQuery($get, exclude: 'product') ?? Product::query(); $query->where('name', 'like', "%{$search}%"); return $query->limit(50)->pluck('name', 'name')->toArray(); }) ->getOptionLabelsUsing(fn (array $values): array => Product::whereIn('name', $values) ->pluck('name', 'name') ->toArray()) ->placeholder('Válasszon terméket...'), Select::make('hooreycaName') ->label('Hooreyca megnevezés :') ->options(function (Get $get) { $selected = $this->data['hooreycaName'] ?? []; DB::statement("SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));"); $query = ($this->buildProductQuery($get, exclude: 'hooreycaName') ?? Product::query()) ->where('buyerProductName', '!=', ''); $options = $query->orderBy('buyerProductName') ->groupBy('buyerProductName') ->pluck('buyerProductName', 'buyerProductName') ->toArray(); DB::statement("SET sql_mode=(SELECT CONCAT(@@sql_mode, ',ONLY_FULL_GROUP_BY'));"); foreach ($selected as $name) { if (filled($name) && ! array_key_exists($name, $options)) { $options[$name] = $name; } } return $options; }) ->multiple() ->searchable() ->live() ->placeholder('Válasszon megnevezést...'), Select::make('producer') ->label('Gyártó :') ->options(function (Get $get) { $selectedIds = $this->data['producer'] ?? []; $query = Producer::query(); $productQuery = $this->buildProductQuery($get, exclude: 'producer'); if ($productQuery) { $query->where(function ($q) use ($productQuery, $selectedIds) { $q->whereIn('id', (clone $productQuery)->whereNotNull('producer_id')->distinct()->pluck('producer_id')) ->orWhereIn('id', $selectedIds); }); } return $query->orderBy('name')->pluck('name', 'id'); }) ->multiple() ->searchable() ->live() ->placeholder('Válasszon gyártót...'), ]) ->statePath('data'); } public function submit(): void { $this->data = $this->form->getState(); $this->page = 1; $this->runSearch(); } public function updatedPerPage(): void { $this->page = 1; if ($this->hasSearched) { $this->runSearch(); } } public function goToPage(int $page): void { $this->page = max(1, min($page, $this->lastPage())); $this->runSearch(); } public function lastPage(): int { return max(1, (int) ceil($this->totalResults / $this->perPage)); } public function exportExcel(): BinaryFileResponse { $products = $this->filteredResultsQuery()->orderBy('name')->get(); $rows = $this->mapProductsToRows($products); return Excel::download(new CurrentPriceExport($rows), 'aktualis-ar-'.now()->format('Y-m-d_His').'.xlsx'); } private function runSearch(): void { $query = $this->filteredResultsQuery(); $this->totalResults = (clone $query)->count(); $this->page = min($this->page, $this->lastPage()); $products = $query->orderBy('name') ->skip(($this->page - 1) * $this->perPage) ->take($this->perPage) ->get(); $this->results = $this->mapProductsToRows($products)->toArray(); $this->hasSearched = true; } /** * A szűrő űrlap aktuális állapota alapján felépített, még nem lapozott/rendezett Product query. */ private function filteredResultsQuery(): Builder { $data = $this->data; $query = Product::query()->with(['Supplier', 'Producer']); if (filled($data['supplier'] ?? [])) { $query->whereIn('supplier_id', $data['supplier']); } if (filled($data['productGroup'] ?? [])) { $query->whereIn('product_group_id', $data['productGroup']); } if (filled($data['producer'] ?? [])) { $query->whereIn('producer_id', $data['producer']); } if (filled($data['product'] ?? [])) { $query->whereIn('name', $data['product']); } if (filled($data['hooreycaName'] ?? [])) { $query->whereIn('buyerProductName', $data['hooreycaName']); } return $query; } /** * Termékekhez tartozó aktuális ár és termékcsoport-hierarchia feloldása, és a táblázat/export * soraivá alakítása. Egyetlen extra lekérdezéssel dolgozza fel a kapott terméklistát (nincs N+1). * * @return Collection */ private function mapProductsToRows(Collection $products): Collection { $today = now()->toDateString(); $currentPrices = DB::table('price_list_prices as plp') ->join('price_lists as pl', 'pl.id', '=', 'plp.price_list_id') ->whereIn('plp.product_id', $products->pluck('id')) ->where('pl.available', '<=', $today) ->orderBy('pl.available', 'desc') ->orderBy('pl.id', 'desc') ->get(['plp.product_id', 'plp.price']) ->groupBy('product_id') ->map(fn ($rows) => (float) $rows->first()->price); $groupPaths = $this->getProductGroupPaths($products->pluck('product_group_id')); return $products->map(function (Product $product) use ($currentPrices, $groupPaths) { $path = $groupPaths->get($product->product_group_id, []); return [ 'supplier' => $product->Supplier?->name, 'producer' => $product->Producer?->name, 'mainGroup' => $path[0] ?? '', 'subGroup1' => $path[1] ?? '', 'subGroup2' => $path[2] ?? '', 'name' => $product->name, 'price' => $currentPrices->get($product->id), ]; })->values(); } /** * A termékcsoport-hierarchia első 3 szintje (Termék Főcsoport / alcsoport 1 / alcsoport 2) * termékcsoport id-nként, ugyanaz a logika, mint a legacy Árváltozás statisztikában * (ProductGroup::allWithPath() — a technikai gyökér csomópont nélkül). * * @param \Illuminate\Support\Collection $productGroupIds * @return \Illuminate\Support\Collection> */ private function getProductGroupPaths($productGroupIds): \Illuminate\Support\Collection { $ids = $productGroupIds->filter()->unique()->values(); if ($ids->isEmpty()) { return collect(); } return ProductGroup::whereIn('id', $ids) ->with('ancestors') ->get() ->mapWithKeys(function (ProductGroup $group) { $names = $group->ancestors->pluck('name')->all(); array_shift($names); // technikai gyökér ("Főcsoportok") elhagyása $names[] = $group->name; return [$group->id => $names]; }); } /** * Product query szűrve a szűrő űrlap összes mezőjének aktuális állapota alapján, * a $exclude-ban megadott mező kihagyásával (kölcsönös/kereszt-szűréshez). * Null-t ad vissza, ha egyik mező sincs kitöltve (nincs mit szűrni). */ private function buildProductQuery(Get $get, string $exclude): ?Builder { $supplierIds = $exclude === 'supplier' ? [] : ($get('supplier') ?? []); $productGroupIds = $exclude === 'productGroup' ? [] : ($get('productGroup') ?? []); $producerIds = $exclude === 'producer' ? [] : ($get('producer') ?? []); $productNames = $exclude === 'product' ? [] : ($get('product') ?? []); $hooreycaNames = $exclude === 'hooreycaName' ? [] : ($get('hooreycaName') ?? []); if (blank($supplierIds) && blank($productGroupIds) && blank($producerIds) && blank($productNames) && blank($hooreycaNames)) { return null; } $query = Product::query(); if (filled($supplierIds)) { $query->whereIn('supplier_id', $supplierIds); } if (filled($productGroupIds)) { $query->whereIn('product_group_id', $productGroupIds); } if (filled($producerIds)) { $query->whereIn('producer_id', $producerIds); } if (filled($productNames)) { $query->whereIn('name', $productNames); } if (filled($hooreycaNames)) { $query->whereIn('buyerProductName', $hooreycaNames); } return $query; } }