Compare commits
16 Commits
4f0f06a7da
...
834f64a011
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
834f64a011 | ||
|
|
4f11e59fce | ||
|
|
e0876e4f25 | ||
|
|
c408e02054 | ||
|
|
bef61a15c5 | ||
|
|
0e3a901ac2 | ||
|
|
bacfbbce88 | ||
|
|
0b1240f972 | ||
|
|
f81f285479 | ||
|
|
898a102517 | ||
|
|
ac3d0de320 | ||
|
|
32240d228a | ||
|
|
940c8ce31a | ||
|
|
f5d04f29b9 | ||
|
|
0ca5eb2255 | ||
|
|
cc6b8af8d8 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -73,3 +73,8 @@ Homestead.yaml
|
||||
/public/images/supplierLogo/*
|
||||
/public/attachments/*
|
||||
/database/csv/*
|
||||
/.gitea/workflows/deploy.yml
|
||||
/.claude/settings.local.json
|
||||
/public/js/
|
||||
/public/css/
|
||||
/public/mix-manifest.json
|
||||
|
||||
229
AGENTS.md
229
AGENTS.md
@ -1,13 +1,46 @@
|
||||
<laravel-boost-guidelines>
|
||||
=== foundation rules ===
|
||||
=== projekt szabályok ===
|
||||
|
||||
# Laravel Boost Guidelines
|
||||
# Hibrid architektúra: Legacy vs. Modern
|
||||
|
||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to ensure the best experience when building Laravel applications.
|
||||
A projekt jelenleg átmeneti fázisban van a régi Laravel 8-as architektúráról a modern Laravel 12-es felépítésre. KRITIKUS fontosságú a két "világ" megkülönböztetése:
|
||||
|
||||
## Foundational Context
|
||||
### 1. Legacy Világ (Csak karbantartás)
|
||||
- **Technológiai stekk**: jQuery, Bootstrap, Laravel Mix (`webpack.mix.js`), DataTables, Mustache.js.
|
||||
- **Belépési pont**: `resources/views/layout/core.blade.php`, `/legacy` útvonalak, és a hagyományos Blade nézeteket használó kontrollerek.
|
||||
- **Assetek**: A `mix()` függvénnyel kezelve. A fájlok a `resources/js/` mappában találhatók (kivéve a `modern` almappát).
|
||||
- **Szabály**: Ezekhez CSAK hibajavítás vagy kisebb módosítás esetén nyúlj. NE implementálj ide új funkciókat, hacsak nincs rá kifejezett kérés.
|
||||
|
||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
||||
### 2. Modern Világ (Elsődleges fejlesztés)
|
||||
- **Technológiai stekk**: Laravel 12, Filament v4 (TALL stekk: Tailwind, Alpine.js, Laravel, Livewire), Vite (`vite.config.js`).
|
||||
- **Belépési pont**: `/admin` (Filament Dashboard), `resources/modern/` mappa.
|
||||
- **Assetek**: A `vite()` függvénnyel kezelve. A stílusokhoz Tailwind CSS v4-et használunk.
|
||||
- **Szabály**: MINDEN új funkciót Filament resource-ok/oldalak vagy modern Livewire komponensek használatával kell megvalósítani.
|
||||
|
||||
### 3. Átállás és Modernizáció
|
||||
- **"Clean Cut" megközelítés**: Szisztematikusan váltjuk ki a régi jQuery megoldásokat modern Laravel 12-es megfelelőkre.
|
||||
- **Auditálás**: Használd a `BaseAuditable` osztályt minden új modellnél a konzisztens követhetőség érdekében.
|
||||
- **Refaktorálás**: Ha egy legacy kontroller/nézet jelentős átalakítást igényel, javasold annak áthelyezését egy Filament Resource-ba.
|
||||
|
||||
# Projekt-specifikus szabályok
|
||||
|
||||
- **API válaszok**: Használd a `flugger/laravel-responder` csomagot (`responder()` helper) minden API válaszhoz. Kövesd az `OrderController.php`-ban látható mintát.
|
||||
- **API verziózás**: Az API verziókat a névterekből kell kinyerni a `parseAPIVersionFromNamespace(__NAMESPACE__)` helper segítségével.
|
||||
- **Dokumentáció**: Használd a Scribe-ot az API dokumentációhoz. Használj `@group`, `@authenticated`, `@bodyParam`, és `@responseField` annotációkat a kontrollerekben.
|
||||
- **Modellek**: Az új modelleknek jellemzően a `BaseAuditable` osztályból kell származniuk a sima Eloquent `Model` helyett, ha auditálás szükséges.
|
||||
- **Helperek**: Használd az `app/helpers.php` fájlban definiált projekt-specifikus helpereket (pl. `formatterPhoneNumber`, `formatterDateTime`, `getSql`).
|
||||
- **Fordítások**: Használd a `laravel-lang/lang` csomagot a többnyelvű támogatáshoz.
|
||||
- **Enumok**: Használd a `bensampo/laravel-enum` csomagot a típusbiztos felsorolásokhoz (pl. `OrderStatusEnum`, `OrderType`).
|
||||
|
||||
=== alapvető szabályok ===
|
||||
|
||||
# Laravel Boost Irányelvek
|
||||
|
||||
A Laravel Boost irányelveket kifejezetten a Laravel karbantartói állították össze ehhez az alkalmazáshoz. Ezeket az irányelveket szigorúan be kell tartani a legjobb Laravel fejlesztési élmény biztosítása érdekében.
|
||||
|
||||
## Alapvető kontextus
|
||||
|
||||
Ez egy Laravel alkalmazás, a fő ökoszisztéma csomagok és verziók alább láthatók. Te ezeknek a szakértője vagy. Gondoskodj róla, hogy tartsd magad ezekhez a specifikus csomagokhoz és verziókhoz.
|
||||
|
||||
- php - 8.4
|
||||
- filament/filament (FILAMENT) - v4
|
||||
@ -23,162 +56,162 @@ ## Foundational Context
|
||||
- phpunit/phpunit (PHPUNIT) - v11
|
||||
- tailwindcss (TAILWINDCSS) - v4
|
||||
|
||||
## Skills Activation
|
||||
## Képességek aktiválása
|
||||
|
||||
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
|
||||
Ez a projekt tartomány-specifikus képességekkel rendelkezik. Kötelező aktiválnod a releváns képességet, amikor abban a tartományban dolgozol — ne várd meg, amíg elakadsz.
|
||||
|
||||
- `laravel-best-practices` — Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code. This includes creating or modifying controllers, models, migrations, form requests, policies, jobs, scheduled commands, service classes, and Eloquent queries. Triggers for N+1 and query performance issues, caching strategies, authorization and security patterns, validation, error handling, queue and job configuration, route definitions, and architectural decisions. Also use for Laravel code reviews and refactoring existing Laravel code to follow best practices. Covers any task involving Laravel backend PHP code patterns.
|
||||
- `livewire-development` — Use for any task or question involving Livewire. Activate if user mentions Livewire, wire: directives, or Livewire-specific concepts like wire:model, wire:click, invoke this skill. Covers building new components, debugging reactivity issues, real-time form validation, loading states, migrating from Livewire 2 to 3, converting component formats (SFC/MFC/class-based), and performance optimization. Do not use for non-Livewire reactive UI (React, Vue, Alpine-only, Inertia.js) or standard Laravel forms without Livewire.
|
||||
- `pest-testing` — Use this skill for Pest PHP testing in Laravel projects only. Trigger whenever any test is being written, edited, fixed, or refactored — including fixing tests that broke after a code change, adding assertions, converting PHPUnit to Pest, adding datasets, and TDD workflows. Always activate when the user asks how to write something in Pest, mentions test files or directories (tests/Feature, tests/Unit) or architecture tests. Covers: it()/expect() syntax, datasets, mocking, browser testing, arch(), Livewire component tests, RefreshDatabase, and all Pest 4 features. Do not use for editing factories, seeders, migrations, controllers, models, or non-test PHP code.
|
||||
- `tailwindcss-development` — Always invoke when the user's message includes 'tailwind' in any form. Also invoke for: building responsive grid layouts (multi-column card grids, product grids), flex/grid page structures (dashboards with sidebars, fixed topbars, mobile-toggle navs), styling UI components (cards, tables, navbars, pricing sections, forms, inputs, badges), adding dark mode variants, fixing spacing or typography, and Tailwind v3/v4 work. The core use case: writing or fixing Tailwind utility classes in HTML templates (Blade, JSX, Vue). Skip for backend PHP logic, database queries, API routes, JavaScript with no HTML/CSS component, CSS file audits, build tool configuration, and vanilla CSS.
|
||||
- `laravel-best-practices` — Használd ezt a képességet Laravel PHP kód írásakor, átnézésekor vagy refaktorálásakor. Ez magában foglalja kontrollerek, modellek, migrációk, form requestek, policy-k, jobok, ütemezett parancsok, service osztályok és Eloquent lekérdezések készítését vagy módosítását. Aktiváld N+1 és lekérdezési teljesítményproblémák, gyorsítótárazási stratégiák, autorizációs és biztonsági minták, validáció, hibakezelés, sor- és job konfiguráció, útvonal definíciók és architektúrális döntések esetén. Használd továbbá Laravel kód áttekintéséhez és meglévő kódok refaktorálásához a legjobb gyakorlatok szerint. Minden Laravel háttér PHP kódmintát érintő feladathoz.
|
||||
- `livewire-development` — Használd minden olyan feladathoz vagy kérdéshez, amely a Livewire-t érinti. Aktiváld, ha a felhasználó említi a Livewire-t, a wire: direktívákat, vagy Livewire-specifikus koncepciókat, mint a wire:model, wire:click. Lefedi az új komponensek építését, reaktivitási hibák keresését, valós idejű form validációt, betöltési állapotokat, a Livewire 2-ről 3-ra való migrációt, komponens formátumok konvertálását és teljesítményoptimalizálást. Ne használd nem-Livewire reaktív UI-hoz (React, Vue, csak Alpine, Inertia.js) vagy standard Laravel formokhoz Livewire nélkül.
|
||||
- `pest-testing` — Ezt a képességet kizárólag Pest PHP teszteléshez használd Laravel projektekben. Aktiváld, amikor tesztet írsz, szerkesztesz, javítasz vagy refaktorálsz — beleértve a kódmódosítás után eltört tesztek javítását, asszerciók hozzáadását, PHPUnit tesztek Pest-re konvertálását, datasetek hozzáadását és TDD munkafolyamatokat. Mindig aktiváld, ha a felhasználó Pest-ben való írásról kérdez, teszt fájlokat vagy könyvtárakat említ (tests/Feature, tests/Unit), vagy architektúra teszteket. Lefedi az it()/expect() szintaxist, dataseteket, mockolást, böngésző tesztelést, arch()-ot, Livewire komponens teszteket, RefreshDatabase-t és minden Pest 4 funkciót. Ne használd factory-k, seeder-ek, migrációk, kontrollerek, modellek vagy nem teszt jellegű PHP kódok szerkesztéséhez.
|
||||
- `tailwindcss-development` — Mindig aktiváld, ha a felhasználó üzenete bármilyen formában tartalmazza a 'tailwind' szót. Továbbá használd: responzív rács elrendezések (többoszlopos kártya rácsok, termék rácsok), flex/grid oldalstruktúrák (oldalsávos dashboardok, fix fejlécek, mobil-navigáció), UI komponensek stílusozása (kártyák, táblázatok, navigációs sávok, árazási szakaszok, formok, inputok, jelvények), sötét mód variánsok hozzáadása, térköz vagy tipográfia javítása, valamint Tailwind v3/v4 munkák esetén. Fő felhasználási eset: Tailwind utility osztályok írása vagy javítása HTML sablonokban (Blade, JSX, Vue). Hagyd ki háttér PHP logika, adatbázis lekérdezések, API útvonalak, HTML/CSS komponens nélküli JavaScript, CSS fájl auditok, build eszköz konfiguráció és vanilla CSS esetén.
|
||||
|
||||
## Conventions
|
||||
## Konvenciók
|
||||
|
||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming.
|
||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
||||
- Check for existing components to reuse before writing a new one.
|
||||
- Követned kell az alkalmazásban használt összes meglévő kódkonvenciót. Fájl létrehozásakor vagy szerkesztésekor ellenőrizd a szomszédos fájlokat a helyes struktúra, megközelítés és elnevezés érdekében.
|
||||
- Használj leíró neveket a változókhoz és metódusokhoz. Például: `isRegisteredForDiscounts`, nem pedig `discount()`.
|
||||
- Új komponens írása előtt ellenőrizd a meglévő komponenseket az újrahasznosíthatóság érdekében.
|
||||
|
||||
## Verification Scripts
|
||||
## Ellenőrző szkriptek
|
||||
|
||||
- Do not create verification scripts or tinker when tests cover that functionality and prove they work. Unit and feature tests are more important.
|
||||
- Ne készíts ellenőrző szkripteket vagy kísérletezz, ha a tesztek lefedik az adott funkciót és bizonyítják a működését. Az egység- és funkcionális tesztek fontosabbak.
|
||||
|
||||
## Application Structure & Architecture
|
||||
## Alkalmazás struktúra és architektúra
|
||||
|
||||
- Stick to existing directory structure; don't create new base folders without approval.
|
||||
- Do not change the application's dependencies without approval.
|
||||
- Tartsd magad a meglévő könyvtárstruktúrához; ne hozz létre új alapkatalógusokat jóváhagyás nélkül.
|
||||
- Ne változtasd meg az alkalmazás függőségeit jóváhagyás nélkül.
|
||||
|
||||
## Frontend Bundling
|
||||
## Frontend csomagolás
|
||||
|
||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
||||
- Ha a felhasználó nem látja a frontend változást a felületen, az jelentheti azt, hogy futtatnia kell az `npm run build`, `npm run dev` vagy `composer run dev` parancsot. Kérdezz rá.
|
||||
|
||||
## Documentation Files
|
||||
## Dokumentációs fájlok
|
||||
|
||||
- You must only create documentation files if explicitly requested by the user.
|
||||
- Dokumentációs fájlokat csak akkor hozz létre, ha a felhasználó kifejezetten kéri.
|
||||
|
||||
## Replies
|
||||
## Válaszok
|
||||
|
||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
||||
- Légy tömör a magyarázatokban - fókuszálj a fontos dolgokra, ahelyett, hogy nyilvánvaló részleteket magyaráznál.
|
||||
|
||||
=== boost rules ===
|
||||
=== boost szabályok ===
|
||||
|
||||
# Laravel Boost
|
||||
|
||||
## Tools
|
||||
## Eszközök
|
||||
|
||||
- Laravel Boost is an MCP server with tools designed specifically for this application. Prefer Boost tools over manual alternatives like shell commands or file reads.
|
||||
- Use `database-query` to run read-only queries against the database instead of writing raw SQL in tinker.
|
||||
- Use `database-schema` to inspect table structure before writing migrations or models.
|
||||
- Use `get-absolute-url` to resolve the correct scheme, domain, and port for project URLs. Always use this before sharing a URL with the user.
|
||||
- Use `browser-logs` to read browser logs, errors, and exceptions. Only recent logs are useful, ignore old entries.
|
||||
- A Laravel Boost egy kifejezetten ehhez az alkalmazáshoz tervezett eszközökkel rendelkező MCP szerver. Preferáld a Boost eszközöket a manuális alternatívákkal szemben, mint a shell parancsok vagy fájlbeolvasások.
|
||||
- Használd a `database-query` eszközt csak olvasható lekérdezések futtatásához az adatbázison, ahelyett, hogy nyers SQL-t írnál a tinkerbe.
|
||||
- Használd a `database-schema` eszközt a táblák szerkezetének vizsgálatához migrációk vagy modellek írása előtt.
|
||||
- Használd a `get-absolute-url` eszközt a projekt URL-jeinek helyes sémájának, domainjének és portjának feloldásához. Mindig használd ezt, mielőtt URL-t osztanál meg a felhasználóval.
|
||||
- Használd a `browser-logs` eszközt a böngésző naplók, hibák és kivételek beolvasásához. Csak a friss naplók hasznosak, hagyd figyelmen kívül a régi bejegyzéseket.
|
||||
|
||||
## Searching Documentation (IMPORTANT)
|
||||
## Dokumentáció keresése (FONTOS)
|
||||
|
||||
- Always use `search-docs` before making code changes. Do not skip this step. It returns version-specific docs based on installed packages automatically.
|
||||
- Pass a `packages` array to scope results when you know which packages are relevant.
|
||||
- Use multiple broad, topic-based queries: `['rate limiting', 'routing rate limiting', 'routing']`. Expect the most relevant results first.
|
||||
- Do not add package names to queries because package info is already shared. Use `test resource table`, not `filament 4 test resource table`.
|
||||
- Kódmódosítás előtt mindig használd a `search-docs` eszközt. Ne hagyd ki ezt a lépést. Ez automatikusan a telepített csomagok alapján ad verzióspecifikus dokumentációt.
|
||||
- Adj át egy `packages` tömböt az eredmények szűkítéséhez, ha tudod, mely csomagok relevánsak.
|
||||
- Használj több széles, téma alapú keresést: `['rate limiting', 'routing rate limiting', 'routing']`. Számíts rá, hogy a legrelevánsabb eredmények lesznek elöl.
|
||||
- Ne adj csomagneveket a kereséshez, mert a csomaginformáció már meg van osztva. Használd a `test resource table` kifejezést, ne a `filament 4 test resource table`-t.
|
||||
|
||||
### Search Syntax
|
||||
### Keresési szintaxis
|
||||
|
||||
1. Use words for auto-stemmed AND logic: `rate limit` matches both "rate" AND "limit".
|
||||
2. Use `"quoted phrases"` for exact position matching: `"infinite scroll"` requires adjacent words in order.
|
||||
3. Combine words and phrases for mixed queries: `middleware "rate limit"`.
|
||||
4. Use multiple queries for OR logic: `queries=["authentication", "middleware"]`.
|
||||
1. Használj szavakat az automatikusan csonkolt ÉS logikához: a `rate limit` találatot ad a "rate" ÉS "limit" szavakra is.
|
||||
2. Használj `"idézőjeles kifejezéseket"` a pontos pozícióillesztéshez: az `"infinite scroll"` megköveteli az egymás melletti szavakat a megadott sorrendben.
|
||||
3. Kombináld a szavakat és kifejezéseket a vegyes kereséshez: `middleware "rate limit"`.
|
||||
4. Használj több keresést a VAGY logikához: `queries=["authentication", "middleware"]`.
|
||||
|
||||
## Artisan
|
||||
|
||||
- Run Artisan commands directly via the command line (e.g., `php artisan route:list`). Use `php artisan list` to discover available commands and `php artisan [command] --help` to check parameters.
|
||||
- Inspect routes with `php artisan route:list`. Filter with: `--method=GET`, `--name=users`, `--path=api`, `--except-vendor`, `--only-vendor`.
|
||||
- Read configuration values using dot notation: `php artisan config:show app.name`, `php artisan config:show database.default`. Or read config files directly from the `config/` directory.
|
||||
- To check environment variables, read the `.env` file directly.
|
||||
- Futtasd az Artisan parancsokat közvetlenül a parancssorból (pl. `php artisan route:list`). Használd a `php artisan list` parancsot az elérhető parancsok felfedezéséhez, és a `php artisan [command] --help` parancsot a paraméterek ellenőrzéséhez.
|
||||
- Vizsgáld meg az útvonalakat a `php artisan route:list` paranccsal. Szűrj: `--method=GET`, `--name=users`, `--path=api`, `--except-vendor`, `--only-vendor`.
|
||||
- Olvass be konfigurációs értékeket pont jelöléssel: `php artisan config:show app.name`, `php artisan config:show database.default`. Vagy olvasd a konfigurációs fájlokat közvetlenül a `config/` könyvtárból.
|
||||
- A környezeti változók ellenőrzéséhez olvasd közvetlenül a `.env` fájlt.
|
||||
|
||||
## Tinker
|
||||
|
||||
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
|
||||
- Always use single quotes to prevent shell expansion: `php artisan tinker --execute 'Your::code();'`
|
||||
- Double quotes for PHP strings inside: `php artisan tinker --execute 'User::where("active", true)->count();'`
|
||||
- Futtass PHP kódot az alkalmazás környezetében hibakereséshez és teszteléshez. Ne hozz létre modelleket felhasználói jóváhagyás nélkül, preferáld a factory-kkal ellátott teszteket. Preferáld a meglévő Artisan parancsokat az egyedi tinker kódok helyett.
|
||||
- Mindig használj szimpla idézőjeleket a shell kifejtés megakadályozására: `php artisan tinker --execute 'Your::code();'`
|
||||
- Használj dupla idézőjelet a PHP stringekhez belül: `php artisan tinker --execute 'User::where("active", true)->count();'`
|
||||
|
||||
=== php rules ===
|
||||
=== php szabályok ===
|
||||
|
||||
# PHP
|
||||
|
||||
- Always use curly braces for control structures, even for single-line bodies.
|
||||
- Use PHP 8 constructor property promotion: `public function __construct(public GitHub $github) { }`. Do not leave empty zero-parameter `__construct()` methods unless the constructor is private.
|
||||
- Use explicit return type declarations and type hints for all method parameters: `function isAccessible(User $user, ?string $path = null): bool`
|
||||
- Use TitleCase for Enum keys: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
- Prefer PHPDoc blocks over inline comments. Only add inline comments for exceptionally complex logic.
|
||||
- Use array shape type definitions in PHPDoc blocks.
|
||||
- Mindig használj kapcsos zárójeleket a vezérlési szerkezeteknél, még az egysoros törzseknél is.
|
||||
- Használd a PHP 8 konstruktor property promotion-t: `public function __construct(public GitHub $github) { }`. Ne hagyj üres, nulla paraméteres `__construct()` metódusokat, hacsak a konstruktor nem privát.
|
||||
- Használj explicit visszatérési típus deklarációkat és típusjelzéseket minden metódus paraméternél: `function isAccessible(User $user, ?string $path = null): bool`
|
||||
- Használj TitleCase-t az Enum kulcsokhoz: `FavoritePerson`, `BestLake`, `Monthly`.
|
||||
- Preferáld a PHPDoc blokkokat az inline kommentekkel szemben. Csak kivételesen összetett logika esetén adj hozzá inline kommenteket.
|
||||
- Használj array shape típusdefiníciókat a PHPDoc blokkokban.
|
||||
|
||||
=== laravel/core rules ===
|
||||
=== laravel/core szabályok ===
|
||||
|
||||
# Do Things the Laravel Way
|
||||
# Csináld a Laravel Útján
|
||||
|
||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using `php artisan list` and check their parameters with `php artisan [command] --help`.
|
||||
- If you're creating a generic PHP class, use `php artisan make:class`.
|
||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
||||
- Használd a `php artisan make:` parancsokat új fájlok (pl. migrációk, kontrollerek, modellek stb.) létrehozásához. Az elérhető Artisan parancsokat a `php artisan list` paranccsal listázhatod, és a paramétereiket a `php artisan [command] --help` paranccsal ellenőrizheted.
|
||||
- Ha generikus PHP osztályt hozol létre, használd a `php artisan make:class` parancsot.
|
||||
- Minden Artisan parancsnak add át a `--no-interaction` jelzőt a felhasználói beavatkozás nélküli működés érdekében. A helyes működéshez a megfelelő `--options` opciókat is meg kell adnod.
|
||||
|
||||
### Model Creation
|
||||
### Modell létrehozás
|
||||
|
||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `php artisan make:model --help` to check the available options.
|
||||
- Új modellek létrehozásakor készíts hozzájuk hasznos factory-kat és seedereket is. Kérdezz rá a felhasználónál, ha másra is szükség van, a `php artisan make:model --help` segítségével ellenőrizve az elérhető opciókat.
|
||||
|
||||
## APIs & Eloquent Resources
|
||||
## API-k és Eloquent Resource-ok
|
||||
|
||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
||||
- API-k esetén alapértelmezés szerint használj Eloquent API Resource-okat és API verziózást, hacsak a meglévő API útvonalak nem másképp teszik, ekkor kövesd a meglévő alkalmazáskonvenciót.
|
||||
|
||||
## URL Generation
|
||||
## URL generálás
|
||||
|
||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
||||
- Más oldalakra mutató linkek generálásakor preferáld a nevesített útvonalakat és a `route()` függvényt.
|
||||
|
||||
## Testing
|
||||
## Tesztelés
|
||||
|
||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
||||
- When creating tests, make use of `php artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
||||
- Modellek létrehozásakor a tesztekhez használd a modellek factory-jait. Ellenőrizd, hogy a factory rendelkezik-e egyedi állapotokkal (states), amelyeket használni lehet, mielőtt manuálisan állítanád be a modellt.
|
||||
- Faker: Használj olyan metódusokat, mint a `$this->faker->word()` vagy a `fake()->randomDigit()`. Kövesd a meglévő konvenciókat, hogy a `$this->faker`-t vagy a `fake()`-et használd.
|
||||
- Tesztek létrehozásakor használd a `php artisan make:test [opciók] {név}` parancsot funkcionális teszt létrehozásához, és add át a `--unit` jelzőt egységteszt készítéséhez. A legtöbb tesztnek funkcionális tesztnek kell lennie.
|
||||
|
||||
## Vite Error
|
||||
## Vite hiba
|
||||
|
||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
||||
- Ha "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" hibát kapsz, futtathatod az `npm run build` parancsot, vagy kérd meg a felhasználót, hogy futtassa az `npm run dev` vagy a `composer run dev` parancsot.
|
||||
|
||||
=== laravel/v12 rules ===
|
||||
=== laravel/v12 szabályok ===
|
||||
|
||||
# Laravel 12
|
||||
|
||||
- CRITICAL: ALWAYS use `search-docs` tool for version-specific Laravel documentation and updated code examples.
|
||||
- This project upgraded from Laravel 10 without migrating to the new streamlined Laravel file structure.
|
||||
- This is perfectly fine and recommended by Laravel. Follow the existing structure from Laravel 10. We do not need to migrate to the new Laravel structure unless the user explicitly requests it.
|
||||
- KRITIKUS: MINDIG használd a `search-docs` eszközt a verzióspecifikus Laravel dokumentációhoz és frissített kódpéldákhoz.
|
||||
- Ez a projekt a Laravel 10-ről lett frissítve az új, áramvonalasított Laravel fájlstruktúrára való áttérés nélkül.
|
||||
- Ez teljesen rendben van és a Laravel által ajánlott. Kövesd a Laravel 10-ből származó meglévő struktúrát. Nem kell áttérnünk az új Laravel struktúrára, hacsak a felhasználó kifejezetten nem kéri.
|
||||
|
||||
## Laravel 10 Structure
|
||||
## Laravel 10 struktúra
|
||||
|
||||
- Middleware typically lives in `app\Http/Middleware/` and service providers in `app\Providers/`.
|
||||
- There is no `bootstrap/app.php` application configuration in a Laravel 10 structure:
|
||||
- Middleware registration happens in `app\Http/Kernel.php`
|
||||
- Exception handling is in `app\Exceptions/Handler.php`
|
||||
- Console commands and schedule register in `app\Console/Kernel.php`
|
||||
- Rate limits likely exist in `RouteServiceProvider` or `app\Http/Kernel.php`
|
||||
- A middleware-ek jellemzően az `app\Http/Middleware/` mappában, a service providerek pedig az `app\Providers/` mappában találhatók.
|
||||
- Nincs `bootstrap/app.php` alkalmazáskonfiguráció a Laravel 10 struktúrában:
|
||||
- A middleware regisztráció az `app\Http/Kernel.php` fájlban történik.
|
||||
- A kivételkezelés az `app\Exceptions/Handler.php` fájlban található.
|
||||
- A konzol parancsok és az ütemezés az `app\Console/Kernel.php` fájlban vannak regisztrálva.
|
||||
- A sebességkorlátok (rate limits) valószínűleg a `RouteServiceProvider`-ben vagy az `app\Http/Kernel.php`-ban találhatók.
|
||||
|
||||
## Database
|
||||
## Adatbázis
|
||||
|
||||
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
|
||||
- Laravel 12 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
|
||||
- Oszlop módosításakor a migrációnak tartalmaznia kell az oszlophoz korábban definiált összes attribútumot. Ellenkező esetben azok elvesznek.
|
||||
- A Laravel 12 natívan lehetővé teszi az eager loaded rekordok korlátozását külső csomagok nélkül: `$query->latest()->limit(10);`.
|
||||
|
||||
### Models
|
||||
### Modellek
|
||||
|
||||
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
|
||||
- A castok beállíthatók és célszerű is beállítani a modell `casts()` metódusában a `$casts` tulajdonság helyett. Kövesd a többi modell meglévő konvencióit.
|
||||
|
||||
=== livewire/core rules ===
|
||||
=== livewire/core szabályok ===
|
||||
|
||||
# Livewire
|
||||
|
||||
- Livewire allow to build dynamic, reactive interfaces in PHP without writing JavaScript.
|
||||
- You can use Alpine.js for client-side interactions instead of JavaScript frameworks.
|
||||
- Keep state server-side so the UI reflects it. Validate and authorize in actions as you would in HTTP requests.
|
||||
- A Livewire lehetővé teszi dinamikus, reaktív felületek építését PHP-ben, JavaScript írása nélkül.
|
||||
- Az Alpine.js-t használhatod kliensoldali interakciókhoz JavaScript keretrendszerek helyett.
|
||||
- Tartsd az állapotot a szerver oldalon, hogy a UI azt tükrözze. Validálj és autorizálj az action-ökben, ahogy a HTTP kéréseknél tennéd.
|
||||
|
||||
=== pest/core rules ===
|
||||
=== pest/core szabályok ===
|
||||
|
||||
## Pest
|
||||
|
||||
- This project uses Pest for testing. Create tests: `php artisan make:test --pest {name}`.
|
||||
- Run tests: `php artisan test --compact` or filter: `php artisan test --compact --filter=testName`.
|
||||
- Do NOT delete tests without approval.
|
||||
- Ez a projekt a Pest-et használja teszteléshez. Hozz létre teszteket: `php artisan make:test --pest {név}`.
|
||||
- Futtasd a teszteket: `php artisan test --compact` vagy szűrj: `php artisan test --compact --filter=tesztNeve`.
|
||||
- NE törölj teszteket jóváhagyás nélkül.
|
||||
|
||||
</laravel-boost-guidelines>
|
||||
|
||||
48
app/Exports/CurrentPriceExport.php
Normal file
48
app/Exports/CurrentPriceExport.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
|
||||
class CurrentPriceExport implements FromCollection, ShouldAutoSize, WithHeadings, WithMapping
|
||||
{
|
||||
/**
|
||||
* @param Collection<int, array{supplier: ?string, producer: ?string, mainGroup: string, subGroup1: string, subGroup2: string, name: string, price: ?float}> $rows
|
||||
*/
|
||||
public function __construct(private Collection $rows) {}
|
||||
|
||||
public function collection(): Collection
|
||||
{
|
||||
return $this->rows;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Beszállító',
|
||||
'Gyártó',
|
||||
'Termék Főcsoport',
|
||||
'Termék alcsoport 1',
|
||||
'Termék alcsoport 2',
|
||||
'Termék megnevezése',
|
||||
'Aktuális ár',
|
||||
];
|
||||
}
|
||||
|
||||
public function map($row): array
|
||||
{
|
||||
return [
|
||||
$row['supplier'] ?? '',
|
||||
$row['producer'] ?? '',
|
||||
$row['mainGroup'] ?? '',
|
||||
$row['subGroup1'] ?? '',
|
||||
$row['subGroup2'] ?? '',
|
||||
$row['name'],
|
||||
$row['price'],
|
||||
];
|
||||
}
|
||||
}
|
||||
366
app/Filament/Pages/CurrentPrice.php
Normal file
366
app/Filament/Pages/CurrentPrice.php
Normal file
@ -0,0 +1,366 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use App\Exports\CurrentPriceExport;
|
||||
use App\Models\Producer;
|
||||
use App\Models\Product;
|
||||
use App\Models\ProductGroup;
|
||||
use App\Models\Supplier;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Pages\Page;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class CurrentPrice extends Page implements HasForms
|
||||
{
|
||||
use InteractsWithForms;
|
||||
|
||||
/** @var int[] */
|
||||
public const PER_PAGE_OPTIONS = [10, 25, 50, 100];
|
||||
|
||||
protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-currency-dollar';
|
||||
|
||||
protected static ?string $title = 'Aktuális ár';
|
||||
|
||||
protected static ?string $navigationLabel = 'Aktuális ár';
|
||||
|
||||
protected static string | \UnitEnum | null $navigationGroup = 'Statisztika';
|
||||
|
||||
public function getHeading(): string|\Illuminate\Contracts\Support\Htmlable
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getBreadcrumbs(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected string $view = 'filament.pages.current-price';
|
||||
|
||||
public ?array $data = [];
|
||||
|
||||
public bool $hasSearched = false;
|
||||
|
||||
public int $perPage = 10;
|
||||
|
||||
public int $page = 1;
|
||||
|
||||
public int $totalResults = 0;
|
||||
|
||||
/** @var array<int, array{supplier: ?string, producer: ?string, mainGroup: string, subGroup1: string, subGroup2: string, name: string, price: ?float}> */
|
||||
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<int, array{supplier: ?string, producer: ?string, mainGroup: string, subGroup1: string, subGroup2: string, name: string, price: ?float}>
|
||||
*/
|
||||
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<int, int|null> $productGroupIds
|
||||
* @return \Illuminate\Support\Collection<int, array<int, string>>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\admin;
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ProductGroup;
|
||||
|
||||
@ -269,7 +269,7 @@ protected function productValidationRules(): array
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'supplierId' => 'required|integer|exists:suppliers,id',
|
||||
'producer' => 'required|exists:producers,id',
|
||||
'producer' => 'nullable|exists:producers,id',
|
||||
'packaging' => 'required|numeric|min:0',
|
||||
'unitValue' => 'required|numeric|min:0',
|
||||
'productUnit' => 'required|string|in:'.implode(',', BasicUnitEnum::getValues()),
|
||||
@ -297,7 +297,7 @@ protected function productValidationRules(): array
|
||||
*/
|
||||
protected function transformValidated(array $validated): array
|
||||
{
|
||||
$validated['producer_id'] = $validated['producer'][0];
|
||||
$validated['producer_id'] = isset($validated['producer']) ? $validated['producer'][0] : null;
|
||||
$validated['product_group_id'] = $validated['productGroup'][0];
|
||||
$validated['supplier_id'] = $validated['supplierId'];
|
||||
$validated['packing'] = $validated['packaging'];
|
||||
|
||||
@ -113,8 +113,13 @@ public function index(): View|Response|JsonResponse
|
||||
$testOrderId = 12140; // napi
|
||||
$testOrderId = 16506; // napi
|
||||
$testOrderId = 16571; // napi
|
||||
$testOrderId = 16571; // napi
|
||||
$testOrderId = 307975; // napi
|
||||
}
|
||||
|
||||
/******** create Pdf from oder ***********/
|
||||
return $this->testPdfCreate($testOrderId);
|
||||
|
||||
/******** create Excel ***********/
|
||||
return $this->testExcelCreate($testOrderId);
|
||||
|
||||
@ -1889,6 +1894,9 @@ public function getDataTableContent(): JsonResponse
|
||||
} else {
|
||||
if (\request()->get('groupId')) {
|
||||
$groupId = \request()->get('groupId');
|
||||
if ($groupId === 'all') {
|
||||
$groupId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -153,14 +153,12 @@ public function unProcessed(Request $request,Responder $responder)
|
||||
//->whereNulll('APIConfirmed')
|
||||
->whereNotNull('confirmed')
|
||||
->whereNull('APIConfirmed')
|
||||
->whereHas('profitCenter', function ($query) {
|
||||
$query->where('hooreycaDataActive', 1);
|
||||
})
|
||||
->orderBy('id','desc')->paginate(3)
|
||||
;
|
||||
|
||||
$filteredProfitCentersOrder=$OrderCollection->filter(function ($v) {
|
||||
return $v->profitCenter!=null;
|
||||
});
|
||||
$OrderCollection->setCollection($filteredProfitCentersOrder);
|
||||
|
||||
/* where condition not working on paginated eloquent collection
|
||||
dd($OrderCollection->toArray());
|
||||
$OrderCollection=$OrderCollection->whereNotNull('profit_center');
|
||||
|
||||
27041
public/css/app.css
27041
public/css/app.css
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,8 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [
|
||||
"bootstrap-toaster.css"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "AASA,aACI,UAAW,OAGf,OAEI,MAAO,MAGX,gBAKI,qBAAsB,QACtB,mBAAoB,QACpB,wBAAyB,sBACzB,sBAAuB,sBACvB,oBAAqB,QACrB,kBAAmB,QACnB,uBAAwB,mBACxB,qBAAsB,mBACtB,WAAY,MACZ,WAAY,OAEZ,gBAAiB,KAEjB,QAAS,KAIb,mCACI,QAAS,KAGb,uBACI,OAAQ,MAIZ,yCACI,gBACI,MAAO,KACP,IAAK,YACL,OAAQ,eACR,KAAM,YACN,UAAW,eAGf,uBACI,OAAQ,MAAO,MAIvB,mCACI,OAAQ,cAAe,qBACnB,MAAO,uBAGX,OACI,iBAAkB,0BAGtB,cACI,iBAAkB,6BAM1B,OACE,IAAK,YAGP,QACE,IAAK,cAGP,UACE,OAAQ,YAGV,QACE,KAAM,YAGR,SACE,KAAM,cAGR,SACE,MAAO,YAGT,kBACE,UAAW,+BAGb,oBACE,UAAW,2BAGb,oBACE,UAAW"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -1,59 +0,0 @@
|
||||
table.invoice{
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
table.invoice th td{
|
||||
font-weight: normal;
|
||||
}
|
||||
table.invoice td{
|
||||
padding-left: 5px;
|
||||
}
|
||||
table.invoice, table.invoice table.invoiceHeadTable {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0px;
|
||||
}
|
||||
table.invoice td,th{
|
||||
border: 1px solid;
|
||||
}
|
||||
table.invoiceHeadTable{
|
||||
border: none;
|
||||
}
|
||||
table.invoice tr.ProductHeadRow{
|
||||
background-color: #e7e7e7;
|
||||
text-align: center;
|
||||
}
|
||||
table.invoice thead tr.orderIdRow{
|
||||
background-color: #e7e7e7;
|
||||
}
|
||||
|
||||
table.invoice tbody td:nth-child(3),td:nth-child(4),td:nth-child(5),td:nth-child(6),td:nth-child(7),td:nth-child(8){
|
||||
text-align: center;
|
||||
}
|
||||
/*
|
||||
table.invoice tbody td:nth-child(3),td:nth-child(4),td:nth-child(5){
|
||||
text-align: center;
|
||||
}
|
||||
table.invoice tbody td:nth-child(6),td:nth-child(7){
|
||||
text-align: right;
|
||||
}
|
||||
*/
|
||||
|
||||
table.invoice tr.invoiceSumRow{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media only screen {
|
||||
/*
|
||||
button.printButton{
|
||||
display: inline;
|
||||
float: right;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {-webkit-print-color-adjust: exact;}
|
||||
button.printButton{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
310
public/js/app.js
310
public/js/app.js
File diff suppressed because one or more lines are too long
@ -1,19 +0,0 @@
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <http://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/*! Axios v1.13.5 Copyright (c) 2026 Matt Zabriskie and contributors */
|
||||
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Lodash <https://lodash.com/>
|
||||
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
|
||||
* Released under MIT license <https://lodash.com/license>
|
||||
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
*/
|
||||
File diff suppressed because one or more lines are too long
@ -1,82 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": [
|
||||
"bootstrap-toaster.js"
|
||||
],
|
||||
"names": [
|
||||
"TOAST_CONTAINER",
|
||||
"document",
|
||||
"createElement",
|
||||
"id",
|
||||
"className",
|
||||
"setAttribute",
|
||||
"body",
|
||||
"appendChild",
|
||||
"TOAST_TEMPLATE",
|
||||
"innerHTML",
|
||||
"TOAST_STATUS",
|
||||
"SUCCESS",
|
||||
"DANGER",
|
||||
"WARNING",
|
||||
"INFO",
|
||||
"TOAST_PLACEMENT",
|
||||
"TOP_LEFT",
|
||||
"TOP_CENTER",
|
||||
"TOP_RIGHT",
|
||||
"MIDDLE_LEFT",
|
||||
"MIDDLE_CENTER",
|
||||
"MIDDLE_RIGHT",
|
||||
"BOTTOM_LEFT",
|
||||
"BOTTOM_CENTER",
|
||||
"BOTTOM_RIGHT",
|
||||
"TOAST_THEME",
|
||||
"LIGHT",
|
||||
"DARK",
|
||||
"maxToastCount",
|
||||
"currentToastCount",
|
||||
"enableTimers",
|
||||
"Toast",
|
||||
"[object Object]",
|
||||
"maxToasts",
|
||||
"placement",
|
||||
"theme",
|
||||
"setMaxCount",
|
||||
"setPlacement",
|
||||
"setTheme",
|
||||
"console",
|
||||
"error",
|
||||
"classList",
|
||||
"add",
|
||||
"header",
|
||||
"querySelector",
|
||||
"close",
|
||||
"style",
|
||||
"backgroundColor",
|
||||
"color",
|
||||
"removeAttribute",
|
||||
"enabled",
|
||||
"title",
|
||||
"message",
|
||||
"status",
|
||||
"timeout",
|
||||
"toast",
|
||||
"cloneNode",
|
||||
"toastTitle",
|
||||
"toastBody",
|
||||
"innerText",
|
||||
"_setStatus",
|
||||
"_render",
|
||||
"statusIcon",
|
||||
"timer",
|
||||
"minutes",
|
||||
"elapsedTimer",
|
||||
"setInterval",
|
||||
"$",
|
||||
"on",
|
||||
"clearInterval",
|
||||
"toastHeader",
|
||||
"removeChild"
|
||||
],
|
||||
"mappings": "AAaA,MAAMA,gBAAkBC,SAASC,cAAc,OAC/CF,gBAAgBG,GAAK,iBACrBH,gBAAgBI,UAAY,+BAC5BJ,gBAAgBK,aAAa,YAAa,UAC1CJ,SAASK,KAAKC,YAAYP,iBAG1B,MAAMQ,eAAiBP,SAASC,cAAc,OAC9CM,eAAeJ,UAAY,QAC3BI,eAAeH,aAAa,OAAQ,UACpCG,eAAeH,aAAa,YAAa,UACzCG,eAAeH,aAAa,cAAe,QAC3CG,eAAeH,aAAa,gBAAiB,SAC7CG,eAAeC,UAAY,8dAY3B,MAAMC,aAAe,CACjBC,QAAS,EACTC,OAAQ,EACRC,QAAS,EACTC,KAAM,GAGJC,gBAAkB,CACpBC,SAAU,EACVC,WAAY,EACZC,UAAW,EACXC,YAAa,EACbC,cAAe,EACfC,aAAc,EACdC,YAAa,EACbC,cAAe,EACfC,aAAc,GAGZC,YAAc,CAChBC,MAAO,EACPC,KAAM,GAIV,IAAIC,cAAgB,EAEhBC,kBAAoB,EAEpBC,cAAe,EAEnB,MAAMC,MASFC,iBAAiBC,UAAY,KAAMC,UAAYnB,gBAAgBG,UAAWiB,MAAQ,KAAML,cAAe,GACnGC,MAAMK,YAAYH,WAElBF,MAAMM,aAAaH,WAEnBH,MAAMO,SAASH,OAEfJ,MAAMD,aAAaA,cAOvBE,mBAAmBC,WACG,OAAdA,YACIA,UAAY,EACZL,cAAgBK,UAGhBM,QAAQC,MAAM,+EAS1BR,oBAAoBE,WAEhB,OADAlC,gBAAgBI,UAAY,iBACpB8B,WACJ,KAAKnB,gBAAgBC,SACjBhB,gBAAgByC,UAAUC,IAAI,QAAS,UACvC,MACJ,KAAK3B,gBAAgBE,WACjBjB,gBAAgByC,UAAUC,IAAI,QAAS,UAAW,sBAClD,MACJ,KAAK3B,gBAAgBG,UACjBlB,gBAAgByC,UAAUC,IAAI,QAAS,WACvC,MACJ,KAAK3B,gBAAgBI,YACjBnB,gBAAgByC,UAAUC,IAAI,SAAU,SAAU,sBAClD,MACJ,KAAK3B,gBAAgBK,cACjBpB,gBAAgByC,UAAUC,IAAI,SAAU,UAAW,oBACnD,MACJ,KAAK3B,gBAAgBM,aACjBrB,gBAAgByC,UAAUC,IAAI,SAAU,UAAW,sBACnD,MACJ,KAAK3B,gBAAgBO,YACjBtB,gBAAgByC,UAAUC,IAAI,WAAY,UAC1C,MACJ,KAAK3B,gBAAgBQ,cACjBvB,gBAAgByC,UAAUC,IAAI,WAAY,UAAW,sBACrD,MACJ,KAAK3B,gBAAgBS,aACjBxB,gBAAgByC,UAAUC,IAAI,WAAY,WAC1C,MACJ,QACI1C,gBAAgByC,UAAUC,IAAI,QAAS,YASnDV,gBAAgBG,MAAQ,MACpB,IAAIQ,OAASnC,eAAeoC,cAAc,iBACtCC,MAAQF,OAAOC,cAAc,UACjC,OAAQT,OACJ,KAAKV,YAAYC,MACblB,eAAesC,MAAMC,gBAAkB,6BACvCvC,eAAesC,MAAME,MAAQ,0BAC7BL,OAAOG,MAAMC,gBAAkB,+BAC/BJ,OAAOG,MAAME,MAAQ,4BACrBH,MAAMC,MAAME,MAAQ,0BACpB,MACJ,KAAKvB,YAAYE,KACbnB,eAAesC,MAAMC,gBAAkB,4BACvCvC,eAAesC,MAAME,MAAQ,yBAC7BL,OAAOG,MAAMC,gBAAkB,8BAC/BJ,OAAOG,MAAME,MAAQ,2BACrBH,MAAMC,MAAME,MAAQ,yBACpB,MACJ,QACIxC,eAAeyC,gBAAgB,SAC/BN,OAAOM,gBAAgB,SACvBJ,MAAMI,gBAAgB,UAUlCjB,oBAAoBkB,SAAU,GAC1BpB,aAAeoB,QAYnBlB,cAAcmB,MAAOC,QAASC,OAAS,EAAGC,QAAU,GAChD,GAAIzB,mBAAqBD,cACrB,OAEJ,IAAI2B,MAAQ/C,eAAegD,WAAU,GAEjCC,WAGAC,UAHaH,MAAMX,cAAc,gBAC1Be,UAAYR,MAEPI,MAAMX,cAAc,eAC1BnC,UAAY2C,QAEtBrB,MAAM6B,WAAWL,MAAOF,QAExBtB,MAAM8B,QAAQN,MAAOD,SAQzBtB,kBAAkBuB,MAAOF,QACrB,IAAIS,WAAaP,MAAMX,cAAc,gBAErC,OAAQS,QACJ,KAAK3C,aAAaC,QACdmD,WAAWrB,UAAUC,IAAI,eAAgB,wBACzC,MACJ,KAAKhC,aAAaE,OACdkD,WAAWrB,UAAUC,IAAI,cAAe,oBACxCa,MAAMlD,aAAa,OAAQ,SAC3BkD,MAAMlD,aAAa,YAAa,aAChC,MACJ,KAAKK,aAAaG,QACdiD,WAAWrB,UAAUC,IAAI,eAAgB,8BACzCa,MAAMlD,aAAa,OAAQ,SAC3BkD,MAAMlD,aAAa,YAAa,aAChC,MACJ,KAAKK,aAAaI,KACdgD,WAAWrB,UAAUC,IAAI,YAAa,uBACtC,MACJ,QACIoB,WAAWrB,UAAUC,IAAI,WAUrCV,eAAeuB,MAAOD,SACdA,QAAU,IACVC,MAAMlD,aAAa,aAAciD,SACjCC,MAAMlD,aAAa,iBAAiB,IAGxC,IAAI0D,MAAQR,MAAMX,cAAc,UAEhC,GAAId,aAAc,CAGd,IAAIkC,QAAU,EACVC,aAAeC,YAAY,KAC3BH,MAAMJ,UAAY,GAAGK,eACrBA,WACD,KAGHG,EAAEZ,OAAOa,GAAG,kBAAmB,KAC3BC,cAAcJ,oBAGjB,CACD,IAAIK,YAAcf,MAAMX,cAAc,iBAC1B2B,YAAYR,OAG5B/D,gBAAgBO,YAAYgD,OAC5BY,EAAEZ,OAAOA,MAAM,QACf1B,oBAGAsC,EAAEZ,OAAOa,GAAG,kBAAmB,KAC3BpE,gBAAgBuE,YAAYhB,OAC5B1B",
|
||||
"file": "bootstrap-toaster.js"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
124161
public/js/customize.js
124161
public/js/customize.js
File diff suppressed because one or more lines are too long
@ -1,6 +0,0 @@
|
||||
function d({getContextMenuActionsUsing:o}){return{open:!1,size:{width:0,height:0},position:{x:0,y:0},mountData:{},context:null,actions:[],isLoading:!1,onCloseCallback:null,menu:{"x-show"(){return this.open},"x-bind:style"(){return`
|
||||
position: absolute;
|
||||
z-index: 40;
|
||||
top: ${this.position.y}px;
|
||||
left: ${this.position.x}px;
|
||||
`},"x-on:click.away"(){this.closeMenu()}},init:async function(){let t=this.$el.querySelector('[x-bind="menu"]');this.size={width:t.offsetWidth,height:t.offsetHeight},this.$el.addEventListener("calendar--open-menu",e=>this.openMenu(e))},loadActions:async function(t,e={}){this.isLoading=!0,this.actions=[],o(t,e).then(n=>{this.actions=n}).finally(()=>this.isLoading=!1)},openMenu:async function(t,e=null){this.$nextTick(()=>{let n=t.clientX,i=t.clientY,s=t.pageX,c=t.pageY,a=n+this.size.width>window.innerWidth?n+this.size.width-window.innerWidth:0,h=i+this.size.height>window.innerHeight?i+this.size.height-window.innerHeight:0;if(this.position.x=s-a,this.position.y=c-h,this.open=!0,e){let l=e.getAttribute("data-event-id");document.querySelectorAll(`.ec-event[data-event-id="${l}"]`).forEach(u=>u.classList.add("gu-context-menu-open"))}})},closeMenu:function(){this.open=!1,document.querySelectorAll(".ec-event.gu-context-menu-open").forEach(t=>t.classList.remove("gu-context-menu-open")),this.onCloseCallback&&this.onCloseCallback()}}}export{d as default};
|
||||
@ -1 +0,0 @@
|
||||
function o({event:t,timeText:r,view:d,hasContextMenu:n}){return{event:t,contextMenu:null,init:function(){n&&this.initializeContextMenu(),this.$el.setAttribute("data-event-id",t.id),this.$el.addEventListener("mouseenter",()=>{document.querySelectorAll(`.ec-event[data-event-id="${t.id}"]`).forEach(e=>{e.classList.add("gu-hover")})}),this.$el.addEventListener("mouseleave",()=>{document.querySelectorAll(`.ec-event[data-event-id="${t.id}"]`).forEach(e=>{e.classList.remove("gu-hover")})})},initializeContextMenu:function(){let e=document.querySelector("[calendar-context-menu]");this.contextMenu=Alpine.$data(e)},onClick:function(e){if(e.event.extendedProps.url){window.open(this.event.extendedProps.url,this.event.extendedProps.url_target??"_blank");return}let i={event:e.event,view:e.view,tzOffset:-new Date().getTimezoneOffset()};if(n){this.contextMenu.loadActions("eventClick",i),this.contextMenu.openMenu(e.jsEvent,this.$el);return}this.$wire.onEventClickJs(i)}}}export{o as default};
|
||||
@ -1,6 +0,0 @@
|
||||
function M({view:c="dayGridMonth",locale:v="en",firstDay:f=1,dayMaxEvents:w=!1,eventContent:l=null,eventClickEnabled:m=!1,eventDragEnabled:i=!1,eventResizeEnabled:d=!1,noEventsClickEnabled:h=!1,dateClickEnabled:D=!1,dateSelectEnabled:u=!1,datesSetEnabled:E=!1,viewDidMountEnabled:O=!1,eventAllUpdatedEnabled:S=!1,hasDateClickContextMenu:p=null,hasDateSelectContextMenu:z=null,hasEventClickContextMenu:g=null,hasNoEventsClickContextMenu:x=null,resources:$=null,resourceLabelContent:r=null,theme:o=null,options:C={},eventAssetUrl:y}){return{init:function(){let n=this.mountCalendar();window.addEventListener("calendar--refresh",()=>{n.refetchEvents()}),this.$wire.on("calendar--set",e=>{n.setOption(e.key,e.value)})},mountCalendar:function(){return EventCalendar.create(this.$el.querySelector("[data-calendar]"),this.getSettings())},getSettings:function(){let n={view:c,locale:v,firstDay:f,dayMaxEvents:w,eventSources:[{events:e=>this.$wire.getEventsJs({...e,tzOffset:-new Date().getTimezoneOffset()})}],resources:$,selectable:u,eventStartEditable:i,eventDurationEditable:d};return l!==null&&(n.eventContent=e=>{let t=e.event.extendedProps.model,s=l[t]??l._default;if(s!==void 0)return{html:s}}),r!==null&&(n.resourceLabelContent=e=>{let t=e.resource.extendedProps.model,s=r[t]??r._default;if(s!==void 0)return{html:this.wrapContent(s,e)}}),D&&(n.dateClick=e=>{let t={date:e.date,dateStr:e.dateStr,allDay:e.allDay,view:e.view,resource:e.resource,tzOffset:-new Date().getTimezoneOffset()};p?this.openContextMenu(e.jsEvent,t,"dateClick"):this.$wire.onDateClickJs(t)}),u&&(n.select=e=>{let t={start:e.start,startStr:e.startStr,end:e.end,endStr:e.endStr,allDay:e.allDay,view:e.view,resource:e.resource,tzOffset:-new Date().getTimezoneOffset()};z?this.openContextMenu(e.jsEvent,t,"dateSelect"):this.$wire.onDateSelectJs(t)}),E&&(n.datesSet=e=>{this.$wire.onDatesSetJs({start:e.start,startStr:e.startStr,end:e.end,endStr:e.endStr,view:e.view,tzOffset:-new Date().getTimezoneOffset()})}),m&&(n.eventClick=e=>{Alpine.$data(e.el).onClick(e)}),n.eventResize=async e=>{let t=e.event.durationEditable,s=d;t!==void 0&&(s=t),s&&await this.$wire.onEventResizeJs({event:e.event,oldEvent:e.oldEvent,endDelta:e.endDelta,view:e.view,tzOffset:-new Date().getTimezoneOffset()}).then(a=>{a===!1&&e.revert()})},n.eventDrop=async e=>{let t=e.event.startEditable,s=i;t!==void 0&&(s=t),s&&await this.$wire.onEventDropJs({event:e.event,oldEvent:e.oldEvent,oldResource:e.oldResource,newResource:e.newResource,delta:e.delta,view:e.view,tzOffset:-new Date().getTimezoneOffset()}).then(a=>{a===!1&&e.revert()})},n.eventDidMount=e=>{e.el.setAttribute("x-load"),e.el.setAttribute("x-load-src",y),e.el.setAttribute("x-data",`calendarEvent({
|
||||
event: ${JSON.stringify(e.event)},
|
||||
timeText: "${e.timeText}",
|
||||
view: ${JSON.stringify(e.view)},
|
||||
hasContextMenu: ${g},
|
||||
})`)},h&&(n.noEventsClick=e=>{let t={view:e.view,tzOffset:-new Date().getTimezoneOffset()};x?this.openContextMenu(e.jsEvent,t,"noEventsClick"):this.$wire.onNoEventsClickJs(t)}),O&&(n.viewDidMount=e=>{this.$wire.onViewDidMountJs({view:e.view,tzOffset:-new Date().getTimezoneOffset()})}),S&&(n.eventAllUpdated=e=>{this.$wire.onEventAllUpdatedJs({view:e.view,tzOffset:-new Date().getTimezoneOffset()})}),o&&(n.theme=function(e){return{...e,...o}}),{...n,...C}},wrapContent:function(n,e){let t=document.createElement("div");return t.innerHTML=n,t.setAttribute("x-data",JSON.stringify(e)),t.classList.add("w-full"),t.outerHTML},openContextMenu:function(n,e,t){let s=document.querySelector("[calendar-context-menu]"),a=Alpine.$data(s);a.loadActions(t,e),a.openMenu(n)}}}export{M as default};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,46 +0,0 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=788435874adbbf8e5ddc27cc9d18e00e",
|
||||
"/js/admin.js": "/js/admin.js?id=10b9adf2a7c0fa319e265e93605c0749",
|
||||
"/js/module.js": "/js/module.js?id=6c18e619075de340eef4e5f108952ff0",
|
||||
"/js/components.js": "/js/components.js?id=34668cee8ac371c98657beffcff579b8",
|
||||
"/css/app.css": "/css/app.css?id=366d6978f145ae9341959edd6e69bed7",
|
||||
"/fonts/vendor/bootstrap-icons/bootstrap-icons.woff2?92ea18a81d737146ff044ddb52010366": "/fonts/vendor/bootstrap-icons/bootstrap-icons.woff2?92ea18a81d737146ff044ddb52010366?id=9ad5aa740d7d5e6a0191b309b9b1986c",
|
||||
"/fonts/vendor/bootstrap-icons/bootstrap-icons.woff?1295669cd4e305c97f2cfc16d56614b8": "/fonts/vendor/bootstrap-icons/bootstrap-icons.woff?1295669cd4e305c97f2cfc16d56614b8?id=d1af9af6052c51b169be6c628ae99bb5",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.eot?23f19bb08961f37aaf692ff943823453": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.eot?23f19bb08961f37aaf692ff943823453?id=0868992b7c56298026b76b22c534eab9",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2?d878b0a6a1144760244ff0665888404c": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2?d878b0a6a1144760244ff0665888404c?id=4ec8652aef2ce3e636bf32c24dd5ce86",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff?2285773e6b4b172f07d9b777c81b0775": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff?2285773e6b4b172f07d9b777c81b0775?id=66ea863732752673548b3b6537b6465b",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf?527940b104eb2ea366c8630f3f038603": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf?527940b104eb2ea366c8630f3f038603?id=9fefebd385ff8e0973f14d0ee1a28601",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.svg?2f517e09eb2ca6650ff5bec5a95157ab": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-brands-400.svg?2f517e09eb2ca6650ff5bec5a95157ab?id=1d5619cd804367cefe6da2d79289218a",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.eot?77206a6bb316fa0aded5083cc57f92b9": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.eot?77206a6bb316fa0aded5083cc57f92b9?id=7077d9231c75a9046a76a7c967fe5a83",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2?7a3337626410ca2f40718481c755640f": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2?7a3337626410ca2f40718481c755640f?id=72236201e0deaf031ce8b91a0554ac8d",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff?bb58e57c48a3e911f15fa834ff00d44a": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff?bb58e57c48a3e911f15fa834ff00d44a?id=5f9919e4ca7ba90270eb4b245401b9a8",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.ttf?491974d108fe4002b2aaf7ffc48249a0": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.ttf?491974d108fe4002b2aaf7ffc48249a0?id=57519834dc5f9c6437e18fe63c7db401",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.svg?4689f52cc96215721344e51e5831eec1": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-regular-400.svg?4689f52cc96215721344e51e5831eec1?id=c5d109be8edd3de0f60eb472bd9ef691",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot?9bbb245e67a133f6e486d8d2545e14a5": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot?9bbb245e67a133f6e486d8d2545e14a5?id=0af95f09495e76b34fb2a911b8c78051",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?1551f4f60c37af51121f106501f69b80": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2?1551f4f60c37af51121f106501f69b80?id=184257670d2e18e37fc93ca106b9c6a7",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff?eeccf4f66002c6f2ba24d3d22f2434c2": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff?eeccf4f66002c6f2ba24d3d22f2434c2?id=26f963f67e793d91cc76426d43836849",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf?be9ee23c0c6390141475d519c2c5fb8f": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf?be9ee23c0c6390141475d519c2c5fb8f?id=d44877cb1fa07af67d56e4d86d39dd96",
|
||||
"/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg?7a8b4f130182d19a2d7c67d80c090397": "/fonts/vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg?7a8b4f130182d19a2d7c67d80c090397?id=37bc7099f6f1ba80236164f22e905837",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_10_eceadf_60x60.png?fcf8539b586ee18bcdea1755486148fb": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_10_eceadf_60x60.png?fcf8539b586ee18bcdea1755486148fb?id=7296ac90a70836a72af140e0346fc932",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_15_ffffff_60x60.png?c514e7ba7589d0f49ac63c298fcdae5e": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_15_ffffff_60x60.png?c514e7ba7589d0f49ac63c298fcdae5e?id=3c8a4c2c86890f38eb35a7a4f17108ac",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_10_f8f7f6_60x60.png?2999b2509cfc0da9d2638ce9f892d541": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_10_f8f7f6_60x60.png?2999b2509cfc0da9d2638ce9f892d541?id=42fbd9c28ff43250024032714111e992",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_65_654b24_60x60.png?6a53536235d962916651e5ade810be9c": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_65_654b24_60x60.png?6a53536235d962916651e5ade810be9c?id=0351aa2b5ee6d5c4a7e2eea67afd9a94",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_15_eceadf_60x60.png?bb99362eb46ac5b5824fabbfe6271e29": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_15_eceadf_60x60.png?bb99362eb46ac5b5824fabbfe6271e29?id=396642d988742f9ee3b73d239a417f59",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_15_f7f3de_60x60.png?9d1facfcb89e21b78242e2eb8cbd491c": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_15_f7f3de_60x60.png?9d1facfcb89e21b78242e2eb8cbd491c?id=425506cc6819db6ad5b01352df235653",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_68_b83400_60x60.png?f786ff5070a9c8cde4f9b567fc84e004": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_fine-grain_68_b83400_60x60.png?f786ff5070a9c8cde4f9b567fc84e004?id=98eb208ad7450212818f3a70f09729d6",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_222222_256x240.png?bcf1cdc9c7d1486173cc9aaa8b1fc77b": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_222222_256x240.png?bcf1cdc9c7d1486173cc9aaa8b1fc77b?id=5eb1d32635db28ba94d9d35ab363c70e",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_b83400_256x240.png?f481d1b47a462e74eed1e20ae7ac7824": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_b83400_256x240.png?f481d1b47a462e74eed1e20ae7ac7824?id=9ac73e8431d4dda3af9e6eb6d29f88ea",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_ffffff_256x240.png?fc616163e14c52dba5af7fdb573d2e64": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_ffffff_256x240.png?fc616163e14c52dba5af7fdb573d2e64?id=c0ac47f58e9e9e4b679101073a3f010a",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_8c291d_256x240.png?faf8dac1c3a19fa71b3349936071548b": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_8c291d_256x240.png?faf8dac1c3a19fa71b3349936071548b?id=732d736a3d70c5279a5ce1b837da69d1",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_3572ac_256x240.png?6b15e6e5507d972be2e15634d0f7bc82": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_3572ac_256x240.png?6b15e6e5507d972be2e15634d0f7bc82?id=beeb872e16251574c55cf3627f9978e1",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_fbdb93_256x240.png?aca518e5efefaf76c067ffb0e2438334": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-icons_fbdb93_256x240.png?aca518e5efefaf76c067ffb0e2438334?id=f5de1bb077a39c0d29d38e6dccaecf4b",
|
||||
"/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_diagonal-maze_20_6e4f1c_10x10.png?bde4cdb5c33f6a9c1c25419a4732ad98": "/images/vendor/jquery-ui-themes/themes/pepper-grinder/ui-bg_diagonal-maze_20_6e4f1c_10x10.png?bde4cdb5c33f6a9c1c25419a4732ad98?id=bff005db4cfc39e962fdd98eb8a0ef33",
|
||||
"/images/vendor/jquery-ui/themes/base/ui-icons_444444_256x240.png?d1b818587c3bc65058fe43800e4a191c": "/images/vendor/jquery-ui/themes/base/ui-icons_444444_256x240.png?d1b818587c3bc65058fe43800e4a191c?id=bed10eb948aa66a924e32f2022f0b7c1",
|
||||
"/images/vendor/jquery-ui/themes/base/ui-icons_555555_256x240.png?35d57320d9df28ec0d0d8bd1b5c75983": "/images/vendor/jquery-ui/themes/base/ui-icons_555555_256x240.png?35d57320d9df28ec0d0d8bd1b5c75983?id=d927e3a7feaea813b9bd0fd242e90de2",
|
||||
"/images/vendor/jquery-ui/themes/base/ui-icons_ffffff_256x240.png?92bef7e45fed3caba8dc9348edef4df2": "/images/vendor/jquery-ui/themes/base/ui-icons_ffffff_256x240.png?92bef7e45fed3caba8dc9348edef4df2?id=1e1f6219e7b6c134d1955b8db1907af5",
|
||||
"/images/vendor/jquery-ui/themes/base/ui-icons_777620_256x240.png?f423048bf942a7a33b33b1b982ecdb51": "/images/vendor/jquery-ui/themes/base/ui-icons_777620_256x240.png?f423048bf942a7a33b33b1b982ecdb51?id=7c2eb0d985914d94938ebc386ad09e37",
|
||||
"/images/vendor/jquery-ui/themes/base/ui-icons_cc0000_256x240.png?5cbbd560bcf30acb95dd3b0b0d61645a": "/images/vendor/jquery-ui/themes/base/ui-icons_cc0000_256x240.png?5cbbd560bcf30acb95dd3b0b0d61645a?id=e5fe3b8d656a0dcf8c574ec8eb4cb6fe",
|
||||
"/images/vendor/jquery-ui/themes/base/ui-icons_777777_256x240.png?f5d5fce2f36b5776eab8b314efc2dfd8": "/images/vendor/jquery-ui/themes/base/ui-icons_777777_256x240.png?f5d5fce2f36b5776eab8b314efc2dfd8?id=0c3579368edda27d14bb4910e27002b6",
|
||||
"/js/customize.js": "/js/customize.js?id=31b57208bc19a039066296cd7322567f",
|
||||
"/css/invoice.css": "/css/invoice.css?id=14b5784b76704d02969da9561631ed3f"
|
||||
}
|
||||
@ -1269,7 +1269,7 @@ solution before template
|
||||
data:function (data) {
|
||||
data.searchStr=dataTableSearchStr;
|
||||
data.krel=dataTableSearchKrel;
|
||||
data.groupId=selectedProductGroup;
|
||||
data.groupId = (selectedProductGroup === 'all') ? null : selectedProductGroup;
|
||||
data.supplierId=Order.supplierId;
|
||||
data.deliveryDate=Order.deliveryDate;
|
||||
data.orderId=Order.id;
|
||||
@ -1417,6 +1417,9 @@ solution before template
|
||||
$('.sidebar-wrapper .sidebar-menu .sidebar-dropdown .sidebar-submenu li a.categoryItem.clickable').on('click',
|
||||
function () {
|
||||
let groupId=$(this).data('id');
|
||||
if (groupId === 'all') {
|
||||
groupId = null;
|
||||
}
|
||||
selectedProductGroup=groupId;
|
||||
dataTableSearchStr=null;
|
||||
console.log(groupId);
|
||||
|
||||
@ -1,2 +1,6 @@
|
||||
/* Modern CSS (Vite) */
|
||||
@import "tailwindcss";
|
||||
|
||||
/* Font Awesome ikonok a legacy statisztika oldalak (pl. Aktuális ár) menüjéhez,
|
||||
a teljes legacy app.css behúzása nélkül. */
|
||||
@import "@fortawesome/fontawesome-free/css/all.min.css";
|
||||
|
||||
@ -373,8 +373,22 @@
|
||||
}
|
||||
this.initNavBarButton=function () {
|
||||
debug('asdadasd');
|
||||
|
||||
let typeFromUrl = new URLSearchParams(window.location.search).get('type');
|
||||
if (typeFromUrl) {
|
||||
let target = $('nav a.sidebar[data-action="' + typeFromUrl + '"]');
|
||||
if (target.length) {
|
||||
setTimeout(function() {
|
||||
target.trigger('click');
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
$('nav a.sidebar').off('click');
|
||||
$('nav a.sidebar').on('click',function (){
|
||||
$('nav a.sidebar').on('click',function (e){
|
||||
if ($(this).attr('href') !== '#') {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//let type=$(this).data('action');
|
||||
|
||||
@ -615,7 +629,20 @@ className: 'dt-body-right',
|
||||
|
||||
buttons: {
|
||||
buttons: [
|
||||
'excel','pdf',
|
||||
{
|
||||
extend: 'excel',
|
||||
exportOptions: {
|
||||
format: {
|
||||
body: function (data, row, column, node) {
|
||||
if ([2, 3, 4, 5, 6].includes(column)) {
|
||||
return typeof data === 'string' ? data.replace(/ /g, '') : data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'pdf',
|
||||
{
|
||||
footer:true,
|
||||
extend: 'print',
|
||||
|
||||
@ -23,23 +23,29 @@
|
||||
<div class="sidebar-menu active">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" class="sidebar OrderFrequency" data-action="OrderFrequency">
|
||||
<a href="{{ url('legacy/admin/statistics') }}?type=OrderFrequency" class="sidebar OrderFrequency" data-action="OrderFrequency">
|
||||
<i class="fa fa-wave-square"></i>
|
||||
<span>Rendelés gyakoriság</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="sidebar PriceChange" data-action="PriceChange">
|
||||
<a href="{{ url('legacy/admin/statistics') }}?type=PriceChange" class="sidebar PriceChange" data-action="PriceChange">
|
||||
<i class="fa fa-chart-bar"></i>
|
||||
<span>Árváltozás</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="sidebar ProductAmount" data-action="ProductAmount">
|
||||
<a href="{{ url('legacy/admin/statistics') }}?type=ProductAmount" class="sidebar ProductAmount" data-action="ProductAmount">
|
||||
<i class="fa fa-dollar-sign"></i>
|
||||
<span>Forgalom</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('filament.admin.pages.current-price') }}">
|
||||
<i class="fa fa-tag"></i>
|
||||
<span>Aktuális ár</span>
|
||||
</a>
|
||||
</li>
|
||||
{{-- <li>
|
||||
<a href="#" class="sidebar often" data-action="often">
|
||||
<i class="fa fa-dollar-sign"></i>
|
||||
@ -155,7 +161,7 @@
|
||||
#show-sidebar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 133px;
|
||||
top: 116px;
|
||||
border-radius: 0 4px 4px 0px;
|
||||
width: 35px;
|
||||
transition-delay: 0.3s;
|
||||
@ -171,7 +177,7 @@
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
position: fixed;
|
||||
top: 123px;
|
||||
top: 106px;
|
||||
left: -300px;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
287
resources/views/filament/pages/current-price.blade.php
Normal file
287
resources/views/filament/pages/current-price.blade.php
Normal file
@ -0,0 +1,287 @@
|
||||
<div class="legacy-stats-wrapper">
|
||||
{{-- Font Awesome ikonok a legacy sidebar menühöz (modern Vite build, nem a teljes legacy app.css) --}}
|
||||
@vite('resources/modern/css/app.css')
|
||||
|
||||
<style>
|
||||
/* Elrejtjük a Filament standard elemeit ezen az oldalon */
|
||||
.fi-sidebar { display: none !important; }
|
||||
.fi-main { padding-left: 0 !important; }
|
||||
.fi-topbar { z-index: 10 !important; }
|
||||
|
||||
/* A Filament wrapper elemeinek nullázása a pontos illeszkedés érdekében */
|
||||
.fi-page, .fi-page-header-main-ctn, .fi-page-main, .fi-page-content, .fi-page-header, .fi-header {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
gap: 0 !important;
|
||||
}
|
||||
|
||||
.fi-page-header, .fi-header {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* A legacy sidebar stílusaihoz szükséges alapok */
|
||||
.page-wrapper.chiller-theme .page-content {
|
||||
padding-left: 260px;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.page-wrapper.chiller-theme .page-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Biztosítjük a szürke hátteret és eltüntetjük a felső üres részt */
|
||||
.fi-main-ctn {
|
||||
background-color: #eceadf !important;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.fi-main {
|
||||
padding-top: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.statistic-card {
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
.statistic-card-header {
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.statistic-card-body {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* Navigációs gombok stílusa (a modern nézetből átemelve, de a legacy-hoz igazítva) */
|
||||
.legacy-nav-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.25rem;
|
||||
color: #212529;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.legacy-nav-item:hover {
|
||||
background-color: #e9ecef;
|
||||
text-decoration: none;
|
||||
}
|
||||
.legacy-nav-item i {
|
||||
font-size: 1.25rem;
|
||||
margin-right: 0.75rem;
|
||||
color: #453821;
|
||||
}
|
||||
|
||||
/* Aktuális ár találati táblázat */
|
||||
.result-table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.result-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.result-table th,
|
||||
.result-table td {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #dee2e6;
|
||||
text-align: left;
|
||||
}
|
||||
.result-table thead th {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.result-table tbody tr:nth-child(even) {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.result-table td.price-cell {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.result-table-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
.per-page-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.per-page-select select {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.result-pager {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.result-pager button {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
}
|
||||
.result-pager button:hover:not(:disabled) {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.result-pager button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.result-pager-info {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.excel-export-button {
|
||||
padding: 6px 14px;
|
||||
border: 1px solid #1e7e34;
|
||||
border-radius: 4px;
|
||||
background-color: #28a745;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
.excel-export-button:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
/* Aktív menüpont stílusa a sidebar-ban */
|
||||
.sidebar-menu ul li.active > a {
|
||||
color: #b8bfce;
|
||||
background: #3a3f48;
|
||||
}
|
||||
.sidebar-menu ul li.active > a i {
|
||||
color: #16c7ff;
|
||||
text-shadow: 0px 0px 10px rgba(22, 199, 255, 0.5);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="page-wrapper chiller-theme toggled">
|
||||
@php
|
||||
// Aktívvá tesszük a CurrentPrice linket a sidebarban, ha az a href megegyezik
|
||||
// De mivel a navSidebar.blade.php-t include-oljuk, a legegyszerűbb ha a CSS-sel oldjuk meg
|
||||
// vagy itt helyben injectálunk egy kis JS-t.
|
||||
@endphp
|
||||
@include('admin.statistics.navSidebar')
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const currentUrl = window.location.href;
|
||||
document.querySelectorAll('.sidebar-wrapper a').forEach(link => {
|
||||
if (link.href === currentUrl) {
|
||||
link.parentElement.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<main class="page-content" style="padding-top: 0;">
|
||||
<div style="max-width: 100%; padding-left: 15px; padding-right: 15px;">
|
||||
<div class="statistic-card">
|
||||
<div class="statistic-card-header">
|
||||
Szűrés
|
||||
</div>
|
||||
<div class="statistic-card-body">
|
||||
<form wire:submit.prevent="submit">
|
||||
{{ $this->form }}
|
||||
|
||||
<div class="mt-4 flex justify-end">
|
||||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition">
|
||||
Szűrés alkalmazása
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="statistic-card">
|
||||
<div class="statistic-card-header" style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<span>Aktuális ár statisztika</span>
|
||||
@if ($hasSearched && ! empty($results))
|
||||
<button type="button" wire:click="exportExcel" class="excel-export-button">
|
||||
Excel export
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="statistic-card-body">
|
||||
@if (! $hasSearched)
|
||||
<p>Válassza ki a szűrési feltételeket, majd nyomja meg a "Szűrés alkalmazása" gombot.</p>
|
||||
@elseif (empty($results))
|
||||
<p>Nincs a szűrésnek megfelelő találat.</p>
|
||||
@else
|
||||
<div class="result-table-toolbar">
|
||||
<div>
|
||||
Összesen <strong>{{ $totalResults }}</strong> találat
|
||||
</div>
|
||||
<div class="per-page-select">
|
||||
<label for="perPage">Sorok oldalanként:</label>
|
||||
<select id="perPage" wire:model.live="perPage">
|
||||
@foreach ($this::PER_PAGE_OPTIONS as $option)
|
||||
<option value="{{ $option }}">{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="result-table-wrapper">
|
||||
<table class="result-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Beszállító</th>
|
||||
<th>Gyártó</th>
|
||||
<th>Termék Főcsoport</th>
|
||||
<th>Termék alcsoport 1</th>
|
||||
<th>Termék alcsoport 2</th>
|
||||
<th>Termék megnevezése</th>
|
||||
<th>Aktuális ár</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($results as $row)
|
||||
<tr>
|
||||
<td>{{ $row['supplier'] ?? '-' }}</td>
|
||||
<td>{{ $row['producer'] ?? '-' }}</td>
|
||||
<td>{{ $row['mainGroup'] ?: '-' }}</td>
|
||||
<td>{{ $row['subGroup1'] ?: '-' }}</td>
|
||||
<td>{{ $row['subGroup2'] ?: '-' }}</td>
|
||||
<td>{{ $row['name'] }}</td>
|
||||
<td class="price-cell">{{ $row['price'] !== null ? number_format($row['price'], 0, ',', ' ') . ' Ft' : '-' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@php $lastPage = $this->lastPage(); @endphp
|
||||
@if ($lastPage > 1)
|
||||
<div class="result-pager">
|
||||
<button type="button" wire:click="goToPage(1)" @disabled($page <= 1)>«</button>
|
||||
<button type="button" wire:click="goToPage({{ $page - 1 }})" @disabled($page <= 1)>‹ Előző</button>
|
||||
<span class="result-pager-info">{{ $page }}. / {{ $lastPage }} oldal</span>
|
||||
<button type="button" wire:click="goToPage({{ $page + 1 }})" @disabled($page >= $lastPage)>Következő ›</button>
|
||||
<button type="button" wire:click="goToPage({{ $lastPage }})" @disabled($page >= $lastPage)>»</button>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,13 +1,13 @@
|
||||
<tr class="ProductHeadRow" >
|
||||
<td >Cikkszám</td>
|
||||
<td>Megnevezés</td>
|
||||
<td>REL</td>
|
||||
<td>Rendelt mennyiség</td>
|
||||
<td>Kiszerelés</td>
|
||||
<td>Egység-szorzó</td>
|
||||
<td>Nettó ár /mennyiségi egység</td>
|
||||
<td>Mennyiségi egység</td>
|
||||
<td>Nettó összesen</td>
|
||||
<td style="width: 8%;">Cikkszám</td>
|
||||
<td style="width: 27%;">Megnevezés</td>
|
||||
<td style="width: 3%;">REL</td>
|
||||
<td style="width: 6%;">R.m.</td>
|
||||
<td style="width: 6%;">Kisz.</td>
|
||||
<td style="width: 6%;">E.sz.</td>
|
||||
<td style="width: 17%;">Nettó ár /m.e.</td>
|
||||
<td style="width: 6%;">M.e.</td>
|
||||
<td style="width: 21%;">Nettó összesen</td>
|
||||
</tr>
|
||||
|
||||
@foreach($items as $key=>$item)
|
||||
|
||||
@ -13,15 +13,15 @@
|
||||
</tr>
|
||||
|
||||
<tr class="ProductHeadRow" >
|
||||
<td >Cikkszám</td>
|
||||
<td>Megnevezés</td>
|
||||
<td>REL</td>
|
||||
<td>Rendelt mennyiség</td>
|
||||
<td>Kiszerelés</td>
|
||||
<td>Egység-szorzó</td>
|
||||
<td>Nettó ár /mennyiségi egység</td>
|
||||
<td>Mennyiségi egység</td>
|
||||
<td>Nettó összesen</td>
|
||||
<td style="width: 8%;">Cikkszám</td>
|
||||
<td style="width: 27%;">Megnevezés</td>
|
||||
<td style="width: 5%;">REL</td>
|
||||
<td style="width: 10%;">R.m.</td>
|
||||
<td style="width: 10%;">Kisz.</td>
|
||||
<td style="width: 10%;">E.sz.</td>
|
||||
<td style="width: 10%;">Nettó ár /m.e.</td>
|
||||
<td style="width: 10%;">M.e.</td>
|
||||
<td style="width: 10%;">Nettó összesen</td>
|
||||
</tr>
|
||||
@foreach($dayItem['items'] as $item)
|
||||
@php
|
||||
|
||||
@ -46,6 +46,9 @@
|
||||
</a>
|
||||
<div class="sidebar-submenu active" style="display: block;">
|
||||
<ul>
|
||||
<li class="list-unstyled">
|
||||
<a class="categoryItem clickable" data-id="all">Összes</a>
|
||||
</li>
|
||||
@if(count($productGroup)>0)
|
||||
@include('modules.order.productSelectSidebarProductGroupPartial',$productGroup)
|
||||
@endif
|
||||
|
||||
22
tests/Feature/CurrentPricePageTest.php
Normal file
22
tests/Feature/CurrentPricePageTest.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Role;
|
||||
use App\Filament\Pages\CurrentPrice;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
|
||||
it('can render current price page', function () {
|
||||
$adminRole = Role::create(['name' => 'admin', 'display_name' => 'Admin', 'description' => 'Admin']);
|
||||
$user = User::factory()->create();
|
||||
$user->addRole($adminRole);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Livewire::test(CurrentPrice::class)
|
||||
->assertOk()
|
||||
->assertFormExists();
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user