diff --git a/.paul/docs/API.md b/.paul/docs/API.md index cce27e0..c39e2fa 100644 --- a/.paul/docs/API.md +++ b/.paul/docs/API.md @@ -1,3 +1,177 @@ -# API +# API -> Endpointy, kontrakty request/response, autentykacja. +## Zakres +- Dokument opisuje aktualne endpointy z `routes/web.php` (stan repo: 2026-04-18). +- Runtime API jest oparte o sesje (`AuthMiddleware`) i CSRF dla formularzy. +- Publiczny endpoint bez sesji: `GET /cron` (token w query lub segmencie sciezki). +- API dla klienta drukowania uzywa `X-Api-Key` (`ApiKeyMiddleware`). + +## Uwierzytelnianie +- Session auth: wszystkie trasy panelowe i wiekszosc tras `/api/*`. +- API key auth: tylko zdalne kolejki druku. +- CSRF: wszystkie trasy `POST` w panelu (`_token` w body). + +## Endpointy publiczne +- `GET /health` - status aplikacji JSON. +- `GET /info` - strona info. +- `GET /cron?token=...` - uruchomienie crona przez HTTPS. +- `GET /cron/{tokenValue}` - alternatywny wariant tokenu w sciezce. + +## Auth +- `GET /login` - formularz logowania. +- `POST /login` - logowanie. +- `POST /logout` - wylogowanie. + +## Nawigacja i dashboard +- `GET /` - redirect do `/settings/users` (zalogowany) albo `/login`. +- `GET /users` - redirect do `/settings/users`. +- `GET /orders` - redirect do `/orders/list`. +- `GET /settings` - redirect do `/settings/users`. + +## Orders +- `GET /orders/list` - lista zamowien; AJAX zwraca fragmenty HTML tabeli/panelu statusow. +- `GET /orders/{id}` - szczegoly zamowienia. +- `POST /orders/{id}/status` - zmiana statusu; obsluguje HTML i AJAX JSON. +- `POST /orders/{id}/details/update` - update formy dostawy/platnosci. +- `POST /orders/{id}/send-email` - wysylka e-mail z szablonu (JSON). +- `POST /orders/{id}/email-preview` - preview e-maila (JSON: subject/body/attachments). +- `POST /orders/{id}/payment/add` - reczne dodanie platnosci (JSON). +- `GET /api/orders/search` - quick search (JSON). +- `GET /api/orders/{id}/preview` - podglad mini karty zamowienia (HTML fragment). + +## Receipts i accounting +- `GET /orders/{id}/receipt/create` +- `POST /orders/{id}/receipt/store` +- `GET /orders/{id}/receipt/{receiptId}` +- `GET /orders/{id}/receipt/{receiptId}/print` +- `GET /orders/{id}/receipt/{receiptId}/pdf` +- `GET /accounting` - lista paragonow. +- `POST /accounting/export` - eksport danych ksiegowych. + +## Shipments +- `GET /orders/{id}/shipment/prepare` +- `POST /orders/{id}/shipment/create` +- `GET /orders/{id}/shipment/{packageId}/status` +- `POST /orders/{id}/shipment/{packageId}/label` +- `POST /orders/{id}/shipment/manual` +- `POST /orders/{id}/shipment/{packageId}/delete` + +## Printing API +- Session auth: +- `POST /api/print/jobs` - dodanie zlecenia druku. +- `GET /api/print/jobs/status` - statusy kolejek. +- API key auth (`X-Api-Key`): +- `GET /api/print/jobs/pending` - lista zadan `pending`. +- `GET /api/print/jobs/{id}/download` - pobranie etykiety. +- `POST /api/print/jobs/{id}/complete` - finalizacja zadania. + +## Settings: users i baza +- `GET /settings/users` +- `POST /settings/users` +- `GET /settings/database` +- `POST /settings/database/migrate` + +## Settings: statusy +- `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` + +## Settings: cron i integracje +- `GET /settings/cron` +- `POST /settings/cron` +- `GET /settings/integrations` + +## Settings: Allegro +- `GET /settings/integrations/allegro` +- `POST /settings/integrations/allegro/save` +- `POST /settings/integrations/allegro/settings/save` +- `POST /settings/integrations/allegro/oauth/start` +- `GET /settings/integrations/allegro/oauth/callback` +- `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/save-pull` +- `POST /settings/integrations/allegro/statuses/sync` +- `POST /settings/integrations/allegro/delivery/save` + +## Settings: Apaczka / Inpost / shopPRO +- `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/save-pull` +- `POST /settings/integrations/shoppro/statuses/sync` +- `POST /settings/integrations/shoppro/delivery/save` + +## Settings: firma, e-mail, automatyzacja, delivery mapping +- `GET /settings/company` +- `POST /settings/company/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/email-templates/variables` +- `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/duplicate` +- `POST /settings/automation/toggle` +- `GET /settings/delivery-status-mappings` +- `POST /settings/delivery-status-mappings/save` +- `POST /settings/delivery-status-mappings/save-bulk` +- `POST /settings/delivery-status-mappings/reset` +- `POST /settings/delivery-status-mappings/reset-all` + +## Settings: druk i mapowania projektow +- `GET /settings/printing` +- `POST /settings/printing/keys/create` +- `POST /settings/printing/keys/{id}/delete` +- `POST /settings/printing/jobs/delete` +- `GET /settings/project-mappings` +- `POST /settings/project-mappings` +- `POST /settings/project-mappings/{id}/update` +- `POST /settings/project-mappings/{id}/delete` +- `POST /settings/project-mappings/{id}/toggle` + +## API shipment presets +- `GET /api/shipment-presets` +- `POST /api/shipment-presets` +- `POST /api/shipment-presets/update` +- `POST /api/shipment-presets/delete` + +## Kontrakty JSON (najwazniejsze) +- `GET /health`: `{status, app, timestamp}`. +- `GET /cron*`: `{ok, message, limit, timestamp}` albo blad `{ok:false, message, error?}`. +- `POST /api/print/jobs`: tworzy rekord kolejki dla `package_id`; zwraca JSON statusu. +- `GET /api/print/jobs/pending`: lista pending dla klienta desktop. +- `POST /api/print/jobs/{id}/complete`: potwierdza wydruk, ustawia `completed`. +- `GET /api/orders/search`: `{results:[...]}`. +- `POST /orders/{id}/payment/add`: `{ok, payment_id, payment_status, total_paid}` lub blad. diff --git a/.paul/docs/ARCHITECTURE.md b/.paul/docs/ARCHITECTURE.md index e76060e..c0c24d8 100644 --- a/.paul/docs/ARCHITECTURE.md +++ b/.paul/docs/ARCHITECTURE.md @@ -1,3 +1,94 @@ -# ARCHITECTURE +# ARCHITECTURE -> Struktura klas, modulow, przeplywow i zaleznosci w projekcie. +## Zakres +- Dokument opisuje aktualna architekture kodu (stan repo: 2026-04-18). +- Zrodlem prawdy sa: `src/`, `routes/web.php`, `database/migrations/`. + +## Warstwy systemu +- `Core`: bootstrap aplikacji, router, request/response, sesja, template, migrator, logger. +- `Modules/*Controller`: obsluga requestow HTTP i walidacja wejscia. +- `Modules/*Repository`: dostep do danych przez PDO/Medoo (prepared statements). +- `Modules/*Service`: logika domenowa i integracje zewnetrzne. +- `Cron`: runner, schedulery i handlery jobow okresowych. + +## Moduly domenowe +- `Auth`: logowanie, wylogowanie, middleware sesyjne. +- `Users`: zarzadzanie uzytkownikami panelu. +- `Orders`: lista, szczegoly, statusy, platnosci reczne, preview, quick search. +- `Shipments`: przygotowanie, tworzenie, status trackingu, etykiety, usuwanie, paczki reczne. +- `Accounting`: paragony i eksport ksiegowy. +- `Email`: wysylka i preview wiadomosci z resolverem zmiennych i zalacznikow. +- `Automation`: reguly event-condition-action, historia wykonan. +- `Settings`: konfiguracja statusow, integracji, cron, skrzynek, szablonow, drukowania, mapowan projektow. +- `Printing`: API kolejkowania wydruku i klucze API dla klienta desktop. +- `Cron`: synchronizacje integracji i zadania utrzymaniowe. +- `Info`: endpoint diagnostyczny `/info`. + +## Kluczowe klasy i odpowiedzialnosci +- `App\Core\Application`: bootstrap, dispatch requestu, opcjonalny web-cron z lockiem DB. +- `App\Modules\Cron\CronRunner`: pobiera kolejke jobow z `cron_schedules/cron_jobs` i wykonuje handlery. +- `App\Modules\Cron\CronHandlerFactory`: sklada zaleznosci i mapuje `job_type -> handler`. +- `App\Modules\Orders\OrdersController`: flow UI zamowien + endpointy AJAX. +- `App\Modules\Orders\OrdersRepository`: query listy/szczegolow zamowien, update statusow, activity log. +- `App\Modules\Shipments\ShipmentController`: flow przesylek i etykiet. +- `App\Modules\Shipments\ShipmentProviderRegistry`: wybor providera wysylki po `provider_code`. +- `App\Modules\Printing\PrintApiController`: endpointy kolejki wydruku (session/api-key). +- `App\Modules\Automation\AutomationService`: trigger eventow, ewaluacja warunkow, wykonanie akcji. +- `App\Modules\Settings\ProjectMappingController`: CRUD mapowania produkt -> skrypt generacji projektu. + +## Integracje zewnetrzne +- Allegro: OAuth, import zamowien, sync statusow push/pull, mapowania statusow i dostaw. +- shopPRO: import zamowien, sync statusow push/pull, sync platnosci, mapowania statusow i dostaw. +- Apaczka: konfiguracja API, tworzenie i tracking przesylek. +- InPost: konfiguracja API, tworzenie i tracking przesylek. + +## Glowny przeplyw HTTP +- Request -> `Router` -> middleware (`AuthMiddleware` lub `ApiKeyMiddleware`) -> Controller. +- Controller waliduje dane i CSRF, wywoluje Repository/Service. +- Response: HTML (widoki) albo JSON (endpointy AJAX/API). + +## Glowny przeplyw Cron +- Trigger: +- `GET /cron` (public token) lub web-cron w `Application::maybeRunCronOnWeb`. +- `CronRunner::run(limit)` przetwarza aktywne zadania. +- Obslugiwane joby: +- `allegro_token_refresh` +- `allegro_orders_import` +- `allegro_status_sync` +- `shoppro_orders_import` +- `shoppro_order_status_sync` +- `shoppro_payment_status_sync` +- `shipment_tracking_sync` +- `automation_history_cleanup` +- `order_status_aged` + +## Automatyzacja +- Triggerowana z wielu miejsc (m.in. zmiana statusu, przesylki, platnosci, wystawienie paragonu, cron age). +- `AutomationService`: +- wyszukuje aktywne reguly po `event_type`, +- sprawdza warunki, +- wykonuje akcje (`send_email`, `issue_receipt`, `update_shipment_status`, `update_order_status`), +- zapisuje wynik do `automation_execution_logs`. + +## Printing +- Panel tworzy job `print_jobs` przez `/api/print/jobs`. +- Klient desktop pobiera pending joby przez API key. +- Klient pobiera etykiete i zamyka job przez `/complete`. +- Konfiguracja i zarzadzanie kluczami: `PrintSettingsController` + `print_api_keys`. + +## Projekt generation +- `project_mappings` mapuje wzorzec nazwy produktu na `script_name` i `output_dir`. +- `order_items.project_generated` i `project_generated_at` trzymaja status wygenerowania artefaktu. +- UI konfiguracji: `/settings/project-mappings`. + +## Bezpieczenstwo +- Session auth dla panelu. +- API key auth dla zdalnego klienta druku. +- CSRF dla POST w panelu. +- Sekrety integracji szyfrowane przez `IntegrationSecretCipher`. + +## Zaleznosci miedzy modulami +- `Orders` korzysta z `Automation`, `Email`, `Printing`, `Shipments`, `Settings`. +- `Shipments` korzysta z `Orders`, `CompanySettings`, `Automation`. +- `Cron` spina `Settings`, `Orders`, `Shipments`, `Automation`, `Email`. +- `Automation` korzysta z `Orders`, `Email`, `Accounting`, `Shipments`. diff --git a/.paul/docs/DB_SCHEMA.md b/.paul/docs/DB_SCHEMA.md index 737ad36..7a62ab0 100644 --- a/.paul/docs/DB_SCHEMA.md +++ b/.paul/docs/DB_SCHEMA.md @@ -1,3 +1,178 @@ -# DB_SCHEMA +# DB_SCHEMA -> Schemat bazy danych — tabele, kolumny, FK, indeksy. +## Zakres i zrodlo prawdy +- Schemat wynika z migracji SQL w `database/migrations`. +- Dokument odzwierciedla stan repo na 2026-04-18 (migracje do `20260413_000100`). + +## Ostatnie istotne migracje +- `20260413_000100_ensure_orders_delivery_payment_columns.sql` +- `20260412_000099_add_requires_photo_to_project_mappings.sql` +- `20260412_000098_rename_external_status_id_to_status_code.sql` +- `20260412_000097_add_project_generation.sql` +- `20260410_000081_add_remember_token_to_users.sql` +- `20260408_000090_backfill_delivery_price.sql` +- `20260407_000083_allegro_pull_status_mappings.sql` +- `20260407_000080_backfill_personalization_message.sql` +- `20260407_000079_pull_status_mappings.sql` +- `20260407_000078_reverse_status_mapping_keys.sql` + +## Kompensacyjne migracje ensure_ +- `000038` - naprawa brakujacej tabeli `order_status_mappings`. +- `000039` - uzupelnienie brakujacych kolumn fetch w `integrations`. +- `000040` - seed/naprawa harmonogramu `shoppro_orders_import`. +- `000041` - seed/naprawa harmonogramu `shoppro_order_status_sync` + direction. +- `000042` - seed/naprawa `shoppro_payment_status_sync` + kolumny payment sync. +- `000100` - kompensacja brakujacych kolumn `orders.payment_method` i `orders.delivery_method`. + +## Kluczowe tabele + +### users +- Uzytkownicy panelu. +- Wazne kolumny: +- `id`, `email` (UNIQUE), `password_hash`, `remember_token` (od `000081`), `is_active`, `created_at`, `updated_at`. + +### orders +- Glowna tabela zamowien (model neutralny wzgledem zrodla). +- Wazne kolumny: +- `id`, `source`, `integration_id`, `source_order_id`, `internal_order_number` (UNIQUE), +- `status_code` (rename z `external_status_id` w `000098`), +- `payment_status`, `total_paid`, `payment_method`, +- `delivery_method`, `delivery_price` (dodane/backfill `000090`), +- daty zrodlowe i techniczne, `payload_json`, `preferences_json`. +- Wydajnosc: +- indeksy na `source`, `status_code`, `ordered_at`, `(source, status_code)`. + +### order_items +- Pozycje zamowienia. +- Wazne kolumny: +- `order_id`, `source_item_id`, `name`, `quantity`, `price_gross`, `media_url`, `payload_json`, +- `personalization` (`000075`, backfill `000080`), +- `project_generated`, `project_generated_at` (`000097`). + +### order_payments +- Platnosci zamowien (import i reczne). +- Wazne kolumny: +- `order_id`, `source_payment_id`, `payment_type_id`, `payment_date`, `amount`, `currency`, `payload_json`. +- Klucz unikalny: +- `(order_id, source_payment_id)`. + +### order_status_history +- Historia zmian statusow zamowienia. +- Wazne kolumny: +- `order_id`, `from_status_id`, `to_status_id`, `change_source`, `changed_by`, `changed_at`. + +### order_activity_log +- Uniwersalny log aktywnosci (`status_change`, `payment`, `shipment`, `import`, itd.). +- Wazne kolumny: +- `order_id`, `event_type`, `summary`, `details_json`, `actor_type`, `actor_name`, `created_at`. + +### order_status_groups i order_statuses +- Slownik statusow biznesowych i grup statusow. +- Relacja: +- `order_statuses.group_id -> order_status_groups.id` (`ON DELETE CASCADE`). + +### integrations +- Bazowa tabela instancji integracji. +- Wazne kolumny: +- `type`, `name`, `base_url`, `api_key_encrypted`, `is_active`, +- `orders_fetch_enabled`, `orders_fetch_start_date`, +- `order_status_sync_direction`, `payment_sync_status_codes_json`, +- pola diagnostyczne testu polaczenia. + +### integration_order_sync_state +- Kursor synchronizacji per integracja. +- Wazne kolumny: +- `integration_id` (PK), `last_synced_order_updated_at`, `last_synced_source_order_id`, +- `last_success_at`, `last_status_pushed_at`, `last_error`. + +### order_status_mappings +- Mapowania push statusow dla shopPRO. +- Po `000078` klucz unikalny: +- `(integration_id, orderpro_status_code)`. +- Dodatkowe indeksy: +- `(integration_id, shoppro_status_code)`. + +### order_status_pull_mappings +- Dedykowane mapowanie pull shopPRO -> orderPRO (`000079`). +- Klucz unikalny: +- `(integration_id, shoppro_status_code)`. + +### allegro_order_status_mappings +- Mapowania statusow Allegro dla kierunku push. +- Po `000078` klucz unikalny: +- `orderpro_status_code`. +- Indeks lookup: +- `allegro_status_code`. + +### allegro_order_status_pull_mappings +- Dedykowane mapowanie pull Allegro -> orderPRO (`000083`). +- Klucz unikalny: +- `allegro_status_code`. + +### allegro_integration_settings +- OAuth i tokeny Allegro per srodowisko/integracja. +- Wazne kolumny: +- `integration_id` (UNIQUE FK), `environment`, `client_id`, `client_secret_encrypted`, +- `redirect_uri`, `access_token_encrypted`, `refresh_token_encrypted`, `token_expires_at`, +- `orders_fetch_enabled`, `orders_fetch_start_date`. + +### apaczka_integration_settings i inpost_integration_settings +- Ustawienia providerow wysylek, powiazane 1:1 z `integrations` przez `integration_id`. + +### company_settings +- Dane firmy/nadawcy, parametry domyslnych paczek i pola ksiegowe. + +### receipt_configs, receipts, receipt_number_counters +- Konfiguracja numeracji, wystawione paragony i liczniki numerow. + +### email_mailboxes, email_templates, email_logs +- Skrzynki SMTP, szablony i log wysylki. + +### automation_rules, automation_conditions, automation_actions, automation_execution_logs +- Definicje regul i historia ich wykonan. + +### shipment_packages +- Rekordy przesylek i etykiet. +- Wazne kolumny trackingowe (od `000060`): +- `delivery_status`, `delivery_status_raw`, `delivery_status_updated_at`. + +### delivery_status_mappings +- Mapowanie statusow przewoznikow na status biznesowy (`provider + raw_status` UNIQUE). + +### carrier_delivery_method_mappings +- Wspolne mapowanie form dostawy na providerow wysylki. + +### shipment_presets +- Presety nadania wykorzystywane przez API presetow przesylek. + +### print_api_keys +- Klucze API dla klienta desktop druku. +- Kolumny: +- `key_hash` (UNIQUE), `key_prefix`, `is_active`, `last_used_at`. + +### print_jobs +- Kolejka wydruku etykiet. +- Kolumny: +- `order_id`, `package_id`, `label_path`, `status`, `created_by`, `created_at`, `completed_at`. + +### project_mappings +- Mapowanie produktu na skrypt generujacy projekt (`000097`). +- Wazne kolumny: +- `product_name_pattern`, `script_name`, `output_dir`, `requires_photo` (`000099`), `is_active`. + +## Harmonogram cron (cron_schedules) +- Wykorzystywane typy jobow: +- `allegro_token_refresh` +- `allegro_orders_import` +- `allegro_status_sync` +- `shoppro_orders_import` +- `shoppro_order_status_sync` +- `shoppro_payment_status_sync` +- `shipment_tracking_sync` +- `automation_history_cleanup` +- `order_status_aged` + +## Notatki kompatybilnosci +- Migracje `ensure_` i `000100` sa idempotentne i kompensuja roznice miedzy srodowiskami. +- Rename `orders.external_status_id -> status_code` wymaga, aby nowe query i dokumentacja uzywaly tylko `status_code`. +- `delivery_price` jest backfillowane z JSON payloadow importu (Allegro/shopPRO). diff --git a/DOCS/ARCHITECTURE.md b/DOCS/ARCHITECTURE.md deleted file mode 100644 index 44f4935..0000000 --- a/DOCS/ARCHITECTURE.md +++ /dev/null @@ -1,629 +0,0 @@ -# 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/save-pull` -- `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`), - - `buildReceiverAddress` laczy delivery + customer z fallbackami: jezeli delivery nie ma ulicy (`street_name`), wszystkie brakujace pola adresowe (name, street, city, zip, country, phone, email) sa uzupelniane z customer, - - 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. - - `ApaczkaShipmentService::buildOptionsPayload(array $formData): array` mapuje pola formularza (`weekend_delivery`) na klucze `option[]` w payloadzie API Apaczki (`order_send`). Klucz `19` = dostawa w sobote (InPost Paczka w Weekend); stala `OPTION_KEYS` trzyma mape pole_formularza -> id_opcji, walidacja boolean przez `filter_var(..., FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE)`. -- `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":""}`, - - 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.status_code`, 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.status_code`, 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/statuses/save-pull`: - - `ShopproIntegrationsController::savePullStatusMappings(Request): Response` - - waliduje CSRF, `integration_id` i kody statusow, - - zapisuje mapowania pull (shopPRO → orderPRO) przez `ShopproPullStatusMappingRepository::replaceForIntegration(...)` do `order_status_pull_mappings` (klucz: `shoppro_status_code`). - - `ShopproIntegrationsController` uzywa `buildPullMappingIndex()` do zaladowania pull mappings do widoku. -- `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`). - - `ShopproOrderMapper::extractPersonalization()` buduje personalizacje z pol: `attributes`, `custom_fields` i `message` (wiadomosc klienta z prefiksem "Wiadomosc:"). -- `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": , "send_email": }`, - - 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: `. -- 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). - diff --git a/DOCS/DB_SCHEMA.md b/DOCS/DB_SCHEMA.md deleted file mode 100644 index eafb66b..0000000 --- a/DOCS/DB_SCHEMA.md +++ /dev/null @@ -1,556 +0,0 @@ -# DB Schema - -## Compensating Migrations - -Migracje z prefiksem `ensure_` to migracje kompensujące — zostały dodane -2026-03-08 aby naprawić rozbieżności schematu między środowiskami. -Środowisko jest zsynchronizowane od 2026-03-08. Migracje są idempotentne. - -| Plik migracji | Kompensuje | Powód | -|---------------|------------|-------| -| 000038_ensure_order_status_mappings_table | 000020_create_order_status_mappings_table | Tabela nie dotarła do środowiska produkcyjnego | -| 000039_ensure_integrations_fetch_columns | 000017_add_shoppro_orders_fetch_settings | ALTER TABLE w 000017 nie-idempotentny; kolumny już istniały | -| 000040_ensure_shoppro_orders_import_schedule | 000018_create_orders_tables_and_schedule (cron seed) | Koryguje interval z 60s na 300s; używa IFNULL zamiast nadpisywania | -| 000041_ensure_shoppro_status_sync_schedule_and_direction | 000021_add_order_status_sync_direction_and_schedule | ALTER TABLE nie-idempotentny; koryguje interval z 3600s na 900s | -| 000042_ensure_shoppro_payment_sync_schedule_and_columns | brak (pierwsza migracja payment sync) | Prefiks ensure_ użyty defensywnie — brak wcześniejszej migracji dla payment sync | - -## Status -- Projekt po resecie do trybu `users-only`. -- Aktualizuj ten plik przy kazdej zmianie migracji/schematu. -- 2026-03-02: Przywrocenie UI `Ustawienia > Baza danych` nie wprowadza zmian w schemacie. -- 2026-03-02: Dodano tabele statusow (grupy + statusy) dla nowej zakladki `Ustawienia > Statusy`. -- 2026-03-02: Przygotowano draft generycznego schematu zamowien (bez aktywnej migracji) w `database/drafts/20260302_orders_schema_v1.sql`. -- 2026-03-03: Wdrozono generyczne tabele zamowien na bazie docelowej skryptem `bin/deploy_and_seed_orders.php` (bez migratora SQL). -- 2026-03-03: Dodano UI `Zamowienia > Lista zamowien` - bez zmian schematu (wykorzystuje istniejace tabele domeny zamowien). -- 2026-03-03: Dodano UI `Zamowienia > Szczegoly zamowienia` (`GET /orders/{id}`) - bez zmian schematu. -- 2026-03-04: Dodano tabele `allegro_integration_settings` pod konfiguracje OAuth2 Allegro i tokeny dostepowe. -- 2026-03-04: Dodano harmonogram crona `allegro_token_refresh` (co 3600s, priorytet 10, max 3 proby). -- 2026-03-04: Dodano reczny import pojedynczego zamowienia Allegro - bez zmian schematu (wykorzystuje istniejace tabele domeny zamowien). -- 2026-03-04: Dodano tabele `allegro_order_status_mappings` do mapowania statusow Allegro na statusy orderPRO. -- 2026-03-04: Zmieniono `allegro_order_status_mappings.orderpro_status_code` na nullable, aby zapisac statusy pobrane z Allegro przed przypisaniem mapowania. -- 2026-03-04: Dodano rozwiazywanie miniatur pozycji zamowien z mapowania produktu orderPRO (`product_channel_map` + `product_images`) - bez zmian schematu. -- 2026-03-04: Dodano diagnostyke importu miniatur Allegro (alerty przyczyn brakow) - bez zmian schematu. -- 2026-03-04: Dodano harmonogram `allegro_orders_import` (auto-import zamowien Allegro) oraz rozszerzono `integration_order_sync_state` o kolumny kursora sync (`last_synced_order_updated_at`, `last_synced_source_order_id`, `last_success_at`) - migracja `20260304_000027_add_allegro_orders_import_schedule.sql`. -- 2026-03-04: Dodano zakladke `Ustawienia` w integracji Allegro z konfiguracja interwalu importu zamowien; zapis aktualizuje istniejacy rekord `cron_schedules` (`job_type=allegro_orders_import`) - bez zmian schematu. -- 2026-03-04: Rozszerzono zakladke `Ustawienia` integracji Allegro o kierunek synchronizacji statusow i interwal synchronizacji statusow; zapis do `app_settings` (`allegro_status_sync_direction`, `allegro_status_sync_interval_minutes`) - bez zmian schematu. -- 2026-03-04: Dodano harmonogram `allegro_status_sync` (cron synchronizacji statusow) + defaulty `app_settings` dla kierunku i interwalu status sync - migracja `20260304_000028_add_allegro_status_sync_schedule.sql`. -- 2026-03-04: Import Allegro mapuje forme wysylki do `orders.external_carrier_id` i `orders.external_carrier_account_id` - bez zmian schematu. -- 2026-03-05: Dodano tabele `order_activity_log` — uniwersalny log aktywnosci zamowien (zmiany statusow, platnosci, przesylki, faktury, wiadomosci itp.). -- 2026-03-05: Dodano tabele `apaczka_integration_settings` pod konfiguracje klucza API Apaczka. -- 2026-03-05: Dodano tabele `inpost_integration_settings` pod konfiguracje integracji InPost ShipX. -- 2026-03-06: Dodano kolumne `carrier` do tabeli `allegro_delivery_method_mappings` (default 'allegro') - umozliwia mapowanie na roznych przewoznikow (Allegro, InPost). -- 2026-03-06: Wdrozono migracje `20260302_000019_add_internal_order_number_to_orders.sql` - kolumna `internal_order_number` VARCHAR(11) UNIQUE w tabeli `orders`, format `OPXXXXXXXXX` (np. `OP000000001`); backfill istniejacych rekordow; UI: lista i szczegoly zamowien wyswietlaja numer wewnetrzny jako glowny identyfikator. -- 2026-03-04: Poprawiono prezentacje daty zamowienia na liscie (`fallback ordered_at -> source_created_at -> source_updated_at -> fetched_at`) - bez zmian schematu. -- 2026-03-08: Rozpoczeto ujednolicanie integracji - migracja `20260308_000037_unify_integrations_base_links.sql`: - - dodano `integration_id` do tabel `allegro_integration_settings`, `apaczka_integration_settings`, `inpost_integration_settings`, - - dodano FK/UNIQUE 1:1 z tabela `integrations`, - - dodano/uzupelniono rekordy bazowe providerow (`allegro`, `apaczka`, `inpost`) w `integrations`. -- 2026-03-08: Dodano UI i endpointy konfiguracji `shopPRO` (wieloinstancyjnie) w oparciu o istniejaca tabele `integrations` (`type=shoppro`) - bez zmian schematu. -- 2026-03-08: Dodano mapowanie statusow dla `shopPRO` (zakladka `Statusy`) z zapisem do istniejacej tabeli `order_status_mappings` per `integration_id` - bez zmian schematu. -- 2026-03-08: Dodano migracje naprawcza `20260308_000038_ensure_order_status_mappings_table.sql` (uzupelnia brakujaca tabele `order_status_mappings` w srodowiskach z niepelna historia migracji). -- 2026-03-08: Dodano migracje naprawcza `20260308_000039_ensure_integrations_fetch_columns.sql` (uzupelnia brakujace kolumny `orders_fetch_enabled` i `orders_fetch_start_date` w `integrations`). -- 2026-03-08: Dodano migracje `20260308_000040_ensure_shoppro_orders_import_schedule.sql` (seed/naprawa harmonogramu `cron_schedules` dla joba `shoppro_orders_import`) - bez zmian schematu tabel. -- 2026-03-08: Dodano migracje `20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql` (seed/naprawa harmonogramu `cron_schedules` dla joba `shoppro_order_status_sync` oraz uzupelnienie kolumny `integrations.order_status_sync_direction` w srodowiskach niezgodnych). -- 2026-03-08: Dodano migracje `20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql`: - - uzupelnienie kolumny `integrations.payment_sync_status_codes_json` (JSON) dla konfiguracji statusow objetych kontrola platnosci, - - seed/naprawa harmonogramu `cron_schedules` dla joba `shoppro_payment_status_sync` (domyslnie 600s, priorytet 105). -- 2026-03-08: Dodano migracje `20260308_000043_create_shoppro_delivery_method_mappings_table.sql`: - - nowa tabela `shoppro_delivery_method_mappings` (mapowanie form dostawy per `integration_id`), - - tabela przechowuje mapowanie formy shopPRO na usluge Allegro WZA/InPost (`allegro_delivery_method_id`, `allegro_credentials_id`, `allegro_carrier_id`, `allegro_service_name`, `carrier`). -- 2026-03-08: Poprawiono mapowanie importu zamowien shopPRO (kwoty i miniatury pozycji) - bez zmian schematu bazy. -- 2026-03-08: Poprawiono mapowanie danych wysylki shopPRO (paczkomat/punkt odbioru + kontakt klienta + koszt transportu) - bez zmian schematu bazy. -- 2026-03-08: Dodano migracje `20260308_000044_create_carrier_delivery_method_mappings_table.sql`: - - nowa tabela `carrier_delivery_method_mappings` (wspolne mapowanie form dostawy dla roznych zrodel zamowien i providerow wysylek), - - migracja backfilluje dane z `allegro_delivery_method_mappings` i `shoppro_delivery_method_mappings`. -- 2026-03-08: Dodano migracje `20260308_000045_extend_apaczka_credentials.sql`: - - rozszerzenie `apaczka_integration_settings` o `app_id` i `app_secret_encrypted`, - - migracja przenosi legacy sekret z `api_key_encrypted` do `app_secret_encrypted`. -- 2026-03-08: Poprawiono mapowanie danych faktury w imporcie shopPRO - bez zmian schematu: - - `orders.is_invoice` jest wykrywany takze po polach firmowych (`firm_*`), - - adres faktury jest zapisywany do istniejacej tabeli `order_addresses` (`address_type=invoice`, `company_name`, `company_tax_number`). -- 2026-03-08: Poprawiono diagnostyke tworzenia przesylek Apaczka - bez zmian schematu: - - payload tworzenia przesylki przekazuje punkty odbioru/nadania (`receiver.point`, `sender.point`) z danych formularza, - - komunikaty bledow tworzenia zawieraja rozszerzona diagnostyke parametrow wyceny. -- 2026-03-08: Poprawiono obsluge bledow etykiet Apaczka - bez zmian schematu: - - przy odpowiedzi API `Label is not available for this order` rekord `shipment_packages` jest oznaczany statusem `error` i zachowuje tresc bledu. -- 2026-03-08: Poprawiono fallback danych odbiorcy dla przesylek punktowych Apaczka (Orlen/InPost) - bez zmian schematu: - - brakujace dane adresowe odbiorcy sa uzupelniane na etapie budowania payloadu z danych zamowienia (`delivery`, `customer`) oraz metadanych punktu (`parcel_name`). -- 2026-03-08: Rozszerzono fallback adresu odbiorcy dla przesylek punktowych Apaczka - bez zmian schematu: - - serwis probuje uzupelnic adres punktu przez API `points` po `receiver_point_id`, - - przy dalszych brakach danych dla przesylki punktowej dopelniane jest minimum techniczne wymagane przez lokalna walidacje payloadu. -- 2026-03-08: Poprawiono przekazywanie punktow w payloadzie Apaczka (nadanie/odbior) - bez zmian schematu: - - payload wysyla aliasy identyfikatora punktu (`point`, `foreign_address_id`, `point_id`) dla zgodnosci z wariantami API. -- 2026-03-08: Uzupelniono payload odbioru kurierem Apaczka (`pickup.date`, `pickup.hours_from`, `pickup.hours_to`) - bez zmian schematu. -- 2026-03-08: Dodano migracje `20260308_000046_extend_company_settings_contact_person.sql`: - - rozszerzenie `company_settings` o `sender_contact_person` (osoba kontaktowa nadawcy), - - wykorzystywane w payloadzie Apaczka jako `address.sender.contact_person`. -- 2026-03-08: Ujednolicono styl naglowkow sekcji UI (`section-title`) - bez zmian schematu bazy. -- 2026-03-14: Dodano migracje `20260314_000048_add_orders_performance_indexes.sql` — indeksy wydajnosciowe na tabeli `orders`: `source`, `status_code`, `ordered_at`, composite `(source, status_code)`. -- 2026-03-14: Dodano migracje `20260314_000049_add_cron_last_run_at_setting.sql` — seed klucza `cron_web_last_run_at` w `app_settings` (cron throttle przeniesiony z sesji do DB). -- 2026-03-14: Przemianowano migracje `20260301_000014_add_products_sku_format_setting.sql` na `20260301_000014b_add_products_sku_format_setting.sql` — deduplikacja numeru sekwencji (kolizja z `000014_create_product_integration_translations`). -- 2026-03-15: Dodano migracje `20260315_000050_create_receipt_configs_table.sql` — tabela konfiguracji paragonow (szablony numeracji, ustawienia imiennosci, zrodlo daty sprzedazy). -- 2026-03-15: Dodano migracje `20260315_000051_create_receipts_table.sql` — tabela wystawionych paragonow ze snapshotem danych (JSON seller/buyer/items), FK do orders i receipt_configs. -- 2026-03-15: Dodano migracje `20260315_000052_create_receipt_number_counters_table.sql` — liczniki numeracji paragonow per konfiguracja i okres (miesiac/rok). -- 2026-03-15: Dodano migracje `20260315_000053_extend_company_settings_extra_fields.sql` — rozszerzenie company_settings o bdo_number, regon, court_register, logo_path. -- 2026-03-15: Dodano migracje `20260315_000054_create_email_mailboxes_table.sql` — tabela skrzynek pocztowych SMTP (credentials szyfrowane IntegrationSecretCipher). -- 2026-03-15: Dodano migracje `20260315_000055_create_email_templates_table.sql` — tabela szablonow wiadomosci email z FK do email_mailboxes. -- 2026-03-15: Dodano migracje `20260315_000056_create_email_logs_table.sql` — tabela logow wyslanych wiadomosci z FK do email_templates, email_mailboxes i indeksami na order_id, status, sent_at. -- 2026-03-16: Dodano migracje `20260316_000001_add_attachment1_to_email_templates.sql` — kolumna attachment_1 VARCHAR(50) w email_templates (typ zalacznika, np. 'receipt'). -- 2026-03-17: Nowa zaleznosc `phpmailer/phpmailer` v7.0.2. Modul `App\Modules\Email` — wysylka e-mail z zamowien, resolwer zmiennych, generowanie zalacznikow PDF. Tabela `email_logs` wykorzystywana do logowania wysylek (bez nowych migracji). -- 2026-03-28: Rozszerzono automatyzacje o akcje `update_order_status` (zmiana statusu zamowienia) - bez zmian schematu (wykorzystuje istniejace `order_statuses`, `orders`, `order_status_history`, `order_activity_log`). -- 2026-03-28: Hotfix Apaczka bledow niedostepnego dnia nadania (`Pickup not available for selected day` oraz `you can't place an order today`) - bez zmian schematu (retry `order_send` z automatycznym przesuwaniem `pickup.date` dla `pickup.type=COURIER`). -- 2026-03-28: Dodano publiczny endpoint triggera crona HTTPS (`/cron`) z tokenem `CRON_PUBLIC_TOKEN` - bez zmian schematu bazy. -- 2026-03-28: Dodano migracje `20260328_000072_create_automation_execution_logs_table.sql`: - - nowa tabela `automation_execution_logs` (historia wykonan regul automatyzacji: co, kiedy, na jakim zamowieniu, wynik), - - indeksy pod filtrowanie po czasie/zdarzeniu/statusie/regule/zamowieniu, - - seed harmonogramu `cron_schedules` dla joba `automation_history_cleanup` (retencja historii starszej niz 30 dni). -- 2026-04-04: Hotfix trackingu Allegro Delivery (edge API) - rozszerzono mapowanie statusow EN i fallback keyword matching (`Parcel is awaiting pick-up`, `Parcel has been delivered`, itp.) w warstwie aplikacyjnej; bez zmian schematu bazy. -- 2026-04-07: Dodano tabele `order_status_pull_mappings` — dedykowane mapowanie pull (shopPRO → orderPRO) z UNIQUE na `(integration_id, shoppro_status_code)`. Migracja `20260407_000079_pull_status_mappings.sql` tworzy tabele i pre-populuje z istniejacych danych push mappings. - -## Tabele - -### `users` -- Uzytkownicy panelu. -- Klucz unikalny: `email`. - -### `order_status_groups` -- Grupy statusow zamowien zarzadzane z UI. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `name` (varchar 120), - - `code` (varchar 64, UNIQUE), - - `color_hex` (char 7, domyslnie `#64748b`), - - `sort_order` (int, domyslnie `0`), - - `is_active` (tinyint(1), domyslnie `1`), - - `created_at`, `updated_at`. -- Indeksy: - - `order_status_groups_code_unique` (UNIQUE: `code`), - - `order_status_groups_sort_order_idx` (`sort_order`). - -### `order_statuses` -- Statusy przypisane do grup statusow. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `group_id` (FK -> `order_status_groups.id`), - - `name` (varchar 120), - - `code` (varchar 64, UNIQUE), - - `sort_order` (int, domyslnie `0`), - - `is_active` (tinyint(1), domyslnie `1`), - - `created_at`, `updated_at`. -- Indeksy: - - `order_statuses_code_unique` (UNIQUE: `code`), - - `order_statuses_group_sort_idx` (`group_id`, `sort_order`, `id`). -- Klucze obce: - - `order_statuses_group_fk`: `group_id` -> `order_status_groups.id` (`ON DELETE CASCADE`, `ON UPDATE CASCADE`). - -### Domena zamowien (generyczna) -- Wdrozone tabele: - - `orders` - - `order_addresses` - - `order_items` - - `order_payments` - - `order_shipments` - - `order_documents` - - `order_notes` - - `order_status_history` - - `order_tags_dict` - - `order_tag_links` - - `integration_order_sync_state` -- Charakterystyka: - - schema neutralna wzgledem dostawcy API (pola `source_*`, `external_*`), - - kolekcje zamowienia rozdzielone na osobne tabele 1:N, - - `payload_json` dostepne dla diagnostyki/replay, - - `personalization` (TEXT, nullable) w `order_items` — dane personalizacji produktu z shopPRO (custom_fields), przechowywane jako czysty tekst, - - historia zmian statusow utrzymywana w `order_status_history`. - -### `integration_order_sync_state` -- Kursor synchronizacji importu zamowien dla integracji (uzywany przez cron auto-importu Allegro i push statusow shopPRO). -- Kolumny: - - `integration_id` (PK), - - `last_synced_order_updated_at` (datetime, nullable) lub historycznie `last_synced_external_updated_at`, - - `last_synced_source_order_id` (varchar, nullable) lub historycznie `last_synced_external_order_id`, - - `last_run_at` (datetime), - - `last_success_at` (datetime), - - `last_status_pushed_at` (datetime, nullable) — kursor synchronizacji push statusow orderPRO -> shopPRO, - - `last_error` (varchar 500), - - `created_at`, `updated_at`. - -### `order_status_mappings` -- Mapowanie statusow zamowien shopPRO na statusy orderPRO per instancja integracji. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `integration_id` (int unsigned, FK -> `integrations.id`), - - `shoppro_status_code` (varchar 64), - - `shoppro_status_name` (varchar 128, nullable), - - `orderpro_status_code` (varchar 64), - - `created_at`, `updated_at`. -- Indeksy: - - `order_status_mappings_integration_orderpro_unique` (UNIQUE: `integration_id`, `orderpro_status_code`), - - `order_status_mappings_integration_idx` (`integration_id`), - - `order_status_mappings_integration_shoppro_idx` (`integration_id`, `shoppro_status_code`). -- Klucze obce: - - `order_status_mappings_integration_fk`: `integration_id` -> `integrations.id` (`ON DELETE CASCADE`, `ON UPDATE CASCADE`). - -### `order_status_pull_mappings` -- Mapowanie pull statusow shopPRO na statusy orderPRO (kierunek import/pull). UNIQUE na shoppro_status_code per integracja. -- Kolumny: - - `id` (PK, int, AI), - - `integration_id` (int, NOT NULL), - - `shoppro_status_code` (varchar 100, NOT NULL), - - `shoppro_status_name` (varchar 255, nullable), - - `orderpro_status_code` (varchar 100, NOT NULL), - - `created_at`, `updated_at`. -- Indeksy: - - `order_status_pull_mappings_integration_shoppro_unique` (UNIQUE: `integration_id`, `shoppro_status_code`), - - `order_status_pull_mappings_integration_idx` (`integration_id`). - -### `allegro_integration_settings` -- Konfiguracja OAuth i sync dla integracji Allegro per srodowisko (`sandbox|production`) zarzadzana z `Ustawienia > Integracje > Allegro`. -- Kolumny: - - `id` (PK, tinyint unsigned), - - `integration_id` (int unsigned, UNIQUE, FK -> `integrations.id`), - - `environment` (varchar 16, `sandbox|production`), - - `client_id` (varchar 128), - - `client_secret_encrypted` (text), - - `redirect_uri` (varchar 255), - - `orders_fetch_enabled` (tinyint(1), domyslnie `0`), - - `orders_fetch_start_date` (date), - - `access_token_encrypted` (mediumtext), - - `refresh_token_encrypted` (mediumtext), - - `token_type` (varchar 32), - - `token_scope` (varchar 255), - - `token_expires_at` (datetime), - - `connected_at` (datetime), - - `created_at`, `updated_at`. -- Indeksy: - - `allegro_integration_settings_environment_idx` (`environment`), - - `allegro_integration_settings_token_expires_at_idx` (`token_expires_at`), - - `allegro_integration_settings_integration_unique` (`integration_id`, UNIQUE). - -### `allegro_order_status_mappings` -- Mapowanie kodow statusow Allegro na kody statusow orderPRO. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `allegro_status_code` (varchar 64, UNIQUE), - - `allegro_status_name` (varchar 120), - - `orderpro_status_code` (varchar 64), - - `created_at`, `updated_at`. -- Indeksy: - - `allegro_order_status_mappings_orderpro_unique` (UNIQUE: `orderpro_status_code`), - - `allegro_order_status_mappings_allegro_code_idx` (`allegro_status_code`). - -### `order_payments` -- Platnosci zamowien (z importu API lub reczne). -- Kolumny: - - `id` (PK, int unsigned, AI), - - `order_id` (int unsigned, FK -> `orders.id`, CASCADE), - - `source_payment_id` (varchar 64, nullable), - - `external_payment_id` (varchar 64, nullable), - - `payment_type_id` (varchar 64, NOT NULL) — typ: ONLINE, TRANSFER, CASH_ON_DELIVERY, - - `payment_date` (datetime, nullable), - - `amount` (decimal 12,2, nullable), - - `currency` (char 3, nullable), - - `comment` (varchar 255, nullable), - - `payload_json` (json, nullable), - - `created_at`, `updated_at`. -- Indeksy: - - `order_payments_order_source_payment_unique` (UNIQUE: `order_id`, `source_payment_id`), - - `order_payments_order_idx` (`order_id`), - - `order_payments_date_idx` (`payment_date`). -- Migracja: `20260330_000073_create_order_payments_table.sql` - -### `order_activity_log` -- Uniwersalny log aktywnosci zamowienia (zmiany statusow, platnosci, przesylki, faktury, wiadomosci itp.). -- Kolumny: - - `id` (PK, bigint unsigned, AI), - - `order_id` (FK -> `orders.id`, CASCADE), - - `event_type` (varchar 32) — typ zdarzenia: `status_change`, `payment`, `invoice`, `shipment`, `message`, `document`, `import`, `note`, - - `summary` (varchar 255) — czytelny opis zdarzenia, - - `details_json` (json, nullable) — dodatkowe dane strukturalne, - - `actor_type` (varchar 16, domyslnie `system`) — `system`, `user`, `import`, `api`, `sync`, - - `actor_name` (varchar 128, nullable) — nazwa uzytkownika lub identyfikator systemu, - - `created_at`. -- Indeksy: - - `order_activity_log_order_created_idx` (`order_id`, `created_at`), - - `order_activity_log_event_type_idx` (`event_type`). - -### `integrations` -- Bazowa tabela wszystkich instancji integracji (model docelowy pod wielu providerow i wiele kont per provider). -- Kolumny: - - `id` (PK, int unsigned, AI), - - `type` (varchar 32, np. `allegro`, `apaczka`, `inpost`, `shoppro`), - - `name` (varchar 128, unikalne w obrebie `type`), - - `base_url` (varchar 255), - - `api_key_encrypted` (text, nullable), - - `timeout_seconds` (smallint unsigned), - - `is_active` (tinyint(1)), - - `orders_fetch_enabled` (tinyint(1)), - - `orders_fetch_start_date` (date, nullable), - - `order_status_sync_direction` (varchar 32), - - `payment_sync_status_codes_json` (json, nullable; lista kodow statusow orderPRO, dla ktorych cron ma sprawdzac oplacenie zamowien), - - pola diagnostyki testu (`last_test_status`, `last_test_http_code`, `last_test_message`, `last_test_at`), - - `created_at`, `updated_at`. - -### `shoppro_delivery_method_mappings` -- Mapowanie form dostawy shopPRO na uslugi dostawy Allegro WZA/InPost per instancja integracji. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `integration_id` (int unsigned, FK -> `integrations.id`), - - `order_delivery_method` (varchar 200), - - `carrier` (varchar 50; np. `allegro`, `inpost`), - - `allegro_delivery_method_id` (varchar 128), - - `allegro_credentials_id` (varchar 128, nullable), - - `allegro_carrier_id` (varchar 128, nullable), - - `allegro_service_name` (varchar 255, nullable), - - `created_at`, `updated_at`. -- Indeksy: - - `shoppro_dm_mapping_unique` (UNIQUE: `integration_id`, `order_delivery_method`), - - `shoppro_dm_mapping_integration_idx` (`integration_id`). -- Klucze obce: - - `shoppro_dm_mapping_integration_fk`: `integration_id` -> `integrations.id` (`ON DELETE CASCADE`, `ON UPDATE CASCADE`). - -### `apaczka_integration_settings` -- Tabela kompatybilnosci dla integracji Apaczka (`id = 1`); sekret API jest utrzymywany bazowo w `integrations.api_key_encrypted`. -- Kolumny: - - `id` (PK, tinyint unsigned), - - `integration_id` (int unsigned, UNIQUE, FK -> `integrations.id`), - - `app_id` (varchar 128, nullable), - - `app_secret_encrypted` (text, nullable), - - `api_key_encrypted` (text, nullable), - - `created_at`, `updated_at`. - -### `carrier_delivery_method_mappings` -- Wspolne mapowanie form dostawy zamowien na providerow wysylek (model docelowy pod wielu kurierow: `allegro_wza`, `apaczka`, kolejne). -- Kolumny: - - `id` (PK, int unsigned, AI), - - `source_system` (varchar 32; np. `allegro`, `shoppro`), - - `source_integration_id` (int unsigned; `0` dla mapowan globalnych, np. Allegro), - - `order_delivery_method` (varchar 200), - - `provider` (varchar 50; np. `allegro_wza`, `apaczka`), - - `provider_service_id` (varchar 128), - - `provider_account_id` (varchar 128, nullable), - - `provider_carrier_id` (varchar 128, nullable), - - `provider_service_name` (varchar 255, nullable), - - `created_at`, `updated_at`. -- Indeksy: - - `carrier_dm_mapping_unique` (UNIQUE: `source_system`, `source_integration_id`, `order_delivery_method`), - - `carrier_dm_mapping_provider_idx` (`provider`), - - `carrier_dm_mapping_source_idx` (`source_system`, `source_integration_id`). - -### `inpost_integration_settings` -- Tabela ustawien specyficznych InPost ShipX (`id = 1`); token API utrzymywany bazowo w `integrations.api_key_encrypted`. -- Kolumny: - - `id` (PK, tinyint unsigned), - - `integration_id` (int unsigned, UNIQUE, FK -> `integrations.id`), - - `api_token_encrypted` (text, nullable), - - `organization_id` (varchar 50, nullable), - - `environment` (enum: sandbox, production), - - `default_dispatch_method` (enum: pop, parcel_locker, courier), - - `default_dispatch_point` (varchar 50, nullable), - - `default_insurance` (decimal 10,2, nullable), - - `default_locker_size` (enum: small, medium, large), - - `default_courier_length`, `default_courier_width`, `default_courier_height` (smallint unsigned), - - `label_format` (enum: Pdf, Zpl, Epl), - - `weekend_delivery`, `auto_insurance_value`, `multi_parcel` (tinyint 0/1), - - `created_at`, `updated_at`. - -### `company_settings` -- Ustawienia firmy/nadawcy wykorzystywane m.in. przy tworzeniu przesylek. -- Kolumny: - - `id` (PK, tinyint unsigned), - - `company_name` (varchar 200, nullable), - - `person_name` (varchar 200, nullable), - - `sender_contact_person` (varchar 200, nullable), - - `street` (varchar 200, nullable), - - `city` (varchar 128, nullable), - - `postal_code` (varchar 16, nullable), - - `country_code` (char 2, default `PL`), - - `phone` (varchar 64, nullable), - - `email` (varchar 128, nullable), - - `tax_number` (varchar 64, nullable), - - `bank_account` (varchar 64, nullable), - - `bank_owner_name` (varchar 200, nullable), - - `bdo_number` (varchar 20, nullable), - - `regon` (varchar 14, nullable), - - `court_register` (varchar 128, nullable), - - `logo_path` (varchar 255, nullable), - - `default_package_length_cm` (decimal 8,1), - - `default_package_width_cm` (decimal 8,1), - - `default_package_height_cm` (decimal 8,1), - - `default_package_weight_kg` (decimal 8,3), - - `default_label_format` (varchar 8), - - `created_at`, `updated_at`. - -### `receipt_configs` -- Konfiguracje paragonow (szablony numeracji, ustawienia). -- Kolumny: - - `id` (PK, int unsigned, AI), - - `name` (varchar 128), - - `is_active` (tinyint(1), default 1), - - `number_format` (varchar 64, default `PAR/%N/%M/%Y`), - - `numbering_type` (enum: monthly, yearly; default monthly), - - `is_named` (tinyint(1), default 0) — czy paragon imienny (dane klienta), - - `sale_date_source` (enum: order_date, payment_date, issue_date; default issue_date), - - `order_reference` (enum: none, orderpro, integration; default none), - - `created_at`, `updated_at`. - -### `receipts` -- Wystawione paragony ze snapshotem danych. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `order_id` (bigint unsigned, FK -> `orders.id` CASCADE), - - `config_id` (int unsigned, FK -> `receipt_configs.id` RESTRICT), - - `receipt_number` (varchar 64, UNIQUE), - - `issue_date` (datetime), - - `sale_date` (date), - - `seller_data_json` (json) — snapshot danych sprzedawcy, - - `buyer_data_json` (json, nullable) — snapshot danych klienta (jesli imienny), - - `items_json` (json) — snapshot pozycji zamowienia, - - `total_net` (decimal 12,2), - - `total_gross` (decimal 12,2), - - `order_reference_value` (varchar 128, nullable), - - `created_by` (int unsigned, nullable), - - `created_at`. -- Indeksy: - - `receipts_number_unique` (UNIQUE: `receipt_number`), - - `receipts_order_idx` (`order_id`), - - `receipts_config_idx` (`config_id`), - - `receipts_issue_date_idx` (`issue_date`). -- Klucze obce: - - `receipts_order_fk`: `order_id` -> `orders.id` (ON DELETE CASCADE), - - `receipts_config_fk`: `config_id` -> `receipt_configs.id` (ON DELETE RESTRICT). - -### `receipt_number_counters` -- Liczniki numeracji paragonow per konfiguracja i okres. -- Kolumny: - - `id` (PK, int unsigned, AI), - - `config_id` (int unsigned, FK -> `receipt_configs.id` CASCADE), - - `year` (smallint unsigned), - - `month` (tinyint unsigned, nullable — null dla numeracji rocznej), - - `last_number` (int unsigned, default 0). -- Indeksy: - - `receipt_counters_config_period_unique` (UNIQUE: `config_id`, `year`, `month`). -- Klucze obce: - - `receipt_counters_config_fk`: `config_id` -> `receipt_configs.id` (ON DELETE CASCADE). - -### `email_mailboxes` -- Skrzynki pocztowe SMTP do wysylki wiadomosci e-mail. -- Kolumny: - - `id` INT UNSIGNED PK AUTO_INCREMENT - - `name` VARCHAR(100) NOT NULL — nazwa wyswietlana - - `smtp_host` VARCHAR(255) NOT NULL - - `smtp_port` SMALLINT UNSIGNED NOT NULL DEFAULT 587 - - `smtp_encryption` ENUM('tls','ssl','none') NOT NULL DEFAULT 'tls' - - `smtp_username` VARCHAR(255) NOT NULL - - `smtp_password_encrypted` TEXT NOT NULL — szyfrowane IntegrationSecretCipher (AES-256-CBC+HMAC) - - `sender_email` VARCHAR(255) NOT NULL - - `sender_name` VARCHAR(200) DEFAULT NULL - - `header_html` TEXT DEFAULT NULL — HTML naglowek dolaczany do kazdego e-maila z tej skrzynki - - `footer_html` TEXT DEFAULT NULL — HTML stopka dolaczana do kazdego e-maila z tej skrzynki - - `is_default` TINYINT(1) NOT NULL DEFAULT 0 - - `is_active` TINYINT(1) NOT NULL DEFAULT 1 - - `created_at`, `updated_at` DATETIME - -### `email_templates` -- Szablony wiadomosci e-mail z systemem zmiennych. -- Kolumny: - - `id` INT UNSIGNED PK AUTO_INCREMENT - - `name` VARCHAR(200) NOT NULL — nazwa szablonu - - `subject` VARCHAR(500) NOT NULL — temat (moze zawierac zmienne) - - `body_html` TEXT NOT NULL — tresc HTML (Quill.js output) - - `mailbox_id` INT UNSIGNED DEFAULT NULL — FK do email_mailboxes ON DELETE SET NULL - - `attachment_1` VARCHAR(50) DEFAULT NULL — typ zalacznika nr 1 (np. 'receipt' = paragon); NULL = brak - - `is_active` TINYINT(1) NOT NULL DEFAULT 1 - - `created_at`, `updated_at` DATETIME -- Indeksy: `idx_email_templates_mailbox` (mailbox_id) - -### `email_logs` -- Log wyslanych wiadomosci e-mail. -- Kolumny: - - `id` BIGINT UNSIGNED PK AUTO_INCREMENT - - `template_id` INT UNSIGNED DEFAULT NULL — FK do email_templates ON DELETE SET NULL - - `mailbox_id` INT UNSIGNED DEFAULT NULL — FK do email_mailboxes ON DELETE SET NULL - - `order_id` INT UNSIGNED DEFAULT NULL - - `recipient_email` VARCHAR(255) NOT NULL - - `recipient_name` VARCHAR(200) DEFAULT NULL - - `subject` VARCHAR(500) NOT NULL - - `body_html` TEXT NOT NULL — tresc po rozwinieciu zmiennych - - `attachments_json` JSON DEFAULT NULL — lista zalacznikow [{name, path, type}] - - `status` ENUM('sent','failed','pending') NOT NULL DEFAULT 'pending' - - `error_message` TEXT DEFAULT NULL - - `sent_at` DATETIME DEFAULT NULL - - `created_at` DATETIME -- Indeksy: `idx_email_logs_template`, `idx_email_logs_mailbox`, `idx_email_logs_order`, `idx_email_logs_status`, `idx_email_logs_sent_at` - -### `automation_rules` -- Reguly automatyzacji (zdarzenie -> warunki -> akcje). -- Kolumny: - - `id` INT UNSIGNED PK AUTO_INCREMENT - - `name` VARCHAR(128) NOT NULL — nazwa reguly - - `event_type` VARCHAR(64) NOT NULL — typ zdarzenia (np. 'receipt.created') - - `is_active` TINYINT(1) NOT NULL DEFAULT 1 - - `created_at`, `updated_at` DATETIME -- Indeksy: - - `auto_rules_event_active_idx` (`event_type`, `is_active`) - -### `automation_conditions` -- Warunki reguly automatyzacji (laczenie logiczne AND). -- Kolumny: - - `id` INT UNSIGNED PK AUTO_INCREMENT - - `rule_id` INT UNSIGNED NOT NULL, FK -> `automation_rules.id` ON DELETE CASCADE - - `condition_type` VARCHAR(64) NOT NULL — typ warunku (np. 'integration') - - `condition_value` JSON NOT NULL — konfiguracja warunku (np. {"integration_ids": [1, 3]}) - - `sort_order` SMALLINT UNSIGNED NOT NULL DEFAULT 0 -- Indeksy: - - `auto_cond_rule_idx` (`rule_id`) -- Klucze obce: - - `auto_cond_rule_fk`: `rule_id` -> `automation_rules.id` (ON DELETE CASCADE) - -### `automation_actions` -- Akcje do wykonania po spelnieniu warunkow reguly. -- Kolumny: - - `id` INT UNSIGNED PK AUTO_INCREMENT - - `rule_id` INT UNSIGNED NOT NULL, FK -> `automation_rules.id` ON DELETE CASCADE - - `action_type` VARCHAR(64) NOT NULL — typ akcji (np. 'send_email') - - `action_config` JSON NOT NULL — konfiguracja akcji (np. {"template_id": 5, "recipient": "client"}) - - `sort_order` SMALLINT UNSIGNED NOT NULL DEFAULT 0 -- Indeksy: - - `auto_act_rule_idx` (`rule_id`) -- Klucze obce: - - `auto_act_rule_fk`: `rule_id` -> `automation_rules.id` (ON DELETE CASCADE) - -### `automation_execution_logs` -- Historia wykonan automatyzacji pokazywana w `Ustawienia > Zadania automatyczne > Historia`. -- Kolumny: - - `id` BIGINT UNSIGNED PK AUTO_INCREMENT - - `event_type` VARCHAR(64) NOT NULL — typ triggera (np. `receipt.created`, `shipment.created`) - - `rule_id` INT UNSIGNED NULL — FK do `automation_rules.id` (NULL gdy regula zostala usunieta) - - `rule_name` VARCHAR(128) NOT NULL — snapshot nazwy reguly w momencie wykonania - - `order_id` INT UNSIGNED NOT NULL — FK do `orders.id` - - `execution_status` VARCHAR(16) NOT NULL — wynik (`success`/`failed`) - - `result_message` VARCHAR(500) NULL — komunikat wykonania lub bledu - - `context_json` JSON NULL — zrzut kontekstu triggera (sanityzowany) - - `executed_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP - - `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP -- Indeksy: - - `auto_exec_logs_executed_idx` (`executed_at`) - - `auto_exec_logs_event_idx` (`event_type`) - - `auto_exec_logs_status_idx` (`execution_status`) - - `auto_exec_logs_rule_idx` (`rule_id`) - - `auto_exec_logs_order_idx` (`order_id`) -- Klucze obce: - - `auto_exec_logs_rule_fk`: `rule_id` -> `automation_rules.id` (`ON DELETE SET NULL`, `ON UPDATE CASCADE`) - - `auto_exec_logs_order_fk`: `order_id` -> `orders.id` (`ON DELETE CASCADE`, `ON UPDATE CASCADE`) - -## Zasady aktualizacji -- Po kazdej migracji dopisz: - - nowe/zmienione tabele i kolumny, - - indeksy i klucze obce, - - wplyw na dane i kompatybilnosc wsteczna. - -## Drafty (nieaktywne) -- `database/drafts/20260302_orders_schema_v1.sql`: - - propozycja normalizacji domeny zamowien pod integracje zewnetrzne (`orders`, `order_items`, `order_status_history`, platnosci, wysylki, dokumenty, notatki, tagi, sync-state), - - plik nie jest odpalany przez obecny migrator (`database/migrations/*.sql`). -- `bin/deploy_and_seed_orders.php`: - - techniczny skrypt wdrozeniowy, ktory aplikuje schema z draftu i opcjonalnie seeduje dane testowe. diff --git a/DOCS/ORDERS_SCHEMA_DRAFT.md b/DOCS/ORDERS_SCHEMA_DRAFT.md deleted file mode 100644 index 88c31f7..0000000 --- a/DOCS/ORDERS_SCHEMA_DRAFT.md +++ /dev/null @@ -1,44 +0,0 @@ -# Orders Schema Draft (Generic) - -## Context -- This is a generic schema proposal for external orders import/sync. -- API docs from Apilo were used only as an example of a rich order payload shape. -- Target is integration-agnostic storage (no vendor lock in table/column names). - -## Proposed tables -- `orders` -- `order_addresses` -- `order_items` -- `order_payments` -- `order_shipments` -- `order_documents` -- `order_notes` -- `order_status_history` -- `order_tags_dict` -- `order_tag_links` -- `integration_order_sync_state` - -SQL draft: -- [20260302_orders_schema_v1.sql](/C:/visual%20studio%20code/projekty/orderPRO/database/drafts/20260302_orders_schema_v1.sql) - -## Design principles -- Keep one row per imported source order in `orders`. -- Store child collections in dedicated tables (1:N). -- Keep source IDs and selected business scalars as first-class columns. -- Keep raw payload snapshots (`payload_json`) for diagnostics and replay safety. -- Keep import idempotent: - - unique `(integration_id, source_order_id)` in `orders`, - - unique child keys per order and source child ID. -- Keep event timeline in separate `order_status_history`. - -## Why these extra tables -- `order_status_history`: audit + timeline reconstruction + sync debugging. -- `integration_order_sync_state`: robust incremental fetch cursor. -- `order_tags_*`: proper many-to-many, easy filtering and deduplication. - -## Notes before implementation -- Draft is intentionally in `database/drafts` (not auto-run by Migrator). -- Before production migration: - - confirm source-specific mapping in service layer, - - confirm retention policy for `payload_json`, - - decide merge strategy for child rows (upsert by source IDs vs hard refresh per sync). diff --git a/DOCS/SHIPMENT_TRACKING_STATUSES.md b/DOCS/SHIPMENT_TRACKING_STATUSES.md deleted file mode 100644 index 98337ae..0000000 --- a/DOCS/SHIPMENT_TRACKING_STATUSES.md +++ /dev/null @@ -1,207 +0,0 @@ -# Statusy śledzenia przesyłek — dokumentacja API przewoźników - -## Spis treści -- [InPost ShipX API v1](#inpost-shipx-api-v1) -- [Apaczka API v2](#apaczka-api-v2) -- [Allegro Shipment Management API](#allegro-shipment-management-api) -- [Mapowanie na statusy znormalizowane](#mapowanie-na-statusy-znormalizowane) - ---- - -## InPost ShipX API v1 - -Endpoint: `GET /v1/organizations/{orgId}/shipments/{shipmentId}` -Pole statusu: `status` (string) -Historia: tablica `tracking_details[]` z polami `status`, `origin_status`, `datetime`, `agency` - -### Tworzenie i przygotowanie - -| Status | Opis PL | -|--------|---------| -| `created` | Przesyłka utworzona | -| `offers_prepared` | Oferty cenowe przygotowane | -| `offer_selected` | Oferta wybrana | -| `confirmed` | Przesyłka potwierdzona / opłacona | -| `dispatched` | Przesyłka nadana (etykieta wygenerowana) | - -### Odbiór od nadawcy - -| Status | Opis PL | -|--------|---------| -| `collected` | Przesyłka odebrana od nadawcy / wrzucona do paczkomatu | -| `taken_by_courier` | Przesyłka odebrana przez kuriera | -| `adopted_at_source_branch` | Przyjęta w oddziale źródłowym | - -### Sortowanie i transport - -| Status | Opis PL | -|--------|---------| -| `adopted_at_sorting_center` | Przyjęta w centrum sortowania | -| `sent_from_sorting_center` | Wysłana z centrum sortowania | -| `adopted_at_target_sorting_center` | Przyjęta w docelowym centrum sortowania | -| `sent_from_target_sorting_center` | Wysłana z docelowego centrum sortowania | -| `adopted_at_target_branch` | Przyjęta w oddziale docelowym | - -### Dostarczanie - -| Status | Opis PL | -|--------|---------| -| `out_for_delivery` | W drodze do odbiorcy / paczkomatu | -| `ready_to_pickup` | Gotowa do odbioru w paczkomacie | -| `pickup_reminder_sent` | Wysłano przypomnienie o odbiorze | -| `delivered` | Dostarczona / odebrana | -| `pickup_time_expired` | Czas odbioru z paczkomatu upłynął | - -### Awizo i ponowne doręczenie - -| Status | Opis PL | -|--------|---------| -| `avizo` | Awizowana (pierwsza próba doręczenia nieudana) | -| `claimed` | Odebrana po awizo | -| `readdressed` | Przekierowana na inny adres | -| `stack_in_box_machine` | Umieszczona w paczkomacie (overflow) | -| `stack_parcel_pickup_time_expired` | Czas odbioru ze stack upłynął | - -### Zwrot do nadawcy - -| Status | Opis PL | -|--------|---------| -| `returned_to_sender` | Zwrócona do nadawcy | -| `undelivered` | Niedoręczona | -| `undelivered_wrong_address` | Niedoręczona — błędny adres | -| `undelivered_incomplete_address` | Niedoręczona — niepełny adres | -| `undelivered_unknown_recipient` | Niedoręczona — nieznany odbiorca | -| `undelivered_cod_cash_receiver` | Niedoręczona — problem z pobraniem | - -### Anulowanie i wygaśnięcie - -| Status | Opis PL | -|--------|---------| -| `cancelled` | Anulowana | -| `expired` | Wygasła | - -### Inne / specjalne - -| Status | Opis PL | -|--------|---------| -| `ready_to_pickup_from_branch` | Gotowa do odbioru z oddziału | -| `ready_to_pickup_from_pok` | Gotowa do odbioru z POK | -| `oversized` | Przesyłka ponadgabarytowa | -| `missing` | Przesyłka zagubiona | -| `delay_in_delivery` | Opóźnienie w dostawie | -| `redirect_to_box` | Przekierowana do paczkomatu | -| `stack_in_customer_service_point` | Umieszczona w punkcie obsługi | -| `pickup_reminder_sent_address` | Przypomnienie wysłane na adres | - -### Uwagi -- InPost okresowo dodaje nowe statusy — warto sprawdzać `tracking_details` zamiast polegać na zamkniętej liście -- W `tracking_details` każdy wpis zawiera: `status`, `origin_status`, `datetime`, `agency` -- Dokładna lista może się różnić w zależności od typu usługi (paczkomat vs kurier vs POP) - ---- - -## Apaczka API v2 - -Endpoint: `GET /api/v2/order/{orderId}/` -Pole statusu: `status` (integer) -Autentykacja: `app_id` + podpis HMAC-SHA256 z `app_secret` - -### Statusy zamówienia - -| Wartość | Nazwa | Opis PL | -|---------|-------|---------| -| `0` | PENDING | Zamówienie utworzone, oczekuje na przetworzenie | -| `1` | CONFIRMED | Zamówienie potwierdzone | -| `2` | PICKED_UP | Przesyłka odebrana przez kuriera | -| `3` | IN_TRANSIT | Przesyłka w transporcie | -| `4` | OUT_FOR_DELIVERY | Przesyłka w doręczeniu | -| `5` | DELIVERED | Przesyłka doręczona | -| `6` | RETURNED | Przesyłka zwrócona do nadawcy | -| `7` | CANCELLED | Zamówienie anulowane | -| `8` | ERROR | Błąd zamówienia | -| `9` | WAITING_FOR_PICKUP | Oczekuje na odbiór w punkcie | -| `10` | REDIRECT | Przesyłka przekierowana | - -### Dodatkowe pola w odpowiedzi - -- `tracking_number` — numer śledzenia -- `tracking_status` — szczegółowy status śledzenia (może różnić się od `status`) -- `service_id` — identyfikator usługi kurierskiej - -### Uwagi -- Apaczka nie publikuje pełnej dokumentacji API publicznie — dostęp wymaga konta -- Powyższa lista wymaga weryfikacji z oficjalną dokumentacją (panel.apaczka.pl) -- Endpoint trackingu: `GET /api/v2/order/{orderId}/tracking/` (jeśli dostępny) - ---- - -## Allegro Shipment Management API - -Endpoint: `GET /shipment-management/shipments/{shipmentId}` -Pole statusu: `status` (string) - -### Statusy przesyłki (Shipment Management) - -| Status | Opis PL | -|--------|---------| -| `NEW` | Przesyłka utworzona, nie przekazana przewoźnikowi | -| `READY_TO_SHIP` | Etykieta wygenerowana, oczekuje na odbiór/nadanie | -| `IN_TRANSIT` | Przesyłka odebrana przez przewoźnika | -| `DELIVERED` | Przesyłka doręczona | -| `CANCELLED` | Przesyłka anulowana | -| `ERROR` | Błąd przetwarzania | -| `RETURNED` | Przesyłka zwrócona do nadawcy | - -### Statusy realizacji zamówienia (Order Fulfillment) - -Endpoint: `GET /order/checkout-forms/{checkoutFormId}` -Pole: `fulfillment.status` - -| Status | Opis PL | -|--------|---------| -| `NEW` | Zamówienie złożone, nie przetworzone | -| `PROCESSING` | Sprzedawca przetwarza zamówienie | -| `READY_FOR_SHIPMENT` | Spakowane, oczekuje na wysyłkę | -| `SENT` | Wysłane (numer śledzenia podany) | -| `DELIVERED` | Potwierdzone doręczenie | -| `CANCELLED` | Zamówienie anulowane | - -### Ważne ograniczenia -- **Allegro NIE ma dedykowanego API śledzenia przesyłek** (brak endpointu typu `/tracking/{trackingNumber}`) -- Shipment Management API daje statusy TYLKO dla przesyłek utworzonych przez zintegrowanych przewoźników Allegro -- Dla szczegółowego śledzenia trzeba odpytywać **API przewoźnika bezpośrednio** (InPost, DPD, DHL, etc.) -- Dla ręcznie wpisanych numerów śledzenia — brak automatycznego trackingu przez Allegro - ---- - -## Mapowanie na statusy znormalizowane - -System orderPRO używa dwupoziomowego systemu statusów: -1. **`delivery_status`** — znormalizowany status (dla UI, filtrów, logiki) -2. **`delivery_status_raw`** — surowy status z API przewoźnika - -### Tabela mapowania - -| Znormalizowany | InPost ShipX | Apaczka | Allegro SM | -|----------------|-------------|---------|------------| -| `unknown` | *(brak danych)* | *(brak danych)* | *(brak danych)* | -| `created` | `created`, `offers_prepared`, `offer_selected` | `0` (PENDING) | `NEW` | -| `confirmed` | `confirmed`, `dispatched` | `1` (CONFIRMED) | `READY_TO_SHIP` | -| `in_transit` | `collected`, `taken_by_courier`, `adopted_at_sorting_center`, `sent_from_sorting_center`, `adopted_at_target_sorting_center`, `sent_from_target_sorting_center`, `adopted_at_target_branch`, `adopted_at_source_branch` | `2` (PICKED_UP), `3` (IN_TRANSIT) | `IN_TRANSIT` | -| `out_for_delivery` | `out_for_delivery` | `4` (OUT_FOR_DELIVERY) | — | -| `ready_for_pickup` | `ready_to_pickup`, `ready_to_pickup_from_branch`, `ready_to_pickup_from_pok`, `stack_in_box_machine`, `stack_in_customer_service_point` | `9` (WAITING_FOR_PICKUP) | — | -| `delivered` | `delivered`, `claimed` | `5` (DELIVERED) | `DELIVERED` | -| `returned` | `returned_to_sender`, `undelivered`, `undelivered_wrong_address`, `undelivered_incomplete_address`, `undelivered_unknown_recipient`, `undelivered_cod_cash_receiver` | `6` (RETURNED) | `RETURNED` | -| `cancelled` | `cancelled`, `expired` | `7` (CANCELLED) | `CANCELLED` | -| `problem` | `avizo`, `pickup_time_expired`, `stack_parcel_pickup_time_expired`, `missing`, `delay_in_delivery`, `oversized` | `8` (ERROR), `10` (REDIRECT) | `ERROR` | - -### Uwagi do mapowania -- Status `problem` zbiera wszystkie nietypowe sytuacje wymagające uwagi (awizo, zagubienie, opóźnienie) -- Surowy status (`delivery_status_raw`) zawsze zachowuje oryginalną wartość z API -- Dla przesyłek `manual` — `delivery_status` zawsze `unknown` (brak automatycznego trackingu) -- Mapowanie powinno być zaimplementowane jako stałe w klasie per provider (łatwe do rozszerzenia) - ---- - -*Dokument utworzony: 2026-03-23* -*Źródła: InPost ShipX API docs, Apaczka API v2 docs (ograniczony dostęp), Allegro REST API docs* diff --git a/DOCS/TECH_CHANGELOG.md b/DOCS/TECH_CHANGELOG.md deleted file mode 100644 index 26e0845..0000000 --- a/DOCS/TECH_CHANGELOG.md +++ /dev/null @@ -1,1007 +0,0 @@ -# Tech Changelog - -## 2026-04-07 — Phase 79: Personalization Message Field - -Rozszerzenie importu personalizacji o pole `message` z API shopPRO. - -- **Problem:** ShopPRO API zwraca pole `message` na pozycjach zamowienia (wiadomosc personalizacji klienta, np. dedykacja), ale `extractPersonalization()` sprawdzalo tylko `attributes` i `custom_fields`. Pole `message` bylo ignorowane. -- **Fix:** `ShopproOrderMapper::extractPersonalization()` sprawdza teraz 3 pola: `attributes`, `custom_fields`, `message`. Pole `message` jest poprzedzone etykieta "Wiadomosc:". Migracja backfill uzupelnila 21 istniejacych pozycji. -- **Pliki:** `src/Modules/Settings/ShopproOrderMapper.php`, `database/migrations/20260407_000080_backfill_personalization_message.sql` - -## 2026-04-07 — Phase 78: Preset Auto Submit - -Presety przesylek automatycznie submituja formularz po autofill. - -- **Zmiana:** Funkcja `applyPreset()` po wypelnieniu pol formularza (200ms) czeka dodatkowe 300ms i wywoluje `form.submit()`. Dodano `id="shipment-form"` na formularz. -- **Pliki:** `resources/views/shipments/prepare.php` - -## 2026-04-07 — Phase 77: COD Amount Fix - -Naprawa automatycznego uzupelniania kwoty pobrania (COD) przy generowaniu przesylki dla zamowien shopPRO. - -- **Problem:** Widok `prepare.php` i `OrdersController` sprawdzaly `external_payment_type_id === 'CASH_ON_DELIVERY'` (format Allegro). ShopPRO wysyla pelna polska nazwe np. `"Platnosc przy odbiorze"`, wiec zamowienia shopPRO nigdy nie byly rozpoznawane jako pobraniowe. -- **Fix:** Nowa centralna metoda `StringHelper::isCodPayment()` z dwupoziomowa detekcja: exact match (CASH_ON_DELIVERY, COD, POBRANIE, ZA POBRANIEM) + keyword match (PRZY ODBIORZE, POBRANIEM, POBRANIE). `ShopproOrderMapper` normalizuje COD na `CASH_ON_DELIVERY` przy nowych importach. Wszystkie hardcoded sprawdzenia zastapione helperem. -- **Pliki:** `src/Core/Support/StringHelper.php`, `src/Modules/Settings/ShopproOrderMapper.php`, `resources/views/shipments/prepare.php`, `resources/views/orders/show.php`, `src/Modules/Orders/OrdersController.php` - -## 2026-04-07 — Phase 76: Shipment Receiver Fallback - -Naprawa pustych danych odbiorcy na stronie przygotowania przesylki dla zamowien shopPRO. - -- **Problem:** Gdy shopPRO zwraca zamowienie z metoda dostawy (np. "Kurier - przedplata: 0 zl") ale bez osobnego adresu dostawy, mapper tworzyl adres delivery z nazwa metody jako `name` i pustymi polami street/city/zip. `buildReceiverAddress` uzywal tego niekompletnego delivery jako bazy bez fallbacku na dane customer. -- **Fix:** `ShipmentController::buildReceiverAddress` — rozszerzono fallbacki z customer na pola `street_name`, `street_number`, `city`, `zip_code`, `country` (obok istniejacych `phone`, `email`). Dodano warunek: jezeli delivery nie ma `street_name`, `name` tez jest pobierane z customer (pokrywa przypadek gdy delivery name to label metody dostawy). -- **Pliki:** `src/Modules/Shipments/ShipmentController.php` - -## 2026-04-07 — Phase 75: Pull Status Mapping - -Rozdzielenie mapowania statusow shopPRO na dwa niezalezne kierunki: PUSH (orderPRO→shopPRO) i PULL (shopPRO→orderPRO). - -**Problem:** Phase 74 usunal UNIQUE na shoppro_status_code, pozwalajac wielu statusom orderPRO mapowac na ten sam kod shopPRO. Logika "first wins" w buildStatusMap() + ORDER BY orderpro_status_code ASC powodowala, ze import zawsze wybieralal alfabetycznie pierwszy status (np. "do_odbioru" zamiast "w_realizacji"). - -**Rozwiazanie:** Nowa tabela `order_status_pull_mappings` z UNIQUE na `(integration_id, shoppro_status_code)` — dedykowana do pull direction. Push mapping w `order_status_mappings` pozostaje bez zmian. - -**DB:** Migracja 20260407_000079 — nowa tabela order_status_pull_mappings, pre-populate z istniejacych danych. - -**Ochrona statusu przy re-imporcie:** Re-import z shopPRO nie nadpisuje `status_code` istniejacego zamowienia, CHYBA ZE obecny status to `nieoplacone` i shopPRO potwierdza platnosc (`payment_status = 2`). Wtedy status zmienia sie na zmapowany (np. `w_realizacji`) i importowane sa dane platnosci. W kazdym innym przypadku status jest zachowany — orderPRO jest master. - -**Pliki:** -- database/migrations/20260407_000079_pull_status_mappings.sql -- src/Modules/Settings/ShopproPullStatusMappingRepository.php — nowy repository (listByIntegration, replaceForIntegration) -- src/Modules/Settings/ShopproIntegrationsController.php — nowa zależność pullStatusMappings, savePullStatusMappings(), buildPullMappingIndex() -- src/Modules/Settings/ShopproOrdersSyncService.php — buildStatusMap() korzysta z pull tabeli gdy dostępna, activity log dla payment transition -- src/Modules/Orders/OrderImportRepository.php — ochrona statusu przy re-imporcie, payment transition logic, getCurrentStatus() -- src/Modules/Cron/CronHandlerFactory.php — wstrzyknięcie ShopproPullStatusMappingRepository -- resources/views/settings/shoppro.php — sekcja pull mapping pod push -- resources/lang/pl.php — klucze tłumaczeń pull + zmiana tytułów push -- routes/web.php — nowa route POST /settings/integrations/shoppro/statuses/save-pull - -## 2026-04-07 — Phase 74: Reverse Status Mapping - -Odwrocenie kierunku mapowania statusow w integracjach shopPRO i Allegro. - -**Zmiana:** UI tab Statusy teraz wyswietla statusy orderPRO po lewej stronie tabeli, a po prawej dropdown z zewnetrznymi statusami (shopPRO/Allegro). Poprzednio bylo odwrotnie. - -**DB:** Migracja 20260407_000078 — zmiana unique key z external_status_code na orderpro_status_code w obu tabelach mapowania. - -**Pliki:** -- database/migrations/20260407_000078_reverse_status_mapping_keys.sql -- src/Modules/Settings/ShopproStatusMappingRepository.php — replaceForIntegration() key na orderpro, +listExternalStatuses() -- src/Modules/Settings/AllegroStatusMappingRepository.php — upsertMapping() key na orderpro, +listExternalStatuses(), +buildAllegroToOrderproMap(), +replaceAllMappings() -- src/Modules/Settings/AllegroStatusMappingController.php — saveStatusMappingsBulk() odwrocony, saveStatusMapping() stub -- src/Modules/Settings/ShopproIntegrationsController.php — buildMappingIndex() + buildExternalStatusOptions() zamiast buildStatusRows() -- resources/views/settings/shoppro.php — odwrocona tabela -- resources/views/settings/allegro.php — odwrocona tabela, usuniety single-add form -- resources/lang/pl.php — nowe klucze tlumaczen - -## 2026-04-07 (Phase 73 - Search by Product, Plan 01) -- `OrdersRepository::buildPaginateFilters()`: dodano EXISTS subquery na `order_items.original_name` do warunku search. - - Alias `oi_s` dla unikniecia konfliktu z `oi_agg` w buildListSql. - - Nowy parametr `:s6` z ta sama wartoscia `%search%`. -- `resources/lang/pl.php`: placeholder filtra search zmieniony na "Szukaj (numer, klient, email, produkt)". -- Brak zmian schematu bazy danych. - -## 2026-04-07 (Phase 72 - Per Page Persistence, Plan 01) -- `resources/views/components/table-list.php`: - - Dodano klucz localStorage `perPageKey` (`tableList_[path]_[key]_per_page`). - - Przy zmianie selecta per_page: zapis do localStorage przed submit formularza. - - Przy ladowaniu strony: odczyt z localStorage i auto-submit jesli per_page nie jest w URL. - - URL per_page ma priorytet nad localStorage (sync, nie override). -- Brak zmian backendu — per_page nadal przychodzi jako query param. - -## 2026-04-07 (Phase 71 - Attributes Import, Plan 01) -- `ShopproOrderMapper::extractPersonalization()`: rozszerzono o odczyt pola `attributes` z API shopPRO. - - Metoda iteruje po `['attributes', 'custom_fields']` i laczy niepuste wyniki separatorem `\n`. - - Atrybuty produktu (kolor, wariant, woreczek jutowy itp.) sa teraz importowane obok personalizacji. -- Jednorazowa naprawa 36 istniejacych pozycji w bazie produkcyjnej (przeliczenie personalizacji z payload_json). -- Brak zmian schematu bazy danych. - -## 2026-04-04 (Email templates - split list/form view) -- `EmailTemplateController`: - - dodano osobne endpointy widokowe `create()` i `edit()` dla formularza szablonu, - - wydzielono render formularza do `renderForm(...)`, - - `save()` przy bledzie walidacji/CSRF wraca na odpowiednia podstrone formularza (`/create` albo `/edit?id=`), zamiast do listy. -- Routing: - - dodano trasy `GET /settings/email-templates/create` oraz `GET /settings/email-templates/edit`. -- Widoki: - - `resources/views/settings/email-templates.php` zawiera tylko liste szablonow i akcje tabeli, - - dodano `resources/views/settings/email-templates-form.php` jako osobna podstrone create/edit (Quill, zmienne, preview). -- Brak zmian schematu bazy danych. - -## 2026-04-04 (Phase 69 - Allegro Tracking English Statuses, Plan 01) -- `DeliveryStatus::slugifyAllegroDescription()`: - - dodano obsluge prefiksow EN (`Parcel has been ...`, `Parcel is ...`, `Courier has ...`) przed slugifikacja. -- `DeliveryStatus`: - - rozszerzono `ALLEGRO_EDGE_MAP` o slugi EN i ich mapowanie na statusy biznesowe (m.in. `awaiting_pick_up`, `delivered`, `dispatched`, `released_for_delivery`), - - rozszerzono `ALLEGRO_EDGE_DESCRIPTIONS` o opisy EN/PL dla nowych slugow, - - rozszerzono `guessStatusFromDescription()` o keyword fallback dla statusow EN (delivery/return/cancel/pickup/transit/confirmed/created/problem). -- Dodano test jednostkowy `tests/Unit/DeliveryStatusTest.php` pokrywajacy: - - mapowanie EN (`Parcel is awaiting pick-up`, `Parcel has been delivered`), - - fallback EN (`released for delivery`), - - regresje mapowania PL (`Przesylka zostala dostarczona`). -- Brak zmian schematu bazy danych. - -## 2026-04-03 (Phase 64 - Receipt Datetime Precision, Plan 01) -- Migracja `20260403_000076_alter_receipts_issue_date_to_datetime.sql`: ALTER TABLE receipts MODIFY issue_date DATETIME NOT NULL. -- `ReceiptController::store()`: zapis issue_date jako Y-m-d H:i:s, konwersja z formatu datetime-local (T separator). -- `AccountingController::toTableRow()` i `export()`: formatowanie issue_date do YYYY-MM-DD HH:MM (substr 0-16). -- `receipt-create.php`: input type=datetime-local z domyslna biezaca data+czas. -- `receipts/show.php`, `receipts/print.php`, `orders/show.php`: wyswietlanie issue_date z godzina (substr 0-16). - -## 2026-04-01 (Phase 63 - Order Item Personalization, Plan 01) -- Migracja `20260401_000075_add_personalization_to_order_items.sql`: kolumna `personalization TEXT NULL` w `order_items`. -- `ShopproOrderMapper::extractPersonalization()`: ekstrakcja `custom_fields` z odpowiedzi shopPRO API, konwersja HTML na czysty tekst (strip_tags, html_entity_decode, br->newline). -- `ShopproOrderMapper::mapItems()`: dodanie klucza `personalization` do mapowanego itemu. -- `OrderImportRepository::replaceItems()`: zapis `personalization` do INSERT query. -- `resources/views/orders/show.php`: warunkowe wyswietlanie personalizacji pod nazwa produktu (div.item-personalization z etykieta i liniami tekstu, escape via `e()`). -- `resources/scss/app.scss`: style `.item-personalization` (kompaktowy blok, border-left, muted colors). - -## 2026-03-31 (Phase 60 - Order Status Aged Event, Plan 01) -- Migracja `20260331_000074_seed_order_status_aged_cron.sql`: seed cron schedule `order_status_aged` co 3600s. -- `OrderStatusAgedService`: skanuje zamowienia w danym statusie od X dni (query HAVING MAX(changed_at) na `order_status_history`), limit 100/regule, trigger `order.status_aged`. -- `OrderStatusAgedHandler`: cron handler delegujacy do `OrderStatusAgedService::scan()`. -- `CronHandlerFactory`: rejestracja handlera `order_status_aged`. -- `AutomationController`: dodano `order.status_aged` do `ALLOWED_EVENTS`, `days_in_status` do `ALLOWED_CONDITION_TYPES`, `parseConditionValue` + branch `days_in_status`. -- `AutomationService::evaluateDaysInStatusCondition()`: ewaluacja `context.days_in_status >= value.days`. -- `resources/views/automation/form.php`: opcja "Minelo X dni od zmiany statusu" w zdarzeniach, "Liczba dni w statusie" w warunkach z polem numerycznym. -- `public/assets/js/modules/automation-form.js`: `buildDaysInStatusInput()`, opcja `days_in_status` w `addCondition()` i `onConditionTypeChange()`. - -## 2026-03-31 (Phase 59 - Order Status Automation Event, Plan 01) -- `AutomationController`: dodano `order.status_changed` do `ALLOWED_EVENTS`, `order_status` do `ALLOWED_CONDITION_TYPES`, `parseConditionValue` + branch `order_status` (walidacja kodow vs DB), `buildRuleFromRequest` + branch `order_status`. -- `AutomationService::evaluateOrderStatusCondition()`: ewaluacja warunku order_status — porownanie `new_status` z context vs dozwolone `order_status_codes`. -- `AutomationService::handleUpdateOrderStatus()`: pobiera old_status przed zmiana, emituje chain event `order.status_changed` przez `emitEvent()` (tylko przy realnej zmianie statusu). -- `OrdersController::changeStatus()`: pobiera old_status przed `updateOrderStatus()`, emisja `order.status_changed` po udanej zmianie (try/catch, non-blocking). -- `resources/views/automation/form.php`: opcja "Zmiana statusu zamowienia" w zdarzeniach, "Status zamowienia" w warunkach z checkboxami aktywnych statusow. -- `resources/views/automation/index.php`: dodano etykiety `payment.status_changed` i `order.status_changed` do `$eventLabels`. -- `public/assets/js/modules/automation-form.js`: `buildOrderStatusCheckboxes()`, opcja `order_status` w `addCondition()` i `onConditionTypeChange()`. - -## 2026-03-30 (Phase 58 - Automation Form Preserve, Plan 01) -- `AutomationController::store()` i `update()`: re-render formularza z danymi z request zamiast redirect przy bledzie walidacji. -- `AutomationController::buildRuleFromRequest()`: buduje tablice `$rule` z POST data w formacie oczekiwanym przez `form.php`. -- `AutomationController::renderForm()`: nowy parametr `$errorMessage` — priorytet nad Flash. -- `resources/views/automation/form.php`: `$isEdit` sprawdza `isset($rule['id'])` (nie `$rule !== null`), conditions/actions wyciagane z `$rule` niezaleznie od `$isEdit`. - -## 2026-03-30 (Phase 57 - Payment Automation Event, Plan 01) -- `AutomationController`: dodano `payment.status_changed` do `ALLOWED_EVENTS`, `payment_status` do `ALLOWED_CONDITION_TYPES`, stala `PAYMENT_STATUS_OPTIONS` (0/1/2), parseConditions dla `payment_status_keys`. -- `AutomationService::evaluatePaymentStatusCondition()`: ewaluacja warunku payment_status — porownanie `new_payment_status` z context vs dozwolone status_keys. -- `OrdersController::addPayment()`: emisja `payment.status_changed` po zapisie platnosci (try/catch, non-blocking). -- `ShopproPaymentStatusSyncService::syncSingleOrderPayment()`: emisja `payment.status_changed` po zmianie payment_status w cron sync (tylko przy realnej zmianie). -- `CronHandlerFactory`: przeniesiono tworzenie `$automationService` przed `$shopproPaymentSyncService`, przekazano jako zależność. -- `resources/views/automation/form.php`: opcja "Zmiana statusu platnosci" w zdarzeniach, "Status platnosci" w warunkach z checkboxami (Nieoplacone/Czesciowo oplacone/Oplacone). -- `public/assets/js/modules/automation-form.js`: `buildPaymentStatusCheckboxes()`, opcja w `addCondition()` i `onConditionTypeChange()`. - -## 2026-03-30 (Phase 56 - Order Payments, Plan 01) -- Migracja `20260330_000073_create_order_payments_table.sql`: tabela `order_payments` (id, order_id, source_payment_id, external_payment_id, payment_type_id, payment_date, amount, currency, comment, payload_json) + idempotentne dodanie kolumn `total_with_tax`, `total_paid`, `external_payment_type_id` do `orders`. -- `OrdersRepository::addPayment()`: INSERT do `order_payments`, przeliczenie `total_paid` i `payment_status` na `orders`. -- `OrdersRepository::findOrderSourceInfo()`: pobiera `source`, `integration_id`, `source_order_id` dla push do shopPRO. -- `OrdersController::addPayment()`: POST `/orders/{id}/payment/add` — walidacja, zapis platnosci, activity log, push do shopPRO. -- `OrdersController::pushPaymentToShoppro()`: po dodaniu platnosci pokrywajacej calosc — PUT `set_paid` do shopPRO API. -- `ShopproApiClient::setOrderPaid()`: PUT `/api.php?endpoint=orders&action=set_paid&id={sourceOrderId}`. -- `resources/views/orders/show.php`: przycisk "Dodaj platnosc", formularz inline (kwota, typ, data, komentarz), AJAX submit z reload. -- Style: `.payment-add-form` w `resources/scss/app.scss`. - -## 2026-03-28 (Phase 51 - Email HTML Layout, Plan 01) -- Migracja `20260328_000001_add_html_layout_to_email_mailboxes.sql`: kolumny `header_html` TEXT NULL i `footer_html` TEXT NULL w `email_mailboxes`. -- `EmailMailboxRepository::save()`: zapis `header_html`/`footer_html` w INSERT i UPDATE. -- `EmailMailboxController::save()`: pobiera `header_html`/`footer_html` z POST i przekazuje do repozytorium. -- `resources/views/settings/email-mailboxes.php`: sekcja "Szablon wiadomosci" z dwoma edytorami Quill.js (email-safe toolbar: bold, italic, underline, kolor, wyrownanie, listy, link, image, naglowki h1-h3). Sync innerHTML do hidden inputs przy submit. -- `EmailSendingService`: nowa metoda `composeBody()` — sklada header + body + footer. Uzywa variableResolver na header/footer. Uzyta w `send()` i `preview()`. NULL/pusty header/footer = pomijany. - -## 2026-03-28 (Phase 50 - Allegro Shipment Waybill Push, Plan 01) -- `AllegroShipmentService`: - - po sukcesie `checkCreationStatus(...)` (gdy jest `tracking_number`) probuje dopiac przesylke do checkout form Allegro, - - wykorzystuje `AllegroApiClient::addShipmentToOrder(...)` (`POST /order/checkout-forms/{id}/shipments`), - - push wykonywany tylko dla zamowien `orders.source='allegro'` i niepustego `source_order_id`, - - retry pushu po `ALLEGRO_HTTP_401` z ponownym `tokenManager->resolveToken()`, - - bledy pushu traktowane jako niekrytyczne (lokalna paczka pozostaje utworzona). -- `AllegroShipmentService::downloadLabel(...)`: - - przy fallbackowym dopelnieniu trackingu (gdy brak numeru w rekordzie paczki) wykonuje ten sam warunkowy push waybilla do Allegro. -- Testy: - - dodano `tests/Unit/AllegroShipmentServiceTest.php` (scenariusze: push dla Allegro, brak pushu dla nie-Allegro, fallback przy bledzie API, retry po 401). - -## 2026-03-28 (Public HTTPS cron endpoint) -- Dodano publiczny endpoint triggera crona: - - `GET /cron?token=` - - dodatkowo kompatybilny wariant sciezki: `GET /cron/token=`. -- Token jest walidowany przez `hash_equals` i pochodzi z nowej zmiennej srodowiskowej `CRON_PUBLIC_TOKEN`. -- Endpoint uruchamia `CronRunner` z limitem z ustawienia `cron_web_limit`. -- `Application::maybeRunCronOnWeb(...)` ignoruje teraz sciezki `/cron` i `/cron/*`, aby uniknac podwojnego triggera. -- Zaktualizowano `.env.example` o `CRON_PUBLIC_TOKEN`. - -## 2026-03-28 (Hotfix - Apaczka pickup day fallback) -- `ApaczkaShipmentService`: - - dodano automatyczny retry `order_send` dla bledu API `Pickup not available for selected day`, - - rozszerzono detekcje bledu o wariant komunikatu: `We're sorry, you can't place an order today. Change its date to another working day.`, - - fallback dotyczy tylko `pickup.type=COURIER`, - - kazdy retry przesuwa `pickup.date` na kolejny dzien roboczy (`normalizeCourierPickupDate`) i ponawia wysylke, - - limit fallbacku: do 7 kolejnych dni, potem zwracany jest oryginalny blad API. - -## 2026-03-28 (Phase 49 - Automation History Tab, Plan 01 - rozszerzenie akcji) -- Rozszerzono automatyzacje o nowy typ akcji `update_order_status` (UI: `Zmiana statusu zamowienia`). -- `AutomationController`: - - `ALLOWED_ACTION_TYPES` zawiera `update_order_status`, - - waliduje i parsuje `order_status_code` tylko do aktywnych statusow z `order_statuses`. -- `AutomationRepository`: - - nowa metoda `listActiveOrderStatuses()` zwracajaca aktywne statusy (`code`, `name`) sortowane rosnaco po nazwie. -- `resources/views/automation/form.php` i `public/assets/js/modules/automation-form.js`: - - nowa opcja akcji z wyborem docelowego statusu zamowienia. -- `AutomationService`: - - nowy handler `handleUpdateOrderStatus(...)`, - - wykonanie zmiany przez `OrdersRepository::updateOrderStatus(...)` z aktorem systemowym `Automatyzacja: `, - - fallback log aktywnosci `automation_order_status_failed` gdy zmiana nie powiedzie sie. - -## 2026-03-28 (Phase 49 - Automation History Tab, Plan 01) -- `Ustawienia > Zadania automatyczne` (`/settings/automation`) rozdzielone na 2 taby: - - `Ustawienia` - obecne zarzadzanie regulami, - - `Historia` - log wykonan automatyzacji z filtrowaniem i paginacja. -- Dodano migracje `20260328_000072_create_automation_execution_logs_table.sql`: - - nowa tabela `automation_execution_logs` (event, regula, order, status, wynik, context, timestamp), - - indeksy pod filtry historii, - - seed harmonogramu crona `automation_history_cleanup` (co 24h). -- Nowe klasy backend: - - `AutomationExecutionLogRepository` - zapis/listowanie/paginacja/licznik historii + purge retencji, - - `AutomationHistoryCleanupHandler` - usuwanie wpisow starszych niz konfigurowalna liczba dni (domyslnie 30). -- `AutomationService::trigger(...)` zapisuje wpis historii per wykonana regula: - - `success` po poprawnym wykonaniu akcji, - - `failed` przy wyjatku w wykonaniu reguly. -- `AutomationController::index(...)` obsluguje filtry historii (`history_*`) i paginacje (`history_page`), zachowujac kompatybilnosc listy regul. -- UI historii wykorzystuje kompaktowy formularz filtrow i paginacje z zachowaniem aktywnych parametrow. - -## 2026-03-28 (Phase 48 - Email Template Shipment Variables, Plan 01) -- Email templates (`/settings/email-templates`): - - dodano zmienne `{{przesylka.numer}}` i `{{przesylka.link_sledzenia}}` w `EmailTemplateController::VARIABLE_GROUPS`, - - rozszerzono `SAMPLE_DATA` do preview o przykladowy numer i URL sledzenia. -- `VariableResolver`: - - otrzymuje zaleznosc `ShipmentPackageRepository`, - - pobiera najnowsza paczke (`findLatestByOrderId(order_id)`), - - mapuje `przesylka.numer` i `przesylka.link_sledzenia`, - - link jest liczony przez `DeliveryStatus::trackingUrl(provider, tracking_number, carrier_id)`. -- DI: - - `routes/web.php` i `CronHandlerFactory` przekazuja `ShipmentPackageRepository` do `VariableResolver`. -- Zachowanie brzegowe: - - brak paczki lub brak numeru trackingowego nie psuje renderu - zmienne przesylki zwracaja pusty string. - -## 2026-03-28 (Phase 47 - Shipment Creation Automation, Plan 01) -- Automatyzacja: - - dodano nowe zdarzenie `shipment.created` (UI: `Utworzenie przesylki`), - - trigger jest uruchamiany natychmiast po sukcesie `ShipmentController::create()` oraz `ShipmentController::createManual()`, - - kontekst triggera zawiera m.in. `package_id`, `provider`, `tracking_number`, `package_status`, `delivery_status`. -- Dodano nowy typ akcji automatyzacji `update_shipment_status` (UI: `Zmiana statusu przesylki`): - - walidacja konfiguracji przez `AutomationController` (`shipment_status_key` -> `status_key`), - - wykonanie przez `AutomationService::handleUpdateShipmentStatus(...)`, - - aktualizacja `delivery_status` tylko przy realnej zmianie (bez falszywych triggerow), - - po zmianie statusu emitowane jest `shipment.status_changed` z kontekstem zmiany. -- Rozszerzono `AutomationService` o zaleznosc `ShipmentPackageRepository`: - - nowa metoda pomocnicza `ShipmentPackageRepository::findLatestByOrderId(int): ?array` (fallback wyboru paczki dla akcji). -- UI automatyzacji (`resources/views/automation/form.php`, `resources/views/automation/index.php`, `public/assets/js/modules/automation-form.js`) rozszerzono o: - - event `Utworzenie przesylki`, - - akcje `Zmiana statusu przesylki` z wyborem docelowego statusu biznesowego. -- Aktualizacja DI: - - `routes/web.php` i `src/Modules/Cron/CronHandlerFactory.php` przekazuja `ShipmentPackageRepository` do `AutomationService`, - - `ShipmentController` otrzymuje `AutomationService` jako zaleznosc konstruktora. - -## 2026-03-28 (Allegro Status Push - orderPRO -> Allegro) -- Zaimplementowano kierunek synchronizacji statusow `orderpro_to_allegro` w `AllegroStatusSyncService`. -- `AllegroStatusSyncService`: - - pobiera reczne zmiany statusow (`order_status_history.change_source=manual`) dla zamowien Allegro, - - buduje reverse mapping (`orderpro_status_code -> allegro_status_code`) na podstawie `allegro_order_status_mappings`, - - pushuje statusy do API Allegro i raportuje `pushed/skipped/failed`, - - aktualizuje kursor `integration_order_sync_state.last_status_pushed_at`. -- Nowa metoda `AllegroApiClient::updateCheckoutFormFulfillment()`: - - PUT `/order/checkout-forms/{id}/fulfillment`, - - body JSON: `{"status":""}`. -- `AllegroOrderSyncStateRepository`: dodano obsluge kursora push (`getLastStatusPushedAt`, `updateLastStatusPushedAt`). -- `AllegroStatusMappingRepository`: dodano reverse map builder `buildOrderproToAllegroMap()`. -- UI `Ustawienia > Integracje > Allegro > Ustawienia`: - - odblokowano wybor opcji `orderPRO -> Allegro` (usunieto `disabled` i dopisek `(wkrotce)`), - - zaktualizowano opis hintu kierunku synchronizacji. -- Dodano testy jednostkowe `tests/Unit/AllegroStatusSyncServiceTest.php` dla scenariuszy push/skip/fail/retry-401. -## 2026-03-27 (ShopPRO Status Push — orderPRO -> shopPRO) -- Zaimplementowano kierunek synchronizacji statusow `orderpro_to_shoppro` w `ShopproStatusSyncService`. -- Nowa metoda `ShopproApiClient::updateOrderStatus()` — PUT `/api.php?endpoint=orders&action=change_status&id={id}`. -- Wydzielono wspolna metode `executeRequest()` w `ShopproApiClient` (reuse GET/PUT). -- `ShopproStatusSyncService::syncPushDirection()`: - - buduje reverse mapping (orderpro_status_code -> shoppro_status_code), - - query `order_status_history` po zmianach `change_source=manual` po kursore, - - pushuje status do shopPRO API, aktualizuje kursor `last_status_pushed_at`. -- Migracja: `20260327_000071_add_last_status_pushed_at_to_sync_state.sql` — kolumna `last_status_pushed_at` w `integration_order_sync_state`. -- `ShopproOrderSyncStateRepository`: nowe metody `getLastStatusPushedAt()`, `updateLastStatusPushedAt()`. -- `CronHandlerFactory`: zaktualizowana kompozycja `ShopproStatusSyncService` z nowymi zaleznosciami. - -## 2026-03-25 (Automation - new action "Wystaw paragon") -- Dodano nowy typ akcji automatyzacji: `issue_receipt` (Wystaw paragon). -- Konfiguracja akcji wymaga kompletu parametrow: - - `receipt_config_id` (aktywna konfiguracja paragonu), - - `issue_date_mode` (`today` / `order_date` / `payment_date`), - - `duplicate_policy` (`skip_if_exists` / `allow_duplicates`). -- `AutomationController`: - - rozszerzono `ALLOWED_ACTION_TYPES`, - - dodano walidacje i parsowanie configu akcji `issue_receipt`, - - formularz dostaje aktywne konfiguracje paragonow i slowniki opcji. -- `resources/views/automation/form.php` i `public/assets/js/modules/automation-form.js`: - - nowa pozycja akcji `Wystaw paragon`, - - dynamiczne pola dla parametrow akcji. -- `AutomationService`: - - wykonuje automatyczne wystawienie paragonu przez `ReceiptRepository`, - - zapisuje activity log sukcesu/pominiecia/bledu, - - ma ochrone przed petla dla eventu `receipt.created` (akcja `issue_receipt` jest pomijana i logowana), - - obsluguje polityke duplikatow. -- Aktualizacja DI: - - `routes/web.php` i `CronHandlerFactory` przekazuja do `AutomationService` zaleznosci `ReceiptRepository` i `ReceiptConfigRepository`. -- Dodano systemowy mechanizm chain automation dla obecnych i przyszlych zdarzen: - - wspolny kontekst lancucha (`__automation_chain`) propagowany miedzy kolejnymi triggerami, - - `emitEvent(...)` jako bezpieczny mechanizm emitowania kolejnych eventow z akcji, - - ochrona anty-petla przez deduplikacje wykonania `event_type + rule_id` w jednym lancuchu, - - limit glebokosci lancucha (`MAX_CHAIN_DEPTH`) i limit historii wykonan (`MAX_CHAIN_EXECUTIONS`). - -## 2026-03-25 (Phase 43 - Print Queue Entry Removal, Plan 01) -- Dodano usuwanie wpisu kolejki wydruku: - - `PrintJobRepository::deleteById(int): bool`, - - `PrintSettingsController::deleteJob(Request): Response`, - - route `POST /settings/printing/jobs/delete` w `routes/web.php`. -- Widok `resources/views/settings/printing.php` ma przycisk `Usun` dla wpisu kolejki z potwierdzeniem `window.OrderProAlerts.confirm(...)`. -- Dodano style `print-queue-actions` i `print-queue-delete-form` w `resources/scss/modules/_printing.scss` + rebuild `public/assets/css/app.css`. - -## 2026-03-25 (Phase 42 - Automation Shipment Status Event, Plan 01) -- Rozszerzono automatyzacje o event `shipment.status_changed` i condition type `shipment_status`: - - `AutomationController` dopuszcza nowe event/condition i waliduje `status_keys`, - - `AutomationService::trigger()` przyjmuje kontekst triggera i ocenia warunki statusowe. -- UI automatyzacji (`resources/views/automation/form.php`, `index.php`, `public/assets/js/modules/automation-form.js`) obsluguje: - - wybor eventu `Zmiana statusu przesylki`, - - nowy warunek biznesowy statusu przesylki: - - zarejestrowana -> `created|confirmed`, - - do odbioru -> `ready_for_pickup`, - - nadana w punkcie -> `confirmed|in_transit`, - - odebrana -> `delivered`, - - anulowana -> `cancelled`, - - nieodebrana -> `problem`, - - odebrana (zwrot) -> `returned`. -- `ShipmentTrackingHandler` triggeruje `AutomationService->trigger('shipment.status_changed', orderId, context)` tylko gdy `delivery_status` realnie sie zmieni. -- `CronHandlerFactory` buduje `AutomationService` dla procesu cron i przekazuje go do `ShipmentTrackingHandler`; konstruktor dostaje teraz dodatkowo `basePath` (zmiany w `bin/cron.php` i `Application::maybeRunCronOnWeb`). - -## 2026-03-25 (Phase 41 - Allegro Import Log Rationalization, Plan 01) -- `AllegroOrderImportService::importSingleOrder(...)` przyjmuje trigger (`manual_import`, `orders_sync`, `status_sync`) i zapisuje go w `details_json` logu `import` (`trigger`, `trigger_label`, `source_updated_at`). -- `AllegroOrdersSyncService` i `AllegroStatusSyncService` przekazuja jawny trigger do importu. -- `OrdersRepository::shouldSkipDuplicateImportActivity(...)` deduplikuje kolejne wpisy `import`, gdy ostatni wpis ma ten sam `source_order_id`, `source_updated_at` i `trigger` (z wyjatkiem nowo utworzonego zamowienia). -- Widok historii zamowienia (`resources/views/orders/show.php`) pokazuje przy wpisie `import` skondensowany kontekst triggera i `source_updated_at`. - -## 2026-03-25 (Phase 40 - Remove Order List Bulk Print, Plan 01) -- Usunieto akcje bulk print z listy zamowien: - - OrdersController::index() nie wystawia juz przycisku Drukuj etykiety w header_actions. - - resources/views/orders/list.php nie zawiera juz skryptu wysylajacego bulk request do drukarki. -- Wycofano endpoint i logike backendowa bulk print: - - usunieto trase POST /api/print/jobs/bulk z routes/web.php, - - usunieto metode PrintApiController::bulkCreateJobs(...), - - usunieto nieuzywana metode PrintJobRepository::findPackagesWithLabelsByOrderIds(...). -- Pozostawiono bez zmian druk pojedynczej etykiety przez POST /api/print/jobs oraz API klienta Windows (pending/download/complete). -## 2026-03-25 (Phase 30 - Button Primary Color Distinction, Plan 01) -- Rozdzielono palete kolorow naglowkow i przyciskow akcji w warstwie SCSS: - - `resources/scss/shared/_ui-components.scss` ma nowe tokeny `--c-action-primary`, `--c-action-primary-dark`, `--focus-ring-action`, - - `btn--primary` i `btn:focus-visible` korzystaja z tokenow akcji, bez zmiany koloru `section-title` opartego o `--c-primary`. -- `resources/scss/modules/_printing.scss`: `btn--outline-primary` zostal przepiety z twardego niebieskiego (`#4a90d9`) na token `--c-action-primary`. -- Przebudowano assety frontendowe komenda `npm run build:css`, co zaktualizowalo `public/assets/css/app.css`. - -## 2026-03-23 (Phase 26 — Manual Tracking Number, Plan 01) -- Nowa metoda `ShipmentPackageRepository::createManual(int, string, ?string): int` — INSERT do `shipment_packages` z `provider='manual'`, `status='created'`. -- Nowa metoda `ShipmentController::createManual(Request): Response` — endpoint `POST /orders/{id}/shipment/manual`, walidacja CSRF + tracking_number, activity log `shipment_manual`. -- Nowa route w `routes/web.php`: `POST /orders/{id}/shipment/manual`. -- `resources/views/orders/show.php` — formularz inline do dodawania recznego numeru przesylki w zakladce Przesylki; zmienione wyswietlanie przesylek manualnych (status "Dodana recznie", przewoznik z carrier_id, brak etykiety). -- `resources/scss/app.scss` — nowa klasa `.manual-tracking-form` (flex, gap 8px). - -## 2026-03-22 (Phase 21 — Order Source Display, Plan 01) -- `OrdersRepository::buildListSql()` — LEFT JOIN `integrations ig ON ig.id = o.integration_id`, nowa kolumna `ig.name AS integration_name`. -- `OrdersRepository::findDetails()` — analogiczny LEFT JOIN dla strony szczegolow zamowienia. -- `OrdersRepository::transformOrderRow()` — nowe pole `integration_name`. -- `OrdersController::toTableRow()` — wyswietla `integration_name` gdy niepuste, fallback na `sourceLabel()` (Allegro/Erli/default). -- `resources/views/orders/show.php` — naglowek zamowienia: dwa osobne spany (nazwa integracji + "ID: identyfikator") zamiast jednego. - -## 2026-03-18 (Phase 16 — Zadania automatyczne, Plan 02: Watcher/Executor) -- Nowa klasa `App\Modules\Automation\AutomationService` — trigger + ewaluacja warunkow (AND) + wykonanie akcji. -- Flow: `ReceiptController::store()` -> `AutomationService::trigger('receipt.created', orderId)` -> sprawdzenie warunkow (integration_id) -> `EmailSendingService::send()`. -- Rozszerzenie `EmailSendingService::send()` o opcjonalne parametry `$recipientEmailOverride` i `$recipientNameOverride` (kompatybilnosc wsteczna). -- 3 tryby odbiorcy: 'client' (kupujacy), 'company' (e-mail firmy z company_settings), 'client_and_company' (oba). -- Trigger w try/catch — blad automatyzacji nie blokuje sukcesu tworzenia paragonu. -- Activity log: automation_email_sent / automation_email_failed z actor_type='system'. - -## 2026-03-18 (Phase 16 — Zadania automatyczne, Plan 01: DB + CRUD) -- Nowe tabele: `automation_rules`, `automation_conditions`, `automation_actions` (migracja 000057). -- Nowy modul `App\Modules\Automation` z 2 klasami: - - `AutomationController` — CRUD regul automatyzacji (index, create, store, edit, update, destroy, toggleStatus). - - `AutomationRepository` — operacje DB z transakcjami (create/update atomowe z conditions+actions), findActiveByEvent dla watchera. -- 7 nowych route'ow: `/settings/automation/*`. -- Widoki: `resources/views/automation/index.php` (lista regul), `resources/views/automation/form.php` (formularz z dynamicznymi warunkami/akcjami). -- Nowy JS: `public/assets/js/modules/automation-form.js` (dodawanie/usuwanie wierszy warunkow i akcji). -- Nowy SCSS: `resources/scss/modules/_automation.scss` (style formularza dynamicznego). -- Menu nawigacji: dodany link "Zadania automatyczne" w sekcji Ustawienia. - -## 2026-03-17 (Phase 15 — Wysylka e-mail z zamowien) -- Nowa zaleznosc: `phpmailer/phpmailer` v7.0.2 (SMTP transport). -- Nowy modul `App\Modules\Email` z 3 klasami: - - `EmailSendingService` — wysylka e-mail (send, preview), logowanie do email_logs, resolwer skrzynki (mailboxId → template → default). - - `VariableResolver` — zamiana `{{grupa.zmienna}}` na dane zamowienia/kupujacego/adresu/firmy. - - `AttachmentGenerator` — generowanie PDF paragonu (dompdf) jako zalacznik in-memory (addStringAttachment). -- `OrdersController`: nowe metody `sendEmail()`, `emailPreview()`, `loadEmailLogs()`. -- Nowe route'y: `POST /orders/{id}/send-email`, `POST /orders/{id}/email-preview`. -- Widok `orders/show.php`: przycisk "Wyslij e-mail" + modal (wybor szablonu/skrzynki, podglad, wysylka AJAX). -- Zakladka Dokumenty: sekcja "Wysylki e-mail" z historia wyslanych maili (status, podglad body). -- Nowy partial: `resources/views/orders/partials/email-send-modal.php`. -- Nowy SCSS: `resources/scss/modules/_email-send.scss` (modal overlay, podglad, style). - -## 2026-03-15 (Phase 13 — DB + Skrzynki pocztowe) -- Dodano 3 migracje email: `000054_create_email_mailboxes_table`, `000055_create_email_templates_table`, `000056_create_email_logs_table`. -- Nowe klasy: `EmailMailboxController` (index, save, delete, toggleStatus, testConnection), `EmailMailboxRepository` (listAll, findById, save, delete, toggleStatus, listActive). -- Test polaczenia SMTP przez natywny `stream_socket_client` z pelnym handshake (EHLO → STARTTLS → AUTH LOGIN) — bez zewnetrznych bibliotek. -- Hasla SMTP szyfrowane przez `IntegrationSecretCipher` (AES-256-CBC + HMAC-SHA256). -- Widok `settings/email-mailboxes.php` — lista skrzynek + formularz CRUD + AJAX test polaczenia. -- Nawigacja: link "Skrzynki pocztowe" w sidebar Settings. -- 5 nowych route'ow: GET/POST `/settings/email-mailboxes/*`. - -## 2026-03-14 -- Zoptymalizowano zapytanie listy zamowien (`OrdersRepository::buildListSql()`): - - 4 correlated subqueries (items_count, items_qty, shipments_count, documents_count) zastapiono aggregating LEFT JOINami — eliminuje N+1 na kazdym wierszu listy. -- `OrdersRepository::canResolveMappedMedia()` — zamiana instance property na `static` — `information_schema` odpytywany co najwyzej raz na cykl PHP zamiast raz per instancja. -- Dodano migracje `20260314_000048_add_orders_performance_indexes.sql` — indeksy na `orders`: `source`, `status_code`, `ordered_at`, composite `(source, status_code)`. -- Dodano SSL verification (`CURLOPT_SSL_VERIFYPEER => true`, `CURLOPT_SSL_VERIFYHOST => 2`, `CURLOPT_CAINFO`) do 4 klas ApiClient: AllegroApiClient (3 metody), AllegroOAuthClient, ShopproApiClient, ApaczkaApiClient. Fallback: `$_ENV['CURL_CA_BUNDLE_PATH']` → XAMPP cacert.pem → system CA bundle. -- Cron web throttle (`isWebCronThrottled()`) przeniesiony z `$_SESSION` do `app_settings` (klucz `cron_web_last_run_at`) — eliminuje wielokrotne uruchamianie crona przy wielu aktywnych sesjach. -- Deduplikacja migracji `000014` → `000014b` (kolizja z `create_product_integration_translations`). -- `AllegroStatusSyncService::sync()` zwraca `ok:false` dla kierunku `orderpro_to_allegro` (wczesniej false-positive `ok:true`). Opcja UI oznaczona jako `disabled` z `(wkrotce)`. -- Lista zamowien: source wyswietlany przed ID z prefixem `ID:`; `sourceLabel()` mapuje shoppro→shopPRO, allegro→Allegro. -- Statusy zamowien na liscie kolorowane kolorem grupy z konfiguracji (`statusColorMap()` → inline `background-color`). -- Ciemniejsze obramowanie pol formularzy: `--c-border` zmieniony z `#e2e8f0` na `#b0bec5`. -- Hotfix SSL: `getCaBundlePath()` zwraca `null` gdy zaden CA bundle nie znaleziony — `CURLOPT_CAINFO` ustawiany warunkowo, cURL uzywa systemowego CA na serwerze. - -## 2026-03-08 -- Poprawiono date podjazdu kuriera w payloadzie Apaczka: - - `pickup.date` dla trybu `COURIER` jest normalizowane tak, aby nie wypadal w niedziele (niedziela -> poniedzialek), - - `pickup.hours_to` jest ograniczane do `16:00` (wg limitu API), a okno godzinowe jest korygowane do poprawnej relacji `hours_from < hours_to`, - - eliminuje blad API `Field PickupLocation->MaxPickupDate cannot be set to Sunday`. -- Dodano pole firmy `sender_contact_person` (osoba kontaktowa nadawcy): - - nowa migracja `20260308_000046_extend_company_settings_contact_person.sql`, - - UI `Ustawienia > Dane firmy` ma nowe pole `Osoba kontaktowa nadawcy`, - - `ApaczkaShipmentService` wysyla `contact_person` dla nadawcy z ustawien firmy. -- Uzupelniono kontakt odbiorcy w payloadzie Apaczka: - - `ApaczkaShipmentService` wysyla `receiver.contact_person` (fallback na dane odbiorcy/klienta z zamowienia), - - eliminuje blad API: `Osoba kontaktowa nadawcy/odbiorcy: Pole jest wymagane`. -- Dla tworzenia przesylek Apaczka dodano jawne pole `pickup.type` w payloadzie `order_send`: - - gdy podano `sender_point_id` ustawiane jest `SELF`, - - gdy brak punktu nadania i usluga dopuszcza odbior kurierem ustawiane jest `COURIER`. -- Poprawiono obsluge punktow nadania/odbioru w payloadzie Apaczka: - - adres `sender` i `receiver` wysyla teraz komplet aliasow punktu (`point`, `foreign_address_id`, `point_id`), - - rozszerzono diagnostyke dla bledu API `Niepoprawny sposob nadania przesylki` o wskazowke dot. `sender_point_id` / doboru uslugi. -- Wzmocniono fallback adresu odbiorcy dla przesylek punktowych Apaczka (Orlen/InPost): - - `ApaczkaShipmentService` probuje teraz dodatkowo uzupelnic adres punktu (`street`, `postal_code`, `city`) przez API `points` na podstawie `receiver_point_id`, - - jezeli zamowienie punktowe dalej nie ma kompletu danych adresowych, serwis uzupelnia techniczne minimum (`line1`, `city`, `postal_code`) zamiast blokowac tworzenie przesylki bledem walidacji lokalnej. -- Ujednolicono i wzmocniono naglowki sekcji UI (`h2/h3/h4.section-title`) w widokach: - - naglowki sekcyjne maja teraz wyrazniejszy styl (akcent lewy, delikatne tlo, obramowanie), - - zmiana jest globalna (SCSS), obejmuje m.in. `Zamowienia > Przygotuj przesylke` oraz pozostale ekrany korzystajace z `section-title`. -- Poprawiono fallback danych odbiorcy dla przesylek punktowych Apaczka (w tym Orlen Paczka): - - `ApaczkaShipmentService::buildReceiverAddress(...)` uzupelnia brakujace pola z wielu zrodel w kolejnosci: - - dane z formularza, - - adres `delivery` z zamowienia, - - dane punktu z `parcel_name` (`ulica`, `kod`, `miasto`), - - dane klienta (`name`, `phone`, `email`, `country`), - - adres ulicy sklada teraz `street_name + street_number`, - - naprawiono fallback `receiver_point_id` (uzywa `delivery.parcel_external_id`, usunieto bledne odwolanie do niezdefiniowanej zmiennej). -- Poprawiono obsluge usunietych/nieosiagalnych etykiet Apaczka: - - gdy API zwraca `Label is not available for this order`, rekord paczki jest oznaczany jako `error` i zapisywany jest `error_message`, - - dzieki temu przycisk etykiety nie jest ponownie pokazywany dla tego rekordu. -- Ujednolicono flow etykiet w `Zamowienia > Przygotuj przesylke` (dla wszystkich providerow): - - po statusie `created` etykieta jest generowana automatycznie przez cykliczne sprawdzanie statusu (backend probuje `downloadLabel`), - - UI nie pokazuje juz przycisku `Generuj etykiete`; do czasu gotowosci widoczny jest stan `Generowanie etykiety...`, - - przycisk `Pobierz` pojawia sie dopiero po zapisaniu pliku etykiety (`label_path`). -- Uzgodniono payload `order_send` Apaczka z dokumentacja API v2: - - `ApaczkaShipmentService` wysyla teraz strukture `address.sender/receiver` + `shipment[]` (`dimension1/2/3`, `weight` w kg), - - `cod` jest przekazywany jako obiekt (`amount`, `currency`), a wartosc ubezpieczenia przez `shipment_value` + `shipment_currency`, - - punkty sa przekazywane jako `foreign_address_id` (z aliasami diagnostycznymi), - - naprawilo to blad wyceny dla zamowienia testowego `#21` (utworzenie przesylki zakonczone sukcesem). -- Dodano techniczny skrypt diagnostyczny `tools/apaczka_probe_order.php`: - - wykonuje automatyczne proby `order_send` dla wskazanego zamowienia (bez klikania w UI), - - testuje kombinacje uslug i wariantow pol punktu, raportujac sukces/blad per proba. -- Rozszerzono payload punktow w tworzeniu przesylki Apaczka: - - oprocz `point` przekazywane sa teraz aliasy `foreign_address_id` i `point_id` (dla odbiorcy i nadawcy), - - cel: kompatybilnosc z wariantami API wymagajacymi innej nazwy pola punktu. -- Korekta walidacji punktu odbioru Apaczka: - - usunieto twarde blokowanie tworzenia przesylki na podstawie prefiksu punktu (`POP-`), - - informacja o prefiksie punktu pozostaje tylko jako sugestia diagnostyczna. -- Poprawiono prefill danych odbiorcy na ekranie `Zamowienia > Przygotuj przesylke`: - - `ShipmentController` dla dostaw do punktu (`parcel_external_id`/`parcel_name`) ustawia `receiver_name` na dane klienta (`address_type=customer`), - - eliminuje przypadek podstawiania nazwy punktu/metody dostawy w polu `Imie i nazwisko`. -- Poprawiono diagnostyke bledow tworzenia przesylki Apaczka: - - `ApaczkaShipmentService` przekazuje teraz `receiver_point_id` do payloadu `receiver.point` (oraz `sender_point_id` do `sender.point`), - - dodano walidacje wymagan uslugi na podstawie `service_structure` (np. wymagany punkt odbioru/nadania), - - dla bledu API `Brak wyceny dla podanych parametrów zamówienia` komunikat zawiera rozszerzona diagnostyke (service_id/nazwa/supplier, punkt odbioru/nadania, gabaryt/waga) i hint o niedopasowaniu uslugi do typu punktu. -- Poprawiono import danych faktury z shopPRO: - - `ShopproOrdersSyncService` wykrywa fakture nie tylko po `is_invoice`/`invoice.required`, ale takze po danych firmowych (`firm_name`/`firm_nip`), - - `ShopproOrdersSyncService::mapAddresses(...)` zapisuje adres `invoice` (firma, NIP, adres) na podstawie pol `invoice`/`billing*`/`firm_*`, - - widok `orders/show` wyswietla teraz `company_name` i `company_tax_number` dla adresu faktury. -- Fix prewyboru uslugi Apaczka na ekranie `Zamowienia > Przygotuj przesylke`: - - widok `resources/views/shipments/prepare.php` odczytuje ID uslugi Apaczka z fallbackiem `service_id -> id`, - - naprawia przypadek, gdy przewoznik (`Apaczka`) byl wybierany poprawnie, ale usluga dostawy pozostawala pusta mimo mapowania. -- Poprawiono diagnostyke mapowania form dostawy na ekranie `Zamowienia > Przygotuj przesylke`: - - `ShipmentController` zwraca teraz komunikat diagnostyczny, gdy brak mapowania metody dostawy, - - komunikat rozroznia brak mapowan dla instancji `shopPRO` (`source_integration_id`) od braku mapowania konkretnej metody, - - widok `resources/views/shipments/prepare.php` wyswietla ten komunikat bezposrednio pod informacja o metodzie z zamowienia. -- Poprawiono UX wyszukiwania w selectach mapowania form dostawy (zakladki `Formy dostawy`): - - `resources/views/settings/allegro.php` przeszlo z przebudowy opcji `