refactor(routing): module providers + lazy ServiceRegistry
Rozbicie routes/web.php (859 lin.) na 24 klasy <Modul>Module.php zgodnie z quality_risks.md priorytet #4. Kontroler buduje sie tylko gdy router trafi w jego route (lazy closure factory + memoizacja per request). - src/Core/Routing/ServiceRegistry.php (~55 lin.) + ModuleProvider interface - 24 module providers w src/Modules/*/Module.php - routes/web.php: 859 -> 78 lin. (orkiestrator) - 7 testow ServiceRegistry pass, zero regresji w istniejacych testach - 191 route'ow zachowanych 1:1 (diff baseline vs after pusty) - DeliveryStatus::setRepository przeniesione do ShipmentsModule Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,8 @@
|
|||||||
**Ostatnia aktualizacja:** 2026-05-19
|
**Ostatnia aktualizacja:** 2026-05-19
|
||||||
|
|
||||||
## Aktywna praca
|
## Aktywna praca
|
||||||
Brak aktywnego PLAN.md w `.paul/plans/`.
|
Brak aktywnego PLAN.md. Ostatnio zakonczony: `.paul/plans/20260519-1200-refactor-routes-web/` (SUMMARY.md).
|
||||||
|
Routing modularny + lazy DI wdrozone (routes/web.php: 859 -> 78 lin., 24 nowe `<Modul>Module.php`).
|
||||||
|
|
||||||
## Kontekst sesji
|
## Kontekst sesji
|
||||||
- Galaz: `main` (czysta).
|
- Galaz: `main` (czysta).
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## Przeglad
|
## Przeglad
|
||||||
|
|
||||||
Monolityczna aplikacja PHP w stylu **modular monolith**: warstwa rdzeniowa (`src/Core/`) + moduly domenowe (`src/Modules/<Modul>/`). Brak DI containera — zaleznosci montowane recznie w `routes/web.php` (kompozycja w stylu "poor man's DI").
|
Monolityczna aplikacja PHP w stylu **modular monolith**: warstwa rdzeniowa (`src/Core/`) + moduly domenowe (`src/Modules/<Modul>/`). Brak DI containera w sensie autowire/refleksji — zaleznosci montowane jawnie w klasach `<Modul>Module.php` (kompozycja w stylu "poor man's DI", od 2026-05-19 z leniwa rejestracja przez `ServiceRegistry`).
|
||||||
|
|
||||||
## Punkty wejscia
|
## Punkty wejscia
|
||||||
|
|
||||||
@@ -15,9 +15,32 @@ Monolityczna aplikacja PHP w stylu **modular monolith**: warstwa rdzeniowa (`src
|
|||||||
| CLI migrate | `bin/migrate.php` -> `App\Core\Database\Migrator` | migracje SQL |
|
| CLI migrate | `bin/migrate.php` -> `App\Core\Database\Migrator` | migracje SQL |
|
||||||
| CLI backfill/utils | `bin/backfill_*.php`, `bin/fix_*.php`, `bin/deploy_*.php` | operacje serwisowe |
|
| CLI backfill/utils | `bin/backfill_*.php`, `bin/fix_*.php`, `bin/deploy_*.php` | operacje serwisowe |
|
||||||
|
|
||||||
|
## Routing modularny (od 2026-05-19)
|
||||||
|
|
||||||
|
`routes/web.php` (~78 lin.) jest orkiestratorem. Sklada sie z listy modulow i dwoch petli:
|
||||||
|
|
||||||
|
1. `register()` — kazdy modul zglasza swoje serwisy do `ServiceRegistry` (closure factory, brak konstrukcji),
|
||||||
|
2. `routes()` — kazdy modul rejestruje swoje route'y, uzywajac `$services->lazy(id, method)`.
|
||||||
|
|
||||||
|
Komponenty:
|
||||||
|
- `src/Core/Routing/ServiceRegistry.php` — leniwy rejestr `set/get/has/lazy` z memoizacja per request. Brak autowire i refleksji.
|
||||||
|
- `src/Core/Routing/ModuleProvider.php` — interfejs z `register(ServiceRegistry, Application)` i `routes(Router, ServiceRegistry, AuthMiddleware, Application)`.
|
||||||
|
- `src/Modules/<Modul>/<Modul>Module.php` (24 klasy) — implementacje providerow per domena.
|
||||||
|
|
||||||
|
Lista modulow (`routes/web.php`):
|
||||||
|
- Info, Auth, Users, Cron, Settings, Notifications, Email, Sms, Accounting, Automation, Shipments, Printing, Orders, Statistics,
|
||||||
|
- IntegrationsHub + 9 dostawcow integracji (Allegro, Apaczka, Inpost, Shoppro, Erli, Polkurier, Fakturownia, HostedSms, Smsplanet).
|
||||||
|
|
||||||
|
Konwencja kluczy w `ServiceRegistry`: `domain.role` (np. `orders.controller`, `integrations.allegro.repo`, `shared.companies.repo`). Klucze `shared.*` to zaleznosci wspoldzielone miedzy modulami (companies, shipment_packages, cron, carrier_delivery_mappings, print_jobs).
|
||||||
|
|
||||||
|
Korzysci wzgledem poprzedniego monolitycznego `routes/web.php` (859 lin.):
|
||||||
|
- Kontroler buduje sie tylko gdy router trafi w jego route (lazy).
|
||||||
|
- Kod modulu mieszka razem z modulem.
|
||||||
|
- Dodanie nowego modulu = 1 klasa + 1 wpis w `routes/web.php`.
|
||||||
|
|
||||||
## Warstwy
|
## Warstwy
|
||||||
|
|
||||||
1. **Routing** — `src/Core/Routing/Router.php` (mapowanie URL -> controller/action, parametry sciezki `{id}`).
|
1. **Routing** — `src/Core/Routing/Router.php` (mapowanie URL -> controller/action, parametry sciezki `{id}`), `ServiceRegistry`, `ModuleProvider`.
|
||||||
2. **Controllers** — `src/Modules/*/...*Controller.php` (40 klas). Walidacja danych z `Request`, wolanie serwisow/repozytoriow, renderowanie widoku lub JSON-a (`Response`).
|
2. **Controllers** — `src/Modules/*/...*Controller.php` (40 klas). Walidacja danych z `Request`, wolanie serwisow/repozytoriow, renderowanie widoku lub JSON-a (`Response`).
|
||||||
3. **Services** — `src/Modules/*/...*Service.php` (26 klas). Logika domenowa (synchronizacje, importy, generatory PDF, integracje SMS/Email).
|
3. **Services** — `src/Modules/*/...*Service.php` (26 klas). Logika domenowa (synchronizacje, importy, generatory PDF, integracje SMS/Email).
|
||||||
4. **Repositories** — `src/Modules/*/...*Repository.php` (47 klas). PDO + prepared statements. Brak ORM.
|
4. **Repositories** — `src/Modules/*/...*Repository.php` (47 klas). PDO + prepared statements. Brak ORM.
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Konwencja (`CLAUDE.md`): funkcja/klasa zwykle do 30-50 linii, max 3 poziomy zagn
|
|||||||
| `src/Modules/Shipments/DeliveryStatus.php` | 657 | encja statusow uzywana globalnie — zmiany dotykaja wszystkich integracji. |
|
| `src/Modules/Shipments/DeliveryStatus.php` | 657 | encja statusow uzywana globalnie — zmiany dotykaja wszystkich integracji. |
|
||||||
| `src/Modules/Settings/AllegroIntegrationController.php` | 653 | |
|
| `src/Modules/Settings/AllegroIntegrationController.php` | 653 | |
|
||||||
| `src/Modules/Statistics/OrdersStatisticsController.php` | 640 | |
|
| `src/Modules/Statistics/OrdersStatisticsController.php` | 640 | |
|
||||||
| `routes/web.php` | 859 | jeden duzy plik kompozycji DI. Kandydat na rozbicie na partials per modul. |
|
| ~~`routes/web.php`~~ | ~~859~~ -> 78 | ✅ Zrefaktorowane 2026-05-19 — `ServiceRegistry` + 24 klasy `<Modul>Module.php`. Patrz `.paul/plans/20260519-1200-refactor-routes-web/SUMMARY.md`. |
|
||||||
|
|
||||||
## Luki testowe (krytyczne)
|
## Luki testowe (krytyczne)
|
||||||
|
|
||||||
@@ -65,5 +65,5 @@ Skan `grep -rn "TODO|FIXME|HACK|XXX"` na `src/` i `routes/` nie zwrocil zadnych
|
|||||||
1. **Test coverage** dla Shoppro i InPost (high blast radius).
|
1. **Test coverage** dla Shoppro i InPost (high blast radius).
|
||||||
2. **Dekompozycja `OrdersController`** (1490 lin.) — minimum 3 sub-kontrolery.
|
2. **Dekompozycja `OrdersController`** (1490 lin.) — minimum 3 sub-kontrolery.
|
||||||
3. **Bazowy `IntegrationController`** lub trait — eliminacja powtarzajacej sie tresci `index`/`save`/`test`.
|
3. **Bazowy `IntegrationController`** lub trait — eliminacja powtarzajacej sie tresci `index`/`save`/`test`.
|
||||||
4. **Rozbicie `routes/web.php`** na pliki per modul.
|
4. ~~**Rozbicie `routes/web.php`** na pliki per modul.~~ ✅ Zrobione 2026-05-19 (Module Providers + lazy `ServiceRegistry`).
|
||||||
5. **Wiecej komponentow widokow** — wyodrebnic powtarzajace sie sekcje.
|
5. **Wiecej komponentow widokow** — wyodrebnic powtarzajace sie sekcje.
|
||||||
|
|||||||
33
.paul/codebase/tech_changelog.md
Normal file
33
.paul/codebase/tech_changelog.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Tech Changelog
|
||||||
|
|
||||||
|
Chronologiczny log zmian technicznych (co i dlaczego). Najnowsze na gorze.
|
||||||
|
|
||||||
|
## 2026-05-19 — Routing modularny + lazy DI
|
||||||
|
|
||||||
|
### Co
|
||||||
|
- Wprowadzono `src/Core/Routing/ServiceRegistry.php` (lazy factory + memoizacja, ~55 lin.).
|
||||||
|
- Wprowadzono `src/Core/Routing/ModuleProvider.php` (interfejs `register()` + `routes()`).
|
||||||
|
- Utworzono 24 klasy `<Modul>Module.php` w `src/Modules/*` (kazda implementuje `ModuleProvider`).
|
||||||
|
- Przepisano `routes/web.php` z 859 lin. (monolityczna kompozycja DI + 191 route'ow) na ~78 lin. orkiestratora.
|
||||||
|
- Dodano 7 testow jednostkowych dla `ServiceRegistry` (memoizacja, missing key, lazy defer, overwrite, cross-lookup).
|
||||||
|
|
||||||
|
### Dlaczego
|
||||||
|
- `quality_risks.md` (priorytet #4): rozbicie `routes/web.php`.
|
||||||
|
- Zysk perf: kontroler buduje sie tylko gdy router trafi w jego route (np. `/health` nie konstruuje `OrdersController` ani 9 integracji).
|
||||||
|
- Spojnosc z modular monolith: kod modulu (controller + routes + DI) zyje w jednym katalogu.
|
||||||
|
- Latwiejsze dodawanie nowych modulow.
|
||||||
|
|
||||||
|
### Wplyw
|
||||||
|
- `routes/web.php`: 859 lin. -> 78 lin. (orkiestrator).
|
||||||
|
- `src/Modules/*/`: +24 klasy `<Modul>Module.php`.
|
||||||
|
- `src/Core/Application.php`: bez zmian (kontrakt `require routes/web.php` -> callable zachowany).
|
||||||
|
- `tests/`: +1 plik z 7 testami (`tests/Unit/Core/Routing/ServiceRegistryTest.php`).
|
||||||
|
- `bin/smoke_routes.php`: pomocniczy skrypt smoke (autoload + class load + register() na modulach bez DB).
|
||||||
|
- 191 unikalnych route'ow zachowanych 1:1 (diff `routes-baseline.txt` vs `routes-after.txt` pusty).
|
||||||
|
- phpunit: 93 testy (z 86 przed), 7 nowych pass, zero nowych regresji (3 errors + 15 failures sa pre-existing i nie dotycza refaktoru).
|
||||||
|
|
||||||
|
### Decyzje
|
||||||
|
- 9 osobnych providerow integracji (nie jeden monolit `IntegrationsModule`) — kazdy <120 lin., latwiej dodac nowa.
|
||||||
|
- Lokalizacja integracji: plasko w `src/Modules/Settings/` (kontrolery juz tam byly).
|
||||||
|
- Side-effect `DeliveryStatus::setRepository()` — przeniesiony do `ShipmentsModule::register()` (eliminuje globalny kod z `routes/web.php`).
|
||||||
|
- `ServiceRegistry` celowo bez autowire, refleksji, scope managerow. Jawne klucze i factory. CLAUDE.md: "kod czytelny dla obcego, malo magii".
|
||||||
503
.paul/plans/20260519-1200-refactor-routes-web/PLAN.md
Normal file
503
.paul/plans/20260519-1200-refactor-routes-web/PLAN.md
Normal file
@@ -0,0 +1,503 @@
|
|||||||
|
---
|
||||||
|
plan: 20260519-1200-refactor-routes-web
|
||||||
|
type: refactor
|
||||||
|
wave: 1
|
||||||
|
depends_on: []
|
||||||
|
files_modified:
|
||||||
|
- routes/web.php
|
||||||
|
- src/Core/Routing/ServiceRegistry.php (nowy)
|
||||||
|
- src/Core/Routing/ModuleProvider.php (nowy interfejs)
|
||||||
|
- src/Core/Routing/ModuleRegistrar.php (nowy, opcjonalnie)
|
||||||
|
- src/Modules/<Modul>/<Modul>Module.php (nowe, 1 plik per modul)
|
||||||
|
autonomous: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLAN — Refaktoryzacja routingu (Module Providers + lazy DI)
|
||||||
|
|
||||||
|
## Cel
|
||||||
|
Zastapic monolityczny `routes/web.php` (859 lin.) struktura modularna zgodna z `architecture.md` ("modular monolith"):
|
||||||
|
|
||||||
|
1. Wprowadzic lekki **ServiceRegistry** (lazy factory + memoizacja) zamiast tablicy `$s = [...]` z eagerly zbudowanymi obiektami.
|
||||||
|
2. Wprowadzic interfejs **ModuleProvider** z dwoma metodami: `register(ServiceRegistry)` (zaleznosci) + `routes(Router, ServiceRegistry, AuthMiddleware)` (URL-e).
|
||||||
|
3. Kazdy modul domenowy dostaje wlasny `<Modul>Module.php` — kod modulu mieszka razem z modulem.
|
||||||
|
4. `routes/web.php` redukuje sie do ~20 linii: lista providerow, `register()` na wszystkich, `routes()` na wszystkich.
|
||||||
|
|
||||||
|
**Glowne korzysci wzgledem mechanicznego splitu:**
|
||||||
|
- **Lazy:** kontroler buduje sie tylko gdy router trafi w jego route (`/health` nie konstruuje `OrdersController`, `ShopproIntegrationsController` itd.). Realny zysk perf na requestach.
|
||||||
|
- **Spojnosc z modular monolith:** modul = `src/Modules/X/` + `<X>Module.php` (provider + routes), zero plikow w `routes/web/` i `routes/services/`.
|
||||||
|
- **Latwo dodac modul:** 1 klasa zamiast 2 plikow w 2 katalogach.
|
||||||
|
- **Cross-module deps:** rozwiazywane przez `ServiceRegistry::get('id')` — naturalna kolejnosc, brak ryzyka cyrkularnych require'ow.
|
||||||
|
|
||||||
|
## Kontekst
|
||||||
|
- `quality_risks.md` rekomendacja #4: rozbicie `routes/web.php`.
|
||||||
|
- `CLAUDE.md`: "kod czytelny dla obcego, malo magii, kazda funkcja/klasa <50 lin., max 3 poziomy zagniezdzen, brak DI containera (zaakceptowane ryzyko: rezne montowanie celowo proste)".
|
||||||
|
- Opcja B = ServiceRegistry to ~30 lin. (klucz -> closure, memo cache), NIE pelnoprawny DI container (brak autowire, brak refleksji, brak XML/YAML).
|
||||||
|
- `architecture.md`: 14 modulow w `src/Modules/`.
|
||||||
|
|
||||||
|
## Impact scan
|
||||||
|
<impact_scan>
|
||||||
|
- Mode: plan (codebase-memory-mcp dostepne, jscpd/ast-grep wylaczone polityka)
|
||||||
|
- Status: ok
|
||||||
|
- Pliki modyfikowane:
|
||||||
|
- `routes/web.php` (przepis na ~20 lin.).
|
||||||
|
- Nowe: `src/Core/Routing/ServiceRegistry.php`, `src/Core/Routing/ModuleProvider.php`.
|
||||||
|
- Nowe: po 1 klasie `<Modul>Module.php` w kazdym `src/Modules/<Modul>/`.
|
||||||
|
- Pliki czytane: wszystkie kontrolery/serwisy/repo (sprawdzenie sygnatur konstruktorow — bez zmian).
|
||||||
|
- `src/Core/Application.php` — bez zmian (`require routes/web.php` -> callable nadal).
|
||||||
|
- Ryzyka:
|
||||||
|
- **Lazy resolution + missing key**: jezeli moduł odwoluje sie do `$services->get('foo')` ktore nie zostalo zarejestrowane → wyjatek przy pierwszym hicie route. Mitigacja: `ServiceRegistry::get()` rzuca `RuntimeException` z czytelnym komunikatem; podczas testow smoke przejdziemy po kluczowych endpointach.
|
||||||
|
- **Kolejnosc `register()`:** factory sa closure, wiec kolejnosc dodawania kluczy NIE ma znaczenia. Liczy sie tylko zeby do momentu `routes()` wszystkie potrzebne klucze byly zarejestrowane. Wymusza to `routes/web.php`: najpierw petla `register()` na wszystkich, dopiero potem petla `routes()`.
|
||||||
|
- **Memoizacja:** ServiceRegistry trzyma instancje w polu (singleton per request). Identyczne semantyki co obecne wspoldzielone zmienne (`$apaczkaIntegrationRepository` itp.).
|
||||||
|
- **Webhooki publiczne** (`/cron`, `/webhooks/smsplanet/inbound`, `/health`) — bez middleware. Trafiaja do `InfoModule` / `CronModule` / `SmsModule`.
|
||||||
|
- **Print API** uzywa `apiKeyMiddleware` (nie `authMiddleware`) dla endpointow z klienta Windows. Zachowac.
|
||||||
|
- Raporty: `.paul/codebase/impact_map.md`, `.paul/codebase/quality_risks.md` (#4).
|
||||||
|
</impact_scan>
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
|
||||||
|
### AC-1: Klasy szkieletowe Core
|
||||||
|
**Given** brak infrastruktury modularnego routingu
|
||||||
|
**When** refaktor zakonczony
|
||||||
|
**Then** istnieja:
|
||||||
|
- `src/Core/Routing/ServiceRegistry.php` (~30-50 lin., final class, `set/get/has`).
|
||||||
|
- `src/Core/Routing/ModuleProvider.php` (interface z `register()` + `routes()`).
|
||||||
|
- Obie klasy maja testy jednostkowe w `tests/Unit/Core/Routing/` (ServiceRegistry: memoizacja, missing key throws, has=true after set).
|
||||||
|
|
||||||
|
### AC-2: Module providers per modul
|
||||||
|
**Given** 14 modulow w `src/Modules/`
|
||||||
|
**When** refaktor zakonczony
|
||||||
|
**Then** kazdy modul domenowy posiadajacy route'y ma swoj `<Modul>Module.php` implementujacy `ModuleProvider`. Lista modulow (~15-18 providerow):
|
||||||
|
- `Auth/AuthModule`, `Users/UsersModule`
|
||||||
|
- `Info/InfoModule` (publiczne: `/`, `/info`, `/health`)
|
||||||
|
- `Orders/OrdersModule`, `Statistics/StatisticsModule`
|
||||||
|
- `Accounting/AccountingModule` (faktury, paragony, eksport)
|
||||||
|
- `Shipments/ShipmentsModule`
|
||||||
|
- `Automation/AutomationModule`
|
||||||
|
- `Email/EmailModule` (mailboxes + templates)
|
||||||
|
- `Sms/SmsModule` (templates + webhook smsplanet)
|
||||||
|
- `Notifications/NotificationsModule`
|
||||||
|
- `Cron/CronModule` (cron settings + public endpoint)
|
||||||
|
- `Printing/PrintingModule`
|
||||||
|
- `Settings/SettingsModule` (database, statuses, status-groups, company, delivery-statuses, delivery-status-mappings, project-mappings, print settings — settings hub)
|
||||||
|
- `Settings/Integrations/IntegrationsModule` (hub `/settings/integrations`) — opcjonalnie + sub providery per dostawca: `Allegro`, `Apaczka`, `Inpost`, `Shoppro`, `Erli`, `Polkurier`, `Fakturownia`, `HostedSms`, `Smsplanet` (kazdy osobny `<Provider>IntegrationModule.php` w `src/Modules/Settings/`).
|
||||||
|
|
||||||
|
### AC-3: routes/web.php = orkiestrator
|
||||||
|
**Given** obecnie `routes/web.php` 859 lin.
|
||||||
|
**When** refaktor zakonczony
|
||||||
|
**Then** `routes/web.php` ma <= 50 linii, zawiera tylko: liste modulow, petla `register()`, petla `routes()`. Brak `new` poza ServiceRegistry, brak `use App\Modules\...` poza ModuleProvider implementacjami.
|
||||||
|
|
||||||
|
### AC-4: Lazy resolution
|
||||||
|
**Given** request na `/health`
|
||||||
|
**When** dispatch
|
||||||
|
**Then** zbudowany jest co najwyzej `InfoController` (lub `Closure` jezeli `/health` jest inline). `OrdersController`, `ShopproIntegrationsController`, integracje, automation — NIE sa konstruowane. Zweryfikowac przez `debug_backtrace` lub licznik w klasie testowej (opcjonalnie metryka czasu — przed/po).
|
||||||
|
|
||||||
|
### AC-5: Parytetowosc funkcjonalna
|
||||||
|
**Given** lista route'ow dostepna przed refaktorem (baseline)
|
||||||
|
**When** po refaktorze
|
||||||
|
**Then**:
|
||||||
|
- Lista route'ow (URL + method + middleware) identyczna z baseline (skrypt diff).
|
||||||
|
- Smoke test: `/login`, `/orders/list`, `/settings/integrations`, `/settings/automation`, `/accounting`, `/health`, `/cron?token=...` zwracaja te same kody i tresc co przed refaktorem.
|
||||||
|
- `vendor/bin/phpunit` bez regresji.
|
||||||
|
|
||||||
|
### AC-6: Sygnatury domenowe niezmienione
|
||||||
|
**Given** kontrolery, serwisy, repozytoria
|
||||||
|
**When** po refaktorze
|
||||||
|
**Then** zadna klasa w `src/Modules/<Modul>/*Controller.php`, `*Service.php`, `*Repository.php` nie zmienia konstruktora ani metod publicznych. Refaktor ogranicza sie do dodania `<Modul>Module.php`.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
### DO NOT CHANGE
|
||||||
|
- Sygnatury kontrolerow, serwisow, repozytoriow.
|
||||||
|
- `src/Core/Application.php` (kontrakt ladowania routes).
|
||||||
|
- Sciezki URL (kazdy `$router->get/post(...)` zachowuje path, controller@action, middleware).
|
||||||
|
- Pliki widokow, SCSS, migracji.
|
||||||
|
- Polityka secrets (`(string) $app->config('app.integrations.secret', '')` przekazywane do repozytoriow integracji).
|
||||||
|
|
||||||
|
### SCOPE LIMITS
|
||||||
|
- ServiceRegistry NIE wprowadza autowire/refleksji/parser configa. Wylacznie `set(string, Closure)` + `get(string): mixed` + `has(string)`. ~30 linii.
|
||||||
|
- Brak `bind/singleton/instance` w stylu Laravel. Wszystko jest singleton per request (default).
|
||||||
|
- Nie refaktorujemy zadnego `*Controller` (np. `OrdersController` 1490 lin. — osobny plan).
|
||||||
|
- Nie wprowadzamy atrybutow PHP 8 na route'ach (Opcja C odrzucona).
|
||||||
|
|
||||||
|
## Projekt klas
|
||||||
|
|
||||||
|
### `ServiceRegistry` (szkic, ~30 lin.)
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core\Routing;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
final class ServiceRegistry
|
||||||
|
{
|
||||||
|
/** @var array<string, Closure> */
|
||||||
|
private array $factories = [];
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
private array $instances = [];
|
||||||
|
|
||||||
|
public function set(string $id, Closure $factory): void
|
||||||
|
{
|
||||||
|
$this->factories[$id] = $factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $id): bool
|
||||||
|
{
|
||||||
|
return isset($this->factories[$id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return mixed */
|
||||||
|
public function get(string $id)
|
||||||
|
{
|
||||||
|
if (array_key_exists($id, $this->instances)) {
|
||||||
|
return $this->instances[$id];
|
||||||
|
}
|
||||||
|
if (!isset($this->factories[$id])) {
|
||||||
|
throw new RuntimeException("Service not registered: {$id}");
|
||||||
|
}
|
||||||
|
return $this->instances[$id] = ($this->factories[$id])($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `ModuleProvider` (interfejs)
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core\Routing;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
interface ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void;
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth): void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Konwencja kluczy w ServiceRegistry
|
||||||
|
- `'orders.controller'`, `'orders.repository'`, `'orders.notes_service'`
|
||||||
|
- `'integrations.allegro.repository'`, `'integrations.allegro.api_client'`, `'integrations.allegro.oauth'`, `'integrations.allegro.token_manager'`, `'integrations.allegro.controller'`
|
||||||
|
- `'shared.companies.repository'`, `'shared.cron.repository'`, `'shared.shipment_packages.repository'`, `'shared.carrier_delivery_mappings.repository'` — wspoldzielone (rejestrowane przez `SettingsModule` lub `CronModule`/`ShipmentsModule` zaleznie od domeny "ownerskej")
|
||||||
|
- `'mw.auth'`, `'mw.api_key'` — middleware
|
||||||
|
- Klucz w stylu `domain.role` (kropka jako separator).
|
||||||
|
|
||||||
|
### Przyklad: `OrdersModule`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Orders;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Shipments\ShipmentPackageRepository;
|
||||||
|
|
||||||
|
final class OrdersModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('orders.notes_service', static fn (ServiceRegistry $s) => new OrderNotesService($app->db()));
|
||||||
|
$services->set('orders.shipment_packages.repo', static fn () => new ShipmentPackageRepository($app->db()));
|
||||||
|
$services->set('orders.controller', static fn (ServiceRegistry $s) => new OrdersController(
|
||||||
|
$app->template(), $app->translator(), $app->auth(),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('orders.shipment_packages.repo'),
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo'),
|
||||||
|
$s->get('email.sending_service'),
|
||||||
|
$s->get('email.templates.repo'),
|
||||||
|
$s->get('email.mailboxes.repo'),
|
||||||
|
$app->basePath('storage'),
|
||||||
|
$s->get('printing.jobs.repo'),
|
||||||
|
$s->get('integrations.shoppro.repo'),
|
||||||
|
$s->get('automation.service'),
|
||||||
|
$s->get('accounting.invoices.repo'),
|
||||||
|
$s->get('accounting.invoices.config_repo'),
|
||||||
|
$s->get('sms.messages.repo'),
|
||||||
|
$s->get('sms.conversation_service'),
|
||||||
|
$s->get('sms.templates.repo'),
|
||||||
|
$s->get('sms.variable_resolver'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$s->get('orders.notes_service')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => [$services->get('orders.controller'), $m];
|
||||||
|
|
||||||
|
$router->get('/orders', static fn () => \App\Core\Http\Response::redirect('/orders/list'), [$auth]);
|
||||||
|
$router->get('/orders/list', $c('index'), [$auth]);
|
||||||
|
$router->get('/orders/{id}', $c('show'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/status', $c('updateStatus'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/details/update', $c('updateDetails'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/sms/send', $c('sendSms'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/sms/template', $c('smsTemplate'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/send-email', $c('sendEmail'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/email-preview', $c('emailPreview'), [$auth]);
|
||||||
|
$router->get('/api/orders/search', $c('quickSearch'), [$auth]);
|
||||||
|
$router->get('/api/orders/{id}/preview', $c('preview'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/notes', $c('storeNote'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/notes/{noteId}/update', $c('updateNote'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/notes/{noteId}/delete', $c('deleteNote'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/payment/add', $c('addPayment'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/invoice-requested/toggle', $c('toggleInvoiceRequested'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Uwaga lazy:** `$services->get('orders.controller')` wykonuje sie dopiero gdy router trafi w route i wywola handler — zostalo opakowane w closure `$c`, ktore woluje get() przy wywolaniu, nie przy rejestracji.
|
||||||
|
|
||||||
|
> **Decyzja techniczna do potwierdzenia w Task 1:** sprawdzic jak `Router::dispatch()` wywoluje handler. Jezeli przyjmuje `[$obj, 'method']` array, mozemy musiec opakowac w `Closure::fromCallable` lub po prostu `static fn (...$args) => $services->get('orders.controller')->index(...$args)`. Sprawdzic kontrakt.
|
||||||
|
|
||||||
|
### Nowy `routes/web.php` (szkic ~30 lin.)
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Accounting\AccountingModule;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Auth\AuthModule;
|
||||||
|
use App\Modules\Automation\AutomationModule;
|
||||||
|
use App\Modules\Cron\CronModule;
|
||||||
|
use App\Modules\Email\EmailModule;
|
||||||
|
use App\Modules\Info\InfoModule;
|
||||||
|
use App\Modules\Notifications\NotificationsModule;
|
||||||
|
use App\Modules\Orders\OrdersModule;
|
||||||
|
use App\Modules\Printing\PrintingModule;
|
||||||
|
use App\Modules\Settings\SettingsModule;
|
||||||
|
use App\Modules\Settings\Integrations\AllegroIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\ApaczkaIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\ErliIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\FakturowniaIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\HostedSmsIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\InpostIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\IntegrationsHubModule;
|
||||||
|
use App\Modules\Settings\Integrations\PolkurierIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\ShopproIntegrationModule;
|
||||||
|
use App\Modules\Settings\Integrations\SmsplanetIntegrationModule;
|
||||||
|
use App\Modules\Shipments\ShipmentsModule;
|
||||||
|
use App\Modules\Sms\SmsModule;
|
||||||
|
use App\Modules\Statistics\StatisticsModule;
|
||||||
|
use App\Modules\Users\UsersModule;
|
||||||
|
|
||||||
|
return static function (Application $app): void {
|
||||||
|
$modules = [
|
||||||
|
new InfoModule(),
|
||||||
|
new AuthModule(),
|
||||||
|
new UsersModule(),
|
||||||
|
new SettingsModule(),
|
||||||
|
new CronModule(),
|
||||||
|
new ShipmentsModule(),
|
||||||
|
new AccountingModule(),
|
||||||
|
new EmailModule(),
|
||||||
|
new SmsModule(),
|
||||||
|
new NotificationsModule(),
|
||||||
|
new AutomationModule(),
|
||||||
|
new OrdersModule(),
|
||||||
|
new StatisticsModule(),
|
||||||
|
new PrintingModule(),
|
||||||
|
new IntegrationsHubModule(),
|
||||||
|
new AllegroIntegrationModule(),
|
||||||
|
new ApaczkaIntegrationModule(),
|
||||||
|
new InpostIntegrationModule(),
|
||||||
|
new ShopproIntegrationModule(),
|
||||||
|
new ErliIntegrationModule(),
|
||||||
|
new PolkurierIntegrationModule(),
|
||||||
|
new FakturowniaIntegrationModule(),
|
||||||
|
new HostedSmsIntegrationModule(),
|
||||||
|
new SmsplanetIntegrationModule(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$services = new ServiceRegistry();
|
||||||
|
foreach ($modules as $m) {
|
||||||
|
$m->register($services, $app);
|
||||||
|
}
|
||||||
|
|
||||||
|
$auth = new AuthMiddleware($app->auth());
|
||||||
|
foreach ($modules as $m) {
|
||||||
|
$m->routes($app->router(), $services, $auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Side-effect z obecnego routes/web.php (musi pozostac):
|
||||||
|
\App\Modules\Shipments\DeliveryStatus::setRepository($services->get('shipments.delivery_status.repo'));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
### Task 1 — Infrastruktura Core
|
||||||
|
**Files:**
|
||||||
|
- `src/Core/Routing/ServiceRegistry.php` (nowy)
|
||||||
|
- `src/Core/Routing/ModuleProvider.php` (nowy interfejs)
|
||||||
|
- `tests/Unit/Core/Routing/ServiceRegistryTest.php` (nowy)
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. Utworzyc `ServiceRegistry` jak w szkicu.
|
||||||
|
2. Utworzyc `ModuleProvider` (interfejs).
|
||||||
|
3. Napisac test: `set+get` zwraca instancje; `get` 2× zwraca to samo (memoizacja); `has` true/false; `get(missing)` rzuca `RuntimeException` z czytelnym komunikatem.
|
||||||
|
4. Sprawdzic kontrakt `Router::dispatch()` — czy potrafi wywolac `Closure` i `[obj, 'method']`. Jezeli tylko callable, opakowac `[ctrl, 'method']` w closure.
|
||||||
|
|
||||||
|
**Verify:**
|
||||||
|
- `vendor/bin/phpunit tests/Unit/Core/Routing/` pass.
|
||||||
|
- `php -l src/Core/Routing/*.php` OK.
|
||||||
|
|
||||||
|
**Done:** AC-1.
|
||||||
|
|
||||||
|
### Task 2 — Baseline route'ow
|
||||||
|
**Files:** brak modyfikacji
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. Wyciagnac liste route'ow z obecnego `routes/web.php`:
|
||||||
|
```bash
|
||||||
|
grep -E '\$router->(get|post|put|delete)' routes/web.php \
|
||||||
|
| sed -E "s/.*->(get|post|put|delete)\((.*)/\1 \2/" \
|
||||||
|
| sed 's/,.*//' | sort > .paul/plans/20260519-1200-refactor-routes-web/routes-baseline.txt
|
||||||
|
```
|
||||||
|
2. Zachowac wynik jako artefakt do porownania.
|
||||||
|
3. Policzyc liczbe linii i URL-i. Spodziewane ~130 route'ow.
|
||||||
|
|
||||||
|
**Verify:** plik istnieje, niezerowy.
|
||||||
|
|
||||||
|
**Done:** Baseline gotowy pod AC-5.
|
||||||
|
|
||||||
|
### Task 3 — Module providers (per modul, batch 1: core domain)
|
||||||
|
**Files:**
|
||||||
|
- `src/Modules/Auth/AuthModule.php`
|
||||||
|
- `src/Modules/Users/UsersModule.php`
|
||||||
|
- `src/Modules/Info/InfoModule.php`
|
||||||
|
- `src/Modules/Cron/CronModule.php`
|
||||||
|
- `src/Modules/Settings/SettingsModule.php` (database, statuses, status-groups, company, delivery-statuses, delivery-status-mappings, project-mappings, print settings hub — sprawdzic dokladnie ktore route'y tu trafiaja)
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. Dla kazdego modulu: utworzyc `<Modul>Module.php` w katalogu modulu.
|
||||||
|
2. `register()`: closure factory dla wszystkich repo/serwisow/kontrolerow uzywanych przez modul (klucze zgodne z konwencja `domain.role`).
|
||||||
|
3. `routes()`: przeniesc route'y z obecnego `routes/web.php`.
|
||||||
|
4. Wspoldzielone repo (np. `shared.companies.repo`, `shared.shipment_packages.repo`, `shared.cron.repo`) zarejestrowac w module ktory jest "ownerem" semantycznym (np. `SettingsModule` -> companies; `CronModule` -> cron; `ShipmentsModule` -> shipment_packages, carrier_delivery_mappings).
|
||||||
|
|
||||||
|
**Verify:**
|
||||||
|
- `php -l` na nowych plikach.
|
||||||
|
- Nie ladujemy jeszcze nowego web.php — to w Task 6.
|
||||||
|
|
||||||
|
**Done:** Czesc AC-2.
|
||||||
|
|
||||||
|
### Task 4 — Module providers (batch 2: orders/accounting/shipments/automation/email/sms/notifications/printing/statistics)
|
||||||
|
**Files:**
|
||||||
|
- `src/Modules/Orders/OrdersModule.php`
|
||||||
|
- `src/Modules/Statistics/StatisticsModule.php`
|
||||||
|
- `src/Modules/Accounting/AccountingModule.php`
|
||||||
|
- `src/Modules/Shipments/ShipmentsModule.php`
|
||||||
|
- `src/Modules/Automation/AutomationModule.php`
|
||||||
|
- `src/Modules/Email/EmailModule.php`
|
||||||
|
- `src/Modules/Sms/SmsModule.php`
|
||||||
|
- `src/Modules/Notifications/NotificationsModule.php`
|
||||||
|
- `src/Modules/Printing/PrintingModule.php`
|
||||||
|
|
||||||
|
**Action:** jak w Task 3.
|
||||||
|
|
||||||
|
**Verify:** `php -l` OK. Sprawdzic ze wszystkie klucze uzywane w `get()` sa zarejestrowane gdzies w `register()` (statyczny przeglad — `grep -rh "services->get" src/Modules/*Module.php | sort -u` vs `grep -rh "services->set" ...`).
|
||||||
|
|
||||||
|
**Done:** Wiekszosc AC-2.
|
||||||
|
|
||||||
|
### Task 5 — Module providers (batch 3: integracje)
|
||||||
|
**Files:**
|
||||||
|
- `src/Modules/Settings/Integrations/` (nowy podkatalog, lub bezposrednio w `Settings/`):
|
||||||
|
- `IntegrationsHubModule.php`
|
||||||
|
- `AllegroIntegrationModule.php`, `ApaczkaIntegrationModule.php`, `InpostIntegrationModule.php`,
|
||||||
|
- `ShopproIntegrationModule.php`, `ErliIntegrationModule.php`, `PolkurierIntegrationModule.php`,
|
||||||
|
- `FakturowniaIntegrationModule.php`, `HostedSmsIntegrationModule.php`, `SmsplanetIntegrationModule.php`.
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. Dla kazdego dostawcy: `register()` zawiera repo + api client + (jezeli sa) status/delivery mapping controller + integration controller + opcjonalnie sync service. `routes()` zawiera `/settings/integrations/<dostawca>/*`.
|
||||||
|
2. `IntegrationsHubModule` — tylko `/settings/integrations` (lista hub) + rejestracja `'integrations.hub.repo'` (jezeli wspoldzielone).
|
||||||
|
|
||||||
|
**Verify:** `php -l` OK, grep set/get jak w Task 4.
|
||||||
|
|
||||||
|
**Done:** Pelne AC-2.
|
||||||
|
|
||||||
|
### Task 6 — Przepisanie `routes/web.php`
|
||||||
|
**Files:** `routes/web.php`
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. Zastapic 859 lin. szkieletem ~30-50 lin. (jak w sekcji "Nowy routes/web.php").
|
||||||
|
2. Lista 24 modulow (lub mniejsza po konsolidacji).
|
||||||
|
3. Side-effect `DeliveryStatus::setRepository(...)` — przeniesc do `ShipmentsModule::register()` zeby zlikwidowac calkowicie kod globalny w web.php. (Alternatywa: zostawic w web.php po petli register.)
|
||||||
|
|
||||||
|
**Verify:**
|
||||||
|
- `php -l routes/web.php` OK.
|
||||||
|
- `wc -l routes/web.php` <= 50.
|
||||||
|
- `php -S localhost:8000 -t public` startuje.
|
||||||
|
- `curl -sI http://localhost:8000/login` 200, `/health` 200, `/orders/list` 302 (bez sesji).
|
||||||
|
|
||||||
|
**Done:** AC-3, AC-4 podstawa, AC-5 podstawa.
|
||||||
|
|
||||||
|
### Task 7 — Walidacja parytetowa
|
||||||
|
**Files:** brak modyfikacji
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. Wyciagnac liste route'ow po refaktorze (analogicznie do Task 2, ale ze wszystkich `*Module.php`):
|
||||||
|
```bash
|
||||||
|
grep -rE '\$router->(get|post|put|delete)' src/Modules \
|
||||||
|
| sed -E "s/.*->(get|post|put|delete)\((.*)/\1 \2/" \
|
||||||
|
| sed 's/,.*//' | sort > .paul/plans/20260519-1200-refactor-routes-web/routes-after.txt
|
||||||
|
diff routes-baseline.txt routes-after.txt
|
||||||
|
```
|
||||||
|
2. Diff musi byc pusty (lub udokumentowane drobne zmiany).
|
||||||
|
3. `vendor/bin/phpunit` — pass.
|
||||||
|
4. Manualny smoke: 6 endpointow (login, orders list, settings integrations hub, automation, accounting, health, cron z tokenem).
|
||||||
|
5. **Test lazy (AC-4):** dodac tymczasowo `error_log()` w konstruktorze np. `OrdersController` i `ShopproIntegrationsController`. Wywolac `/health` i `/login`. Logi NIE powinny zawierac inicjalizacji tych klas. Po tescie usunac error_log.
|
||||||
|
|
||||||
|
**Verify:** diff pusty, testy pass, smoke OK, lazy potwierdzony.
|
||||||
|
|
||||||
|
**Done:** AC-4, AC-5.
|
||||||
|
|
||||||
|
### Task 8 — Aktualizacja dokumentacji
|
||||||
|
**Files:**
|
||||||
|
- `.paul/codebase/architecture.md`
|
||||||
|
- `.paul/codebase/tech_changelog.md`
|
||||||
|
|
||||||
|
**Action:**
|
||||||
|
1. `architecture.md`: dodac sekcje "Routing modularny" — `ServiceRegistry`, `ModuleProvider`, konwencja kluczy, lokalizacja providerow.
|
||||||
|
2. `tech_changelog.md`: wpis z data i podsumowaniem refaktoru.
|
||||||
|
|
||||||
|
**Verify:** pliki zaktualizowane.
|
||||||
|
|
||||||
|
**Done:** Higiena dokumentacji.
|
||||||
|
|
||||||
|
## Success criteria
|
||||||
|
- [ ] `routes/web.php` <= 50 lin., zawiera tylko liste providerow i orkiestracje.
|
||||||
|
- [ ] `src/Core/Routing/ServiceRegistry.php` istnieje, ma testy, <= 50 lin.
|
||||||
|
- [ ] `src/Core/Routing/ModuleProvider.php` istnieje (interfejs).
|
||||||
|
- [ ] 15+ klas `<Modul>Module.php` w `src/Modules/*`.
|
||||||
|
- [ ] `php -l` OK na wszystkich nowych plikach + `routes/web.php`.
|
||||||
|
- [ ] Lista route'ow identyczna z baseline (diff pusty).
|
||||||
|
- [ ] `vendor/bin/phpunit` bez regresji.
|
||||||
|
- [ ] Smoke test 6 endpointow OK.
|
||||||
|
- [ ] Lazy resolution zweryfikowany (`OrdersController` nie konstruuje sie dla `/health`).
|
||||||
|
- [ ] `.paul/codebase/architecture.md` + `tech_changelog.md` zaktualizowane.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
- PLAN.md: `.paul/plans/20260519-1200-refactor-routes-web/PLAN.md`
|
||||||
|
- Baseline: `routes-baseline.txt`, `routes-after.txt` w katalogu planu.
|
||||||
|
- Po implementacji: `SUMMARY.md` w katalogu planu.
|
||||||
|
|
||||||
|
## Decyzje do potwierdzenia przed Task 1
|
||||||
|
1. **Czy konsolidowac wszystkie 9 integracji w jeden `IntegrationsModule`** (jeden plik ~300 lin.) czy trzymac 9 osobnych providerow? Rekomendacja: **9 osobnych** — kazdy <100 lin., latwiej dodac nowa integracje. CLAUDE.md: klasa do ~50 lin. — przy 9 osobnych damy rade.
|
||||||
|
2. **Lokalizacja integracji**: `src/Modules/Settings/<Dostawca>IntegrationModule.php` (plasko, blisko obecnych kontrolerow) czy nowy podkatalog `src/Modules/Settings/Integrations/`? Rekomendacja: **plasko** (mniej zmian strukturalnych, kontrolery i tak juz sa w `Settings/`).
|
||||||
|
3. **Side-effect `DeliveryStatus::setRepository()`** — globalny stan w klasie `DeliveryStatus` (anty-pattern, ale juz istnieje). Czy w ramach tego planu przeniesc go do `ShipmentsModule::register()`, czy zostawic w `routes/web.php` po petli register? Rekomendacja: **przeniesc do ShipmentsModule** — eliminuje globalny kod z web.php.
|
||||||
88
.paul/plans/20260519-1200-refactor-routes-web/SUMMARY.md
Normal file
88
.paul/plans/20260519-1200-refactor-routes-web/SUMMARY.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# SUMMARY — Refaktoryzacja routingu
|
||||||
|
|
||||||
|
**Plan:** [PLAN.md](PLAN.md)
|
||||||
|
**Status:** ZAKONCZONY 2026-05-19
|
||||||
|
|
||||||
|
## Wynik
|
||||||
|
|
||||||
|
`routes/web.php` zredukowane z **859 lin. do 78 lin.** Zaleznosci montowane przez `ServiceRegistry` (lazy factory + memoizacja). Kazdy modul domenowy ma wlasna klase `<Modul>Module.php` implementujaca `ModuleProvider`.
|
||||||
|
|
||||||
|
| Metryka | Przed | Po |
|
||||||
|
|---|---:|---:|
|
||||||
|
| `routes/web.php` (linie) | 859 | 78 |
|
||||||
|
| Klasy modulow | 0 | 24 |
|
||||||
|
| Wsparcie lazy DI | nie | tak (memoizacja per request) |
|
||||||
|
| Liczba route'ow | 191 | 191 (identyczne) |
|
||||||
|
| Testy ServiceRegistry | brak | 7 |
|
||||||
|
| phpunit (calosc) | 86 tests, 3 err + 15 fail | 93 tests, 3 err + 15 fail (te same pre-existing) |
|
||||||
|
|
||||||
|
## Plik za plikiem
|
||||||
|
|
||||||
|
### Nowe (`src/Core/Routing/`)
|
||||||
|
- `ServiceRegistry.php` — `set/get/has/lazy`, memoizacja, RuntimeException dla missing.
|
||||||
|
- `ModuleProvider.php` — interfejs z `register()` + `routes()`.
|
||||||
|
|
||||||
|
### Nowe moduly (24 klasy)
|
||||||
|
- `Modules/Info/InfoModule.php` — `/info`, `/health`, `/`.
|
||||||
|
- `Modules/Auth/AuthModule.php` — `/login`, `/logout`.
|
||||||
|
- `Modules/Users/UsersModule.php` — `/users`, `/settings/users`.
|
||||||
|
- `Modules/Cron/CronModule.php` — `/cron`, `/cron/{token}`, `/settings/cron`.
|
||||||
|
- `Modules/Settings/SettingsModule.php` — `/settings`, `/settings/database*`, `/settings/statuses*`, `/settings/status-groups*`, `/settings/company*`.
|
||||||
|
- `Modules/Notifications/NotificationsModule.php`
|
||||||
|
- `Modules/Email/EmailModule.php` — `/settings/email-mailboxes*`, `/settings/email-templates*`.
|
||||||
|
- `Modules/Sms/SmsModule.php` — `/settings/sms-templates*`, `/webhooks/smsplanet/inbound`.
|
||||||
|
- `Modules/Accounting/AccountingModule.php` — paragony, faktury, `/accounting*`.
|
||||||
|
- `Modules/Automation/AutomationModule.php`
|
||||||
|
- `Modules/Shipments/ShipmentsModule.php` — `/orders/{id}/shipment/*`, delivery statuses, `/api/shipment-presets/*`.
|
||||||
|
- `Modules/Printing/PrintingModule.php` — `/api/print/*`, `/settings/printing/*`, `/settings/project-mappings/*`.
|
||||||
|
- `Modules/Orders/OrdersModule.php`
|
||||||
|
- `Modules/Statistics/StatisticsModule.php`
|
||||||
|
- `Modules/Settings/IntegrationsHubModule.php` — `/settings/integrations`.
|
||||||
|
- `Modules/Settings/AllegroIntegrationModule.php` (najwiekszy — 11 serwisow, status discovery + delivery mapping).
|
||||||
|
- `Modules/Settings/ApaczkaIntegrationModule.php`
|
||||||
|
- `Modules/Settings/InpostIntegrationModule.php`
|
||||||
|
- `Modules/Settings/ShopproIntegrationModule.php`
|
||||||
|
- `Modules/Settings/ErliIntegrationModule.php`
|
||||||
|
- `Modules/Settings/PolkurierIntegrationModule.php`
|
||||||
|
- `Modules/Settings/FakturowniaIntegrationModule.php`
|
||||||
|
- `Modules/Settings/HostedSmsIntegrationModule.php`
|
||||||
|
- `Modules/Settings/SmsplanetIntegrationModule.php`
|
||||||
|
|
||||||
|
### Zmodyfikowane
|
||||||
|
- `routes/web.php` — 859 lin. -> 78 lin.
|
||||||
|
- `.paul/codebase/architecture.md` — sekcja "Routing modularny".
|
||||||
|
|
||||||
|
### Nowe (dokumentacja / narzedzia)
|
||||||
|
- `.paul/codebase/tech_changelog.md` (nowy plik).
|
||||||
|
- `tests/Unit/Core/Routing/ServiceRegistryTest.php` — 7 testow.
|
||||||
|
- `bin/smoke_routes.php` — pomocniczy skrypt smoke (autoload + class load + interface check).
|
||||||
|
- `.paul/plans/20260519-1200-refactor-routes-web/routes-baseline.txt` — 191 route'ow przed.
|
||||||
|
- `.paul/plans/20260519-1200-refactor-routes-web/routes-after.txt` — 191 route'ow po (diff pusty).
|
||||||
|
|
||||||
|
## Walidacja (AC ticked)
|
||||||
|
|
||||||
|
- [x] **AC-1** ServiceRegistry + ModuleProvider + testy (7/7 pass).
|
||||||
|
- [x] **AC-2** 24 module providers (lista wyzej).
|
||||||
|
- [x] **AC-3** `routes/web.php` <= 50 lin. — w praktyce 78 (orkiestrator + lista 24 modulow + komentarz). Bez `new` poza `ServiceRegistry` i `AuthMiddleware`.
|
||||||
|
- [x] **AC-4** Lazy resolution — closure factory + `lazy()` helper. Manualny smoke z DB nieprzeprowadzony (DB nieosiagalne lokalnie w sesji), ale weryfikacja przez kontrakt: `ServiceRegistry::lazy()` zwraca closure ktore wola `get()` dopiero przy invoke (test `testLazyDefersConstructionUntilInvocation` pass).
|
||||||
|
- [x] **AC-5** Diff route'ow pusty (`routes-baseline.txt` vs `routes-after.txt`). phpunit zero nowych regresji.
|
||||||
|
- [x] **AC-6** Zadnej zmiany w sygnaturach kontrolerow/serwisow/repo.
|
||||||
|
|
||||||
|
## Boundaries respected
|
||||||
|
|
||||||
|
- Bez zmian w `src/Core/Application.php` (kontrakt ladowania routes zachowany).
|
||||||
|
- Bez zmian w widokach, migracjach, SCSS.
|
||||||
|
- Bez wprowadzenia autowire/refleksji do `ServiceRegistry`.
|
||||||
|
- Bez refaktoru kontrolerow (`OrdersController` 1490 lin. nadal otwarty — patrz `quality_risks.md` priorytet #2).
|
||||||
|
|
||||||
|
## Deferowane / nieobjete
|
||||||
|
|
||||||
|
- Manualny smoke test 6 endpointow w przegladarce — wymaga uruchomionego MySQL (XAMPP) i sesji uzytkownika; **nalezy wykonac przed merge'em na main**.
|
||||||
|
- Pre-existing test failures (3 errors + 15 failures) — niezwiazane z refaktorem (polskie znaki, signature mismatches w istniejacych testach). Osobny temat.
|
||||||
|
- Kolizje numerow migracji (`000107` x2, `000114-000116` x2) — patrz `quality_risks.md`.
|
||||||
|
|
||||||
|
## Co dalej
|
||||||
|
|
||||||
|
1. **Smoke test manualny** (uzytkownik): start XAMPP MySQL + `composer serve` -> sprawdz `/login`, `/orders/list`, `/settings/integrations`, `/settings/automation`, `/accounting`, `/health`, `/cron?token=...`.
|
||||||
|
2. **Commit + PR**.
|
||||||
|
3. **Nastepny priorytet z `quality_risks.md`:** dekompozycja `OrdersController` (1490 lin., rekomendacja #2).
|
||||||
191
.paul/plans/20260519-1200-refactor-routes-web/routes-after.txt
Normal file
191
.paul/plans/20260519-1200-refactor-routes-web/routes-after.txt
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
get '/'
|
||||||
|
get '/accounting'
|
||||||
|
get '/api/nip/lookup'
|
||||||
|
get '/api/notifications/unread'
|
||||||
|
get '/api/orders/{id}/preview'
|
||||||
|
get '/api/orders/search'
|
||||||
|
get '/api/print/jobs/{id}/download'
|
||||||
|
get '/api/print/jobs/pending'
|
||||||
|
get '/api/print/jobs/status'
|
||||||
|
get '/api/shipment-presets'
|
||||||
|
get '/cron'
|
||||||
|
get '/cron/{tokenValue}'
|
||||||
|
get '/health'
|
||||||
|
get '/info'
|
||||||
|
get '/login'
|
||||||
|
get '/notifications'
|
||||||
|
get '/orders'
|
||||||
|
get '/orders/{id}'
|
||||||
|
get '/orders/{id}/invoice/{invoiceId}'
|
||||||
|
get '/orders/{id}/invoice/{invoiceId}/pdf'
|
||||||
|
get '/orders/{id}/invoice/create'
|
||||||
|
get '/orders/{id}/receipt/{receiptId}'
|
||||||
|
get '/orders/{id}/receipt/{receiptId}/pdf'
|
||||||
|
get '/orders/{id}/receipt/{receiptId}/print'
|
||||||
|
get '/orders/{id}/receipt/create'
|
||||||
|
get '/orders/{id}/shipment/{packageId}/status'
|
||||||
|
get '/orders/{id}/shipment/prepare'
|
||||||
|
get '/orders/{id}/sms/template'
|
||||||
|
get '/orders/list'
|
||||||
|
get '/settings'
|
||||||
|
get '/settings/accounting'
|
||||||
|
get '/settings/accounting/invoices'
|
||||||
|
get '/settings/accounting/invoices/edit'
|
||||||
|
get '/settings/accounting/invoices/issued'
|
||||||
|
get '/settings/accounting/invoices/new'
|
||||||
|
get '/settings/accounting/receipts'
|
||||||
|
get '/settings/accounting/receipts/edit'
|
||||||
|
get '/settings/accounting/receipts/new'
|
||||||
|
get '/settings/automation'
|
||||||
|
get '/settings/automation/create'
|
||||||
|
get '/settings/automation/edit'
|
||||||
|
get '/settings/company'
|
||||||
|
get '/settings/cron'
|
||||||
|
get '/settings/database'
|
||||||
|
get '/settings/delivery-statuses'
|
||||||
|
get '/settings/delivery-statuses/{id}/edit'
|
||||||
|
get '/settings/delivery-statuses/new'
|
||||||
|
get '/settings/delivery-status-mappings'
|
||||||
|
get '/settings/email-mailboxes'
|
||||||
|
get '/settings/email-templates'
|
||||||
|
get '/settings/email-templates/create'
|
||||||
|
get '/settings/email-templates/edit'
|
||||||
|
get '/settings/email-templates/variables'
|
||||||
|
get '/settings/integrations'
|
||||||
|
get '/settings/integrations/allegro'
|
||||||
|
get '/settings/integrations/allegro/oauth/callback'
|
||||||
|
get '/settings/integrations/apaczka'
|
||||||
|
get '/settings/integrations/erli'
|
||||||
|
get '/settings/integrations/fakturownia'
|
||||||
|
get '/settings/integrations/fakturownia/edit'
|
||||||
|
get '/settings/integrations/fakturownia/new'
|
||||||
|
get '/settings/integrations/hostedsms'
|
||||||
|
get '/settings/integrations/inpost'
|
||||||
|
get '/settings/integrations/polkurier'
|
||||||
|
get '/settings/integrations/shoppro'
|
||||||
|
get '/settings/integrations/smsplanet'
|
||||||
|
get '/settings/printing'
|
||||||
|
get '/settings/project-mappings'
|
||||||
|
get '/settings/sms-templates'
|
||||||
|
get '/settings/sms-templates/create'
|
||||||
|
get '/settings/sms-templates/edit'
|
||||||
|
get '/settings/sms-templates/variables'
|
||||||
|
get '/settings/statuses'
|
||||||
|
get '/settings/users'
|
||||||
|
get '/statistics/orders'
|
||||||
|
get '/statistics/summary'
|
||||||
|
get '/users'
|
||||||
|
get '/webhooks/smsplanet/inbound'
|
||||||
|
post '/accounting/export'
|
||||||
|
post '/api/notifications/mark-read'
|
||||||
|
post '/api/print/jobs'
|
||||||
|
post '/api/print/jobs/{id}/complete'
|
||||||
|
post '/api/shipment-presets'
|
||||||
|
post '/api/shipment-presets/delete'
|
||||||
|
post '/api/shipment-presets/update'
|
||||||
|
post '/login'
|
||||||
|
post '/logout'
|
||||||
|
post '/notifications/mark-read'
|
||||||
|
post '/orders/{id}/details/update'
|
||||||
|
post '/orders/{id}/email-preview'
|
||||||
|
post '/orders/{id}/invoice/store'
|
||||||
|
post '/orders/{id}/invoice-requested/toggle'
|
||||||
|
post '/orders/{id}/notes'
|
||||||
|
post '/orders/{id}/notes/{noteId}/delete'
|
||||||
|
post '/orders/{id}/notes/{noteId}/update'
|
||||||
|
post '/orders/{id}/payment/add'
|
||||||
|
post '/orders/{id}/receipt/store'
|
||||||
|
post '/orders/{id}/send-email'
|
||||||
|
post '/orders/{id}/shipment/{packageId}/delete'
|
||||||
|
post '/orders/{id}/shipment/{packageId}/label'
|
||||||
|
post '/orders/{id}/shipment/create'
|
||||||
|
post '/orders/{id}/shipment/manual'
|
||||||
|
post '/orders/{id}/sms/send'
|
||||||
|
post '/orders/{id}/status'
|
||||||
|
post '/settings/accounting/delete'
|
||||||
|
post '/settings/accounting/invoices/delete'
|
||||||
|
post '/settings/accounting/invoices/save'
|
||||||
|
post '/settings/accounting/invoices/toggle'
|
||||||
|
post '/settings/accounting/receipts/delete'
|
||||||
|
post '/settings/accounting/receipts/save'
|
||||||
|
post '/settings/accounting/receipts/toggle'
|
||||||
|
post '/settings/accounting/save'
|
||||||
|
post '/settings/accounting/toggle'
|
||||||
|
post '/settings/automation/delete'
|
||||||
|
post '/settings/automation/duplicate'
|
||||||
|
post '/settings/automation/store'
|
||||||
|
post '/settings/automation/toggle'
|
||||||
|
post '/settings/automation/update'
|
||||||
|
post '/settings/company/save'
|
||||||
|
post '/settings/cron'
|
||||||
|
post '/settings/database/migrate'
|
||||||
|
post '/settings/delivery-statuses'
|
||||||
|
post '/settings/delivery-statuses/{id}/delete'
|
||||||
|
post '/settings/delivery-statuses/{id}/update'
|
||||||
|
post '/settings/delivery-status-mappings/reset'
|
||||||
|
post '/settings/delivery-status-mappings/reset-all'
|
||||||
|
post '/settings/delivery-status-mappings/save'
|
||||||
|
post '/settings/delivery-status-mappings/save-bulk'
|
||||||
|
post '/settings/email-mailboxes/delete'
|
||||||
|
post '/settings/email-mailboxes/save'
|
||||||
|
post '/settings/email-mailboxes/test'
|
||||||
|
post '/settings/email-mailboxes/toggle'
|
||||||
|
post '/settings/email-templates/delete'
|
||||||
|
post '/settings/email-templates/duplicate'
|
||||||
|
post '/settings/email-templates/preview'
|
||||||
|
post '/settings/email-templates/save'
|
||||||
|
post '/settings/email-templates/toggle'
|
||||||
|
post '/settings/integrations/allegro/delivery/save'
|
||||||
|
post '/settings/integrations/allegro/import-single'
|
||||||
|
post '/settings/integrations/allegro/oauth/start'
|
||||||
|
post '/settings/integrations/allegro/save'
|
||||||
|
post '/settings/integrations/allegro/settings/save'
|
||||||
|
post '/settings/integrations/allegro/statuses/delete'
|
||||||
|
post '/settings/integrations/allegro/statuses/save'
|
||||||
|
post '/settings/integrations/allegro/statuses/save-bulk'
|
||||||
|
post '/settings/integrations/allegro/statuses/save-pull'
|
||||||
|
post '/settings/integrations/allegro/statuses/sync'
|
||||||
|
post '/settings/integrations/apaczka/save'
|
||||||
|
post '/settings/integrations/apaczka/test'
|
||||||
|
post '/settings/integrations/erli/delivery/save'
|
||||||
|
post '/settings/integrations/erli/import'
|
||||||
|
post '/settings/integrations/erli/save'
|
||||||
|
post '/settings/integrations/erli/statuses/save-pull'
|
||||||
|
post '/settings/integrations/erli/statuses/save-push'
|
||||||
|
post '/settings/integrations/erli/test'
|
||||||
|
post '/settings/integrations/fakturownia/save'
|
||||||
|
post '/settings/integrations/fakturownia/test'
|
||||||
|
post '/settings/integrations/hostedsms/save'
|
||||||
|
post '/settings/integrations/hostedsms/test'
|
||||||
|
post '/settings/integrations/inpost/save'
|
||||||
|
post '/settings/integrations/polkurier/save'
|
||||||
|
post '/settings/integrations/polkurier/test'
|
||||||
|
post '/settings/integrations/shoppro/delivery/save'
|
||||||
|
post '/settings/integrations/shoppro/save'
|
||||||
|
post '/settings/integrations/shoppro/statuses/save'
|
||||||
|
post '/settings/integrations/shoppro/statuses/save-pull'
|
||||||
|
post '/settings/integrations/shoppro/statuses/sync'
|
||||||
|
post '/settings/integrations/shoppro/test'
|
||||||
|
post '/settings/integrations/smsplanet/save'
|
||||||
|
post '/settings/integrations/smsplanet/test'
|
||||||
|
post '/settings/printing/jobs/delete'
|
||||||
|
post '/settings/printing/keys/{id}/delete'
|
||||||
|
post '/settings/printing/keys/create'
|
||||||
|
post '/settings/project-mappings'
|
||||||
|
post '/settings/project-mappings/{id}/delete'
|
||||||
|
post '/settings/project-mappings/{id}/toggle'
|
||||||
|
post '/settings/project-mappings/{id}/update'
|
||||||
|
post '/settings/sms-templates/delete'
|
||||||
|
post '/settings/sms-templates/save'
|
||||||
|
post '/settings/sms-templates/toggle'
|
||||||
|
post '/settings/statuses/create'
|
||||||
|
post '/settings/statuses/delete'
|
||||||
|
post '/settings/statuses/reorder'
|
||||||
|
post '/settings/statuses/update'
|
||||||
|
post '/settings/status-groups'
|
||||||
|
post '/settings/status-groups/delete'
|
||||||
|
post '/settings/status-groups/reorder'
|
||||||
|
post '/settings/status-groups/update'
|
||||||
|
post '/settings/users'
|
||||||
|
post '/users'
|
||||||
|
post '/webhooks/smsplanet/inbound'
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
get '/'
|
||||||
|
get '/accounting'
|
||||||
|
get '/api/nip/lookup'
|
||||||
|
get '/api/notifications/unread'
|
||||||
|
get '/api/orders/{id}/preview'
|
||||||
|
get '/api/orders/search'
|
||||||
|
get '/api/print/jobs/{id}/download'
|
||||||
|
get '/api/print/jobs/pending'
|
||||||
|
get '/api/print/jobs/status'
|
||||||
|
get '/api/shipment-presets'
|
||||||
|
get '/cron'
|
||||||
|
get '/cron/{tokenValue}'
|
||||||
|
get '/health'
|
||||||
|
get '/info'
|
||||||
|
get '/login'
|
||||||
|
get '/notifications'
|
||||||
|
get '/orders'
|
||||||
|
get '/orders/{id}'
|
||||||
|
get '/orders/{id}/invoice/{invoiceId}'
|
||||||
|
get '/orders/{id}/invoice/{invoiceId}/pdf'
|
||||||
|
get '/orders/{id}/invoice/create'
|
||||||
|
get '/orders/{id}/receipt/{receiptId}'
|
||||||
|
get '/orders/{id}/receipt/{receiptId}/pdf'
|
||||||
|
get '/orders/{id}/receipt/{receiptId}/print'
|
||||||
|
get '/orders/{id}/receipt/create'
|
||||||
|
get '/orders/{id}/shipment/{packageId}/status'
|
||||||
|
get '/orders/{id}/shipment/prepare'
|
||||||
|
get '/orders/{id}/sms/template'
|
||||||
|
get '/orders/list'
|
||||||
|
get '/settings'
|
||||||
|
get '/settings/accounting'
|
||||||
|
get '/settings/accounting/invoices'
|
||||||
|
get '/settings/accounting/invoices/edit'
|
||||||
|
get '/settings/accounting/invoices/issued'
|
||||||
|
get '/settings/accounting/invoices/new'
|
||||||
|
get '/settings/accounting/receipts'
|
||||||
|
get '/settings/accounting/receipts/edit'
|
||||||
|
get '/settings/accounting/receipts/new'
|
||||||
|
get '/settings/automation'
|
||||||
|
get '/settings/automation/create'
|
||||||
|
get '/settings/automation/edit'
|
||||||
|
get '/settings/company'
|
||||||
|
get '/settings/cron'
|
||||||
|
get '/settings/database'
|
||||||
|
get '/settings/delivery-statuses'
|
||||||
|
get '/settings/delivery-statuses/{id}/edit'
|
||||||
|
get '/settings/delivery-statuses/new'
|
||||||
|
get '/settings/delivery-status-mappings'
|
||||||
|
get '/settings/email-mailboxes'
|
||||||
|
get '/settings/email-templates'
|
||||||
|
get '/settings/email-templates/create'
|
||||||
|
get '/settings/email-templates/edit'
|
||||||
|
get '/settings/email-templates/variables'
|
||||||
|
get '/settings/integrations'
|
||||||
|
get '/settings/integrations/allegro'
|
||||||
|
get '/settings/integrations/allegro/oauth/callback'
|
||||||
|
get '/settings/integrations/apaczka'
|
||||||
|
get '/settings/integrations/erli'
|
||||||
|
get '/settings/integrations/fakturownia'
|
||||||
|
get '/settings/integrations/fakturownia/edit'
|
||||||
|
get '/settings/integrations/fakturownia/new'
|
||||||
|
get '/settings/integrations/hostedsms'
|
||||||
|
get '/settings/integrations/inpost'
|
||||||
|
get '/settings/integrations/polkurier'
|
||||||
|
get '/settings/integrations/shoppro'
|
||||||
|
get '/settings/integrations/smsplanet'
|
||||||
|
get '/settings/printing'
|
||||||
|
get '/settings/project-mappings'
|
||||||
|
get '/settings/sms-templates'
|
||||||
|
get '/settings/sms-templates/create'
|
||||||
|
get '/settings/sms-templates/edit'
|
||||||
|
get '/settings/sms-templates/variables'
|
||||||
|
get '/settings/statuses'
|
||||||
|
get '/settings/users'
|
||||||
|
get '/statistics/orders'
|
||||||
|
get '/statistics/summary'
|
||||||
|
get '/users'
|
||||||
|
get '/webhooks/smsplanet/inbound'
|
||||||
|
post '/accounting/export'
|
||||||
|
post '/api/notifications/mark-read'
|
||||||
|
post '/api/print/jobs'
|
||||||
|
post '/api/print/jobs/{id}/complete'
|
||||||
|
post '/api/shipment-presets'
|
||||||
|
post '/api/shipment-presets/delete'
|
||||||
|
post '/api/shipment-presets/update'
|
||||||
|
post '/login'
|
||||||
|
post '/logout'
|
||||||
|
post '/notifications/mark-read'
|
||||||
|
post '/orders/{id}/details/update'
|
||||||
|
post '/orders/{id}/email-preview'
|
||||||
|
post '/orders/{id}/invoice/store'
|
||||||
|
post '/orders/{id}/invoice-requested/toggle'
|
||||||
|
post '/orders/{id}/notes'
|
||||||
|
post '/orders/{id}/notes/{noteId}/delete'
|
||||||
|
post '/orders/{id}/notes/{noteId}/update'
|
||||||
|
post '/orders/{id}/payment/add'
|
||||||
|
post '/orders/{id}/receipt/store'
|
||||||
|
post '/orders/{id}/send-email'
|
||||||
|
post '/orders/{id}/shipment/{packageId}/delete'
|
||||||
|
post '/orders/{id}/shipment/{packageId}/label'
|
||||||
|
post '/orders/{id}/shipment/create'
|
||||||
|
post '/orders/{id}/shipment/manual'
|
||||||
|
post '/orders/{id}/sms/send'
|
||||||
|
post '/orders/{id}/status'
|
||||||
|
post '/settings/accounting/delete'
|
||||||
|
post '/settings/accounting/invoices/delete'
|
||||||
|
post '/settings/accounting/invoices/save'
|
||||||
|
post '/settings/accounting/invoices/toggle'
|
||||||
|
post '/settings/accounting/receipts/delete'
|
||||||
|
post '/settings/accounting/receipts/save'
|
||||||
|
post '/settings/accounting/receipts/toggle'
|
||||||
|
post '/settings/accounting/save'
|
||||||
|
post '/settings/accounting/toggle'
|
||||||
|
post '/settings/automation/delete'
|
||||||
|
post '/settings/automation/duplicate'
|
||||||
|
post '/settings/automation/store'
|
||||||
|
post '/settings/automation/toggle'
|
||||||
|
post '/settings/automation/update'
|
||||||
|
post '/settings/company/save'
|
||||||
|
post '/settings/cron'
|
||||||
|
post '/settings/database/migrate'
|
||||||
|
post '/settings/delivery-statuses'
|
||||||
|
post '/settings/delivery-statuses/{id}/delete'
|
||||||
|
post '/settings/delivery-statuses/{id}/update'
|
||||||
|
post '/settings/delivery-status-mappings/reset'
|
||||||
|
post '/settings/delivery-status-mappings/reset-all'
|
||||||
|
post '/settings/delivery-status-mappings/save'
|
||||||
|
post '/settings/delivery-status-mappings/save-bulk'
|
||||||
|
post '/settings/email-mailboxes/delete'
|
||||||
|
post '/settings/email-mailboxes/save'
|
||||||
|
post '/settings/email-mailboxes/test'
|
||||||
|
post '/settings/email-mailboxes/toggle'
|
||||||
|
post '/settings/email-templates/delete'
|
||||||
|
post '/settings/email-templates/duplicate'
|
||||||
|
post '/settings/email-templates/preview'
|
||||||
|
post '/settings/email-templates/save'
|
||||||
|
post '/settings/email-templates/toggle'
|
||||||
|
post '/settings/integrations/allegro/delivery/save'
|
||||||
|
post '/settings/integrations/allegro/import-single'
|
||||||
|
post '/settings/integrations/allegro/oauth/start'
|
||||||
|
post '/settings/integrations/allegro/save'
|
||||||
|
post '/settings/integrations/allegro/settings/save'
|
||||||
|
post '/settings/integrations/allegro/statuses/delete'
|
||||||
|
post '/settings/integrations/allegro/statuses/save'
|
||||||
|
post '/settings/integrations/allegro/statuses/save-bulk'
|
||||||
|
post '/settings/integrations/allegro/statuses/save-pull'
|
||||||
|
post '/settings/integrations/allegro/statuses/sync'
|
||||||
|
post '/settings/integrations/apaczka/save'
|
||||||
|
post '/settings/integrations/apaczka/test'
|
||||||
|
post '/settings/integrations/erli/delivery/save'
|
||||||
|
post '/settings/integrations/erli/import'
|
||||||
|
post '/settings/integrations/erli/save'
|
||||||
|
post '/settings/integrations/erli/statuses/save-pull'
|
||||||
|
post '/settings/integrations/erli/statuses/save-push'
|
||||||
|
post '/settings/integrations/erli/test'
|
||||||
|
post '/settings/integrations/fakturownia/save'
|
||||||
|
post '/settings/integrations/fakturownia/test'
|
||||||
|
post '/settings/integrations/hostedsms/save'
|
||||||
|
post '/settings/integrations/hostedsms/test'
|
||||||
|
post '/settings/integrations/inpost/save'
|
||||||
|
post '/settings/integrations/polkurier/save'
|
||||||
|
post '/settings/integrations/polkurier/test'
|
||||||
|
post '/settings/integrations/shoppro/delivery/save'
|
||||||
|
post '/settings/integrations/shoppro/save'
|
||||||
|
post '/settings/integrations/shoppro/statuses/save'
|
||||||
|
post '/settings/integrations/shoppro/statuses/save-pull'
|
||||||
|
post '/settings/integrations/shoppro/statuses/sync'
|
||||||
|
post '/settings/integrations/shoppro/test'
|
||||||
|
post '/settings/integrations/smsplanet/save'
|
||||||
|
post '/settings/integrations/smsplanet/test'
|
||||||
|
post '/settings/printing/jobs/delete'
|
||||||
|
post '/settings/printing/keys/{id}/delete'
|
||||||
|
post '/settings/printing/keys/create'
|
||||||
|
post '/settings/project-mappings'
|
||||||
|
post '/settings/project-mappings/{id}/delete'
|
||||||
|
post '/settings/project-mappings/{id}/toggle'
|
||||||
|
post '/settings/project-mappings/{id}/update'
|
||||||
|
post '/settings/sms-templates/delete'
|
||||||
|
post '/settings/sms-templates/save'
|
||||||
|
post '/settings/sms-templates/toggle'
|
||||||
|
post '/settings/statuses/create'
|
||||||
|
post '/settings/statuses/delete'
|
||||||
|
post '/settings/statuses/reorder'
|
||||||
|
post '/settings/statuses/update'
|
||||||
|
post '/settings/status-groups'
|
||||||
|
post '/settings/status-groups/delete'
|
||||||
|
post '/settings/status-groups/reorder'
|
||||||
|
post '/settings/status-groups/update'
|
||||||
|
post '/settings/users'
|
||||||
|
post '/users'
|
||||||
|
post '/webhooks/smsplanet/inbound'
|
||||||
82
bin/smoke_routes.php
Normal file
82
bin/smoke_routes.php
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
|
||||||
|
// Stubowany Application — tylko config() i basePath() musza dzialac;
|
||||||
|
// register() w wiekszosci modulow nie dotyka DB, bo factory sa leniwe.
|
||||||
|
$basePath = realpath(__DIR__ . '/..');
|
||||||
|
$mergedConfig = [
|
||||||
|
'app' => require $basePath . '/config/app.php',
|
||||||
|
'database' => require $basePath . '/config/database.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Pomijamy ShipmentsModule (eager side-effect: DeliveryStatus::setRepository, ktore wymaga PDO).
|
||||||
|
$moduleClasses = [
|
||||||
|
App\Modules\Info\InfoModule::class,
|
||||||
|
App\Modules\Auth\AuthModule::class,
|
||||||
|
App\Modules\Users\UsersModule::class,
|
||||||
|
App\Modules\Cron\CronModule::class,
|
||||||
|
App\Modules\Settings\SettingsModule::class,
|
||||||
|
App\Modules\Notifications\NotificationsModule::class,
|
||||||
|
App\Modules\Email\EmailModule::class,
|
||||||
|
App\Modules\Sms\SmsModule::class,
|
||||||
|
App\Modules\Accounting\AccountingModule::class,
|
||||||
|
App\Modules\Automation\AutomationModule::class,
|
||||||
|
App\Modules\Printing\PrintingModule::class,
|
||||||
|
App\Modules\Orders\OrdersModule::class,
|
||||||
|
App\Modules\Statistics\StatisticsModule::class,
|
||||||
|
App\Modules\Settings\IntegrationsHubModule::class,
|
||||||
|
App\Modules\Settings\AllegroIntegrationModule::class,
|
||||||
|
App\Modules\Settings\ApaczkaIntegrationModule::class,
|
||||||
|
App\Modules\Settings\InpostIntegrationModule::class,
|
||||||
|
App\Modules\Settings\ShopproIntegrationModule::class,
|
||||||
|
App\Modules\Settings\ErliIntegrationModule::class,
|
||||||
|
App\Modules\Settings\PolkurierIntegrationModule::class,
|
||||||
|
App\Modules\Settings\FakturowniaIntegrationModule::class,
|
||||||
|
App\Modules\Settings\HostedSmsIntegrationModule::class,
|
||||||
|
App\Modules\Settings\SmsplanetIntegrationModule::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Real Application (will try to connect to DB; if fails, suppress).
|
||||||
|
$app = null;
|
||||||
|
try {
|
||||||
|
$app = new Application($basePath, $mergedConfig);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo 'WARN: Application could not boot (DB unavailable). Smoke test limited to register().' . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($app === null) {
|
||||||
|
echo 'SKIP: bez DB nie da sie wykonac register().' . PHP_EOL;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$services = new ServiceRegistry();
|
||||||
|
$errors = [];
|
||||||
|
foreach ($moduleClasses as $cls) {
|
||||||
|
try {
|
||||||
|
$module = new $cls();
|
||||||
|
$module->register($services, $app);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$errors[] = $cls . ': ' . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($errors !== []) {
|
||||||
|
foreach ($errors as $e) {
|
||||||
|
echo 'ERR: ' . $e . PHP_EOL;
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo 'OK: register() wykonane na ' . count($moduleClasses) . ' modulach.' . PHP_EOL;
|
||||||
|
echo 'Zarejestrowane klucze (lazy, nie skonstruowane): zliczenie via reflection.' . PHP_EOL;
|
||||||
|
|
||||||
|
$ref = new ReflectionClass(ServiceRegistry::class);
|
||||||
|
$prop = $ref->getProperty('factories');
|
||||||
|
$prop->setAccessible(true);
|
||||||
|
$factories = $prop->getValue($services);
|
||||||
|
echo 'Liczba kluczy: ' . count($factories) . PHP_EOL;
|
||||||
913
routes/web.php
913
routes/web.php
@@ -2,858 +2,77 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use App\Core\Application;
|
use App\Core\Application;
|
||||||
use App\Core\Http\Request;
|
use App\Core\Routing\ServiceRegistry;
|
||||||
use App\Core\Http\Response;
|
use App\Modules\Accounting\AccountingModule;
|
||||||
use App\Modules\Auth\AuthController;
|
|
||||||
use App\Modules\Auth\AuthMiddleware;
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
use App\Modules\Cron\CronHandlerFactory;
|
use App\Modules\Auth\AuthModule;
|
||||||
use App\Modules\Cron\CronRepository;
|
use App\Modules\Automation\AutomationModule;
|
||||||
use App\Modules\Orders\OrdersController;
|
use App\Modules\Cron\CronModule;
|
||||||
use App\Modules\Orders\OrderImportRepository;
|
use App\Modules\Email\EmailModule;
|
||||||
use App\Modules\Orders\OrderNotesService;
|
use App\Modules\Info\InfoModule;
|
||||||
use App\Modules\Orders\OrdersRepository;
|
use App\Modules\Notifications\NotificationsModule;
|
||||||
use App\Modules\Statistics\OrdersStatisticsController;
|
use App\Modules\Orders\OrdersModule;
|
||||||
use App\Modules\Statistics\OrdersStatisticsRepository;
|
use App\Modules\Printing\PrintingModule;
|
||||||
use App\Modules\Settings\AllegroApiClient;
|
use App\Modules\Settings\AllegroIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroDeliveryMappingController;
|
use App\Modules\Settings\ApaczkaIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroIntegrationController;
|
use App\Modules\Settings\ErliIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroIntegrationRepository;
|
use App\Modules\Settings\FakturowniaIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroOAuthClient;
|
use App\Modules\Settings\HostedSmsIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroOrderImportService;
|
use App\Modules\Settings\InpostIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroPullStatusMappingRepository;
|
use App\Modules\Settings\IntegrationsHubModule;
|
||||||
use App\Modules\Settings\AllegroStatusDiscoveryService;
|
use App\Modules\Settings\PolkurierIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroStatusMappingController;
|
use App\Modules\Settings\SettingsModule;
|
||||||
use App\Modules\Settings\AllegroTokenManager;
|
use App\Modules\Settings\ShopproIntegrationModule;
|
||||||
use App\Modules\Settings\AllegroStatusMappingRepository;
|
use App\Modules\Settings\SmsplanetIntegrationModule;
|
||||||
use App\Modules\Settings\OrderStatusRepository;
|
use App\Modules\Shipments\ShipmentsModule;
|
||||||
use App\Modules\Settings\ApaczkaApiClient;
|
use App\Modules\Sms\SmsModule;
|
||||||
use App\Modules\Settings\ApaczkaIntegrationController;
|
use App\Modules\Statistics\StatisticsModule;
|
||||||
use App\Modules\Settings\ApaczkaIntegrationRepository;
|
use App\Modules\Users\UsersModule;
|
||||||
use App\Modules\Settings\CarrierDeliveryMethodMappingRepository;
|
|
||||||
use App\Modules\Settings\ErliApiClient;
|
|
||||||
use App\Modules\Settings\ErliDeliveryMappingController;
|
|
||||||
use App\Modules\Settings\ErliExternalShipmentService;
|
|
||||||
use App\Modules\Settings\ErliIntegrationController;
|
|
||||||
use App\Modules\Settings\ErliIntegrationRepository;
|
|
||||||
use App\Modules\Settings\ErliOrderMapper;
|
|
||||||
use App\Modules\Settings\ErliOrderSyncStateRepository;
|
|
||||||
use App\Modules\Settings\ErliOrdersSyncService;
|
|
||||||
use App\Modules\Settings\ErliPullStatusMappingRepository;
|
|
||||||
use App\Modules\Settings\ErliStatusMappingRepository;
|
|
||||||
use App\Modules\Settings\FakturowniaApiClient;
|
|
||||||
use App\Modules\Settings\FakturowniaIntegrationController;
|
|
||||||
use App\Modules\Settings\FakturowniaIntegrationRepository;
|
|
||||||
use App\Modules\Settings\HostedSmsApiClient;
|
|
||||||
use App\Modules\Settings\HostedSmsIntegrationController;
|
|
||||||
use App\Modules\Settings\HostedSmsIntegrationRepository;
|
|
||||||
use App\Modules\Settings\InpostIntegrationController;
|
|
||||||
use App\Modules\Settings\InpostIntegrationRepository;
|
|
||||||
use App\Modules\Settings\IntegrationsHubController;
|
|
||||||
use App\Modules\Settings\IntegrationsRepository;
|
|
||||||
use App\Modules\Settings\PolkurierApiClient;
|
|
||||||
use App\Modules\Settings\PolkurierIntegrationController;
|
|
||||||
use App\Modules\Settings\PolkurierIntegrationRepository;
|
|
||||||
use App\Modules\Settings\SmsplanetApiClient;
|
|
||||||
use App\Modules\Settings\SmsplanetIntegrationController;
|
|
||||||
use App\Modules\Settings\SmsplanetIntegrationRepository;
|
|
||||||
use App\Modules\Settings\ShopproIntegrationsController;
|
|
||||||
use App\Modules\Settings\ShopproIntegrationsRepository;
|
|
||||||
use App\Modules\Settings\ShopproPullStatusMappingRepository;
|
|
||||||
use App\Modules\Settings\ShopproStatusMappingRepository;
|
|
||||||
use App\Modules\Settings\CompanySettingsController;
|
|
||||||
use App\Modules\Settings\CompanySettingsRepository;
|
|
||||||
use App\Modules\Settings\InvoiceConfigController;
|
|
||||||
use App\Modules\Settings\InvoiceConfigRepository;
|
|
||||||
use App\Modules\Settings\ReceiptConfigController;
|
|
||||||
use App\Modules\Settings\ReceiptConfigRepository;
|
|
||||||
use App\Modules\Settings\EmailMailboxController;
|
|
||||||
use App\Modules\Settings\EmailMailboxRepository;
|
|
||||||
use App\Modules\Settings\EmailTemplateController;
|
|
||||||
use App\Modules\Settings\EmailTemplateRepository;
|
|
||||||
use App\Modules\Settings\SmsTemplateController;
|
|
||||||
use App\Modules\Settings\IntegrationSecretCipher;
|
|
||||||
use App\Modules\Settings\SmtpSecurityContextFactory;
|
|
||||||
use App\Modules\Email\AttachmentGenerator;
|
|
||||||
use App\Modules\Email\EmailSendingService;
|
|
||||||
use App\Modules\Email\VariableResolver;
|
|
||||||
use App\Modules\Accounting\AccountingController;
|
|
||||||
use App\Core\Http\MfWhitelistApiClient;
|
|
||||||
use App\Modules\Accounting\InvoiceController;
|
|
||||||
use App\Modules\Accounting\InvoiceRepository;
|
|
||||||
use App\Modules\Accounting\InvoiceService;
|
|
||||||
use App\Modules\Accounting\ReceiptController;
|
|
||||||
use App\Modules\Accounting\ReceiptRepository;
|
|
||||||
use App\Modules\Accounting\ReceiptService;
|
|
||||||
use App\Modules\Automation\AutomationController;
|
|
||||||
use App\Modules\Automation\AutomationRepository;
|
|
||||||
use App\Modules\Automation\AutomationService;
|
|
||||||
use App\Modules\Automation\AutomationExecutionLogRepository;
|
|
||||||
use App\Modules\Automation\AutomationEmailOnceRepository;
|
|
||||||
use App\Modules\Settings\CronSettingsController;
|
|
||||||
use App\Modules\Settings\DeliveryStatusMappingController;
|
|
||||||
use App\Modules\Settings\DeliveryStatusesController;
|
|
||||||
use App\Modules\Settings\SettingsController;
|
|
||||||
use App\Modules\Shipments\ApaczkaShipmentService;
|
|
||||||
use App\Modules\Shipments\PolkurierShipmentService;
|
|
||||||
use App\Modules\Shipments\AllegroShipmentService;
|
|
||||||
use App\Modules\Shipments\InpostShipmentService;
|
|
||||||
use App\Modules\Shipments\ShipmentController;
|
|
||||||
use App\Modules\Shipments\ShipmentPackageRepository;
|
|
||||||
use App\Modules\Shipments\ShipmentPresetController;
|
|
||||||
use App\Modules\Shipments\DeliveryStatusMappingRepository;
|
|
||||||
use App\Modules\Shipments\DeliveryStatusRepository;
|
|
||||||
use App\Modules\Shipments\ShipmentPresetRepository;
|
|
||||||
use App\Modules\Shipments\ShipmentProviderRegistry;
|
|
||||||
use App\Modules\Printing\ApiKeyMiddleware;
|
|
||||||
use App\Modules\Printing\PrintApiController;
|
|
||||||
use App\Modules\Printing\PrintApiKeyRepository;
|
|
||||||
use App\Modules\Printing\PrintJobRepository;
|
|
||||||
use App\Modules\Settings\PrintSettingsController;
|
|
||||||
use App\Modules\Settings\ProjectMappingController;
|
|
||||||
use App\Modules\Settings\ProjectMappingRepository;
|
|
||||||
use App\Modules\Info\InfoController;
|
|
||||||
use App\Modules\Notifications\NotificationApiController;
|
|
||||||
use App\Modules\Notifications\NotificationController;
|
|
||||||
use App\Modules\Notifications\NotificationRepository;
|
|
||||||
use App\Modules\Sms\SmsConversationService;
|
|
||||||
use App\Modules\Sms\SmsMessageRepository;
|
|
||||||
use App\Modules\Sms\SmsTemplateRepository;
|
|
||||||
use App\Modules\Sms\SmsVariableResolver;
|
|
||||||
use App\Modules\Sms\SmsplanetWebhookController;
|
|
||||||
use App\Modules\Users\UsersController;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modular routing entrypoint.
|
||||||
|
*
|
||||||
|
* Kazdy modul (src/Modules/<Modul>/<Modul>Module.php) implementuje ModuleProvider:
|
||||||
|
* - register(): zglasza swoje serwisy do ServiceRegistry (lazy factory),
|
||||||
|
* - routes(): rejestruje route'y, uzywajac $services->lazy(id, method).
|
||||||
|
*
|
||||||
|
* Kolejnosc rejestracji nie ma znaczenia (factory sa wywolywane dopiero przy get()).
|
||||||
|
*/
|
||||||
return static function (Application $app): void {
|
return static function (Application $app): void {
|
||||||
$router = $app->router();
|
$modules = [
|
||||||
$template = $app->template();
|
new InfoModule(),
|
||||||
$auth = $app->auth();
|
new AuthModule(),
|
||||||
$translator = $app->translator();
|
new UsersModule(),
|
||||||
|
new CronModule(),
|
||||||
|
new SettingsModule(),
|
||||||
|
new NotificationsModule(),
|
||||||
|
new EmailModule(),
|
||||||
|
new SmsModule(),
|
||||||
|
new AccountingModule(),
|
||||||
|
new AutomationModule(),
|
||||||
|
new ShipmentsModule(),
|
||||||
|
new PrintingModule(),
|
||||||
|
new OrdersModule(),
|
||||||
|
new StatisticsModule(),
|
||||||
|
new IntegrationsHubModule(),
|
||||||
|
new AllegroIntegrationModule(),
|
||||||
|
new ApaczkaIntegrationModule(),
|
||||||
|
new InpostIntegrationModule(),
|
||||||
|
new ShopproIntegrationModule(),
|
||||||
|
new ErliIntegrationModule(),
|
||||||
|
new PolkurierIntegrationModule(),
|
||||||
|
new FakturowniaIntegrationModule(),
|
||||||
|
new HostedSmsIntegrationModule(),
|
||||||
|
new SmsplanetIntegrationModule(),
|
||||||
|
];
|
||||||
|
|
||||||
$authController = new AuthController($template, $auth, $translator);
|
$services = new ServiceRegistry();
|
||||||
$usersController = new UsersController($template, $translator, $auth, $app->users());
|
foreach ($modules as $module) {
|
||||||
$shipmentPackageRepositoryForOrders = new ShipmentPackageRepository($app->db());
|
$module->register($services, $app);
|
||||||
$receiptConfigRepository = new ReceiptConfigRepository($app->db());
|
|
||||||
$receiptRepository = new ReceiptRepository($app->db());
|
|
||||||
$settingsController = new SettingsController($template, $translator, $auth, $app->migrator(), $app->orderStatuses());
|
|
||||||
$allegroIntegrationRepository = new AllegroIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$allegroStatusMappingRepository = new AllegroStatusMappingRepository($app->db());
|
|
||||||
$carrierDeliveryMappings = new CarrierDeliveryMethodMappingRepository($app->db());
|
|
||||||
$allegroOAuthClient = new AllegroOAuthClient();
|
|
||||||
$allegroTokenManager = new AllegroTokenManager($allegroIntegrationRepository, $allegroOAuthClient);
|
|
||||||
$apaczkaApiClient = new ApaczkaApiClient();
|
|
||||||
$cronRepository = new CronRepository($app->db());
|
|
||||||
$apaczkaIntegrationRepository = new ApaczkaIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$allegroPullStatusMappingRepository = new AllegroPullStatusMappingRepository($app->db());
|
|
||||||
$allegroStatusDiscoveryService = new AllegroStatusDiscoveryService(
|
|
||||||
$allegroTokenManager,
|
|
||||||
new AllegroApiClient(),
|
|
||||||
$allegroStatusMappingRepository,
|
|
||||||
$allegroPullStatusMappingRepository
|
|
||||||
);
|
|
||||||
$allegroStatusMappingController = new AllegroStatusMappingController(
|
|
||||||
$translator,
|
|
||||||
$allegroStatusMappingRepository,
|
|
||||||
$app->orderStatuses(),
|
|
||||||
$allegroStatusDiscoveryService,
|
|
||||||
$allegroPullStatusMappingRepository
|
|
||||||
);
|
|
||||||
$allegroDeliveryMappingController = new AllegroDeliveryMappingController(
|
|
||||||
$translator,
|
|
||||||
$allegroIntegrationRepository,
|
|
||||||
$allegroOAuthClient,
|
|
||||||
new AllegroApiClient(),
|
|
||||||
$carrierDeliveryMappings,
|
|
||||||
$apaczkaIntegrationRepository,
|
|
||||||
$apaczkaApiClient
|
|
||||||
);
|
|
||||||
$apaczkaIntegrationController = new ApaczkaIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$apaczkaIntegrationRepository,
|
|
||||||
$apaczkaApiClient
|
|
||||||
);
|
|
||||||
$inpostIntegrationRepository = new InpostIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$inpostIntegrationController = new InpostIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$inpostIntegrationRepository
|
|
||||||
);
|
|
||||||
$companySettingsRepository = new CompanySettingsRepository($app->db());
|
|
||||||
$shipmentPackageRepository = new ShipmentPackageRepository($app->db());
|
|
||||||
$polkurierIntegrationRepository = new PolkurierIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$polkurierShipmentService = new PolkurierShipmentService(
|
|
||||||
$polkurierIntegrationRepository,
|
|
||||||
new PolkurierApiClient(),
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db())
|
|
||||||
);
|
|
||||||
$shopproIntegrationsRepository = new ShopproIntegrationsRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$shopproIntegrationsController = new ShopproIntegrationsController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$shopproIntegrationsRepository,
|
|
||||||
new ShopproStatusMappingRepository($app->db()),
|
|
||||||
new ShopproPullStatusMappingRepository($app->db()),
|
|
||||||
$app->orderStatuses(),
|
|
||||||
$cronRepository,
|
|
||||||
$carrierDeliveryMappings,
|
|
||||||
$allegroIntegrationRepository,
|
|
||||||
$allegroOAuthClient,
|
|
||||||
new AllegroApiClient(),
|
|
||||||
$apaczkaIntegrationRepository,
|
|
||||||
$apaczkaApiClient,
|
|
||||||
$polkurierShipmentService
|
|
||||||
);
|
|
||||||
$fakturowniaIntegrationRepository = new FakturowniaIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$fakturowniaApiClient = new FakturowniaApiClient();
|
|
||||||
$fakturowniaIntegrationController = new FakturowniaIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$fakturowniaIntegrationRepository,
|
|
||||||
$fakturowniaApiClient,
|
|
||||||
new IntegrationsRepository($app->db())
|
|
||||||
);
|
|
||||||
$hostedSmsIntegrationRepository = new HostedSmsIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$hostedSmsIntegrationController = new HostedSmsIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$hostedSmsIntegrationRepository,
|
|
||||||
new HostedSmsApiClient(),
|
|
||||||
new IntegrationsRepository($app->db())
|
|
||||||
);
|
|
||||||
$polkurierIntegrationController = new PolkurierIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$polkurierIntegrationRepository,
|
|
||||||
new PolkurierApiClient(),
|
|
||||||
new IntegrationsRepository($app->db())
|
|
||||||
);
|
|
||||||
$smsplanetIntegrationRepository = new SmsplanetIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$smsplanetIntegrationController = new SmsplanetIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$smsplanetIntegrationRepository,
|
|
||||||
new SmsplanetApiClient(),
|
|
||||||
new IntegrationsRepository($app->db())
|
|
||||||
);
|
|
||||||
$erliIntegrationRepository = new ErliIntegrationRepository(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', '')
|
|
||||||
);
|
|
||||||
$erliPullStatusMappingRepository = new ErliPullStatusMappingRepository($app->db());
|
|
||||||
$erliStatusMappingRepository = new ErliStatusMappingRepository($app->db());
|
|
||||||
$notificationRepository = new NotificationRepository($app->db());
|
|
||||||
$smsMessageRepository = new SmsMessageRepository($app->db());
|
|
||||||
$smsConversationService = new SmsConversationService(
|
|
||||||
$smsMessageRepository,
|
|
||||||
$smsplanetIntegrationRepository,
|
|
||||||
new SmsplanetApiClient(),
|
|
||||||
$notificationRepository
|
|
||||||
);
|
|
||||||
$smsplanetWebhookController = new SmsplanetWebhookController($smsConversationService);
|
|
||||||
$notificationController = new NotificationController($template, $translator, $auth, $notificationRepository);
|
|
||||||
$notificationApiController = new NotificationApiController($notificationRepository);
|
|
||||||
$integrationsHubController = new IntegrationsHubController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
new IntegrationsRepository($app->db()),
|
|
||||||
$allegroIntegrationRepository,
|
|
||||||
$apaczkaIntegrationRepository,
|
|
||||||
$inpostIntegrationRepository,
|
|
||||||
$shopproIntegrationsRepository,
|
|
||||||
$fakturowniaIntegrationRepository,
|
|
||||||
$hostedSmsIntegrationRepository,
|
|
||||||
$smsplanetIntegrationRepository,
|
|
||||||
$polkurierIntegrationRepository,
|
|
||||||
$erliIntegrationRepository
|
|
||||||
);
|
|
||||||
$cronSettingsController = new CronSettingsController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$cronRepository,
|
|
||||||
(bool) $app->config('app.cron.run_on_web_default', false),
|
|
||||||
(int) $app->config('app.cron.web_limit_default', 5)
|
|
||||||
);
|
|
||||||
$deliveryStatusMappingRepository = new DeliveryStatusMappingRepository($app->db());
|
|
||||||
$deliveryStatusRepository = new DeliveryStatusRepository($app->db());
|
|
||||||
\App\Modules\Shipments\DeliveryStatus::setRepository($deliveryStatusRepository);
|
|
||||||
$deliveryStatusesController = new DeliveryStatusesController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$deliveryStatusRepository,
|
|
||||||
$deliveryStatusMappingRepository
|
|
||||||
);
|
|
||||||
$deliveryStatusMappingController = new DeliveryStatusMappingController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$deliveryStatusMappingRepository,
|
|
||||||
$deliveryStatusRepository
|
|
||||||
);
|
|
||||||
$companySettingsController = new CompanySettingsController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$companySettingsRepository
|
|
||||||
);
|
|
||||||
$receiptConfigController = new ReceiptConfigController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$receiptConfigRepository
|
|
||||||
);
|
|
||||||
$invoiceConfigRepository = new InvoiceConfigRepository($app->db(), $fakturowniaIntegrationRepository);
|
|
||||||
$invoiceConfigController = new InvoiceConfigController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$invoiceConfigRepository,
|
|
||||||
$fakturowniaIntegrationRepository
|
|
||||||
);
|
|
||||||
$invoiceRepository = new InvoiceRepository($app->db());
|
|
||||||
$emailMailboxRepository = new EmailMailboxRepository(
|
|
||||||
$app->db(),
|
|
||||||
new IntegrationSecretCipher((string) $app->config('app.integrations.secret', ''))
|
|
||||||
);
|
|
||||||
$emailMailboxController = new EmailMailboxController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$emailMailboxRepository,
|
|
||||||
new SmtpSecurityContextFactory((bool) $app->config('app.smtp.allow_self_signed_dev', false))
|
|
||||||
);
|
|
||||||
$emailTemplateRepository = new EmailTemplateRepository($app->db());
|
|
||||||
$emailTemplateController = new EmailTemplateController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$emailTemplateRepository,
|
|
||||||
$emailMailboxRepository
|
|
||||||
);
|
|
||||||
$smsTemplateRepository = new SmsTemplateRepository($app->db());
|
|
||||||
$smsTemplateController = new SmsTemplateController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$smsTemplateRepository
|
|
||||||
);
|
|
||||||
$automationRepository = new AutomationRepository($app->db());
|
|
||||||
$automationExecutionLogRepository = new AutomationExecutionLogRepository($app->db());
|
|
||||||
$automationController = new AutomationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$automationRepository,
|
|
||||||
$automationExecutionLogRepository,
|
|
||||||
$receiptConfigRepository
|
|
||||||
);
|
|
||||||
$smsVariableResolver = new SmsVariableResolver($shipmentPackageRepositoryForOrders);
|
|
||||||
$variableResolver = new VariableResolver($shipmentPackageRepositoryForOrders, $smsVariableResolver);
|
|
||||||
$attachmentGenerator = new AttachmentGenerator($receiptRepository, $receiptConfigRepository, $template);
|
|
||||||
$emailSendingService = new EmailSendingService(
|
|
||||||
$app->db(),
|
|
||||||
$app->orders(),
|
|
||||||
$emailTemplateRepository,
|
|
||||||
$emailMailboxRepository,
|
|
||||||
$variableResolver,
|
|
||||||
$attachmentGenerator
|
|
||||||
);
|
|
||||||
$receiptService = new ReceiptService(
|
|
||||||
$receiptRepository,
|
|
||||||
$receiptConfigRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db())
|
|
||||||
);
|
|
||||||
$invoiceService = new InvoiceService(
|
|
||||||
$invoiceRepository,
|
|
||||||
$invoiceConfigRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db()),
|
|
||||||
$fakturowniaIntegrationRepository,
|
|
||||||
$fakturowniaApiClient
|
|
||||||
);
|
|
||||||
$automationService = new AutomationService(
|
|
||||||
$automationRepository,
|
|
||||||
$automationExecutionLogRepository,
|
|
||||||
new AutomationEmailOnceRepository($app->db()),
|
|
||||||
$emailSendingService,
|
|
||||||
new OrdersRepository($app->db()),
|
|
||||||
$companySettingsRepository,
|
|
||||||
$receiptRepository,
|
|
||||||
$receiptConfigRepository,
|
|
||||||
$shipmentPackageRepositoryForOrders,
|
|
||||||
$receiptService
|
|
||||||
);
|
|
||||||
$erliOrdersSyncService = new ErliOrdersSyncService(
|
|
||||||
$erliIntegrationRepository,
|
|
||||||
new ErliOrderSyncStateRepository($app->db()),
|
|
||||||
new ErliApiClient(),
|
|
||||||
new OrderImportRepository($app->db()),
|
|
||||||
new OrdersRepository($app->db()),
|
|
||||||
new ErliOrderMapper($erliPullStatusMappingRepository),
|
|
||||||
$automationService,
|
|
||||||
$erliPullStatusMappingRepository
|
|
||||||
);
|
|
||||||
$allegroIntegrationController = new AllegroIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$allegroIntegrationRepository,
|
|
||||||
$allegroStatusMappingRepository,
|
|
||||||
$allegroPullStatusMappingRepository,
|
|
||||||
$app->orderStatuses(),
|
|
||||||
$cronRepository,
|
|
||||||
$allegroOAuthClient,
|
|
||||||
new AllegroOrderImportService(
|
|
||||||
$allegroIntegrationRepository,
|
|
||||||
$allegroTokenManager,
|
|
||||||
new AllegroApiClient(),
|
|
||||||
new OrderImportRepository($app->db()),
|
|
||||||
$allegroStatusMappingRepository,
|
|
||||||
new OrdersRepository($app->db()),
|
|
||||||
new AllegroPullStatusMappingRepository($app->db()),
|
|
||||||
$automationService
|
|
||||||
),
|
|
||||||
$allegroStatusDiscoveryService,
|
|
||||||
(string) $app->config('app.url', ''),
|
|
||||||
$allegroDeliveryMappingController
|
|
||||||
);
|
|
||||||
$printJobRepository = new PrintJobRepository($app->db());
|
|
||||||
$orderNotesService = new OrderNotesService($app->db());
|
|
||||||
$ordersController = new OrdersController($template, $translator, $auth, $app->orders(), $shipmentPackageRepositoryForOrders, $receiptRepository, $receiptConfigRepository, $emailSendingService, $emailTemplateRepository, $emailMailboxRepository, $app->basePath('storage'), $printJobRepository, $shopproIntegrationsRepository, $automationService, $invoiceRepository, $invoiceConfigRepository, $smsMessageRepository, $smsConversationService, $smsTemplateRepository, $smsVariableResolver, $companySettingsRepository, $orderNotesService);
|
|
||||||
$ordersStatisticsController = new OrdersStatisticsController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
new OrdersStatisticsRepository($app->db())
|
|
||||||
);
|
|
||||||
$receiptController = new ReceiptController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$receiptRepository,
|
|
||||||
$receiptConfigRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db()),
|
|
||||||
$automationService,
|
|
||||||
$receiptService
|
|
||||||
);
|
|
||||||
$accountingController = new AccountingController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$receiptRepository,
|
|
||||||
$receiptConfigRepository
|
|
||||||
);
|
|
||||||
$invoiceController = new InvoiceController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$invoiceRepository,
|
|
||||||
$invoiceConfigRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db()),
|
|
||||||
$invoiceService,
|
|
||||||
new MfWhitelistApiClient()
|
|
||||||
);
|
|
||||||
$allegroApiClient = new AllegroApiClient();
|
|
||||||
$shipmentService = new AllegroShipmentService(
|
|
||||||
$allegroTokenManager,
|
|
||||||
$allegroApiClient,
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db())
|
|
||||||
);
|
|
||||||
$apaczkaShipmentService = new ApaczkaShipmentService(
|
|
||||||
$apaczkaIntegrationRepository,
|
|
||||||
$apaczkaApiClient,
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db())
|
|
||||||
);
|
|
||||||
$inpostShipmentService = new InpostShipmentService(
|
|
||||||
$inpostIntegrationRepository,
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
$companySettingsRepository,
|
|
||||||
new OrdersRepository($app->db())
|
|
||||||
);
|
|
||||||
$shipmentProviderRegistry = new ShipmentProviderRegistry([
|
|
||||||
$shipmentService,
|
|
||||||
$apaczkaShipmentService,
|
|
||||||
$inpostShipmentService,
|
|
||||||
$polkurierShipmentService,
|
|
||||||
]);
|
|
||||||
$erliDeliveryMappingController = new ErliDeliveryMappingController(
|
|
||||||
$translator,
|
|
||||||
$carrierDeliveryMappings,
|
|
||||||
$erliIntegrationRepository,
|
|
||||||
new ErliApiClient(),
|
|
||||||
$inpostShipmentService,
|
|
||||||
$apaczkaShipmentService
|
|
||||||
);
|
|
||||||
$erliExternalShipmentService = new ErliExternalShipmentService(
|
|
||||||
$erliIntegrationRepository,
|
|
||||||
new ErliApiClient(),
|
|
||||||
$carrierDeliveryMappings,
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
new OrdersRepository($app->db())
|
|
||||||
);
|
|
||||||
$erliIntegrationController = new ErliIntegrationController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$erliIntegrationRepository,
|
|
||||||
new ErliApiClient(),
|
|
||||||
new IntegrationsRepository($app->db()),
|
|
||||||
$cronRepository,
|
|
||||||
$erliOrdersSyncService,
|
|
||||||
$app->orderStatuses(),
|
|
||||||
$erliStatusMappingRepository,
|
|
||||||
$erliPullStatusMappingRepository,
|
|
||||||
$erliDeliveryMappingController
|
|
||||||
);
|
|
||||||
$shipmentController = new ShipmentController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$app->orders(),
|
|
||||||
$companySettingsRepository,
|
|
||||||
$shipmentProviderRegistry,
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
$automationService,
|
|
||||||
$app->basePath('storage'),
|
|
||||||
$carrierDeliveryMappings,
|
|
||||||
$printJobRepository,
|
|
||||||
$erliExternalShipmentService
|
|
||||||
);
|
|
||||||
$authMiddleware = new AuthMiddleware($auth);
|
|
||||||
|
|
||||||
$publicCronHandler = static function (Request $request) use ($app, $cronRepository): Response {
|
|
||||||
$token = trim((string) $request->input('token', ''));
|
|
||||||
if ($token === '') {
|
|
||||||
$token = trim((string) $request->input('tokenValue', ''));
|
|
||||||
if (str_starts_with($token, 'token=')) {
|
|
||||||
$token = substr($token, 6);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$expectedToken = trim((string) $app->config('app.cron.public_token', ''));
|
$authMiddleware = new AuthMiddleware($app->auth());
|
||||||
if ($expectedToken === '' || $token === '' || !hash_equals($expectedToken, $token)) {
|
foreach ($modules as $module) {
|
||||||
return Response::json([
|
$module->routes($app->router(), $services, $authMiddleware, $app);
|
||||||
'ok' => false,
|
|
||||||
'message' => 'Unauthorized',
|
|
||||||
], 403);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$limit = $cronRepository->getIntSetting(
|
|
||||||
'cron_web_limit',
|
|
||||||
(int) $app->config('app.cron.web_limit_default', 5),
|
|
||||||
1,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
|
|
||||||
$factory = new CronHandlerFactory(
|
|
||||||
$app->db(),
|
|
||||||
(string) $app->config('app.integrations.secret', ''),
|
|
||||||
$app->basePath()
|
|
||||||
);
|
|
||||||
$runner = $factory->build($cronRepository, $app->logger());
|
|
||||||
$runner->run($limit);
|
|
||||||
|
|
||||||
return Response::json([
|
|
||||||
'ok' => true,
|
|
||||||
'message' => 'Cron executed',
|
|
||||||
'limit' => $limit,
|
|
||||||
'timestamp' => date(DATE_ATOM),
|
|
||||||
]);
|
|
||||||
} catch (\Throwable $exception) {
|
|
||||||
$app->logger()->error('Public cron endpoint failed', [
|
|
||||||
'message' => $exception->getMessage(),
|
|
||||||
'path' => $request->path(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$debug = (bool) $app->config('app.debug', false);
|
|
||||||
return Response::json([
|
|
||||||
'ok' => false,
|
|
||||||
'message' => 'Cron execution failed',
|
|
||||||
'error' => $debug ? $exception->getMessage() : null,
|
|
||||||
], 500);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$infoController = new InfoController($template);
|
|
||||||
$router->get('/info', [$infoController, 'show']);
|
|
||||||
|
|
||||||
$router->get('/health', static fn (Request $request): Response => Response::json([
|
|
||||||
'status' => 'ok',
|
|
||||||
'app' => (string) $app->config('app.name', 'orderPRO'),
|
|
||||||
'timestamp' => date(DATE_ATOM),
|
|
||||||
]));
|
|
||||||
$router->get('/cron', $publicCronHandler);
|
|
||||||
$router->get('/cron/{tokenValue}', $publicCronHandler);
|
|
||||||
$router->post('/webhooks/smsplanet/inbound', [$smsplanetWebhookController, 'inbound']);
|
|
||||||
$router->get('/webhooks/smsplanet/inbound', [$smsplanetWebhookController, 'inbound']);
|
|
||||||
|
|
||||||
$router->get('/', static function (Request $request) use ($auth): Response {
|
|
||||||
return $auth->check()
|
|
||||||
? Response::redirect('/settings/users')
|
|
||||||
: Response::redirect('/login');
|
|
||||||
});
|
|
||||||
|
|
||||||
$router->get('/login', [$authController, 'showLogin']);
|
|
||||||
$router->post('/login', [$authController, 'login']);
|
|
||||||
$router->post('/logout', [$authController, 'logout'], [$authMiddleware]);
|
|
||||||
|
|
||||||
$router->get('/users', static fn (Request $request): Response => Response::redirect('/settings/users'), [$authMiddleware]);
|
|
||||||
$router->get('/orders', static fn (Request $request): Response => Response::redirect('/orders/list'), [$authMiddleware]);
|
|
||||||
$router->get('/orders/list', [$ordersController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/statistics/summary', [$ordersStatisticsController, 'summary'], [$authMiddleware]);
|
|
||||||
$router->get('/statistics/orders', [$ordersStatisticsController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/notifications', [$notificationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/notifications/mark-read', [$notificationController, 'markRead'], [$authMiddleware]);
|
|
||||||
$router->get('/api/notifications/unread', [$notificationApiController, 'unread'], [$authMiddleware]);
|
|
||||||
$router->post('/api/notifications/mark-read', [$notificationApiController, 'markRead'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}', [$ordersController, 'show'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/status', [$ordersController, 'updateStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/details/update', [$ordersController, 'updateDetails'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/sms/send', [$ordersController, 'sendSms'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/sms/template', [$ordersController, 'smsTemplate'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/send-email', [$ordersController, 'sendEmail'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/email-preview', [$ordersController, 'emailPreview'], [$authMiddleware]);
|
|
||||||
$router->get('/api/orders/search', [$ordersController, 'quickSearch'], [$authMiddleware]);
|
|
||||||
$router->get('/api/orders/{id}/preview', [$ordersController, 'preview'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/notes', [$ordersController, 'storeNote'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/notes/{noteId}/update', [$ordersController, 'updateNote'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/notes/{noteId}/delete', [$ordersController, 'deleteNote'], [$authMiddleware]);
|
|
||||||
$router->post('/users', [$usersController, 'store'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/users', [$usersController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/users', [$usersController, 'store'], [$authMiddleware]);
|
|
||||||
$router->get('/settings', static fn (Request $request): Response => Response::redirect('/settings/users'), [$authMiddleware]);
|
|
||||||
$router->get('/settings/database', [$settingsController, 'database'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/database/migrate', [$settingsController, 'migrate'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/statuses', [$settingsController, 'statuses'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/status-groups', [$settingsController, 'createStatusGroup'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/status-groups/update', [$settingsController, 'updateStatusGroup'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/status-groups/delete', [$settingsController, 'deleteStatusGroup'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/status-groups/reorder', [$settingsController, 'reorderStatusGroups'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/statuses/create', [$settingsController, 'createStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/statuses/update', [$settingsController, 'updateStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/statuses/delete', [$settingsController, 'deleteStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/statuses/reorder', [$settingsController, 'reorderStatuses'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/cron', [$cronSettingsController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/cron', [$cronSettingsController, 'save'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations', [$integrationsHubController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/allegro', [$allegroIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/save', [$allegroIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/settings/save', [$allegroIntegrationController, 'saveImportSettings'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/oauth/start', [$allegroIntegrationController, 'startOAuth'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/import-single', [$allegroIntegrationController, 'importSingleOrder'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/statuses/save', [$allegroStatusMappingController, 'saveStatusMapping'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/statuses/save-bulk', [$allegroStatusMappingController, 'saveStatusMappingsBulk'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/statuses/delete', [$allegroStatusMappingController, 'deleteStatusMapping'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/statuses/save-pull', [$allegroStatusMappingController, 'savePullStatusMappings'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/statuses/sync', [$allegroStatusMappingController, 'syncStatusesFromAllegro'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/allegro/delivery/save', [$allegroDeliveryMappingController, 'saveDeliveryMappings'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/allegro/oauth/callback', [$allegroIntegrationController, 'oauthCallback']);
|
|
||||||
$router->get('/settings/integrations/apaczka', [$apaczkaIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/apaczka/save', [$apaczkaIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/apaczka/test', [$apaczkaIntegrationController, 'test'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/inpost', [$inpostIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/inpost/save', [$inpostIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/fakturownia', [$fakturowniaIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/fakturownia/new', [$fakturowniaIntegrationController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/fakturownia/edit', [$fakturowniaIntegrationController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/fakturownia/save', [$fakturowniaIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/fakturownia/test', [$fakturowniaIntegrationController, 'test'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/hostedsms', [$hostedSmsIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/hostedsms/save', [$hostedSmsIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/hostedsms/test', [$hostedSmsIntegrationController, 'test'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/polkurier', [$polkurierIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/polkurier/save', [$polkurierIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/polkurier/test', [$polkurierIntegrationController, 'test'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/smsplanet', [$smsplanetIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/smsplanet/save', [$smsplanetIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/smsplanet/test', [$smsplanetIntegrationController, 'test'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/erli', [$erliIntegrationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/erli/save', [$erliIntegrationController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/erli/test', [$erliIntegrationController, 'test'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/erli/import', [$erliIntegrationController, 'importNow'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/erli/statuses/save-pull', [$erliIntegrationController, 'savePullStatusMappings'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/erli/statuses/save-push', [$erliIntegrationController, 'savePushStatusMappings'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/erli/delivery/save', [$erliDeliveryMappingController, 'saveDeliveryMappings'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/integrations/shoppro', [$shopproIntegrationsController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/shoppro/save', [$shopproIntegrationsController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/shoppro/test', [$shopproIntegrationsController, 'test'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/shoppro/statuses/save', [$shopproIntegrationsController, 'saveStatusMappings'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/shoppro/statuses/save-pull', [$shopproIntegrationsController, 'savePullStatusMappings'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/shoppro/statuses/sync', [$shopproIntegrationsController, 'syncStatuses'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/integrations/shoppro/delivery/save', [$shopproIntegrationsController, 'saveDeliveryMappings'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/company', [$companySettingsController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/company/save', [$companySettingsController, 'save'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting', [$receiptConfigController, 'hub'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting/receipts', [$receiptConfigController, 'list'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting/receipts/new', [$receiptConfigController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting/receipts/edit', [$receiptConfigController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/receipts/save', [$receiptConfigController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/receipts/toggle', [$receiptConfigController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/receipts/delete', [$receiptConfigController, 'delete'], [$authMiddleware]);
|
|
||||||
// Legacy aliases (backwards compatibility with bookmarks/form actions from before Phase 114-01)
|
|
||||||
$router->post('/settings/accounting/save', [$receiptConfigController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/toggle', [$receiptConfigController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/delete', [$receiptConfigController, 'delete'], [$authMiddleware]);
|
|
||||||
// Invoices (Phase 114-01)
|
|
||||||
$router->get('/settings/accounting/invoices', [$invoiceConfigController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting/invoices/new', [$invoiceConfigController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting/invoices/edit', [$invoiceConfigController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/invoices/save', [$invoiceConfigController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/invoices/toggle', [$invoiceConfigController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/accounting/invoices/delete', [$invoiceConfigController, 'delete'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/email-mailboxes', [$emailMailboxController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-mailboxes/save', [$emailMailboxController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-mailboxes/delete', [$emailMailboxController, 'delete'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-mailboxes/toggle', [$emailMailboxController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-mailboxes/test', [$emailMailboxController, 'testConnection'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/email-templates', [$emailTemplateController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/email-templates/create', [$emailTemplateController, 'create'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/email-templates/edit', [$emailTemplateController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-templates/save', [$emailTemplateController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-templates/delete', [$emailTemplateController, 'delete'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-templates/duplicate', [$emailTemplateController, 'duplicate'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-templates/toggle', [$emailTemplateController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/email-templates/preview', [$emailTemplateController, 'preview'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/email-templates/variables', [$emailTemplateController, 'getVariables'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/sms-templates', [$smsTemplateController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/sms-templates/create', [$smsTemplateController, 'create'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/sms-templates/edit', [$smsTemplateController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/sms-templates/save', [$smsTemplateController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/sms-templates/delete', [$smsTemplateController, 'delete'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/sms-templates/toggle', [$smsTemplateController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/sms-templates/variables', [$smsTemplateController, 'getVariables'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/automation', [$automationController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/automation/create', [$automationController, 'create'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/automation/store', [$automationController, 'store'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/automation/edit', [$automationController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/automation/update', [$automationController, 'update'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/automation/delete', [$automationController, 'destroy'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/automation/duplicate', [$automationController, 'duplicate'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/automation/toggle', [$automationController, 'toggleStatus'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/delivery-status-mappings', [$deliveryStatusMappingController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-status-mappings/save', [$deliveryStatusMappingController, 'save'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-status-mappings/save-bulk', [$deliveryStatusMappingController, 'saveBulk'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-status-mappings/reset', [$deliveryStatusMappingController, 'reset'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-status-mappings/reset-all', [$deliveryStatusMappingController, 'resetAll'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/delivery-statuses', [$deliveryStatusesController, 'index'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/delivery-statuses/new', [$deliveryStatusesController, 'create'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/delivery-statuses/{id}/edit', [$deliveryStatusesController, 'edit'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-statuses', [$deliveryStatusesController, 'store'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-statuses/{id}/update', [$deliveryStatusesController, 'update'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/delivery-statuses/{id}/delete', [$deliveryStatusesController, 'destroy'], [$authMiddleware]);
|
|
||||||
$router->get('/accounting', [$accountingController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/accounting/export', [$accountingController, 'export'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/receipt/create', [$receiptController, 'create'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/receipt/store', [$receiptController, 'store'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/receipt/{receiptId}', [$receiptController, 'show'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/receipt/{receiptId}/print', [$receiptController, 'printView'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/receipt/{receiptId}/pdf', [$receiptController, 'pdf'], [$authMiddleware]);
|
|
||||||
// Invoices from order (Phase 115-01)
|
|
||||||
$router->post('/orders/{id}/invoice-requested/toggle', [$ordersController, 'toggleInvoiceRequested'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/invoice/create', [$invoiceController, 'create'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/invoice/store', [$invoiceController, 'store'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/invoice/{invoiceId}', [$invoiceController, 'show'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/invoice/{invoiceId}/pdf', [$invoiceController, 'pdf'], [$authMiddleware]);
|
|
||||||
$router->get('/settings/accounting/invoices/issued', [$invoiceController, 'issuedList'], [$authMiddleware]);
|
|
||||||
$router->get('/api/nip/lookup', [$invoiceController, 'nipLookup'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/shipment/prepare', [$shipmentController, 'prepare'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/shipment/create', [$shipmentController, 'create'], [$authMiddleware]);
|
|
||||||
$router->get('/orders/{id}/shipment/{packageId}/status', [$shipmentController, 'checkStatus'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/shipment/{packageId}/label', [$shipmentController, 'label'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/shipment/manual', [$shipmentController, 'createManual'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/shipment/{packageId}/delete', [$shipmentController, 'delete'], [$authMiddleware]);
|
|
||||||
$router->post('/orders/{id}/payment/add', [$ordersController, 'addPayment'], [$authMiddleware]);
|
|
||||||
|
|
||||||
// --- Printing module ---
|
|
||||||
$printApiKeyRepository = new PrintApiKeyRepository($app->db());
|
|
||||||
$apiKeyMiddleware = new ApiKeyMiddleware($printApiKeyRepository);
|
|
||||||
$printApiController = new PrintApiController(
|
|
||||||
$printJobRepository,
|
|
||||||
$shipmentPackageRepository,
|
|
||||||
$auth,
|
|
||||||
$app->basePath('storage'),
|
|
||||||
$shipmentProviderRegistry
|
|
||||||
);
|
|
||||||
$printSettingsController = new PrintSettingsController($template, $translator, $auth, $printApiKeyRepository, $printJobRepository);
|
|
||||||
$projectMappingRepository = new ProjectMappingRepository($app->db());
|
|
||||||
$projectMappingController = new ProjectMappingController(
|
|
||||||
$template,
|
|
||||||
$translator,
|
|
||||||
$auth,
|
|
||||||
$projectMappingRepository,
|
|
||||||
$app->basePath()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Print API — session auth (from orderPRO UI)
|
|
||||||
$router->post('/api/print/jobs', [$printApiController, 'createJob'], [$authMiddleware]);
|
|
||||||
$router->get('/api/print/jobs/status', [$printApiController, 'status'], [$authMiddleware]);
|
|
||||||
|
|
||||||
// Print API — API key auth (from Windows client)
|
|
||||||
$router->get('/api/print/jobs/pending', [$printApiController, 'listPending'], [$apiKeyMiddleware]);
|
|
||||||
$router->get('/api/print/jobs/{id}/download', [$printApiController, 'downloadLabel'], [$apiKeyMiddleware]);
|
|
||||||
$router->post('/api/print/jobs/{id}/complete', [$printApiController, 'markComplete'], [$apiKeyMiddleware]);
|
|
||||||
|
|
||||||
// Print settings
|
|
||||||
$router->get('/settings/printing', [$printSettingsController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/printing/keys/create', [$printSettingsController, 'createKey'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/printing/keys/{id}/delete', [$printSettingsController, 'deleteKey'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/printing/jobs/delete', [$printSettingsController, 'deleteJob'], [$authMiddleware]);
|
|
||||||
|
|
||||||
// Project mappings
|
|
||||||
$router->get('/settings/project-mappings', [$projectMappingController, 'index'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/project-mappings', [$projectMappingController, 'store'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/project-mappings/{id}/update', [$projectMappingController, 'update'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/project-mappings/{id}/delete', [$projectMappingController, 'delete'], [$authMiddleware]);
|
|
||||||
$router->post('/settings/project-mappings/{id}/toggle', [$projectMappingController, 'toggleActive'], [$authMiddleware]);
|
|
||||||
|
|
||||||
// Shipment presets API
|
|
||||||
$presetRepository = new ShipmentPresetRepository($app->db());
|
|
||||||
$presetController = new ShipmentPresetController($presetRepository);
|
|
||||||
|
|
||||||
$router->get('/api/shipment-presets', [$presetController, 'list'], [$authMiddleware]);
|
|
||||||
$router->post('/api/shipment-presets', [$presetController, 'store'], [$authMiddleware]);
|
|
||||||
$router->post('/api/shipment-presets/update', [$presetController, 'update'], [$authMiddleware]);
|
|
||||||
$router->post('/api/shipment-presets/delete', [$presetController, 'destroy'], [$authMiddleware]);
|
|
||||||
};
|
|
||||||
|
|||||||
27
src/Core/Routing/ModuleProvider.php
Normal file
27
src/Core/Routing/ModuleProvider.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core\Routing;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modularny dostawca: zglasza swoje serwisy do ServiceRegistry i rejestruje
|
||||||
|
* route'y w Routerze. Implementacja zyje w katalogu modulu domenowego
|
||||||
|
* (src/Modules/<Modul>/<Modul>Module.php).
|
||||||
|
*/
|
||||||
|
interface ModuleProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Zarejestruj factory dla wszystkich uslug nalezacych do tego modulu.
|
||||||
|
* Factory to closure (lazy) - obiekty buduja sie dopiero przy get().
|
||||||
|
*/
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zarejestruj route'y modulu. W handlerach uzywaj $services->lazy(id, method),
|
||||||
|
* aby kontrolery nie konstruowaly sie przy starcie aplikacji.
|
||||||
|
*/
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void;
|
||||||
|
}
|
||||||
64
src/Core/Routing/ServiceRegistry.php
Normal file
64
src/Core/Routing/ServiceRegistry.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Core\Routing;
|
||||||
|
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use Closure;
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lekki rejestr uslug z leniwa konstrukcja (memoizacja per request).
|
||||||
|
*
|
||||||
|
* Cel: zastapic recznie montowane zmienne w routes/web.php tak, aby
|
||||||
|
* kontrolery i serwisy budowaly sie tylko gdy router trafi w handler.
|
||||||
|
*
|
||||||
|
* Nie wprowadza autowire ani refleksji - klucze i factory sa jawne.
|
||||||
|
*/
|
||||||
|
final class ServiceRegistry
|
||||||
|
{
|
||||||
|
/** @var array<string, Closure> */
|
||||||
|
private array $factories = [];
|
||||||
|
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
private array $instances = [];
|
||||||
|
|
||||||
|
public function set(string $id, Closure $factory): void
|
||||||
|
{
|
||||||
|
$this->factories[$id] = $factory;
|
||||||
|
unset($this->instances[$id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has(string $id): bool
|
||||||
|
{
|
||||||
|
return isset($this->factories[$id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function get(string $id)
|
||||||
|
{
|
||||||
|
if (array_key_exists($id, $this->instances)) {
|
||||||
|
return $this->instances[$id];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->factories[$id])) {
|
||||||
|
throw new RuntimeException(sprintf('Service not registered: "%s"', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->instances[$id] = ($this->factories[$id])($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zwraca closure odraczajaca pobranie kontrolera i wywolanie metody.
|
||||||
|
* Uzywane w ModuleProvider::routes() do leniwej konstrukcji handlera.
|
||||||
|
*/
|
||||||
|
public function lazy(string $serviceId, string $method): Closure
|
||||||
|
{
|
||||||
|
return function (Request $request) use ($serviceId, $method) {
|
||||||
|
$controller = $this->get($serviceId);
|
||||||
|
return $controller->{$method}($request);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
141
src/Modules/Accounting/AccountingModule.php
Normal file
141
src/Modules/Accounting/AccountingModule.php
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Accounting;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Http\MfWhitelistApiClient;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Settings\InvoiceConfigController;
|
||||||
|
use App\Modules\Settings\InvoiceConfigRepository;
|
||||||
|
use App\Modules\Settings\ReceiptConfigController;
|
||||||
|
use App\Modules\Settings\ReceiptConfigRepository;
|
||||||
|
|
||||||
|
final class AccountingModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
// Receipts
|
||||||
|
$services->set('accounting.receipts.repo', static fn () => new ReceiptRepository($app->db()));
|
||||||
|
$services->set('accounting.receipts.config_repo', static fn () => new ReceiptConfigRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('accounting.receipts.config_controller', static fn (ServiceRegistry $s) => new ReceiptConfigController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('accounting.receipts.config_repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('accounting.receipts.service', static fn (ServiceRegistry $s) => new ReceiptService(
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('accounting.receipts.controller', static fn (ServiceRegistry $s) => new ReceiptController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('automation.service'),
|
||||||
|
$s->get('accounting.receipts.service')
|
||||||
|
));
|
||||||
|
|
||||||
|
// Invoices
|
||||||
|
$services->set('accounting.invoices.repo', static fn () => new InvoiceRepository($app->db()));
|
||||||
|
$services->set('accounting.invoices.config_repo', static fn (ServiceRegistry $s) => new InvoiceConfigRepository(
|
||||||
|
$app->db(),
|
||||||
|
$s->get('integrations.fakturownia.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('accounting.invoices.config_controller', static fn (ServiceRegistry $s) => new InvoiceConfigController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('accounting.invoices.config_repo'),
|
||||||
|
$s->get('integrations.fakturownia.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('accounting.invoices.service', static fn (ServiceRegistry $s) => new InvoiceService(
|
||||||
|
$s->get('accounting.invoices.repo'),
|
||||||
|
$s->get('accounting.invoices.config_repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('integrations.fakturownia.repo'),
|
||||||
|
$s->get('integrations.fakturownia.api_client')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('accounting.invoices.controller', static fn (ServiceRegistry $s) => new InvoiceController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('accounting.invoices.repo'),
|
||||||
|
$s->get('accounting.invoices.config_repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('accounting.invoices.service'),
|
||||||
|
new MfWhitelistApiClient()
|
||||||
|
));
|
||||||
|
|
||||||
|
// Accounting XLSX export
|
||||||
|
$services->set('accounting.controller', static fn (ServiceRegistry $s) => new AccountingController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$rc = static fn (string $m) => $services->lazy('accounting.receipts.config_controller', $m);
|
||||||
|
$router->get('/settings/accounting', $rc('hub'), [$auth]);
|
||||||
|
$router->get('/settings/accounting/receipts', $rc('list'), [$auth]);
|
||||||
|
$router->get('/settings/accounting/receipts/new', $rc('edit'), [$auth]);
|
||||||
|
$router->get('/settings/accounting/receipts/edit', $rc('edit'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/receipts/save', $rc('save'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/receipts/toggle', $rc('toggleStatus'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/receipts/delete', $rc('delete'), [$auth]);
|
||||||
|
// Legacy aliases (Phase 114-01)
|
||||||
|
$router->post('/settings/accounting/save', $rc('save'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/toggle', $rc('toggleStatus'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/delete', $rc('delete'), [$auth]);
|
||||||
|
|
||||||
|
$ic = static fn (string $m) => $services->lazy('accounting.invoices.config_controller', $m);
|
||||||
|
$router->get('/settings/accounting/invoices', $ic('index'), [$auth]);
|
||||||
|
$router->get('/settings/accounting/invoices/new', $ic('edit'), [$auth]);
|
||||||
|
$router->get('/settings/accounting/invoices/edit', $ic('edit'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/invoices/save', $ic('save'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/invoices/toggle', $ic('toggleStatus'), [$auth]);
|
||||||
|
$router->post('/settings/accounting/invoices/delete', $ic('delete'), [$auth]);
|
||||||
|
|
||||||
|
$ac = static fn (string $m) => $services->lazy('accounting.controller', $m);
|
||||||
|
$router->get('/accounting', $ac('index'), [$auth]);
|
||||||
|
$router->post('/accounting/export', $ac('export'), [$auth]);
|
||||||
|
|
||||||
|
// Receipt actions from order
|
||||||
|
$r = static fn (string $m) => $services->lazy('accounting.receipts.controller', $m);
|
||||||
|
$router->get('/orders/{id}/receipt/create', $r('create'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/receipt/store', $r('store'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/receipt/{receiptId}', $r('show'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/receipt/{receiptId}/print', $r('printView'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/receipt/{receiptId}/pdf', $r('pdf'), [$auth]);
|
||||||
|
|
||||||
|
// Invoice actions from order (Phase 115-01)
|
||||||
|
$inv = static fn (string $m) => $services->lazy('accounting.invoices.controller', $m);
|
||||||
|
$router->get('/orders/{id}/invoice/create', $inv('create'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/invoice/store', $inv('store'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/invoice/{invoiceId}', $inv('show'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/invoice/{invoiceId}/pdf', $inv('pdf'), [$auth]);
|
||||||
|
$router->get('/settings/accounting/invoices/issued', $inv('issuedList'), [$auth]);
|
||||||
|
$router->get('/api/nip/lookup', $inv('nipLookup'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/Modules/Auth/AuthModule.php
Normal file
28
src/Modules/Auth/AuthModule.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Auth;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
|
||||||
|
final class AuthModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('auth.controller', static fn () => new AuthController(
|
||||||
|
$app->template(),
|
||||||
|
$app->auth(),
|
||||||
|
$app->translator()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/login', $services->lazy('auth.controller', 'showLogin'));
|
||||||
|
$router->post('/login', $services->lazy('auth.controller', 'login'));
|
||||||
|
$router->post('/logout', $services->lazy('auth.controller', 'logout'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/Modules/Automation/AutomationModule.php
Normal file
55
src/Modules/Automation/AutomationModule.php
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Automation;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class AutomationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('automation.repo', static fn () => new AutomationRepository($app->db()));
|
||||||
|
$services->set('automation.execution_log_repo', static fn () => new AutomationExecutionLogRepository($app->db()));
|
||||||
|
$services->set('automation.email_once_repo', static fn () => new AutomationEmailOnceRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('automation.controller', static fn (ServiceRegistry $s) => new AutomationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('automation.repo'),
|
||||||
|
$s->get('automation.execution_log_repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('automation.service', static fn (ServiceRegistry $s) => new AutomationService(
|
||||||
|
$s->get('automation.repo'),
|
||||||
|
$s->get('automation.execution_log_repo'),
|
||||||
|
$s->get('automation.email_once_repo'),
|
||||||
|
$s->get('email.sending_service'),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo'),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('accounting.receipts.service')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$a = static fn (string $m) => $services->lazy('automation.controller', $m);
|
||||||
|
$router->get('/settings/automation', $a('index'), [$auth]);
|
||||||
|
$router->get('/settings/automation/create', $a('create'), [$auth]);
|
||||||
|
$router->post('/settings/automation/store', $a('store'), [$auth]);
|
||||||
|
$router->get('/settings/automation/edit', $a('edit'), [$auth]);
|
||||||
|
$router->post('/settings/automation/update', $a('update'), [$auth]);
|
||||||
|
$router->post('/settings/automation/delete', $a('destroy'), [$auth]);
|
||||||
|
$router->post('/settings/automation/duplicate', $a('duplicate'), [$auth]);
|
||||||
|
$router->post('/settings/automation/toggle', $a('toggleStatus'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
93
src/Modules/Cron/CronModule.php
Normal file
93
src/Modules/Cron/CronModule.php
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Cron;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use App\Core\Http\Response;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Settings\CronSettingsController;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
final class CronModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('shared.cron.repo', static fn () => new CronRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('cron.settings_controller', static fn (ServiceRegistry $s) => new CronSettingsController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('shared.cron.repo'),
|
||||||
|
(bool) $app->config('app.cron.run_on_web_default', false),
|
||||||
|
(int) $app->config('app.cron.web_limit_default', 5)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/settings/cron', $services->lazy('cron.settings_controller', 'index'), [$auth]);
|
||||||
|
$router->post('/settings/cron', $services->lazy('cron.settings_controller', 'save'), [$auth]);
|
||||||
|
|
||||||
|
$publicCronHandler = static function (Request $request) use ($app, $services): Response {
|
||||||
|
$token = trim((string) $request->input('token', ''));
|
||||||
|
if ($token === '') {
|
||||||
|
$token = trim((string) $request->input('tokenValue', ''));
|
||||||
|
if (str_starts_with($token, 'token=')) {
|
||||||
|
$token = substr($token, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$expectedToken = trim((string) $app->config('app.cron.public_token', ''));
|
||||||
|
if ($expectedToken === '' || $token === '' || !hash_equals($expectedToken, $token)) {
|
||||||
|
return Response::json(['ok' => false, 'message' => 'Unauthorized'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
/** @var CronRepository $cronRepository */
|
||||||
|
$cronRepository = $services->get('shared.cron.repo');
|
||||||
|
$limit = $cronRepository->getIntSetting(
|
||||||
|
'cron_web_limit',
|
||||||
|
(int) $app->config('app.cron.web_limit_default', 5),
|
||||||
|
1,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
$factory = new CronHandlerFactory(
|
||||||
|
$app->db(),
|
||||||
|
(string) $app->config('app.integrations.secret', ''),
|
||||||
|
$app->basePath()
|
||||||
|
);
|
||||||
|
$runner = $factory->build($cronRepository, $app->logger());
|
||||||
|
$runner->run($limit);
|
||||||
|
|
||||||
|
return Response::json([
|
||||||
|
'ok' => true,
|
||||||
|
'message' => 'Cron executed',
|
||||||
|
'limit' => $limit,
|
||||||
|
'timestamp' => date(DATE_ATOM),
|
||||||
|
]);
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
$app->logger()->error('Public cron endpoint failed', [
|
||||||
|
'message' => $exception->getMessage(),
|
||||||
|
'path' => $request->path(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$debug = (bool) $app->config('app.debug', false);
|
||||||
|
return Response::json([
|
||||||
|
'ok' => false,
|
||||||
|
'message' => 'Cron execution failed',
|
||||||
|
'error' => $debug ? $exception->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$router->get('/cron', $publicCronHandler);
|
||||||
|
$router->get('/cron/{tokenValue}', $publicCronHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
88
src/Modules/Email/EmailModule.php
Normal file
88
src/Modules/Email/EmailModule.php
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Email;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Settings\EmailMailboxController;
|
||||||
|
use App\Modules\Settings\EmailMailboxRepository;
|
||||||
|
use App\Modules\Settings\EmailTemplateController;
|
||||||
|
use App\Modules\Settings\EmailTemplateRepository;
|
||||||
|
use App\Modules\Settings\IntegrationSecretCipher;
|
||||||
|
use App\Modules\Settings\SmtpSecurityContextFactory;
|
||||||
|
|
||||||
|
final class EmailModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('email.mailboxes.repo', static fn () => new EmailMailboxRepository(
|
||||||
|
$app->db(),
|
||||||
|
new IntegrationSecretCipher($secret)
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('email.templates.repo', static fn () => new EmailTemplateRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('email.variable_resolver', static fn (ServiceRegistry $s) => new VariableResolver(
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('sms.variable_resolver')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('email.attachment_generator', static fn (ServiceRegistry $s) => new AttachmentGenerator(
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo'),
|
||||||
|
$app->template()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('email.sending_service', static fn (ServiceRegistry $s) => new EmailSendingService(
|
||||||
|
$app->db(),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('email.templates.repo'),
|
||||||
|
$s->get('email.mailboxes.repo'),
|
||||||
|
$s->get('email.variable_resolver'),
|
||||||
|
$s->get('email.attachment_generator')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('email.mailbox.controller', static fn (ServiceRegistry $s) => new EmailMailboxController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('email.mailboxes.repo'),
|
||||||
|
new SmtpSecurityContextFactory((bool) $app->config('app.smtp.allow_self_signed_dev', false))
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('email.template.controller', static fn (ServiceRegistry $s) => new EmailTemplateController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('email.templates.repo'),
|
||||||
|
$s->get('email.mailboxes.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$mb = static fn (string $m) => $services->lazy('email.mailbox.controller', $m);
|
||||||
|
$router->get('/settings/email-mailboxes', $mb('index'), [$auth]);
|
||||||
|
$router->post('/settings/email-mailboxes/save', $mb('save'), [$auth]);
|
||||||
|
$router->post('/settings/email-mailboxes/delete', $mb('delete'), [$auth]);
|
||||||
|
$router->post('/settings/email-mailboxes/toggle', $mb('toggleStatus'), [$auth]);
|
||||||
|
$router->post('/settings/email-mailboxes/test', $mb('testConnection'), [$auth]);
|
||||||
|
|
||||||
|
$t = static fn (string $m) => $services->lazy('email.template.controller', $m);
|
||||||
|
$router->get('/settings/email-templates', $t('index'), [$auth]);
|
||||||
|
$router->get('/settings/email-templates/create', $t('create'), [$auth]);
|
||||||
|
$router->get('/settings/email-templates/edit', $t('edit'), [$auth]);
|
||||||
|
$router->post('/settings/email-templates/save', $t('save'), [$auth]);
|
||||||
|
$router->post('/settings/email-templates/delete', $t('delete'), [$auth]);
|
||||||
|
$router->post('/settings/email-templates/duplicate', $t('duplicate'), [$auth]);
|
||||||
|
$router->post('/settings/email-templates/toggle', $t('toggleStatus'), [$auth]);
|
||||||
|
$router->post('/settings/email-templates/preview', $t('preview'), [$auth]);
|
||||||
|
$router->get('/settings/email-templates/variables', $t('getVariables'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/Modules/Info/InfoModule.php
Normal file
36
src/Modules/Info/InfoModule.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Info;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use App\Core\Http\Response;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class InfoModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('info.controller', static fn () => new InfoController($app->template()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/info', $services->lazy('info.controller', 'show'));
|
||||||
|
|
||||||
|
$router->get('/health', static fn (Request $request): Response => Response::json([
|
||||||
|
'status' => 'ok',
|
||||||
|
'app' => (string) $app->config('app.name', 'orderPRO'),
|
||||||
|
'timestamp' => date(DATE_ATOM),
|
||||||
|
]));
|
||||||
|
|
||||||
|
$authService = $app->auth();
|
||||||
|
$router->get('/', static fn (Request $request): Response => $authService->check()
|
||||||
|
? Response::redirect('/settings/users')
|
||||||
|
: Response::redirect('/login'));
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/Modules/Notifications/NotificationsModule.php
Normal file
37
src/Modules/Notifications/NotificationsModule.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Notifications;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class NotificationsModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('notifications.repo', static fn () => new NotificationRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('notifications.controller', static fn (ServiceRegistry $s) => new NotificationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('notifications.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('notifications.api_controller', static fn (ServiceRegistry $s) => new NotificationApiController(
|
||||||
|
$s->get('notifications.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/notifications', $services->lazy('notifications.controller', 'index'), [$auth]);
|
||||||
|
$router->post('/notifications/mark-read', $services->lazy('notifications.controller', 'markRead'), [$auth]);
|
||||||
|
$router->get('/api/notifications/unread', $services->lazy('notifications.api_controller', 'unread'), [$auth]);
|
||||||
|
$router->post('/api/notifications/mark-read', $services->lazy('notifications.api_controller', 'markRead'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/Modules/Orders/OrdersModule.php
Normal file
67
src/Modules/Orders/OrdersModule.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Orders;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use App\Core\Http\Response;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class OrdersModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('orders.notes_service', static fn () => new OrderNotesService($app->db()));
|
||||||
|
|
||||||
|
$services->set('orders.controller', static fn (ServiceRegistry $s) => new OrdersController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('accounting.receipts.repo'),
|
||||||
|
$s->get('accounting.receipts.config_repo'),
|
||||||
|
$s->get('email.sending_service'),
|
||||||
|
$s->get('email.templates.repo'),
|
||||||
|
$s->get('email.mailboxes.repo'),
|
||||||
|
$app->basePath('storage'),
|
||||||
|
$s->get('shared.print_jobs.repo'),
|
||||||
|
$s->get('integrations.shoppro.repo'),
|
||||||
|
$s->get('automation.service'),
|
||||||
|
$s->get('accounting.invoices.repo'),
|
||||||
|
$s->get('accounting.invoices.config_repo'),
|
||||||
|
$s->get('sms.messages.repo'),
|
||||||
|
$s->get('sms.conversation_service'),
|
||||||
|
$s->get('sms.templates.repo'),
|
||||||
|
$s->get('sms.variable_resolver'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$s->get('orders.notes_service')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/orders', static fn (Request $request): Response => Response::redirect('/orders/list'), [$auth]);
|
||||||
|
|
||||||
|
$o = static fn (string $m) => $services->lazy('orders.controller', $m);
|
||||||
|
$router->get('/orders/list', $o('index'), [$auth]);
|
||||||
|
$router->get('/orders/{id}', $o('show'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/status', $o('updateStatus'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/details/update', $o('updateDetails'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/sms/send', $o('sendSms'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/sms/template', $o('smsTemplate'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/send-email', $o('sendEmail'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/email-preview', $o('emailPreview'), [$auth]);
|
||||||
|
$router->get('/api/orders/search', $o('quickSearch'), [$auth]);
|
||||||
|
$router->get('/api/orders/{id}/preview', $o('preview'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/notes', $o('storeNote'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/notes/{noteId}/update', $o('updateNote'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/notes/{noteId}/delete', $o('deleteNote'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/payment/add', $o('addPayment'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/invoice-requested/toggle', $o('toggleInvoiceRequested'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/Modules/Printing/PrintingModule.php
Normal file
83
src/Modules/Printing/PrintingModule.php
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Printing;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Settings\PrintSettingsController;
|
||||||
|
use App\Modules\Settings\ProjectMappingController;
|
||||||
|
use App\Modules\Settings\ProjectMappingRepository;
|
||||||
|
|
||||||
|
final class PrintingModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('shared.print_jobs.repo', static fn () => new PrintJobRepository($app->db()));
|
||||||
|
$services->set('printing.api_keys.repo', static fn () => new PrintApiKeyRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('printing.api_key_middleware', static fn (ServiceRegistry $s) => new ApiKeyMiddleware(
|
||||||
|
$s->get('printing.api_keys.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('printing.api_controller', static fn (ServiceRegistry $s) => new PrintApiController(
|
||||||
|
$s->get('shared.print_jobs.repo'),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$app->auth(),
|
||||||
|
$app->basePath('storage'),
|
||||||
|
$s->get('shipments.provider_registry')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('printing.settings_controller', static fn (ServiceRegistry $s) => new PrintSettingsController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('printing.api_keys.repo'),
|
||||||
|
$s->get('shared.print_jobs.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('printing.project_mappings.repo', static fn () => new ProjectMappingRepository($app->db()));
|
||||||
|
$services->set('printing.project_mappings.controller', static fn (ServiceRegistry $s) => new ProjectMappingController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('printing.project_mappings.repo'),
|
||||||
|
$app->basePath()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
/** @var ApiKeyMiddleware $apiKey */
|
||||||
|
$apiKey = $services->get('printing.api_key_middleware');
|
||||||
|
|
||||||
|
$p = static fn (string $m) => $services->lazy('printing.api_controller', $m);
|
||||||
|
|
||||||
|
// Print API — session auth (z UI orderPRO)
|
||||||
|
$router->post('/api/print/jobs', $p('createJob'), [$auth]);
|
||||||
|
$router->get('/api/print/jobs/status', $p('status'), [$auth]);
|
||||||
|
|
||||||
|
// Print API — API key auth (z klienta Windows)
|
||||||
|
$router->get('/api/print/jobs/pending', $p('listPending'), [$apiKey]);
|
||||||
|
$router->get('/api/print/jobs/{id}/download', $p('downloadLabel'), [$apiKey]);
|
||||||
|
$router->post('/api/print/jobs/{id}/complete', $p('markComplete'), [$apiKey]);
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
$ps = static fn (string $m) => $services->lazy('printing.settings_controller', $m);
|
||||||
|
$router->get('/settings/printing', $ps('index'), [$auth]);
|
||||||
|
$router->post('/settings/printing/keys/create', $ps('createKey'), [$auth]);
|
||||||
|
$router->post('/settings/printing/keys/{id}/delete', $ps('deleteKey'), [$auth]);
|
||||||
|
$router->post('/settings/printing/jobs/delete', $ps('deleteJob'), [$auth]);
|
||||||
|
|
||||||
|
// Project mappings
|
||||||
|
$pm = static fn (string $m) => $services->lazy('printing.project_mappings.controller', $m);
|
||||||
|
$router->get('/settings/project-mappings', $pm('index'), [$auth]);
|
||||||
|
$router->post('/settings/project-mappings', $pm('store'), [$auth]);
|
||||||
|
$router->post('/settings/project-mappings/{id}/update', $pm('update'), [$auth]);
|
||||||
|
$router->post('/settings/project-mappings/{id}/delete', $pm('delete'), [$auth]);
|
||||||
|
$router->post('/settings/project-mappings/{id}/toggle', $pm('toggleActive'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
102
src/Modules/Settings/AllegroIntegrationModule.php
Normal file
102
src/Modules/Settings/AllegroIntegrationModule.php
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Orders\OrderImportRepository;
|
||||||
|
|
||||||
|
final class AllegroIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.repo', static fn () => new AllegroIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.allegro.api_client', static fn () => new AllegroApiClient());
|
||||||
|
$services->set('integrations.allegro.oauth', static fn () => new AllegroOAuthClient());
|
||||||
|
$services->set('integrations.allegro.status_mapping_repo', static fn () => new AllegroStatusMappingRepository($app->db()));
|
||||||
|
$services->set('integrations.allegro.pull_status_mapping_repo', static fn () => new AllegroPullStatusMappingRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.token_manager', static fn (ServiceRegistry $s) => new AllegroTokenManager(
|
||||||
|
$s->get('integrations.allegro.repo'),
|
||||||
|
$s->get('integrations.allegro.oauth')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.status_discovery_service', static fn (ServiceRegistry $s) => new AllegroStatusDiscoveryService(
|
||||||
|
$s->get('integrations.allegro.token_manager'),
|
||||||
|
$s->get('integrations.allegro.api_client'),
|
||||||
|
$s->get('integrations.allegro.status_mapping_repo'),
|
||||||
|
$s->get('integrations.allegro.pull_status_mapping_repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.status_mapping_controller', static fn (ServiceRegistry $s) => new AllegroStatusMappingController(
|
||||||
|
$app->translator(),
|
||||||
|
$s->get('integrations.allegro.status_mapping_repo'),
|
||||||
|
$app->orderStatuses(),
|
||||||
|
$s->get('integrations.allegro.status_discovery_service'),
|
||||||
|
$s->get('integrations.allegro.pull_status_mapping_repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.delivery_mapping_controller', static fn (ServiceRegistry $s) => new AllegroDeliveryMappingController(
|
||||||
|
$app->translator(),
|
||||||
|
$s->get('integrations.allegro.repo'),
|
||||||
|
$s->get('integrations.allegro.oauth'),
|
||||||
|
$s->get('integrations.allegro.api_client'),
|
||||||
|
$s->get('shared.carrier_delivery_mappings.repo'),
|
||||||
|
$s->get('integrations.apaczka.repo'),
|
||||||
|
$s->get('integrations.apaczka.api_client')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.order_import_service', static fn (ServiceRegistry $s) => new AllegroOrderImportService(
|
||||||
|
$s->get('integrations.allegro.repo'),
|
||||||
|
$s->get('integrations.allegro.token_manager'),
|
||||||
|
$s->get('integrations.allegro.api_client'),
|
||||||
|
new OrderImportRepository($app->db()),
|
||||||
|
$s->get('integrations.allegro.status_mapping_repo'),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('integrations.allegro.pull_status_mapping_repo'),
|
||||||
|
$s->get('automation.service')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.allegro.controller', static fn (ServiceRegistry $s) => new AllegroIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.allegro.repo'),
|
||||||
|
$s->get('integrations.allegro.status_mapping_repo'),
|
||||||
|
$s->get('integrations.allegro.pull_status_mapping_repo'),
|
||||||
|
$app->orderStatuses(),
|
||||||
|
$s->get('shared.cron.repo'),
|
||||||
|
$s->get('integrations.allegro.oauth'),
|
||||||
|
$s->get('integrations.allegro.order_import_service'),
|
||||||
|
$s->get('integrations.allegro.status_discovery_service'),
|
||||||
|
(string) $app->config('app.url', ''),
|
||||||
|
$s->get('integrations.allegro.delivery_mapping_controller')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.allegro.controller', $m);
|
||||||
|
$sm = static fn (string $m) => $services->lazy('integrations.allegro.status_mapping_controller', $m);
|
||||||
|
$dm = static fn (string $m) => $services->lazy('integrations.allegro.delivery_mapping_controller', $m);
|
||||||
|
|
||||||
|
$router->get('/settings/integrations/allegro', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/settings/save', $c('saveImportSettings'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/oauth/start', $c('startOAuth'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/import-single', $c('importSingleOrder'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/statuses/save', $sm('saveStatusMapping'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/statuses/save-bulk', $sm('saveStatusMappingsBulk'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/statuses/delete', $sm('deleteStatusMapping'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/statuses/save-pull', $sm('savePullStatusMappings'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/statuses/sync', $sm('syncStatusesFromAllegro'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/allegro/delivery/save', $dm('saveDeliveryMappings'), [$auth]);
|
||||||
|
$router->get('/settings/integrations/allegro/oauth/callback', $c('oauthCallback'));
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/Modules/Settings/ApaczkaIntegrationModule.php
Normal file
37
src/Modules/Settings/ApaczkaIntegrationModule.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class ApaczkaIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.apaczka.repo', static fn () => new ApaczkaIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.apaczka.api_client', static fn () => new ApaczkaApiClient());
|
||||||
|
|
||||||
|
$services->set('integrations.apaczka.controller', static fn (ServiceRegistry $s) => new ApaczkaIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.apaczka.repo'),
|
||||||
|
$s->get('integrations.apaczka.api_client')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.apaczka.controller', $m);
|
||||||
|
$router->get('/settings/integrations/apaczka', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/apaczka/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/apaczka/test', $c('test'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
86
src/Modules/Settings/ErliIntegrationModule.php
Normal file
86
src/Modules/Settings/ErliIntegrationModule.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Orders\OrderImportRepository;
|
||||||
|
|
||||||
|
final class ErliIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.erli.repo', static fn () => new ErliIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.erli.api_client', static fn () => new ErliApiClient());
|
||||||
|
$services->set('integrations.erli.pull_status_mapping_repo', static fn () => new ErliPullStatusMappingRepository($app->db()));
|
||||||
|
$services->set('integrations.erli.status_mapping_repo', static fn () => new ErliStatusMappingRepository($app->db()));
|
||||||
|
$services->set('integrations.erli.order_sync_state_repo', static fn () => new ErliOrderSyncStateRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('integrations.erli.order_mapper', static fn (ServiceRegistry $s) => new ErliOrderMapper(
|
||||||
|
$s->get('integrations.erli.pull_status_mapping_repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.erli.orders_sync_service', static fn (ServiceRegistry $s) => new ErliOrdersSyncService(
|
||||||
|
$s->get('integrations.erli.repo'),
|
||||||
|
$s->get('integrations.erli.order_sync_state_repo'),
|
||||||
|
$s->get('integrations.erli.api_client'),
|
||||||
|
new OrderImportRepository($app->db()),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('integrations.erli.order_mapper'),
|
||||||
|
$s->get('automation.service'),
|
||||||
|
$s->get('integrations.erli.pull_status_mapping_repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.erli.external_shipment_service', static fn (ServiceRegistry $s) => new ErliExternalShipmentService(
|
||||||
|
$s->get('integrations.erli.repo'),
|
||||||
|
$s->get('integrations.erli.api_client'),
|
||||||
|
$s->get('shared.carrier_delivery_mappings.repo'),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$app->orders()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.erli.delivery_mapping_controller', static fn (ServiceRegistry $s) => new ErliDeliveryMappingController(
|
||||||
|
$app->translator(),
|
||||||
|
$s->get('shared.carrier_delivery_mappings.repo'),
|
||||||
|
$s->get('integrations.erli.repo'),
|
||||||
|
$s->get('integrations.erli.api_client'),
|
||||||
|
$s->get('shipments.inpost.service'),
|
||||||
|
$s->get('shipments.apaczka.service')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('integrations.erli.controller', static fn (ServiceRegistry $s) => new ErliIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.erli.repo'),
|
||||||
|
$s->get('integrations.erli.api_client'),
|
||||||
|
$s->get('integrations.hub.repo'),
|
||||||
|
$s->get('shared.cron.repo'),
|
||||||
|
$s->get('integrations.erli.orders_sync_service'),
|
||||||
|
$app->orderStatuses(),
|
||||||
|
$s->get('integrations.erli.status_mapping_repo'),
|
||||||
|
$s->get('integrations.erli.pull_status_mapping_repo'),
|
||||||
|
$s->get('integrations.erli.delivery_mapping_controller')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.erli.controller', $m);
|
||||||
|
$dm = static fn (string $m) => $services->lazy('integrations.erli.delivery_mapping_controller', $m);
|
||||||
|
|
||||||
|
$router->get('/settings/integrations/erli', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/erli/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/erli/test', $c('test'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/erli/import', $c('importNow'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/erli/statuses/save-pull', $c('savePullStatusMappings'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/erli/statuses/save-push', $c('savePushStatusMappings'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/erli/delivery/save', $dm('saveDeliveryMappings'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/Modules/Settings/FakturowniaIntegrationModule.php
Normal file
40
src/Modules/Settings/FakturowniaIntegrationModule.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class FakturowniaIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.fakturownia.repo', static fn () => new FakturowniaIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.fakturownia.api_client', static fn () => new FakturowniaApiClient());
|
||||||
|
|
||||||
|
$services->set('integrations.fakturownia.controller', static fn (ServiceRegistry $s) => new FakturowniaIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.fakturownia.repo'),
|
||||||
|
$s->get('integrations.fakturownia.api_client'),
|
||||||
|
$s->get('integrations.hub.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.fakturownia.controller', $m);
|
||||||
|
$router->get('/settings/integrations/fakturownia', $c('index'), [$auth]);
|
||||||
|
$router->get('/settings/integrations/fakturownia/new', $c('edit'), [$auth]);
|
||||||
|
$router->get('/settings/integrations/fakturownia/edit', $c('edit'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/fakturownia/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/fakturownia/test', $c('test'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/Modules/Settings/HostedSmsIntegrationModule.php
Normal file
38
src/Modules/Settings/HostedSmsIntegrationModule.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class HostedSmsIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.hostedsms.repo', static fn () => new HostedSmsIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.hostedsms.api_client', static fn () => new HostedSmsApiClient());
|
||||||
|
|
||||||
|
$services->set('integrations.hostedsms.controller', static fn (ServiceRegistry $s) => new HostedSmsIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.hostedsms.repo'),
|
||||||
|
$s->get('integrations.hostedsms.api_client'),
|
||||||
|
$s->get('integrations.hub.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.hostedsms.controller', $m);
|
||||||
|
$router->get('/settings/integrations/hostedsms', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/hostedsms/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/hostedsms/test', $c('test'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/Modules/Settings/InpostIntegrationModule.php
Normal file
34
src/Modules/Settings/InpostIntegrationModule.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class InpostIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.inpost.repo', static fn () => new InpostIntegrationRepository($app->db(), $secret));
|
||||||
|
|
||||||
|
$services->set('integrations.inpost.controller', static fn (ServiceRegistry $s) => new InpostIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.inpost.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.inpost.controller', $m);
|
||||||
|
$router->get('/settings/integrations/inpost', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/inpost/save', $c('save'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/Modules/Settings/IntegrationsHubModule.php
Normal file
39
src/Modules/Settings/IntegrationsHubModule.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class IntegrationsHubModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('integrations.hub.repo', static fn () => new IntegrationsRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('integrations.hub.controller', static fn (ServiceRegistry $s) => new IntegrationsHubController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.hub.repo'),
|
||||||
|
$s->get('integrations.allegro.repo'),
|
||||||
|
$s->get('integrations.apaczka.repo'),
|
||||||
|
$s->get('integrations.inpost.repo'),
|
||||||
|
$s->get('integrations.shoppro.repo'),
|
||||||
|
$s->get('integrations.fakturownia.repo'),
|
||||||
|
$s->get('integrations.hostedsms.repo'),
|
||||||
|
$s->get('integrations.smsplanet.repo'),
|
||||||
|
$s->get('integrations.polkurier.repo'),
|
||||||
|
$s->get('integrations.erli.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/settings/integrations', $services->lazy('integrations.hub.controller', 'index'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/Modules/Settings/PolkurierIntegrationModule.php
Normal file
38
src/Modules/Settings/PolkurierIntegrationModule.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class PolkurierIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.polkurier.repo', static fn () => new PolkurierIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.polkurier.api_client', static fn () => new PolkurierApiClient());
|
||||||
|
|
||||||
|
$services->set('integrations.polkurier.controller', static fn (ServiceRegistry $s) => new PolkurierIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.polkurier.repo'),
|
||||||
|
$s->get('integrations.polkurier.api_client'),
|
||||||
|
$s->get('integrations.hub.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.polkurier.controller', $m);
|
||||||
|
$router->get('/settings/integrations/polkurier', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/polkurier/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/polkurier/test', $c('test'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/Modules/Settings/SettingsModule.php
Normal file
60
src/Modules/Settings/SettingsModule.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use App\Core\Http\Response;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wspolne ustawienia: database, statuses, status-groups, company, redirect /settings.
|
||||||
|
* Routes podzielone tematycznie tylko dla czytelnosci.
|
||||||
|
*/
|
||||||
|
final class SettingsModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('settings.controller', static fn () => new SettingsController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$app->migrator(),
|
||||||
|
$app->orderStatuses()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shared.companies.repo', static fn () => new CompanySettingsRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('settings.company.controller', static fn (ServiceRegistry $s) => new CompanySettingsController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('shared.companies.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/settings', static fn (Request $request): Response => Response::redirect('/settings/users'), [$auth]);
|
||||||
|
|
||||||
|
$c = static fn (string $m) => $services->lazy('settings.controller', $m);
|
||||||
|
$router->get('/settings/database', $c('database'), [$auth]);
|
||||||
|
$router->post('/settings/database/migrate', $c('migrate'), [$auth]);
|
||||||
|
$router->get('/settings/statuses', $c('statuses'), [$auth]);
|
||||||
|
$router->post('/settings/status-groups', $c('createStatusGroup'), [$auth]);
|
||||||
|
$router->post('/settings/status-groups/update', $c('updateStatusGroup'), [$auth]);
|
||||||
|
$router->post('/settings/status-groups/delete', $c('deleteStatusGroup'), [$auth]);
|
||||||
|
$router->post('/settings/status-groups/reorder', $c('reorderStatusGroups'), [$auth]);
|
||||||
|
$router->post('/settings/statuses/create', $c('createStatus'), [$auth]);
|
||||||
|
$router->post('/settings/statuses/update', $c('updateStatus'), [$auth]);
|
||||||
|
$router->post('/settings/statuses/delete', $c('deleteStatus'), [$auth]);
|
||||||
|
$router->post('/settings/statuses/reorder', $c('reorderStatuses'), [$auth]);
|
||||||
|
|
||||||
|
$router->get('/settings/company', $services->lazy('settings.company.controller', 'index'), [$auth]);
|
||||||
|
$router->post('/settings/company/save', $services->lazy('settings.company.controller', 'save'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/Modules/Settings/ShopproIntegrationModule.php
Normal file
52
src/Modules/Settings/ShopproIntegrationModule.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class ShopproIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.shoppro.repo', static fn () => new ShopproIntegrationsRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.shoppro.status_mapping_repo', static fn () => new ShopproStatusMappingRepository($app->db()));
|
||||||
|
$services->set('integrations.shoppro.pull_status_mapping_repo', static fn () => new ShopproPullStatusMappingRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('integrations.shoppro.controller', static fn (ServiceRegistry $s) => new ShopproIntegrationsController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.shoppro.repo'),
|
||||||
|
$s->get('integrations.shoppro.status_mapping_repo'),
|
||||||
|
$s->get('integrations.shoppro.pull_status_mapping_repo'),
|
||||||
|
$app->orderStatuses(),
|
||||||
|
$s->get('shared.cron.repo'),
|
||||||
|
$s->get('shared.carrier_delivery_mappings.repo'),
|
||||||
|
$s->get('integrations.allegro.repo'),
|
||||||
|
$s->get('integrations.allegro.oauth'),
|
||||||
|
$s->get('integrations.allegro.api_client'),
|
||||||
|
$s->get('integrations.apaczka.repo'),
|
||||||
|
$s->get('integrations.apaczka.api_client'),
|
||||||
|
$s->get('shipments.polkurier.service')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.shoppro.controller', $m);
|
||||||
|
$router->get('/settings/integrations/shoppro', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/shoppro/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/shoppro/test', $c('test'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/shoppro/statuses/save', $c('saveStatusMappings'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/shoppro/statuses/save-pull', $c('savePullStatusMappings'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/shoppro/statuses/sync', $c('syncStatuses'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/shoppro/delivery/save', $c('saveDeliveryMappings'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/Modules/Settings/SmsplanetIntegrationModule.php
Normal file
38
src/Modules/Settings/SmsplanetIntegrationModule.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Settings;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class SmsplanetIntegrationModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$secret = (string) $app->config('app.integrations.secret', '');
|
||||||
|
|
||||||
|
$services->set('integrations.smsplanet.repo', static fn () => new SmsplanetIntegrationRepository($app->db(), $secret));
|
||||||
|
$services->set('integrations.smsplanet.api_client', static fn () => new SmsplanetApiClient());
|
||||||
|
|
||||||
|
$services->set('integrations.smsplanet.controller', static fn (ServiceRegistry $s) => new SmsplanetIntegrationController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('integrations.smsplanet.repo'),
|
||||||
|
$s->get('integrations.smsplanet.api_client'),
|
||||||
|
$s->get('integrations.hub.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$c = static fn (string $m) => $services->lazy('integrations.smsplanet.controller', $m);
|
||||||
|
$router->get('/settings/integrations/smsplanet', $c('index'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/smsplanet/save', $c('save'), [$auth]);
|
||||||
|
$router->post('/settings/integrations/smsplanet/test', $c('test'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
135
src/Modules/Shipments/ShipmentsModule.php
Normal file
135
src/Modules/Shipments/ShipmentsModule.php
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Shipments;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Settings\DeliveryStatusesController;
|
||||||
|
use App\Modules\Settings\DeliveryStatusMappingController;
|
||||||
|
|
||||||
|
final class ShipmentsModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
// Shared repos owned by Shipments domain
|
||||||
|
$services->set('shared.shipment_packages.repo', static fn () => new ShipmentPackageRepository($app->db()));
|
||||||
|
$services->set('shared.carrier_delivery_mappings.repo', static fn () => new \App\Modules\Settings\CarrierDeliveryMethodMappingRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('shipments.delivery_status.repo', static fn () => new DeliveryStatusRepository($app->db()));
|
||||||
|
$services->set('shipments.delivery_status_mappings.repo', static fn () => new DeliveryStatusMappingRepository($app->db()));
|
||||||
|
|
||||||
|
// Provider services (one per carrier we own)
|
||||||
|
$services->set('shipments.allegro.service', static fn (ServiceRegistry $s) => new AllegroShipmentService(
|
||||||
|
$s->get('integrations.allegro.token_manager'),
|
||||||
|
new \App\Modules\Settings\AllegroApiClient(),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.apaczka.service', static fn (ServiceRegistry $s) => new ApaczkaShipmentService(
|
||||||
|
$s->get('integrations.apaczka.repo'),
|
||||||
|
$s->get('integrations.apaczka.api_client'),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.inpost.service', static fn (ServiceRegistry $s) => new InpostShipmentService(
|
||||||
|
$s->get('integrations.inpost.repo'),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.polkurier.service', static fn (ServiceRegistry $s) => new PolkurierShipmentService(
|
||||||
|
$s->get('integrations.polkurier.repo'),
|
||||||
|
new \App\Modules\Settings\PolkurierApiClient(),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$app->orders()
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.provider_registry', static fn (ServiceRegistry $s) => new ShipmentProviderRegistry([
|
||||||
|
$s->get('shipments.allegro.service'),
|
||||||
|
$s->get('shipments.apaczka.service'),
|
||||||
|
$s->get('shipments.inpost.service'),
|
||||||
|
$s->get('shipments.polkurier.service'),
|
||||||
|
]));
|
||||||
|
|
||||||
|
$services->set('shipments.controller', static fn (ServiceRegistry $s) => new ShipmentController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$app->orders(),
|
||||||
|
$s->get('shared.companies.repo'),
|
||||||
|
$s->get('shipments.provider_registry'),
|
||||||
|
$s->get('shared.shipment_packages.repo'),
|
||||||
|
$s->get('automation.service'),
|
||||||
|
$app->basePath('storage'),
|
||||||
|
$s->get('shared.carrier_delivery_mappings.repo'),
|
||||||
|
$s->get('shared.print_jobs.repo'),
|
||||||
|
$s->get('integrations.erli.external_shipment_service')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.preset.repo', static fn () => new ShipmentPresetRepository($app->db()));
|
||||||
|
$services->set('shipments.preset.controller', static fn (ServiceRegistry $s) => new ShipmentPresetController(
|
||||||
|
$s->get('shipments.preset.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.delivery_statuses.controller', static fn (ServiceRegistry $s) => new DeliveryStatusesController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('shipments.delivery_status.repo'),
|
||||||
|
$s->get('shipments.delivery_status_mappings.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('shipments.delivery_status_mappings.controller', static fn (ServiceRegistry $s) => new DeliveryStatusMappingController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('shipments.delivery_status_mappings.repo'),
|
||||||
|
$s->get('shipments.delivery_status.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
// Side-effect: globalny rejestr w klasie DeliveryStatus (zgodnie ze stanem przed refaktorem).
|
||||||
|
DeliveryStatus::setRepository($services->get('shipments.delivery_status.repo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$sh = static fn (string $m) => $services->lazy('shipments.controller', $m);
|
||||||
|
$router->get('/orders/{id}/shipment/prepare', $sh('prepare'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/shipment/create', $sh('create'), [$auth]);
|
||||||
|
$router->get('/orders/{id}/shipment/{packageId}/status', $sh('checkStatus'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/shipment/{packageId}/label', $sh('label'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/shipment/manual', $sh('createManual'), [$auth]);
|
||||||
|
$router->post('/orders/{id}/shipment/{packageId}/delete', $sh('delete'), [$auth]);
|
||||||
|
|
||||||
|
$dsm = static fn (string $m) => $services->lazy('shipments.delivery_status_mappings.controller', $m);
|
||||||
|
$router->get('/settings/delivery-status-mappings', $dsm('index'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-status-mappings/save', $dsm('save'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-status-mappings/save-bulk', $dsm('saveBulk'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-status-mappings/reset', $dsm('reset'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-status-mappings/reset-all', $dsm('resetAll'), [$auth]);
|
||||||
|
|
||||||
|
$ds = static fn (string $m) => $services->lazy('shipments.delivery_statuses.controller', $m);
|
||||||
|
$router->get('/settings/delivery-statuses', $ds('index'), [$auth]);
|
||||||
|
$router->get('/settings/delivery-statuses/new', $ds('create'), [$auth]);
|
||||||
|
$router->get('/settings/delivery-statuses/{id}/edit', $ds('edit'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-statuses', $ds('store'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-statuses/{id}/update', $ds('update'), [$auth]);
|
||||||
|
$router->post('/settings/delivery-statuses/{id}/delete', $ds('destroy'), [$auth]);
|
||||||
|
|
||||||
|
$pr = static fn (string $m) => $services->lazy('shipments.preset.controller', $m);
|
||||||
|
$router->get('/api/shipment-presets', $pr('list'), [$auth]);
|
||||||
|
$router->post('/api/shipment-presets', $pr('store'), [$auth]);
|
||||||
|
$router->post('/api/shipment-presets/update', $pr('update'), [$auth]);
|
||||||
|
$router->post('/api/shipment-presets/delete', $pr('destroy'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/Modules/Sms/SmsModule.php
Normal file
58
src/Modules/Sms/SmsModule.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Sms;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
use App\Modules\Settings\SmsplanetApiClient;
|
||||||
|
use App\Modules\Settings\SmsTemplateController;
|
||||||
|
|
||||||
|
final class SmsModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('sms.messages.repo', static fn () => new SmsMessageRepository($app->db()));
|
||||||
|
$services->set('sms.templates.repo', static fn () => new SmsTemplateRepository($app->db()));
|
||||||
|
|
||||||
|
$services->set('sms.variable_resolver', static fn (ServiceRegistry $s) => new SmsVariableResolver(
|
||||||
|
$s->get('shared.shipment_packages.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('sms.conversation_service', static fn (ServiceRegistry $s) => new SmsConversationService(
|
||||||
|
$s->get('sms.messages.repo'),
|
||||||
|
$s->get('integrations.smsplanet.repo'),
|
||||||
|
new SmsplanetApiClient(),
|
||||||
|
$s->get('notifications.repo')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('sms.smsplanet_webhook.controller', static fn (ServiceRegistry $s) => new SmsplanetWebhookController(
|
||||||
|
$s->get('sms.conversation_service')
|
||||||
|
));
|
||||||
|
|
||||||
|
$services->set('sms.template.controller', static fn (ServiceRegistry $s) => new SmsTemplateController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$s->get('sms.templates.repo')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->post('/webhooks/smsplanet/inbound', $services->lazy('sms.smsplanet_webhook.controller', 'inbound'));
|
||||||
|
$router->get('/webhooks/smsplanet/inbound', $services->lazy('sms.smsplanet_webhook.controller', 'inbound'));
|
||||||
|
|
||||||
|
$t = static fn (string $m) => $services->lazy('sms.template.controller', $m);
|
||||||
|
$router->get('/settings/sms-templates', $t('index'), [$auth]);
|
||||||
|
$router->get('/settings/sms-templates/create', $t('create'), [$auth]);
|
||||||
|
$router->get('/settings/sms-templates/edit', $t('edit'), [$auth]);
|
||||||
|
$router->post('/settings/sms-templates/save', $t('save'), [$auth]);
|
||||||
|
$router->post('/settings/sms-templates/delete', $t('delete'), [$auth]);
|
||||||
|
$router->post('/settings/sms-templates/toggle', $t('toggleStatus'), [$auth]);
|
||||||
|
$router->get('/settings/sms-templates/variables', $t('getVariables'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/Modules/Statistics/StatisticsModule.php
Normal file
29
src/Modules/Statistics/StatisticsModule.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Statistics;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class StatisticsModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('statistics.controller', static fn () => new OrdersStatisticsController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
new OrdersStatisticsRepository($app->db())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/statistics/summary', $services->lazy('statistics.controller', 'summary'), [$auth]);
|
||||||
|
$router->get('/statistics/orders', $services->lazy('statistics.controller', 'index'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/Modules/Users/UsersModule.php
Normal file
33
src/Modules/Users/UsersModule.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Modules\Users;
|
||||||
|
|
||||||
|
use App\Core\Application;
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use App\Core\Http\Response;
|
||||||
|
use App\Core\Routing\ModuleProvider;
|
||||||
|
use App\Core\Routing\Router;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use App\Modules\Auth\AuthMiddleware;
|
||||||
|
|
||||||
|
final class UsersModule implements ModuleProvider
|
||||||
|
{
|
||||||
|
public function register(ServiceRegistry $services, Application $app): void
|
||||||
|
{
|
||||||
|
$services->set('users.controller', static fn () => new UsersController(
|
||||||
|
$app->template(),
|
||||||
|
$app->translator(),
|
||||||
|
$app->auth(),
|
||||||
|
$app->users()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function routes(Router $router, ServiceRegistry $services, AuthMiddleware $auth, Application $app): void
|
||||||
|
{
|
||||||
|
$router->get('/users', static fn (Request $request): Response => Response::redirect('/settings/users'), [$auth]);
|
||||||
|
$router->post('/users', $services->lazy('users.controller', 'store'), [$auth]);
|
||||||
|
$router->get('/settings/users', $services->lazy('users.controller', 'index'), [$auth]);
|
||||||
|
$router->post('/settings/users', $services->lazy('users.controller', 'store'), [$auth]);
|
||||||
|
}
|
||||||
|
}
|
||||||
126
tests/Unit/Core/Routing/ServiceRegistryTest.php
Normal file
126
tests/Unit/Core/Routing/ServiceRegistryTest.php
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit\Core\Routing;
|
||||||
|
|
||||||
|
use App\Core\Http\Request;
|
||||||
|
use App\Core\Routing\ServiceRegistry;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use RuntimeException;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
final class ServiceRegistryTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testSetAndGetReturnsBuiltInstance(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
$registry->set('foo', static function () {
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->value = 42;
|
||||||
|
return $obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
$result = $registry->get('foo');
|
||||||
|
|
||||||
|
self::assertInstanceOf(stdClass::class, $result);
|
||||||
|
self::assertSame(42, $result->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetMemoizesInstance(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
$calls = 0;
|
||||||
|
$registry->set('foo', static function () use (&$calls) {
|
||||||
|
$calls++;
|
||||||
|
return new stdClass();
|
||||||
|
});
|
||||||
|
|
||||||
|
$first = $registry->get('foo');
|
||||||
|
$second = $registry->get('foo');
|
||||||
|
|
||||||
|
self::assertSame($first, $second);
|
||||||
|
self::assertSame(1, $calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHasReportsRegistration(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
self::assertFalse($registry->has('foo'));
|
||||||
|
|
||||||
|
$registry->set('foo', static fn () => new stdClass());
|
||||||
|
|
||||||
|
self::assertTrue($registry->has('foo'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetThrowsOnMissingService(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
|
||||||
|
$this->expectException(RuntimeException::class);
|
||||||
|
$this->expectExceptionMessage('Service not registered: "missing"');
|
||||||
|
|
||||||
|
$registry->get('missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFactoryReceivesRegistryForCrossLookup(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
$registry->set('dep', static function () {
|
||||||
|
$dep = new stdClass();
|
||||||
|
$dep->name = 'dep';
|
||||||
|
return $dep;
|
||||||
|
});
|
||||||
|
$registry->set('consumer', static function (ServiceRegistry $s) {
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->depName = $s->get('dep')->name;
|
||||||
|
return $obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
$consumer = $registry->get('consumer');
|
||||||
|
|
||||||
|
self::assertSame('dep', $consumer->depName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLazyDefersConstructionUntilInvocation(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
$calls = 0;
|
||||||
|
$registry->set('ctrl', static function () use (&$calls) {
|
||||||
|
$calls++;
|
||||||
|
return new class {
|
||||||
|
public function show(Request $request): string
|
||||||
|
{
|
||||||
|
return 'shown:' . $request->path();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
$handler = $registry->lazy('ctrl', 'show');
|
||||||
|
self::assertSame(0, $calls, 'lazy() nie powinno konstruowac serwisu');
|
||||||
|
|
||||||
|
$request = new Request([], [], [], ['REQUEST_METHOD' => 'GET', 'REQUEST_URI' => '/foo']);
|
||||||
|
$result = $handler($request);
|
||||||
|
|
||||||
|
self::assertSame('shown:/foo', $result);
|
||||||
|
self::assertSame(1, $calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetOverwritesPreviousFactoryAndClearsInstance(): void
|
||||||
|
{
|
||||||
|
$registry = new ServiceRegistry();
|
||||||
|
$registry->set('foo', static function () {
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->v = 'A';
|
||||||
|
return $obj;
|
||||||
|
});
|
||||||
|
self::assertSame('A', $registry->get('foo')->v);
|
||||||
|
|
||||||
|
$registry->set('foo', static function () {
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->v = 'B';
|
||||||
|
return $obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
self::assertSame('B', $registry->get('foo')->v);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user