621 lines
42 KiB
Markdown
621 lines
42 KiB
Markdown
# Architecture
|
|
|
|
## Status
|
|
- Projekt po resecie do trybu `users-only`.
|
|
- UI korzysta z globalnego standardu naglowkow sekcji (`h2/h3/h4.section-title`) definiowanego centralnie w `resources/scss/app.scss` i buildowanego do `public/assets/css/app.css`.
|
|
- Kolory akcji UI (przyciski `btn--primary` i warianty `btn--outline-primary`) sa odseparowane od koloru naglowkow (`section-title`) przez dedykowane tokeny `--c-action-primary` i `--c-action-primary-dark` w `resources/scss/shared/_ui-components.scss`.
|
|
- Import Allegro zapisuje log `import` z kontekstem triggera (`manual_import`, `orders_sync`, `status_sync`) i deduplikuje powtarzalne wpisy bez realnej zmiany.
|
|
- Automatyzacja obsluguje zdarzenia `shipment.created` (natychmiast po utworzeniu paczki), `shipment.status_changed` (po realnej zmianie statusu dostawy), `payment.status_changed` (po zmianie statusu platnosci — reczne dodanie lub cron sync shopPRO), `order.status_changed` (po zmianie statusu zamowienia — reczna zmiana lub chain z akcji automatyzacji), oraz `order.status_aged` (cron co 1h — zamowienie w danym statusie od X dni).
|
|
- Automatyzacja obsluguje warunek `shipment_status` oparty o statusy biznesowe, warunek `payment_status` (0=nieoplacone, 1=czesciowo oplacone, 2=oplacone), warunek `order_status` (kody aktywnych statusow zamowien z `order_statuses`), oraz warunek `days_in_status` (pole numeryczne, ewaluacja >=).
|
|
- Automatyzacja obsluguje akcje `issue_receipt` (Wystaw paragon) z parametrami: `receipt_config_id`, `issue_date_mode`, `duplicate_policy`.
|
|
- Automatyzacja obsluguje akcje `update_shipment_status` (Zmiana statusu przesylki) z parametrem `status_key` mapowanym na techniczny `delivery_status`.
|
|
- Automatyzacja obsluguje akcje `update_order_status` (Zmiana statusu zamowienia) z parametrem `status_code` (aktywny kod z `order_statuses`).
|
|
- Orkiestracja automatyzacji obsluguje chain events: akcja moze emitowac kolejne zdarzenie (`emitEvent`), a engine propaguje wspolny kontekst lancucha.
|
|
- Zabezpieczenia chain automation (dla obecnych i przyszlych eventow):
|
|
- limit glebokosci lancucha (`MAX_CHAIN_DEPTH`),
|
|
- deduplikacja wykonania tej samej pary `event_type + rule_id` w obrebie jednego lancucha,
|
|
- limit historii wykonan w kontekście (`MAX_CHAIN_EXECUTIONS`).
|
|
- `ShipmentTrackingHandler` triggeruje automatyzacje tylko po zmianie `delivery_status` i przekazuje kontekst (`package_id`, `provider`, `delivery_status`, `delivery_status_raw`, `previous_status`).
|
|
- `DeliveryStatus` normalizuje statusy Allegro edge zarowno z opisow PL, jak i EN (mapa slugow + fallback keyword matching), dzieki czemu opisy typu `Parcel is awaiting pick-up` i `Parcel has been delivered` sa mapowane na statusy biznesowe zamiast `unknown`.
|
|
- Kolejka wydruku ma akcje usuwania wpisu przez route `POST /settings/printing/jobs/delete` (CSRF + `OrderProAlerts.confirm`).
|
|
- Szablony e-mail obsluguja zmienne przesylki:
|
|
- `{{przesylka.numer}}` -> `shipment_packages.tracking_number` (najnowsza paczka zamowienia),
|
|
- `{{przesylka.link_sledzenia}}` -> `DeliveryStatus::trackingUrl(provider, tracking_number, carrier_id)`,
|
|
- fallback: gdy brak paczki lub tracking number, wartosci sa puste.
|
|
|
|
## Moduly aktywne
|
|
- `App\Modules\Auth`
|
|
- `App\Modules\Orders`
|
|
- `App\Modules\Users`
|
|
- `App\Modules\Settings`
|
|
- `App\Modules\Accounting` (modul paragonow — wystawianie, podglad, druk, PDF, lista, eksport XLSX)
|
|
- `App\Modules\Settings\EmailMailbox*` (skrzynki pocztowe SMTP — CRUD + test polaczenia)
|
|
- `App\Modules\Settings\EmailTemplate*` (szablony e-mail - lista + osobna podstrona formularza create/edit + Quill.js + zmienne + zalaczniki)
|
|
- `App\Modules\Email` (wysylka e-mail z zamowien — EmailSendingService, VariableResolver, AttachmentGenerator; kompozycja: header (mailbox) + body (template) + footer (mailbox))
|
|
- `App\Modules\Automation` (zadania automatyczne — reguly zdarzenie/warunki/akcje, CRUD)
|
|
|
|
## Routing
|
|
- `GET /login`, `POST /login`, `POST /logout`
|
|
- `GET /settings/users`, `POST /settings/users`
|
|
- `GET /orders` (redirect do `/orders/list`)
|
|
- `GET /orders/list`
|
|
- `GET /orders/{id}`
|
|
- `POST /orders/{id}/status`
|
|
- `POST /orders/{id}/send-email` (wysylka e-mail z zamowienia, AJAX)
|
|
- `POST /orders/{id}/email-preview` (podglad szablonu z rozwiazanymi zmiennymi, AJAX)
|
|
- `POST /orders/{id}/payment/add` (dodanie platnosci recznej, AJAX + push set_paid do shopPRO)
|
|
- `GET /accounting` (lista paragonow z filtrami i paginacja)
|
|
- `GET /accounting/export` (eksport XLSX z aktywnymi filtrami)
|
|
- `GET /users` (redirect do `/settings/users`)
|
|
- `POST /users` (compat route)
|
|
- `GET /settings` (redirect do `/settings/users`)
|
|
- `GET /settings/database`
|
|
- `POST /settings/database/migrate`
|
|
- `GET /cron` (publiczny trigger crona HTTPS, autoryzacja tokenem)
|
|
- `GET /settings/statuses`
|
|
- `POST /settings/status-groups`
|
|
- `POST /settings/status-groups/update`
|
|
- `POST /settings/status-groups/delete`
|
|
- `POST /settings/status-groups/reorder`
|
|
- `POST /settings/statuses/create`
|
|
- `POST /settings/statuses/update`
|
|
- `POST /settings/statuses/delete`
|
|
- `POST /settings/statuses/reorder`
|
|
- `GET /settings/cron`
|
|
- `POST /settings/cron`
|
|
- `GET /settings/integrations`
|
|
- `GET /settings/integrations/allegro`
|
|
- `POST /settings/integrations/allegro/save`
|
|
- `POST /settings/integrations/allegro/oauth/start`
|
|
- `POST /settings/integrations/allegro/import-single`
|
|
- `POST /settings/integrations/allegro/statuses/save`
|
|
- `POST /settings/integrations/allegro/statuses/save-bulk`
|
|
- `POST /settings/integrations/allegro/statuses/delete`
|
|
- `POST /settings/integrations/allegro/statuses/sync`
|
|
- `GET /settings/integrations/allegro/oauth/callback`
|
|
- `GET /settings/integrations/apaczka`
|
|
- `POST /settings/integrations/apaczka/save`
|
|
- `POST /settings/integrations/apaczka/test`
|
|
- `GET /settings/integrations/inpost`
|
|
- `POST /settings/integrations/inpost/save`
|
|
- `GET /settings/integrations/shoppro`
|
|
- `POST /settings/integrations/shoppro/save`
|
|
- `POST /settings/integrations/shoppro/test`
|
|
- `POST /settings/integrations/shoppro/statuses/save`
|
|
- `POST /settings/integrations/shoppro/statuses/sync`
|
|
- `POST /settings/integrations/shoppro/delivery/save`
|
|
- `GET /settings/accounting`
|
|
- `POST /settings/accounting/save`
|
|
- `POST /settings/accounting/toggle`
|
|
- `POST /settings/accounting/delete`
|
|
- `GET /settings/email-mailboxes`
|
|
- `POST /settings/email-mailboxes/save`
|
|
- `POST /settings/email-mailboxes/delete`
|
|
- `POST /settings/email-mailboxes/toggle`
|
|
- `POST /settings/email-mailboxes/test`
|
|
- `GET /settings/email-templates`
|
|
- `GET /settings/email-templates/create`
|
|
- `GET /settings/email-templates/edit`
|
|
- `POST /settings/email-templates/save`
|
|
- `POST /settings/email-templates/delete`
|
|
- `POST /settings/email-templates/duplicate`
|
|
- `POST /settings/email-templates/toggle`
|
|
- `POST /settings/email-templates/preview`
|
|
- `GET /settings/automation`
|
|
- `GET /settings/automation/create`
|
|
- `POST /settings/automation/store`
|
|
- `GET /settings/automation/edit`
|
|
- `POST /settings/automation/update`
|
|
- `POST /settings/automation/delete`
|
|
- `POST /settings/automation/toggle`
|
|
- `POST /settings/printing/jobs/delete`
|
|
- `GET /health`
|
|
- `GET /` (redirect)
|
|
|
|
## Korekta logowania
|
|
- `AuthController::showLogin(Request): Response`:
|
|
- dla zalogowanego usera redirect na `/settings/users` (zamiast nieistniejacego `/dashboard`).
|
|
- `AuthController::login(Request): Response`:
|
|
- po poprawnym logowaniu redirect na `/settings/users`.
|
|
|
|
## Kluczowe klasy
|
|
- `App\Core\Application`
|
|
- `App\Modules\Auth\AuthController`
|
|
- `App\Modules\Auth\AuthService`
|
|
- `App\Modules\Orders\OrdersController`
|
|
- `App\Modules\Orders\OrdersRepository`
|
|
- `App\Modules\Settings\SettingsController`
|
|
- `App\Modules\Settings\OrderStatusRepository`
|
|
- `App\Modules\Settings\AllegroIntegrationController`
|
|
- `App\Modules\Settings\AllegroIntegrationRepository`
|
|
- `App\Modules\Settings\AllegroOAuthClient`
|
|
- `App\Modules\Settings\AllegroTokenManager`
|
|
- `App\Modules\Settings\AllegroApiClient`
|
|
- `App\Modules\Settings\AllegroOrderImportService`
|
|
- `App\Modules\Settings\AllegroStatusMappingRepository`
|
|
- `App\Modules\Settings\AllegroStatusDiscoveryService`
|
|
- `App\Modules\Settings\IntegrationsRepository`
|
|
- `App\Modules\Settings\IntegrationSecretCipher`
|
|
- `App\Modules\Settings\EmailMailboxController`
|
|
- `App\Modules\Settings\EmailMailboxRepository`
|
|
- `App\Modules\Orders\OrderImportRepository`
|
|
- `App\Modules\Settings\CronSettingsController`
|
|
- `App\Modules\Cron\CronRepository`
|
|
- `App\Modules\Cron\CronRunner`
|
|
- `App\Modules\Cron\AllegroTokenRefreshHandler`
|
|
- `App\Modules\Cron\AllegroOrdersImportHandler`
|
|
- `App\Modules\Cron\AllegroStatusSyncHandler`
|
|
- `App\Modules\Cron\ShopproOrdersImportHandler`
|
|
- `App\Modules\Cron\ShopproStatusSyncHandler`
|
|
- `App\Modules\Cron\ShopproPaymentStatusSyncHandler`
|
|
- `App\Modules\Users\UsersController`
|
|
- `App\Modules\Users\UserRepository`
|
|
- `App\Modules\Settings\ApaczkaIntegrationController`
|
|
- `App\Modules\Settings\ApaczkaIntegrationRepository`
|
|
- `App\Modules\Settings\ApaczkaApiClient`
|
|
- `App\Modules\Settings\CarrierDeliveryMethodMappingRepository`
|
|
- `App\Modules\Settings\InpostIntegrationController`
|
|
- `App\Modules\Settings\InpostIntegrationRepository`
|
|
- `App\Modules\Settings\IntegrationsHubController`
|
|
- `App\Modules\Settings\ShopproIntegrationsController`
|
|
- `App\Modules\Settings\ShopproIntegrationsRepository`
|
|
- `App\Modules\Settings\ShopproStatusMappingRepository`
|
|
- `App\Modules\Settings\ShopproDeliveryMethodMappingRepository`
|
|
- `App\Modules\Settings\ShopproApiClient`
|
|
- `App\Modules\Settings\ShopproOrdersSyncService`
|
|
- `App\Modules\Settings\ShopproStatusSyncService`
|
|
- `App\Modules\Settings\ShopproPaymentStatusSyncService`
|
|
- `App\Modules\Settings\AllegroOrdersSyncService`
|
|
- `App\Modules\Settings\AllegroOrderSyncStateRepository`
|
|
- `App\Modules\Settings\AllegroStatusSyncService`
|
|
- `App\Modules\Settings\ReceiptConfigController`
|
|
- `App\Modules\Settings\ReceiptConfigRepository`
|
|
- `App\Modules\Accounting\ReceiptRepository` (findById, findByOrderId, create, getNextNumber, paginate, exportData)
|
|
- `App\Modules\Accounting\ReceiptController` (create, store, show, printView, pdf)
|
|
- `App\Modules\Accounting\AccountingController` (index — lista paragonow, export — XLSX)
|
|
- `App\Modules\Automation\AutomationController` (index, create, store, edit, update, destroy, toggleStatus)
|
|
- `App\Modules\Automation\AutomationRepository` (findAll, findById, create, update, delete, toggleActive, findActiveByEvent)
|
|
- `App\Modules\Automation\AutomationService` (trigger, evaluateConditions, executeActions — watcher/executor regul automatyzacji; flow: ReceiptController::store() -> trigger('receipt.created'), ShipmentController::create()/createManual() -> trigger('shipment.created', context), ShipmentTrackingHandler::handle() -> trigger('shipment.status_changed', context) -> ewaluacja warunkow -> akcje: EmailSendingService::send() / auto issue_receipt / update_shipment_status / update_order_status)
|
|
- `App\Modules\Shipments\ShipmentProviderInterface`
|
|
- `App\Modules\Shipments\ShipmentProviderRegistry`
|
|
- `App\Modules\Shipments\ApaczkaShipmentService`
|
|
|
|
## Przeplyw Zamowienia > Lista zamowien
|
|
- `GET /orders/list`:
|
|
- `OrdersController::index(Request): Response`
|
|
- pobiera dane listy przez `OrdersRepository::paginate(...)`,
|
|
- data zamowienia na liscie korzysta z fallbacku: `orders.ordered_at` -> `orders.source_created_at` -> `orders.source_updated_at` -> `orders.fetched_at`,
|
|
- domyslne sortowanie i filtry zakresu dat (`date_from`, `date_to`) korzystaja z tej samej daty efektywnej,
|
|
- pobiera slowniki filtrow (`sourceOptions()`, `statusOptions()`), statystyki (`quickStats()`), agregaty statusow (`statusCounts()`) i konfiguracje grup/statusow (`statusPanelConfig()`),
|
|
- buduje panel statusow z grupami i licznikami (`buildStatusPanel(...)`) z linkami filtrujacymi po statusie,
|
|
- panel statusow i etykiety statusow sa zgodne z konfiguracja z `Ustawienia > Statusy` (z fallbackiem `Pozostale`),
|
|
- renderuje podglad pozycji zamowienia (nazwa, miniatura, ilosc) na bazie `order_items`,
|
|
- miniatura pozycji jest rozwiazywana priorytetowo: `order_items.media_url` -> glowny obraz powiazanego produktu orderPRO (`product_channel_map` + `sales_channels[allegro]` + `product_images`),
|
|
- obsluguje modal podgladu zdjecia pozycji po kliknieciu miniatury,
|
|
- normalizuje status techniczny na etykiete biznesowa (bez kodu statusu),
|
|
- renderuje widok `resources/views/orders/list.php` i komponent tabeli `resources/views/components/table-list.php`.
|
|
- na liscie zamowien nie ma juz akcji bulk print Drukuj etykiety; druk etykiet odbywa sie tylko przez flow pojedynczy (POST /api/print/jobs).
|
|
- `GET /orders/{id}`:
|
|
- `OrdersController::show(Request): Response`
|
|
- pobiera szczegoly przez `OrdersRepository::findDetails(int $orderId)`, statystyke statusow przez `statusCounts()` oraz konfiguracje przez `statusPanelConfig()`,
|
|
- pozycje zamowienia maja ten sam mechanizm rozwiazywania miniatur co lista (`media_url` z zamowienia lub obraz z mapowania produktu),
|
|
- buduje panel statusow z grupami i licznikami (`buildStatusPanel(...)`),
|
|
- renderuje klikalne taby sekcji i przelaczanie paneli po stronie klienta (JS w `orders/show.php`),
|
|
- renderuje widok `resources/views/orders/show.php` z sekcjami:
|
|
- pozycje zamowienia,
|
|
- szczegoly zamowienia,
|
|
- platnosc i wysylka,
|
|
- adresy (`customer`, `invoice`, `delivery`),
|
|
- notatki i historia statusow.
|
|
- Sidebar ma oddzielna grupe nawigacyjna:
|
|
- `Zamowienia` -> `Lista zamowien`.
|
|
|
|
## Skrypty techniczne (CLI)
|
|
- `bin/fix_status_codes.php`
|
|
- naprawa kodow grup/statusow (transliteracja PL -> ASCII, tryb `--dry-run`, opcja `--use-remote`).
|
|
- `bin/deploy_and_seed_orders.php`
|
|
- aplikuje generyczny schema zamowien z `database/drafts/20260302_orders_schema_v1.sql`,
|
|
- seeduje dane testowe (`--count`, `--append`, `--use-remote`, `--profile=default|realistic`),
|
|
- profil `realistic` utrzymuje spojne zaleznosci miedzy:
|
|
- statusem zamowienia,
|
|
- statusem i kwota platnosci,
|
|
- obecnoscia wysylek i dokumentow,
|
|
- historia przejsc statusow (deterministyczne sciezki zamiast losowych przeskokow).
|
|
|
|
## Przeplyw Ustawienia > Statusy
|
|
- `GET /settings/statuses`:
|
|
- `SettingsController::statuses(Request): Response`
|
|
- pobiera dane przez `OrderStatusRepository::listGroups()` i `OrderStatusRepository::listStatuses()`,
|
|
- renderuje widok `resources/views/settings/statuses.php`.
|
|
- `POST /settings/status-groups`:
|
|
- `SettingsController::createStatusGroup(Request): Response`
|
|
- waliduje CSRF i dane (`name`, `color_hex`, `is_active`),
|
|
- `code` jest generowany automatycznie z `name` i nie jest edytowany z UI,
|
|
- zapisuje przez `OrderStatusRepository::createGroup(...)`.
|
|
- `POST /settings/status-groups/update`:
|
|
- `SettingsController::updateStatusGroup(Request): Response`
|
|
- waliduje istnienie grupy i aktualizuje rekord przez `updateGroup(...)`,
|
|
- `code` pozostaje bez zmian (read-only po utworzeniu).
|
|
- `POST /settings/status-groups/delete`:
|
|
- `SettingsController::deleteStatusGroup(Request): Response`
|
|
- usuwa grupe przez `deleteGroup(...)`; statusy z tej grupy usuwane sa kaskadowo (FK).
|
|
- `POST /settings/status-groups/reorder`:
|
|
- `SettingsController::reorderStatusGroups(Request): Response`
|
|
- zapisuje kolejnosc drag-and-drop grup przez `OrderStatusRepository::reorderGroups(...)`,
|
|
- endpoint jest wywolywany automatycznie po upuszczeniu elementu listy (auto-save).
|
|
- `POST /settings/statuses/create`:
|
|
- `SettingsController::createStatus(Request): Response`
|
|
- waliduje grupe, pola statusu i zapisuje przez `createStatus(...)`.
|
|
- `POST /settings/statuses/update`:
|
|
- `SettingsController::updateStatus(Request): Response`
|
|
- waliduje dane i aktualizuje status przez `updateStatus(...)`,
|
|
- `code` pozostaje bez zmian (read-only po utworzeniu).
|
|
- `POST /settings/statuses/delete`:
|
|
- `SettingsController::deleteStatus(Request): Response`
|
|
- usuwa status przez `deleteStatus(...)`.
|
|
- `POST /settings/statuses/reorder`:
|
|
- `SettingsController::reorderStatuses(Request): Response`
|
|
- zapisuje kolejnosc drag-and-drop statusow w ramach grupy przez `OrderStatusRepository::reorderStatusesByGroup(...)`,
|
|
- endpoint jest wywolywany automatycznie po upuszczeniu elementu listy (auto-save).
|
|
|
|
## Nawigacja ustawien
|
|
- Sidebar (`resources/views/layouts/app.php`) ma nowy podlink:
|
|
- `Statusy` (`/settings/statuses`).
|
|
- `Cron` (`/settings/cron`).
|
|
- `Integracje` (`/settings/integrations`) - wspolny hub konfiguracji providerow.
|
|
- `Ksiegowosc` (`/settings/accounting`) - konfiguracja paragonow.
|
|
|
|
## Przeplyw Ustawienia > Ksiegowosc (konfiguracja paragonow)
|
|
- `GET /settings/accounting`:
|
|
- `ReceiptConfigController::index(Request): Response`
|
|
- pobiera liste konfiguracji przez `ReceiptConfigRepository::listAll()`,
|
|
- opcjonalnie laduje konfiguracje do edycji przez `findById()` (query param `edit`),
|
|
- renderuje widok `resources/views/settings/accounting.php`.
|
|
- `POST /settings/accounting/save`:
|
|
- `ReceiptConfigController::save(Request): Response`
|
|
- waliduje CSRF, nazwe (wymagana) i format numeracji (wymagany, musi zawierac `%N`),
|
|
- zapisuje przez `ReceiptConfigRepository::save(...)` (INSERT lub UPDATE wg obecnosci `id`).
|
|
- `POST /settings/accounting/toggle`:
|
|
- `ReceiptConfigController::toggleStatus(Request): Response`
|
|
- przelacza `is_active` przez `ReceiptConfigRepository::toggleStatus(...)`.
|
|
- `POST /settings/accounting/delete`:
|
|
- `ReceiptConfigController::delete(Request): Response`
|
|
- usuwa konfiguracje przez `ReceiptConfigRepository::delete(...)`,
|
|
- FK RESTRICT blokuje usuniecie jesli istnieja powiazane paragony.
|
|
|
|
## Przeplyw Wystawianie paragonu z zamowienia
|
|
- `GET /orders/{id}/receipt/create`:
|
|
- `ReceiptController::create(Request): Response`
|
|
- pobiera zamowienie (OrdersRepository::findDetails), aktywne konfiguracje, dane sprzedawcy,
|
|
- renderuje formularz `resources/views/orders/receipt-create.php`.
|
|
- `POST /orders/{id}/receipt/store`:
|
|
- `ReceiptController::store(Request): Response`
|
|
- waliduje CSRF, config_id, istnienie zamowienia,
|
|
- buduje snapshoty: seller_data_json (z company_settings), buyer_data_json (z adresow zamowienia), items_json (z pozycji),
|
|
- oblicza total_gross, sale_date (wg sale_date_source z konfiguracji), order_reference_value,
|
|
- generuje numer atomowo przez `ReceiptRepository::getNextNumber(...)` (INSERT ON DUPLICATE KEY UPDATE na receipt_number_counters),
|
|
- zapisuje paragon przez `ReceiptRepository::create(...)`,
|
|
- redirect na /orders/{id} z flash success.
|
|
|
|
## Przeplyw Ustawienia > Cron
|
|
- `GET /settings/cron`:
|
|
- `CronSettingsController::index(Request): Response`
|
|
- pobiera ustawienia `cron_run_on_web`, `cron_web_limit`,
|
|
- renderuje harmonogramy (`cron_schedules`) oraz kolejke/historie (`cron_jobs`),
|
|
- historia (`past_jobs`) ma stronicowanie po parametrze query `past_page` (25 rekordow na strone).
|
|
- `POST /settings/cron`:
|
|
- `CronSettingsController::save(Request): Response`
|
|
- waliduje CSRF,
|
|
- zapisuje `cron_run_on_web` i `cron_web_limit` do `app_settings`.
|
|
|
|
## Przeplyw wykonania crona
|
|
- `bin/cron.php`:
|
|
- laduje aplikacje i uruchamia `CronRunner::run($limit)`.
|
|
- `GET /cron?token=...`:
|
|
- publiczny trigger uruchamiany z zewnetrznego crona HTTPS,
|
|
- waliduje token `CRON_PUBLIC_TOKEN`,
|
|
- uruchamia `CronRunner::run($limit)` z limitem opartym o `cron_web_limit`.
|
|
- `App\Core\Application::maybeRunCronOnWeb(Request): void`:
|
|
- przy wlaczonej opcji `cron_run_on_web=1` uruchamia `CronRunner` podczas requestu HTTP,
|
|
- pomija endpointy `/cron` i `/cron/*` (dedykowany trigger uruchamia cron recznie, bez podwojenia),
|
|
- stosuje throttling sesyjny i lock DB (`GET_LOCK`) zeby uniknac wielu rownoleglych workerow.
|
|
- `CronRunner`:
|
|
- dispatchuje due schedule z `cron_schedules` do `cron_jobs`,
|
|
- pobiera pending joby wg priorytetu i czasu,
|
|
- wykonuje handler po `job_type`.
|
|
- Pierwszy aktywny handler:
|
|
- `allegro_token_refresh` -> `AllegroTokenRefreshHandler::handle(...)` (odswiezenie tokenu OAuth Allegro).
|
|
- Dodatkowy handler:
|
|
- `allegro_orders_import` -> `AllegroOrdersImportHandler::handle(...)` (automatyczny import zamowien Allegro).
|
|
- `allegro_status_sync` -> `AllegroStatusSyncHandler::handle(...)` (synchronizacja statusow wg kierunku z ustawien integracji Allegro).
|
|
- `shoppro_orders_import` -> `ShopproOrdersImportHandler::handle(...)` (automatyczny import zamowien z aktywnych integracji `shopPRO` z wlaczonym pobieraniem).
|
|
- `shoppro_order_status_sync` -> `ShopproStatusSyncHandler::handle(...)` (synchronizacja statusow shopPRO wg kierunku ustawionego per instancja).
|
|
- `shoppro_payment_status_sync` -> `ShopproPaymentStatusSyncHandler::handle(...)` (odswiezanie statusu platnosci zamowien shopPRO na podstawie flagi `paid`).
|
|
|
|
## Przeplyw tworzenia przesylki
|
|
- `GET /orders/{id}/shipment/prepare`:
|
|
- `ShipmentController::prepare(Request): Response`,
|
|
- laduje uslugi dostawy providerow z `ShipmentProviderRegistry` (aktualnie: `allegro_wza`, `apaczka`),
|
|
- pobiera automatyczne mapowanie formy dostawy przez `CarrierDeliveryMethodMappingRepository` (`source_system` + `source_integration_id` + `order_delivery_method`),
|
|
- dla dostaw punktowych (`parcel_external_id`/`parcel_name`) prefillem `receiver_name` sa dane klienta (a nie nazwa punktu/metody dostawy),
|
|
- gdy mapowanie nie zostanie znalezione, buduje komunikat diagnostyczny (brak mapowan dla instancji lub brak mapowania konkretnej metody) i przekazuje go do widoku.
|
|
- `POST /orders/{id}/shipment/create`:
|
|
- `ShipmentController::create(Request): Response`,
|
|
- wybiera providera dynamicznie po `provider_code` i deleguje do `ShipmentProviderInterface::createShipment(...)`,
|
|
- po sukcesie tworzenia paczki triggeruje automatyzacje `shipment.created` z kontekstem paczki (`package_id`, `provider`, `tracking_number`, `package_status`, `delivery_status`),
|
|
- dla `apaczka` waliduje wymagane punkty odbioru/nadania wg definicji uslugi (`service_structure`) i przy bledzie wyceny zwraca rozszerzona diagnostyke parametrow,
|
|
- dla `apaczka` przy bledzie API niedostepnego dnia nadania (np. `Pickup not available for selected day` lub `you can't place an order today`) w trybie `COURIER` serwis automatycznie ponawia `order_send` z `pickup.date` przesunieta na kolejny dzien roboczy (max 7 przesuniec),
|
|
- `apaczka` uzupelnia i wysyla `contact_person` dla nadawcy (z `Ustawienia > Dane firmy`) i odbiorcy (fallback z danych zamowienia),
|
|
- `apaczka` ustawia jawnie `pickup.type` (`SELF`/`COURIER`) na podstawie uslugi i obecnosci `sender_point_id`; dla `COURIER` dopelnia tez `pickup.date`, `pickup.hours_from`, `pickup.hours_to`,
|
|
- dla uslug punktowych `apaczka` payload adresu zawiera aliasy identyfikatora punktu (`point`, `foreign_address_id`, `point_id`) dla nadania i odbioru,
|
|
- `ApaczkaShipmentService::buildReceiverAddress(...)` sklada dane odbiorcy z fallbackami (formularz -> delivery -> punkt odbioru z `parcel_name` -> customer), a dla przesylek punktowych dodatkowo probuje uzupelnic adres punktu przez API `points`; przy dalszych brakach dopelnia minimum techniczne, aby nie blokowac tworzenia.
|
|
- `GET /orders/{id}/shipment/{packageId}/status`:
|
|
- `ShipmentController::checkStatus(Request): Response`,
|
|
- wybiera providera po `shipment_packages.provider` i deleguje `checkCreationStatus(...)`.
|
|
- dla providera `allegro_wza` po uzyskaniu `tracking_number` serwis probuje przekazac waybill do Allegro przez `POST /order/checkout-forms/{id}/shipments` (`AllegroApiClient::addShipmentToOrder(...)`),
|
|
- push waybilla jest wykonywany tylko dla zamowien `orders.source='allegro'` i niepustego `orders.source_order_id`,
|
|
- blad pushu waybilla do Allegro nie przerywa lokalnego flow tworzenia paczki (fallback niekrytyczny, paczka zostaje zapisana w orderPRO).
|
|
- `POST /orders/{id}/shipment/{packageId}/label`:
|
|
- `ShipmentController::label(Request): Response`,
|
|
- wybiera providera po `shipment_packages.provider` i deleguje `downloadLabel(...)`,
|
|
- dla Apaczka bledy typu `Label is not available for this order` oznaczaja paczke jako `error`, aby nie ponawiac nieskutecznych prob pobrania.
|
|
- `POST /orders/{id}/shipment/manual`:
|
|
- `ShipmentController::createManual(Request): Response`,
|
|
- tworzy rekord w `shipment_packages` z `provider='manual'`, `status='created'` i podanym `tracking_number`,
|
|
- opcjonalnie zapisuje nazwe przewoznika w `carrier_id`,
|
|
- loguje zdarzenie `shipment_manual` w `order_activity_log`,
|
|
- po sukcesie triggeruje automatyzacje `shipment.created` dla recznie dodanej paczki,
|
|
- `ShipmentPackageRepository::createManual(int $orderId, string $trackingNumber, ?string $carrierName): int`.
|
|
|
|
## Przeplyw Ustawienia > Integracje > Allegro
|
|
- `GET /settings/integrations/allegro`:
|
|
- `AllegroIntegrationController::index(Request): Response`
|
|
- odczytuje konfiguracje przez `AllegroIntegrationRepository::getSettings()`,
|
|
- renderuje `resources/views/settings/allegro.php` z domyslnym callback URL.
|
|
- `POST /settings/integrations/allegro/save`:
|
|
- `AllegroIntegrationController::save(Request): Response`
|
|
- waliduje CSRF, srodowisko, `redirect_uri` i date startu,
|
|
- zapisuje ustawienia przez `AllegroIntegrationRepository::saveSettings(...)`.
|
|
- `POST /settings/integrations/allegro/settings/save`:
|
|
- `AllegroIntegrationController::saveImportSettings(Request): Response`
|
|
- zapisuje interwal harmonogramu `allegro_orders_import` (w minutach) do `cron_schedules.interval_seconds`,
|
|
- zapisuje kierunek synchronizacji statusow i interwal synchronizacji statusow do `app_settings`,
|
|
- zapisuje interwal joba `allegro_status_sync` do `cron_schedules.interval_seconds`.
|
|
- `POST /settings/integrations/allegro/oauth/start`:
|
|
- `AllegroIntegrationController::startOAuth(Request): Response`
|
|
- waliduje CSRF i komplet danych OAuth (`client_id`, `client_secret`, `redirect_uri`),
|
|
- buduje URL autoryzacji przez `AllegroOAuthClient::buildAuthorizeUrl(...)` (scope: `orders:read` + `sale:offers:read`),
|
|
- zapisuje `state` w sesji i przekierowuje do Allegro.
|
|
- `POST /settings/integrations/allegro/import-single`:
|
|
- `AllegroIntegrationController::importSingleOrder(Request): Response`
|
|
- waliduje CSRF i `checkout_form_id`,
|
|
- uruchamia `AllegroOrderImportService::importSingleOrder(...)`,
|
|
- po imporcie pokazuje diagnostyke miniatur pozycji (ile pozycji ma obrazek i przyczyny brakow).
|
|
- `POST /settings/integrations/allegro/statuses/save`:
|
|
- `AllegroIntegrationController::saveStatusMapping(Request): Response`
|
|
- redirect stub — logika przeniesiona do `saveStatusMappingsBulk()`.
|
|
- `POST /settings/integrations/allegro/statuses/save-bulk`:
|
|
- `AllegroIntegrationController::saveStatusMappingsBulk(Request): Response`
|
|
- zapisuje mapowania zbiorczo z kluczem `orderpro_status_code` przez `AllegroStatusMappingRepository::replaceAllMappings(...)`.
|
|
- `AllegroStatusMappingRepository::listExternalStatuses()` — zwraca liste zewnetrznych statusow Allegro.
|
|
- `AllegroStatusMappingRepository::buildAllegroToOrderproMap()` — buduje mape allegro_status -> orderpro_status.
|
|
- `AllegroStatusMappingRepository::replaceAllMappings(array)` — atomowy zapis wszystkich mapowan.
|
|
- `AllegroStatusMappingRepository::upsertMapping(...)` — teraz klucz na `orderpro_status_code`.
|
|
- `POST /settings/integrations/allegro/statuses/delete`:
|
|
- `AllegroIntegrationController::deleteStatusMapping(Request): Response`
|
|
- usuwa mapowanie po `mapping_id`.
|
|
- `POST /settings/integrations/allegro/statuses/sync`:
|
|
- `AllegroIntegrationController::syncStatusesFromAllegro(Request): Response`
|
|
- pobiera statusy z API Allegro (`checkout-forms`) i dopisuje je do tabeli mapowan.
|
|
- `GET /settings/integrations/allegro/oauth/callback`:
|
|
- `AllegroIntegrationController::oauthCallback(Request): Response`
|
|
- waliduje `state` i `code`,
|
|
- wymienia `code` na tokeny przez `AllegroOAuthClient::exchangeAuthorizationCode(...)`,
|
|
- zapisuje tokeny przez `AllegroIntegrationRepository::saveTokens(...)`.
|
|
- `AllegroTokenManager`:
|
|
- Shared Allegro OAuth token resolver. Checks expiry and refreshes via `AllegroOAuthClient` when needed. Injected into all Allegro service classes (`AllegroOrderImportService`, `AllegroOrdersSyncService`, `AllegroStatusDiscoveryService`, `AllegroShipmentService`).
|
|
- `AllegroOrderImportService`:
|
|
- pilnuje waznosci tokenu przez `AllegroTokenManager::resolveToken()` (refresh przed requestem lub retry po `401`),
|
|
- pobiera zamowienie `GET /order/checkout-forms/{id}` przez `AllegroApiClient`,
|
|
- pobiera przesylki zamowienia `GET /order/checkout-forms/{id}/shipments` przez `AllegroApiClient::getCheckoutFormShipments(...)`,
|
|
- dla pozycji bez obrazka w checkout-form pobiera szczegoly oferty `GET /sale/product-offers/{offerId}` i uzupelnia `order_items.media_url`,
|
|
- mapuje forme wysylki Allegro (`delivery.method.name`/`delivery.method.id`) do pol zamowienia (`external_carrier_id`, `external_carrier_account_id`),
|
|
- dla dostawy do punktu odbioru mapuje adres `delivery.pickupPoint.address` i nazwe punktu do adresu typu `delivery`,
|
|
- mapuje terminy wysylki z `delivery.time.dispatch` do `send_date_min` / `send_date_max`,
|
|
- buduje diagnostyke importu miniatur (statystyki + przyczyny brakow),
|
|
- mapuje status Allegro na status orderPRO na podstawie `allegro_order_status_mappings`,
|
|
- mapuje payload Allegro na neutralny model tabel zamowien (z `integration_id` aktywnej instancji Allegro),
|
|
- zapisuje aggregate przez `OrderImportRepository::upsertOrderAggregate(...)`.
|
|
- `AllegroOrdersSyncService`:
|
|
- uruchamiany z crona (`allegro_orders_import`),
|
|
- korzysta z dynamicznego `integration_id` aktywnego srodowiska Allegro (zamiast stalej),
|
|
- respektuje ustawienia integracji (`orders_fetch_enabled`, `orders_fetch_start_date`),
|
|
- pobiera listy checkout forms (`GET /order/checkout-forms?sort=-updatedAt`) i importuje nowe/zmienione zamowienia,
|
|
- utrzymuje kursor sync i status ostatniego wykonania w `integration_order_sync_state`.
|
|
- `AllegroStatusSyncService`:
|
|
- uruchamiany z crona (`allegro_status_sync`),
|
|
- respektuje ustawienie kierunku `allegro_status_sync_direction`,
|
|
- dla kierunku `allegro_to_orderpro` wykorzystuje mechanizm importu zamowien do aktualizacji statusow,
|
|
- dla kierunku `orderpro_to_allegro` pushuje reczne zmiany statusow (`order_status_history.change_source=manual`) do API Allegro,
|
|
- push buduje mapping `orderpro_status_code -> allegro_status_code` z `allegro_order_status_mappings` (po odwroceniu kluczy mapowanie jest bezposrednie),
|
|
- push aktualizuje kursor `integration_order_sync_state.last_status_pushed_at` po sukcesie.
|
|
- `AllegroApiClient::updateCheckoutFormFulfillment()`:
|
|
- PUT `/order/checkout-forms/{id}/fulfillment`,
|
|
- body JSON: `{"status":"<ALLEGRO_STATUS>"}`,
|
|
- uzywane przez `AllegroStatusSyncService` w kierunku `orderpro_to_allegro`.
|
|
|
|
## Log aktywnosci zamowien
|
|
- Tabela `order_activity_log` rejestruje wszystkie zdarzenia dotyczace zamowienia.
|
|
- Typy zdarzen: `status_change`, `payment`, `invoice`, `shipment`, `message`, `document`, `import`, `note`.
|
|
- Rejestracja zdarzen: `OrdersRepository::recordActivity(...)`.
|
|
- Zmiana statusu: `OrdersRepository::updateOrderStatus(...)` — aktualizuje `orders.external_status_id`, wpisuje do `order_status_history` i `order_activity_log`.
|
|
- Import zamowienia: `AllegroOrderImportService::importSingleOrder(...)` — po upsert zamowienia rejestruje zdarzenie `import` w `order_activity_log` (nowy import lub re-import/aktualizacja), actor_type `import`, actor_name `Allegro`.
|
|
- Widok szczegolow zamowienia (`GET /orders/{id}`) wyswietla log aktywnosci w zakladce `Historia zmian`.
|
|
|
|
## Zmiana statusu zamowienia z widoku szczegolow
|
|
- `POST /orders/{id}/status`:
|
|
- `OrdersController::updateStatus(Request): Response`
|
|
- waliduje CSRF i wybrany status,
|
|
- wywoluje `OrdersRepository::updateOrderStatus(...)` (aktualizuje `orders.external_status_id`, wpisuje do `order_status_history` i `order_activity_log`),
|
|
- actor_type: `user`, actor_name: nazwa zalogowanego uzytkownika,
|
|
- po zapisie redirect do `GET /orders/{id}` z flash message (sukces/blad).
|
|
- Widok szczegolow zamowienia wyswietla dropdown ze wszystkimi aktywnymi statusami (pogrupowanymi wg grup statusow) obok aktualnego statusu.
|
|
|
|
## Przeplyw Ustawienia > Integracja Apaczka
|
|
- `GET /settings/integrations/apaczka`:
|
|
- `ApaczkaIntegrationController::index(Request): Response`
|
|
- odczytuje konfiguracje przez `ApaczkaIntegrationRepository::getSettings()`,
|
|
- renderuje `resources/views/settings/apaczka.php`.
|
|
- `POST /settings/integrations/apaczka/save`:
|
|
- `ApaczkaIntegrationController::save(Request): Response`
|
|
- waliduje CSRF i klucz API,
|
|
- zapisuje zaszyfrowany klucz API przez `ApaczkaIntegrationRepository::saveSettings(...)` do tabeli bazowej `integrations` (`type=apaczka`).
|
|
|
|
## Przeplyw Ustawienia > Integracja InPost
|
|
- `GET /settings/integrations/inpost`:
|
|
- `InpostIntegrationController::index(Request): Response`
|
|
- odczytuje konfiguracje przez `InpostIntegrationRepository::getSettings()`,
|
|
- renderuje `resources/views/settings/inpost.php`.
|
|
- `POST /settings/integrations/inpost/save`:
|
|
- `InpostIntegrationController::save(Request): Response`
|
|
- waliduje CSRF,
|
|
- zapisuje ustawienia przez `InpostIntegrationRepository::saveSettings(...)`:
|
|
- token API w `integrations.api_key_encrypted` (`type=inpost`),
|
|
- parametry specyficzne przewoznika w `inpost_integration_settings`.
|
|
|
|
## Przeplyw Ustawienia > Baza danych
|
|
- `GET /settings/database`:
|
|
- `SettingsController::database(Request): Response`
|
|
- pobiera `Migrator::status()`, przekazuje statystyki i liste pending migracji do widoku `resources/views/settings/database.php`.
|
|
- `POST /settings/database/migrate`:
|
|
- `SettingsController::migrate(Request): Response`
|
|
- waliduje CSRF,
|
|
- uruchamia `Migrator::runPending()`,
|
|
- zapisuje wynik do flash (`settings_success` / `settings_error`, `settings_migrate_logs`),
|
|
- wykonuje redirect do `GET /settings/database`.
|
|
|
|
## Zmiany nawigacji
|
|
- Sidebar ma teraz grupe `Ustawienia` z podlinkami:
|
|
- `Uzytkownicy` (`/settings/users`)
|
|
- `Baza danych` (`/settings/database`)
|
|
- `UsersController::index(Request): Response` ustawia:
|
|
- `activeMenu = settings`
|
|
- `activeSettings = users`
|
|
- Usunieto wewnetrzny pasek `settings-nav` z widokow podstron ustawien.
|
|
|
|
## Przeplyw Ustawienia > Szablony e-mail
|
|
- `GET /settings/email-templates`:
|
|
- `EmailTemplateController::index(Request): Response`
|
|
- renderuje liste szablonow (`resources/views/settings/email-templates.php`) i akcje tabeli.
|
|
- `GET /settings/email-templates/create`:
|
|
- `EmailTemplateController::create(Request): Response`
|
|
- renderuje osobna podstrone formularza tworzenia (`resources/views/settings/email-templates-form.php`).
|
|
- `GET /settings/email-templates/edit?id={id}`:
|
|
- `EmailTemplateController::edit(Request): Response`
|
|
- laduje wskazany szablon i renderuje osobna podstrone formularza edycji.
|
|
- `POST /settings/email-templates/save`:
|
|
- `EmailTemplateController::save(Request): Response`
|
|
- waliduje CSRF i wymagane pola,
|
|
- przy bledzie wraca na odpowiednia podstrone formularza (`create` lub `edit`),
|
|
- po sukcesie zapisuje szablon i wraca do listy.
|
|
|
|
## Zasady aktualizacji
|
|
- Przy kazdej zmianie dopisz:
|
|
- nowe klasy i metody (sygnatury + odpowiedzialnosc),
|
|
- zmiany przeplywu request -> controller -> repository,
|
|
- kontrakty wejscia/wyjscia istotnych metod.
|
|
## Przeplyw Ustawienia > Integracje (hub)
|
|
- `GET /settings/integrations`:
|
|
- `IntegrationsHubController::index(Request): Response`
|
|
- buduje liste instancji providerow (Allegro sandbox/production, Apaczka, InPost, shopPRO),
|
|
- pokazuje tabele podsumowania i przycisk `Ustawienia` w kazdym wierszu,
|
|
- przycisk `Ustawienia` prowadzi do dedykowanego ekranu providera (`/settings/integrations/allegro|apaczka|inpost|shoppro`),
|
|
- renderuje `resources/views/settings/integrations.php`.
|
|
|
|
## Przeplyw Ustawienia > Integracje > shopPRO
|
|
- `GET /settings/integrations/shoppro`:
|
|
- `ShopproIntegrationsController::index(Request): Response`
|
|
- pobiera liste instancji przez `ShopproIntegrationsRepository::listIntegrations()`,
|
|
- opcjonalnie laduje wskazana instancje (`?id=`) przez `findIntegration(...)`,
|
|
- renderuje `resources/views/settings/shoppro.php` z zakladkami: `Integracja`, `Statusy`, `Ustawienia`, `Formy dostawy`.
|
|
- `POST /settings/integrations/shoppro/save`:
|
|
- `ShopproIntegrationsController::save(Request): Response`
|
|
- waliduje CSRF, nazwe, URL (`http|https`), klucz API (wymagany przy nowej konfiguracji) oraz format daty `orders_fetch_start_date` (`Y-m-d`),
|
|
- zapisuje konfiguracje przez `ShopproIntegrationsRepository::saveIntegration(...)` do tabeli bazowej `integrations` (`type=shoppro`),
|
|
- zapisuje interwal joba `shoppro_orders_import` (minuty) do `cron_schedules.interval_seconds`,
|
|
- zapisuje kierunek synchronizacji statusow per instancja (`integrations.order_status_sync_direction`),
|
|
- zapisuje interwal joba `shoppro_order_status_sync` (minuty) do `cron_schedules.interval_seconds`,
|
|
- zapisuje interwal joba `shoppro_payment_status_sync` (minuty) do `cron_schedules.interval_seconds`,
|
|
- zapisuje liste statusow orderPRO (per instancja) dla kontroli platnosci (`integrations.payment_sync_status_codes_json`).
|
|
- `POST /settings/integrations/shoppro/test`:
|
|
- `ShopproIntegrationsController::test(Request): Response`
|
|
- waliduje CSRF i `integration_id`,
|
|
- wykonuje test API przez `ShopproIntegrationsRepository::testConnection(...)`,
|
|
- zapisuje wynik testu w `integrations.last_test_*` i `integration_test_logs`.
|
|
- `POST /settings/integrations/shoppro/statuses/sync`:
|
|
- `ShopproIntegrationsController::syncStatuses(Request): Response`
|
|
- pobiera slownik statusow z API (`dictionaries/statuses`) przez `ShopproIntegrationsRepository::fetchOrderStatuses(...)`,
|
|
- przekazuje odkryte statusy do widoku zakladki `Statusy` (flash/sesja).
|
|
- `POST /settings/integrations/shoppro/statuses/save`:
|
|
- `ShopproIntegrationsController::saveStatusMappings(Request): Response`
|
|
- waliduje CSRF, `integration_id` i kody statusow orderPRO,
|
|
- zapisuje mapowania per instancja shopPRO przez `ShopproStatusMappingRepository::replaceForIntegration(...)` do `order_status_mappings` (klucz: `orderpro_status_code`).
|
|
- `ShopproStatusMappingRepository::listExternalStatuses(int)` — zwraca liste zewnetrznych statusow shopPRO dla danej integracji.
|
|
- `ShopproIntegrationsController` uzywa `buildMappingIndex()` + `buildExternalStatusOptions()` zamiast poprzedniego `buildStatusRows()`.
|
|
- `POST /settings/integrations/shoppro/delivery/save`:
|
|
- `ShopproIntegrationsController::saveDeliveryMappings(Request): Response`
|
|
- waliduje CSRF i `integration_id`,
|
|
- zapisuje mapowania form dostawy przez `ShopproDeliveryMethodMappingRepository::saveMappings(...)` (per instancja).
|
|
- `ShopproOrdersSyncService`:
|
|
- uruchamiany z crona (`shoppro_orders_import`),
|
|
- pobiera liste zamowien i (opcjonalnie) szczegoly zamowienia z API shopPRO,
|
|
- mapuje kwoty z fallbackami (`summary`, `paid`, `transport_cost`) oraz ceny pozycji (`price_brutto`),
|
|
- uzupelnia `order_items.media_url` przez pobranie `products/get` po `product_id`, gdy zamowienie nie zawiera obrazu.
|
|
- wykrywa zadanie faktury takze po obecnosci danych firmowych (`firm_*`) i ustawia `orders.is_invoice`,
|
|
- mapuje adres faktury do `order_addresses.address_type=invoice` (firma/NIP/adres) na podstawie pol `invoice`/`billing*`/`firm_*`,
|
|
- mapuje punkty odbioru (`inpost_paczkomat` / `orlen_point`) do adresu `delivery` (`parcel_external_id`, `parcel_name`, ulica/kod/miasto),
|
|
- uzupelnia `delivery` o telefon/e-mail klienta i etykiete metody dostawy z kosztem (`transport_cost`).
|
|
- `ShopproStatusSyncService`:
|
|
- uruchamiany z crona (`shoppro_order_status_sync`),
|
|
- obsluguje oba kierunki synchronizacji statusow:
|
|
- `shoppro_to_orderpro` (pull): wykorzystuje `ShopproOrdersSyncService` do odswiezenia statusow/importu danych,
|
|
- `orderpro_to_shoppro` (push): `syncPushDirection()` buduje reverse mapping (orderpro -> shoppro), query `order_status_history` po zmianach `change_source=manual`, wywoluje `ShopproApiClient::updateOrderStatus()` (PUT) dla kazdego zamowienia z mapowaniem, aktualizuje kursor `last_status_pushed_at`.
|
|
- push nie wysyla zmian z `change_source=import/sync` (zapobieganie petli).
|
|
- `ShopproApiClient::updateOrderStatus()`:
|
|
- PUT `/api.php?endpoint=orders&action=change_status&id={orderId}`,
|
|
- body JSON: `{"status_id": <int>, "send_email": <bool>}`,
|
|
- zwraca `{ok, http_code, message, changed}`.
|
|
- `ShopproPaymentStatusSyncService`:
|
|
- uruchamiany z crona (`shoppro_payment_status_sync`),
|
|
- pobiera zamowienia shopPRO nieoznaczone jako oplacone (`orders.payment_status != 2`) i nie-finalne,
|
|
- dla kazdego zamowienia odpytuje API `orders/get|details` i odczytuje flage `paid`,
|
|
- aktualizuje `orders.payment_status`, `orders.total_paid` i `order_payments`,
|
|
- zapisuje log `payment` do `order_activity_log`,
|
|
- respektuje liste statusow z `integrations.payment_sync_status_codes_json` (gdy pusta: fallback na pomijanie statusow finalnych).
|
|
- Zakladka `Formy dostawy` (shopPRO):
|
|
- laduje formy dostawy wykryte w zamowieniach danej instancji (`orders.source=shoppro` + `orders.integration_id`),
|
|
- laduje uslugi dostawy z Allegro API (`delivery-services`) z fallbackiem na odswiezenie tokenu OAuth,
|
|
- zapisuje mapowanie: forma dostawy shopPRO -> usluga Allegro/InPost WZA.
|
|
|
|
## Przeplyw Ustawienia > Zadania automatyczne (aktualizacja 2026-03-28)
|
|
- `GET /settings/automation`:
|
|
- `AutomationController::index(Request): Response` renderuje taby `Ustawienia` i `Historia`.
|
|
- tab `Ustawienia` zawiera istniejacy CRUD regul automatyzacji.
|
|
- tab `Historia` pokazuje wpisy z `automation_execution_logs` z filtrami (`event_type`, `execution_status`, `rule_id`, `order_id`, `date_from`, `date_to`) i paginacja (`history_page`, 25/strona).
|
|
- `AutomationService::trigger(...)` zapisuje historie wykonania reguly:
|
|
- status `success` po wykonaniu akcji,
|
|
- status `failed` przy wyjatku podczas wykonania reguly,
|
|
- zapisywany kontrakt: `event_type`, `rule_id`, `rule_name`, `order_id`, `execution_status`, `result_message`, `executed_at`, `context_json`.
|
|
- Akcja `update_order_status`:
|
|
- konfiguracja reguly przechowuje `status_code`,
|
|
- wykonanie delegowane do `OrdersRepository::updateOrderStatus(...)` (wspolny flow historii statusow i activity logu),
|
|
- aktor zmiany: `system` / `Automatyzacja: <nazwa reguly>`.
|
|
- Retencja historii:
|
|
- cron job `automation_history_cleanup` wywoluje `AutomationHistoryCleanupHandler::handle(...)`,
|
|
- handler usuwa wpisy starsze niz N dni (domyslnie 30) przez `AutomationExecutionLogRepository::purgeOlderThanDays(...)`.
|
|
|
|
## Klasy (aktualizacja 2026-03-28)
|
|
- `App\Modules\Automation\AutomationExecutionLogRepository` (create, paginate, count, listEventTypes, purgeOlderThanDays).
|
|
- `App\Modules\Cron\AutomationHistoryCleanupHandler` (cleanup retencji historii automatyzacji).
|
|
|