# Tech Changelog

## 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=<CRON_PUBLIC_TOKEN>`
  - dodatkowo kompatybilny wariant sciezki: `GET /cron/token=<CRON_PUBLIC_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: <nazwa reguly>`,
  - 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":"<ALLEGRO_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`, `external_status_id`, `ordered_at`, composite `(source, external_status_id)`.
- 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 `<select>` na tryb bezpieczny (`focus first match` bez modyfikacji listy opcji),
  - eliminuje przypadki „znikajacych” opcji i problem z wyborem uslugi po zmianie przewoznika na `Apaczka`,
  - ujednolicono zachowanie z `resources/views/settings/shoppro.php`.
- Poprawiono inicjalizacje stanu mapowania przewoznika (`allegro.php`, `shoppro.php`):
  - dla niezamapowanych form domyslny przewoznik to teraz pusty wybor (zamiast `allegro`),
  - panel uslugi (`Allegro/InPost/Apaczka/pusty`) jest synchronizowany na starcie z realna wartoscia selecta przewoznika (`showPanel(carrierSelect.value)`),
  - usunieto pozostaly po refaktorze odwolanie do nieistniejacej zmiennej `$currentAllegroId` (zastapione `$currentMethodId`).
- Dodano architekture provider-agnostic dla wysylek:
  - nowy kontrakt `ShipmentProviderInterface`,
  - nowy rejestr `ShipmentProviderRegistry`,
  - `ShipmentController` wybiera providera dynamicznie (`allegro_wza` / `apaczka`) przy tworzeniu przesylki, sprawdzaniu statusu i pobieraniu etykiety.
- Dodano integracje API Apaczka v2:
  - nowy klient `App\Modules\Settings\ApaczkaApiClient` (`service_structure`, `order_send`, `order_details`, `waybill`, `points`),
  - nowy serwis wysylkowy `App\Modules\Shipments\ApaczkaShipmentService`,
  - rozszerzone `Ustawienia > Integracje > Apaczka` o pola `App ID`, `App Secret` oraz test polaczenia (`POST /settings/integrations/apaczka/test`).
  - poprawiono format podpisu/requestu zgodnie z API v2 (`app_id:route:request_json:expires`, endpointy URL zamiast pola `method`), co naprawia blad testu polaczenia (`brak JSON`).
- Dodano wspolny model mapowania form dostawy dla wielu providerow:
  - nowa tabela `carrier_delivery_method_mappings` (migracja `20260308_000044_create_carrier_delivery_method_mappings_table.sql`),
  - nowy repo `CarrierDeliveryMethodMappingRepository`,
  - backfill danych z tabel legacy (`allegro_delivery_method_mappings`, `shoppro_delivery_method_mappings`),
  - zakladki `Formy dostawy` w Allegro i shopPRO obsluguja mapowanie na `allegro_wza` i `apaczka`.
- Dodano migracje `20260308_000045_extend_apaczka_credentials.sql`:
  - rozszerzenie `apaczka_integration_settings` o `app_id` i `app_secret_encrypted`,
  - migracja danych legacy sekretu z `api_key_encrypted`.
- Dodano zakladke `Formy dostawy` dla integracji `shopPRO` (analogicznie do Allegro):
  - nowy endpoint `POST /settings/integrations/shoppro/delivery/save`,
  - mapowanie per instancja: forma dostawy shopPRO -> usluga dostawy Allegro/InPost WZA,
  - UI z wyborem przewoznika (`allegro`/`inpost`) i wyszukiwaniem uslug Allegro.
- Dodano `ShopproDeliveryMethodMappingRepository` i tabele mapowan per `integration_id`.
- Dodano migracje `20260308_000043_create_shoppro_delivery_method_mappings_table.sql`.
- Dodano synchronizacje platnosci shopPRO oparta o flage `paid`:
  - nowy job cron `shoppro_payment_status_sync`,
  - nowy handler `App\Modules\Cron\ShopproPaymentStatusSyncHandler`,
  - nowy serwis `App\Modules\Settings\ShopproPaymentStatusSyncService`,
  - runner podlaczony w `App\Core\Application::maybeRunCronOnWeb(...)` oraz `bin/cron.php`.
- Rozszerzono `Ustawienia > Integracje > shopPRO > Ustawienia`:
  - dodano interwal sprawdzania platnosci (minuty) dla joba `shoppro_payment_status_sync`,
  - dodano wybor statusow orderPRO, dla ktorych cron ma sprawdzac oplacenie zamowien,
  - zapis konfiguracji listy statusow per instancja trafia do `integrations.payment_sync_status_codes_json`.
- Import zamowien shopPRO zapisuje status platnosci numerycznie (`orders.payment_status`) na podstawie flagi `paid`, co unifikuje filtry/statystyki platnosci z Allegro.
- Dodano migracje `20260308_000042_ensure_shoppro_payment_sync_schedule_and_columns.sql`:
  - uzupelnienie kolumny `integrations.payment_sync_status_codes_json`,
  - seed/naprawa harmonogramu `shoppro_payment_status_sync` (domyslnie 600s, priorytet 105).
- Fix danych wysylki dla zamowien shopPRO (np. `OP000000016`):
  - `ShopproOrdersSyncService` mapuje `inpost_paczkomat`/`orlen_point` do adresu `delivery` (punkt, ulica, kod, miasto),
  - zapisuje `parcel_external_id` i `parcel_name` dla punktu odbioru,
  - `delivery` dziedziczy telefon i e-mail klienta, gdy API nie zwraca osobnych danych odbiorcy,
  - etykieta metody dostawy (`external_carrier_id`) zawiera koszt transportu (`transport_cost`), np. `Paczkomaty InPost - przedpłata: 13.5 zł`.
- Fix importu shopPRO dla listy zamowien (`Kwoty` + miniatury):
  - `ShopproOrdersSyncService` mapuje kwoty zamowienia z `summary` i `paid` (fallback), ceny pozycji z `price_brutto`,
  - poprawiono laczenie payloadow `orders/list` i `orders/get|details` (zachowanie kluczowych pol z listy),
  - dodano fallback miniatur pozycji przez API `products/get` po `product_id`,
  - dodano dodatkowy fallback miniatur po `parent_product_id` (warianty), gdy obraz nie istnieje na produkcie potomnym.
- `OrdersRepository`:
  - resolver miniatur pozycji uwzglednia kod kanalu zgodny ze zrodlem zamowienia (`o.source`) zamiast stalego `allegro`.
- Korekta layoutu sekcji `Ustawienia` dla integracji `shopPRO`:
  - wyrownano pola w siatce (`integration-settings-group__grid`) przez `align-items: start`,
  - wymuszono spojna wysokosc kontrolek (`.form-control`), w tym pola `date`,
  - przebudowano CSS (`public/assets/css/app.css`) dla rownego przebiegu linii i pol w obu kolumnach.
- Fix UX przycisku `Nowa integracja` w `Ustawienia > Integracje > shopPRO`:
  - przycisk otwiera teraz tryb wymuszonego tworzenia (`?new=1`),
  - `ShopproIntegrationsController::index(...)` nie auto-wybiera wtedy pierwszej istniejacej integracji,
  - formularz tworzenia otwiera sie zawsze jako pusty.
- Poprawiono prezentacje dostawy na szczegolach zamowienia (`orders/show`):
  - `Platnosc i wysylka` sanitizuje nazwe przewoznika (usuwa tagi HTML typu `<b>...</b>`),
  - `Dane wysylki` pokazuja `parcel_name` i `parcel_external_id` (np. punkt/paczkomat Allegro),
  - gdy brak adresu `delivery`, sekcja `Dane wysylki` pokazuje fallback z metody dostawy (`external_carrier_id`).
- Poprawiono import shopPRO dla formy dostawy:
  - `ShopproOrdersSyncService` sanitizuje `external_carrier_id` i `order_shipments.carrier_provider_id` (usuwanie HTML + dekodowanie encji),
  - rozszerzono fallbacki mapowania przewoznika (`transport`, `transport_description`, `transport_id`).
- Fix mapowania formy dostawy z shopPRO:
  - `ShopproOrdersSyncService` mapuje teraz `orders.external_carrier_id` z fallbackiem na pola `transport` i `transport_description`,
  - `orders.external_carrier_account_id` mapowane z `transport_id`,
  - `order_shipments.carrier_provider_id` rozszerzone o fallback `transport`/`transport_description`.
- Fix importu adresow shopPRO na realnym payloadzie zamowien (`client_name`, `client_surname`, `client_email`, `client_phone`):
  - `ShopproOrdersSyncService::mapAddresses(...)` mapuje teraz pola klienta w formacie flat (bez zagniezdzenia),
  - usunieto przypadek tworzenia pustego adresu `delivery` tylko na bazie fallbacku e-mail,
  - po wymuszonym re-sync zamowienia #13 dane zamawiajacego zapisaly sie jako `Jacek Pyziak`, `pyziak84@gmail.com`, `530755774`.
- Poprawiono mapowanie danych adresowych w imporcie zamowien `shopPRO`:
  - `ShopproOrdersSyncService::mapAddresses(...)` obsluguje rozszerzony zestaw aliasow pol klienta i dostawy (`buyer/customer/client`, `billing_address`, `shipping_address`, `delivery_address`, `receiver`, warianty `first_name/last_name`, `postcode` itd.),
  - adres dostawy jest zapisywany takze wtedy, gdy brak pelnej nazwy, ale istnieja inne dane adresowe,
  - rozszerzono mapowanie `orders.customer_login` i `orders.external_carrier_id` o dodatkowe fallbacki z payloadu shopPRO.
- Poprawiono UX zakladki `Ustawienia` integracji `shopPRO`:
  - ustawienia sa pogrupowane w sekcje `Pobieranie zamowien` oraz `Synchronizacja statusow`,
  - dodano naglowki sekcji i opisy kontekstu, aby pola nie zlewaly sie wizualnie,
  - dodano dedykowane style SCSS (`integration-settings-group*`) i przebudowano `public/assets/css/app.css`.
- Dodano cron synchronizacji statusow `shopPRO`:
  - nowy handler `App\Modules\Cron\ShopproStatusSyncHandler`,
  - nowy serwis `App\Modules\Settings\ShopproStatusSyncService`,
  - nowy job `shoppro_order_status_sync` podlaczony do runnera w `App\Core\Application::maybeRunCronOnWeb(...)` i `bin/cron.php`.
- Rozszerzono `Ustawienia > Integracje > shopPRO > Ustawienia`:
  - dodano wybor kierunku synchronizacji statusow (`shopPRO -> orderPRO`, `orderPRO -> shopPRO`),
  - dodano pole interwalu synchronizacji statusow (minuty),
  - zapis aktualizuje `integrations.order_status_sync_direction` i harmonogram `cron_schedules` dla `shoppro_order_status_sync`.
- Dodano migracje `20260308_000041_ensure_shoppro_status_sync_schedule_and_direction.sql`:
  - seed/naprawa harmonogramu `shoppro_order_status_sync` (domyslnie 900s, priorytet 100),
  - uzupelnienie kolumny `integrations.order_status_sync_direction` jesli brak.
- Rozszerzono `ShopproOrdersSyncService` o opcje uruchomienia filtrowanego po `integration_id` i z pominięciem flagi `orders_fetch_enabled` (wykorzystane przez cron synchronizacji statusow).
- Dodano cron importu zamowien z `shopPRO`:
  - nowy handler `App\Modules\Cron\ShopproOrdersImportHandler`,
  - nowy serwis `App\Modules\Settings\ShopproOrdersSyncService`,
  - nowy klient API `App\Modules\Settings\ShopproApiClient`,
  - job `shoppro_orders_import` jest podlaczony do wykonania zarowno w `App\Core\Application::maybeRunCronOnWeb(...)`, jak i w `bin/cron.php`.
- Rozszerzono `Ustawienia > Integracje > shopPRO > Ustawienia`:
  - dodano pole interwalu pobierania zamowien (minuty),
  - zapis aktualizuje harmonogram `cron_schedules` dla joba `shoppro_orders_import`.
- Dodano migracje `20260308_000040_ensure_shoppro_orders_import_schedule.sql`:
  - seed/naprawa harmonogramu `shoppro_orders_import` (domyslnie 300s, priorytet 90).
- Zadanie #13 z `DOCS/todo.md`: dodano stronicowanie historii w `Ustawienia > Cron`:
  - `CronSettingsController` pobiera `past_page` z query i przekazuje metadane paginacji do widoku,
  - `CronRepository` rozszerzono o `countPastJobs()` oraz `listPastJobs(limit, offset)`,
  - widok `settings/cron.php` renderuje kontrolki paginacji dla sekcji `Historia jobow (przeszle)`.
- Rozpoczeto ujednolicanie modelu integracji na baze `integrations`:
  - dodano klasy wspolne `App\Modules\Settings\IntegrationsRepository` oraz `App\Modules\Settings\IntegrationSecretCipher`,
  - ograniczono duplikacje szyfrowania sekretow integracji (wspolny cipher dla repozytoriow integracji).
- Migracja `20260308_000037_unify_integrations_base_links.sql`:
  - dodaje `integration_id` do `allegro_integration_settings`, `apaczka_integration_settings`, `inpost_integration_settings`,
  - podpina relacje 1:1 FK do `integrations`,
  - seeduje bazowe rekordy providerow (`allegro`, `apaczka`, `inpost`) i backfilluje powiazania.
- `ApaczkaIntegrationRepository`:
  - klucz API zapisuje/odczytuje z `integrations.api_key_encrypted` (`type=apaczka`).
- `InpostIntegrationRepository`:
  - token API zapisuje/odczytuje z `integrations.api_key_encrypted` (`type=inpost`),
  - ustawienia specyficzne przewoznika pozostaja w `inpost_integration_settings`.
- `AllegroIntegrationRepository`:
  - zapewnia powiazanie aktywnego srodowiska OAuth z rekordem bazowym `integrations`,
  - dodana metoda `getActiveIntegrationId()` pod spojnosc domeny zamowien/sync.
- `AllegroOrderImportService` i `AllegroOrdersSyncService`:
  - przestaly uzywac stalej/`null` dla `integration_id`,
  - korzystaja z aktywnego `integration_id` Allegro, co eliminuje sztywne zalozenie `integration_id=1`.
- Dodano wspolny ekran `Ustawienia > Integracje`:
  - nowa route `GET /settings/integrations`,
  - nowa klasa `App\Modules\Settings\IntegrationsHubController`,
  - nawigacja boczna prowadzi do jednego huba integracji.
- Hub integracji zawiera tabele podsumowania oraz akcje per instancja:
  - przycisk `Ustawienia` w kazdym wierszu prowadzi do dedykowanego ekranu zaawansowanego providera.
- Fix UI: rozciaganie przyciskow w formularzach (`.form-actions`) przy ukladzie grid:
  - ustawiono `align-items: flex-start` oraz `align-self: flex-start` dla `.form-actions .btn`,
  - eliminuje pionowe rozciaganie przyciskow do wysokosci sasiednich pol formularza.
- Dodano wieloinstancyjna konfiguracje integracji `shopPRO`:
  - nowe endpointy: `GET /settings/integrations/shoppro`, `POST /settings/integrations/shoppro/save`, `POST /settings/integrations/shoppro/test`,
  - nowa klasa `App\Modules\Settings\ShopproIntegrationsController`,
  - nowy widok `resources/views/settings/shoppro.php` (lista instancji, formularz dodawania/edycji, test polaczenia),
  - hub integracji (`/settings/integrations`) zawiera wiersz `shopPRO` z przejsciem do ekranu ustawien,
  - dodano pomocnicze style `.table-row-actions` dla kompaktowych akcji w tabelach.
- Ekran `shopPRO` rozbudowano o zakladki analogiczne do Allegro:
  - `Integracja`, `Statusy`, `Ustawienia`, `Formy dostawy`,
  - `Ustawienia` zawiera pola `Pobieraj zamowienia` i `Data startu pobierania`,
  - zapis/odczyt tych pol jest realizowany przez tabele bazowa `integrations` (`orders_fetch_enabled`, `orders_fetch_start_date`).
- Wdrozone mapowanie statusow shopPRO (zakladka `Statusy`):
  - nowe endpointy: `POST /settings/integrations/shoppro/statuses/sync` oraz `POST /settings/integrations/shoppro/statuses/save`,
  - dodana klasa `App\Modules\Settings\ShopproStatusMappingRepository`,
  - synchronizacja statusow pobiera slownik `dictionaries/statuses` z API shopPRO,
  - zapis mapowan trafia do `order_status_mappings` per `integration_id` (wieloinstancyjnie).
- Poprawiono parser statusow shopPRO:
  - obsluguje odpowiedzi zagniezdzone w `data`,
  - obsluguje rowniez format mapy `kod => nazwa` oraz dodatkowe aliasy pol (`status_code`, `status_name`, `symbol`, `slug`).
- Dodano migracje naprawcza `20260308_000038_ensure_order_status_mappings_table.sql`:
  - tworzy `order_status_mappings` jesli tabela nie istnieje (scenariusz niepelnej historii migracji na srodowisku).
- Dodano migracje naprawcza `20260308_000039_ensure_integrations_fetch_columns.sql`:
  - uzupelnia w `integrations` brakujace kolumny `orders_fetch_enabled` i `orders_fetch_start_date`
    dla srodowisk, gdzie tabela `integrations` zostala odtworzona pozniej niz pierwotne migracje shopPRO.
- Poprawiono UX ekranu `shopPRO`:
  - przy istniejacych instancjach automatycznie wybierana jest pierwsza integracja (bez koniecznosci wracania do zakladki `Integracja`),
  - dodano przełącznik instancji nad zakladkami (`Wybrana integracja`) dostepny globalnie dla `Statusy/Ustawienia/Formy dostawy`.

## 2026-03-06
- Fix: synchronizacja statusow Allegro nie aktualizowala zamowien.
  - Przyczyna: Allegro API nie zmienia `updatedAt` przy zmianie `fulfillment.status`.
    Cursor-based sync (`AllegroOrdersSyncService`) pomijal takie zamowienia.
  - Rozwiazanie: `AllegroStatusSyncService` przepisany na podejscie direct-query:
    odpytuje baze o zamowienia Allegro w nie-finalnych statusach i re-importuje je
    przez `AllegroOrderImportService::importSingleOrder()`.
  - `AllegroStatusSyncService` nie zalezy juz od `AllegroOrdersSyncService`.
  - Dodano `ensureDefaultSchedulesExist()` w `AllegroIntegrationController`,
    aby harmonogramy cron byly tworzone automatycznie.
- Rozszerzono zakladke `Formy dostawy` o wybor przewoznika (Allegro / InPost) per wiersz:
  - nowa kolumna `carrier` w tabeli `allegro_delivery_method_mappings`,
  - select przewoznika determinuje dostepne uslugi (Allegro z API, InPost statyczna lista),
  - JS przelacza panele uslug w zaleznosci od wybranego przewoznika.
- Migracja `20260306_000036_add_carrier_to_delivery_method_mappings.sql`.

## 2026-03-05
- Dodano nowa zakladke `Ustawienia > Integracja InPost`:
  - route `GET /settings/integrations/inpost` i `POST /settings/integrations/inpost/save`,
  - widok konfiguracji z polami: token API (szyfrowany), ID organizacji, srodowisko (sandbox/production),
  - domyslny sposob nadania (POP/paczkomat/kurier), punkt nadania,
  - domyslny rozmiar paczki (A/B/C), wymiary przesylek kurierskich,
  - typ etykiety (PDF/ZPL/EPL), paczka weekendowa, auto-ubezpieczenie, multi-paczki.
- Dodano klasy:
  - `App\Modules\Settings\InpostIntegrationController`,
  - `App\Modules\Settings\InpostIntegrationRepository` (szyfrowanie AES-256-CBC + deszyfrowanie tokenu).
- Dodano migracje `20260305_000035_create_inpost_integration_settings_table.sql`.
- Rozszerzono nawigacje `Ustawienia` o link `Integracja InPost`.
- Import Allegro pobiera przesylki z dedykowanego endpointu `GET /order/checkout-forms/{id}/shipments` zamiast szukac ich w payloadzie checkout form (naprawa zerowej liczby przesylek).
- Dodano metode `AllegroApiClient::getCheckoutFormShipments(...)`.
- Usunieto duplikat ID zamowienia Allegro w naglowku szczegolow zamowienia (wyswietlane bylo `source_order_id` i `external_order_id` z ta sama wartoscia).
- Dodano nazwe integracji (np. "Allegro") przed ID zamowienia w naglowku szczegolow.
- Dodano nowa zakladke `Ustawienia > Integracja Apaczka`:
  - route `GET /settings/integrations/apaczka` i `POST /settings/integrations/apaczka/save`,
  - widok konfiguracji z polem klucza API (szyfrowany AES-256-CBC jak w integracji Allegro).
- Dodano klasy:
  - `App\Modules\Settings\ApaczkaIntegrationController`,
  - `App\Modules\Settings\ApaczkaIntegrationRepository`.
- Dodano migracje `20260305_000029_create_apaczka_integration_settings_table.sql`:
  - tabela `apaczka_integration_settings` na konfiguracje klucza API (zaszyfrowany).
- Rozszerzono nawigacje `Ustawienia` o link `Integracja Apaczka`.
- Dodano reczna zmiane statusu zamowienia z widoku szczegolow:
  - nowa route `POST /orders/{id}/status`,
  - nowa metoda `OrdersController::updateStatus(...)`,
  - dropdown ze wszystkimi aktywnymi statusami (pogrupowane wg grup) w naglowku szczegolow zamowienia,
  - zmiana rejestrowana w `order_status_history` i `order_activity_log` (actor_type: `user`),
  - flash messages (sukces/blad) po redirect,
  - bez zmian schematu.
- Import zamowienia z Allegro (reczny i auto-sync) rejestruje zdarzenie `import` w `order_activity_log`:
  - `AllegroOrderImportService` rozszerzony o zaleznosc `OrdersRepository`,
  - po kazdym upsert zamowienia wpisywany jest log z informacja o nowym imporcie lub re-imporcie,
  - actor_type: `import`, actor_name: `Allegro`,
  - bez zmian schematu.
- Dodano uniwersalny log aktywnosci zamowien:
  - nowa tabela `order_activity_log` (migracja `20260305_000030_create_order_activity_log_table.sql`),
  - nowe metody w `OrdersRepository`: `recordActivity()`, `recordStatusChange()`, `updateOrderStatus()`,
  - zakladka `Historia zmian` w szczegolow zamowienia wyswietla tabele z logiem aktywnosci (data, typ, opis, wykonawca),
  - typy zdarzen: zmiana statusu, platnosc, faktura, przesylka, wiadomosc, dokument, import, notatka,
  - kolorowe badge'e typow zdarzen,
  - historia statusow w zakladce `Szczegoly` pokazuje teraz nazwy statusow zamiast surowych kodow.

## 2026-03-04
- Poprawiono kolumne `Data zamowienia` na liscie zamowien:
  - wartosc jest liczona fallbackiem `orders.ordered_at -> orders.source_created_at -> orders.source_updated_at -> orders.fetched_at`,
  - domyslne sortowanie listy i filtry zakresu dat korzystaja z tej samej daty efektywnej, co eliminuje puste wartosci przy rekordach bez `ordered_at`.
- Import zamowienia Allegro zapisuje teraz forme wysylki:
  - `delivery.method.name` (fallback `delivery.method.id`) trafia do `orders.external_carrier_id`,
  - techniczne `delivery.method.id` trafia do `orders.external_carrier_account_id`.
- Dopracowano mapowanie dostawy dla zamowien Allegro:
  - dla dostawy do punktu odbioru adres `Dane wysylki` jest budowany z `delivery.pickupPoint` (nazwa punktu + adres punktu),
  - terminy z `delivery.time.dispatch` sa zapisywane do `orders.send_date_min` / `orders.send_date_max`.
- Rozszerzono UI `Ustawienia > Integracje > Allegro` o zakladke `Ustawienia`:
  - dodano opcje konfiguracji interwalu pobierania zamowien (minuty),
  - nowy endpoint zapisu `POST /settings/integrations/allegro/settings/save`,
  - zapis aktualizuje harmonogram joba `allegro_orders_import` w `cron_schedules`.
- Rozszerzono zakladke `Ustawienia` integracji Allegro:
  - dodano `kierunek synchronizacji statusow` (`Allegro -> orderPRO`, `orderPRO -> Allegro`),
  - dodano `interwal synchronizacji statusow` (minuty),
  - zapis do `app_settings` (`allegro_status_sync_direction`, `allegro_status_sync_interval_minutes`) pod przyszly cron synchronizacji statusow.
- Dodano cron synchronizacji statusow Allegro:
  - nowy job type `allegro_status_sync` z harmonogramem domyslnym co 900s,
  - nowy handler `App\Modules\Cron\AllegroStatusSyncHandler`,
  - nowy serwis `App\Modules\Settings\AllegroStatusSyncService` (obsluga kierunku sync z ustawien integracji).
- Dodano migracje `20260304_000028_add_allegro_status_sync_schedule.sql`:
  - seed `cron_schedules` dla `allegro_status_sync`,
  - seed domyslnych ustawien `app_settings` dla kierunku i interwalu synchronizacji statusow.
- Dodano automatyczny import zamowien Allegro przez cron:
  - nowy job type `allegro_orders_import` z harmonogramem co 300s (priorytet 20, max_attempts 3),
  - nowy handler `App\Modules\Cron\AllegroOrdersImportHandler`,
  - nowy serwis `App\Modules\Settings\AllegroOrdersSyncService` (stronicowanie checkout forms, deduplikacja/idempotentny import, limity batcha),
  - nowy repo `App\Modules\Settings\AllegroOrderSyncStateRepository` utrzymujacy kursor i status wykonania w `integration_order_sync_state`.
- Podlaczono handler `allegro_orders_import` do runnera crona:
  - `bin/cron.php` (CLI worker),
  - `App\Core\Application::maybeRunCronOnWeb` (tryb cron-on-web).
- Dodano migracje `20260304_000027_add_allegro_orders_import_schedule.sql`:
  - seed harmonogramu `allegro_orders_import`,
  - uzupelnienie kompatybilnosci tabeli `integration_order_sync_state` o kolumny kursora sync.
- Dodano obsluge miniatur produktow dla importu Allegro i widokow zamowien:
  - import pojedynczego zamowienia Allegro zapisuje URL obrazka pozycji (`lineItems.offer.image*`) do `order_items.media_url`,
  - lista i szczegoly zamowienia rozwiazuja miniature priorytetowo: `order_items.media_url` -> glowny obraz powiazanego produktu orderPRO (`product_channel_map` + `sales_channels=allegro` + `product_images`).
  - dodano bezpieczny fallback zgodnosci: jesli wymagane tabele/kolumny mapowania produktu nie istnieja w aktualnym schemacie DB, UI korzysta tylko z `order_items.media_url` (bez bledu 404 na szczegolach zamowienia).
- Rozszerzono import pojedynczego zamowienia Allegro o fallback pobrania obrazka po `offerId`:
  - gdy `checkout-form lineItem` nie zawiera obrazka, importer pobiera dane oferty przez `GET /sale/product-offers/{offerId}` i zapisuje URL miniatury do `order_items.media_url`,
  - obslugiwane sa rowniez URL w formacie `//...` (normalizacja do `https://...`).
- Dodano diagnostyke importu obrazkow Allegro:
  - po imporcie pojedynczego zamowienia UI pokazuje podsumowanie `obrazki: X/Y` i ostrzezenie z przyczynami brakow,
  - diagnostyka rozroznia m.in. brak obrazka w checkout-form, brak obrazka w API oferty, brak `offerId` oraz bledy HTTP API ofert (np. `403`).
- Rozszerzono zakres scope zadany w OAuth Allegro:
  - autoryzacja prosi teraz o `allegro:api:orders:read` oraz `allegro:api:sale:offers:read`,
  - po zmianie scope wymagane jest ponowne polaczenie OAuth (`Polacz ponownie`), aby nowe tokeny mialy dostep do API ofert.
- Poprawiono odczyt statusow zamowien w UI listy/szczegolow:
  - status efektywny jest liczony dynamicznie z mapowaniem `allegro_order_status_mappings` (nie tylko przy imporcie),
  - panel statusow, filtr statusu i etykieta statusu w tabeli korzystaja z tego samego statusu po mapowaniu.
- UI mapowania statusow Allegro zmieniono na zapis zbiorczy:
  - jeden przycisk `Zapisz mapowania` dla wszystkich selectow w tabeli,
  - nowy endpoint `POST /settings/integrations/allegro/statuses/save-bulk`.
- Dodano automatyczne pobieranie statusow Allegro do mapowania:
  - endpoint `POST /settings/integrations/allegro/statuses/sync`,
  - przycisk `Pobierz statusy z Allegro` w zakladce `Ustawienia > Integracje > Allegro > Statusy`,
  - nowa klasa `App\Modules\Settings\AllegroStatusDiscoveryService` (statusy z API `checkout-forms`).
- Dodano migracje `20260304_000026_make_allegro_status_mapping_nullable.sql`:
  - `allegro_order_status_mappings.orderpro_status_code` jest teraz nullable (statusy moga byc najpierw odkryte, potem mapowane).
- Zmieniono podejscie do statusow Allegro:
  - usunieto fallbackowe tlumaczenia statusow z kodu listy zamowien,
  - dodano zakladke `Statusy` w `Ustawienia > Integracje > Allegro` z recznym mapowaniem `status Allegro -> status orderPRO`.
- Dodano migracje `20260304_000025_create_allegro_order_status_mappings_table.sql`.
- Dodano `App\Modules\Settings\AllegroStatusMappingRepository`.
- Import pojedynczego zamowienia Allegro mapuje teraz status przez `allegro_order_status_mappings` (jesli istnieje wpis), zamiast fallbackowej translacji.
- Poprawiono prezentacje statusow na liscie zamowien:
  - filtr statusu pokazuje etykiety biznesowe zamiast surowych kodow (`external_status_id`),
  - kody bez mapowania sa tylko formatowane technicznie do czytelnej postaci (`do_odbioru` -> `Do odbioru`).
- Dodano reczny import pojedynczego zamowienia Allegro z poziomu `Ustawienia > Integracje > Allegro`:
  - endpoint `POST /settings/integrations/allegro/import-single`,
  - formularz z polem `checkout_form_id` w widoku integracji Allegro.
- Dodano klasy importu Allegro:
  - `App\Modules\Settings\AllegroApiClient` (request `GET /order/checkout-forms/{id}`),
  - `App\Modules\Settings\AllegroOrderImportService` (refresh tokenu + mapowanie payloadu),
  - `App\Modules\Orders\OrderImportRepository` (upsert aggregate do tabel zamowien).
- Import pojedynczego zamowienia dziala idempotentnie po kluczu biznesowym (`source=allegro`, `source_order_id`) i nadpisuje kolekcje 1:N (adresy/pozycje/platnosci/wysylki/notatki/historia) aktualnym snapshotem z API.
- Dodano nowy modul crona oparty o tabele `cron_schedules` + `cron_jobs`:
  - `App\Modules\Cron\CronRepository`,
  - `App\Modules\Cron\CronRunner`.
- Dodano pierwszy handler crona:
  - `App\Modules\Cron\AllegroTokenRefreshHandler` dla joba `allegro_token_refresh`.
- Dodano odswiezanie tokenu OAuth w `App\Modules\Settings\AllegroOAuthClient::refreshAccessToken(...)`.
- Rozszerzono `App\Modules\Settings\AllegroIntegrationRepository` o odczyt danych refresh tokenu.
- Odtworzono CLI worker `bin/cron.php` (uruchomienie jobow wg harmonogramu i priorytetu).
- Dodano migracje `20260304_000024_add_allegro_token_refresh_schedule.sql`:
  - harmonogram `allegro_token_refresh` (`interval_seconds=3600`, `priority=10`, `max_attempts=3`, `enabled=1`).
- Dodano zakladke `Ustawienia > Cron`:
  - `GET /settings/cron`,
  - `POST /settings/cron`,
  - kontrola opcji `cron_run_on_web` i `cron_web_limit`,
  - podglad harmonogramow i kolejki/historii jobow.
- Podlaczono wykonanie crona podczas requestow HTTP:
  - `App\Core\Application::maybeRunCronOnWeb(Request)` jest uruchamiane w `Application::run()`,
  - aktywowane ustawieniem `cron_run_on_web` i ograniczane lockiem DB + throttlingiem sesyjnym.
- Dodano nowa zakladke `Ustawienia > Integracje > Allegro`:
  - route i widok konfiguracji,
  - sekcja z gotowym `redirect_uri` do rejestracji aplikacji Allegro.
- Dodano endpointy Allegro OAuth:
  - `GET /settings/integrations/allegro`,
  - `POST /settings/integrations/allegro/save`,
  - `POST /settings/integrations/allegro/oauth/start`,
  - `GET /settings/integrations/allegro/oauth/callback`.
- Dodano klasy:
  - `App\Modules\Settings\AllegroIntegrationController`,
  - `App\Modules\Settings\AllegroIntegrationRepository`,
  - `App\Modules\Settings\AllegroOAuthClient`.
- Dodano migracje `20260304_000023_create_allegro_integration_settings_table.sql`:
  - tabela `allegro_integration_settings` na konfiguracje OAuth2 i tokeny (`client_secret`, `access_token`, `refresh_token` trzymane jako zaszyfrowane).
- Dodano walidacje i obsluge flow Authorization Code:
  - generowanie `state` i walidacja callbacku,
  - wymiana `code` na tokeny przez endpoint tokenowy Allegro (sandbox/production).
- Rozszerzono nawigacje `Ustawienia` o link `Integracje Allegro`.
- Dodano style SCSS dla bloku prezentacji callback URL i przebudowano asset CSS (`public/assets/css/app.css`).

## 2026-03-02
- Dodano zakladke `Ustawienia > Statusy` do zarzadzania:
  - grupami statusow (z kolorem na poziomie grupy),
  - statusami przypisanymi do grup.
- Dodano migracje `20260302_000022_create_order_status_groups_and_statuses_tables.sql`:
  - tabela `order_status_groups`,
  - tabela `order_statuses` z FK `order_statuses_group_fk` i kasowaniem kaskadowym.
- Dodano `App\Modules\Settings\OrderStatusRepository` (CRUD grup/statusow i walidacja unikalnosci kodow).
- Rozszerzono `App\Modules\Settings\SettingsController` o endpointy:
  - `statuses`,
  - `createStatusGroup`, `updateStatusGroup`, `deleteStatusGroup`,
  - `createStatus`, `updateStatus`, `deleteStatus`.
- Rozszerzono routing o trasy `/settings/statuses*` i `/settings/status-groups*`.
- Sidebar ustawien ma nowy link `Statusy`.
- Dodano widok `resources/views/settings/statuses.php` oraz style SCSS dla formularzy/akcji tego widoku.
- Potwierdzenia usuwania w nowym widoku realizowane sa przez `window.OrderProAlerts.confirm(...)`.
- Przebudowano UI `Ustawienia > Statusy`:
  - 2 taby (`Statusy`, `Grupy statusow`),
  - sortowanie realizowane przez drag-and-drop z automatycznym zapisem kolejnosci po upuszczeniu.
- Skondensowano UI zakladki `Ustawienia > Statusy`:
  - elementy listy statusow i grup maja bardziej kompaktowy, jednoliniowy uklad,
  - zmniejszono paddingi/gapy i wysokosci kontrolek, aby zwiekszyc ilosc danych widocznych bez scrolla.
- Wprowadzono globalna preferencje kompaktowego UI w `AGENTS.md`.
- Poprawiono generowanie `code` dla statusow/grup: polskie znaki sa transliterowane do ASCII
  (np. `Nieopłacone` -> `nieoplacone`), zamiast zamiany na `_`.
- Dodano skrypt serwisowy `bin/fix_status_codes.php`:
  - przelicza kody grup/statusow na podstawie aktualnych nazw z transliteracja PL->ASCII,
  - zapewnia unikalnosc kodow (`_2`, `_3` przy konfliktach),
  - wspiera `--dry-run` i `--use-remote`.
- Wykonano naprawe kodow na bazie zdalnej (`--use-remote`): zaktualizowano 2 grupy i 1 status.
- Przygotowano draft generycznego schematu tabel zamowien (Apilo tylko jako przyklad pol API):
  - dokumentacja: `DOCS/ORDERS_SCHEMA_DRAFT.md`,
  - draft SQL (nieuruchamiany automatycznie): `database/drafts/20260302_orders_schema_v1.sql`.
- Wdrozono generyczny schema zamowien na bazie docelowej przez `bin/deploy_and_seed_orders.php`.
- Zasiano dane testowe:
  - `orders`: 30,
  - `order_items`: 90,
  - `order_status_history`: 123,
  - pozostale kolekcje (adresy/platnosci/wysylki/dokumenty/notatki/tagi) proporcjonalnie.
- Dodano endpointy zapisu kolejnosci:
  - `POST /settings/status-groups/reorder`,
  - `POST /settings/statuses/reorder`.
- Zmieniono obsluge pola `code`:
  - `code` jest automatycznie generowany przy tworzeniu z nazwy,
  - po utworzeniu jest tylko do odczytu i nie podlega edycji z formularza.
- Reset projektu do trybu `users-only`.
- Zarchiwizowano moduly poza `Auth` i `Users` do `archive/2026-03-02_users-only-reset/`.
- Uproszczono routing i layout do obslugi logowania i zarzadzania uzytkownikami.
- Ustalono nowy standard dokumentacji technicznej w plikach root:
  - `DB_SCHEMA.md`
  - `ARCHITECTURE.md`
  - `TECH_CHANGELOG.md`
- Przywrocono sekcje `Ustawienia` w nawigacji jako grupe z podkategoriami:
  - `Uzytkownicy` (`/users`)
  - `Baza danych` (`/settings/database`)
- Dodano modul `App\Modules\Settings` z kontrolerem `SettingsController` (metody `database`, `migrate`).
- Przywrocono reczne uruchamianie migracji z UI:
  - `GET /settings/database` (status migracji + lista pending plikow),
  - `POST /settings/database/migrate` (wykonanie pending migracji + log ostatniego uruchomienia).
- Zmieniono tlumaczenie `settings.database.title` na `Baza danych` oraz dodano `navigation.database`.
- Poprawiono redirect po logowaniu (`AuthController`): `/dashboard` -> `/settings/users`.
- Usunieto wewnetrzny pasek zakladek (`settings-nav`) z podstron ustawien.
- Podstrona uzytkownikow jest adresowana jako `GET/POST /settings/users` (z zachowaniem tras kompatybilnosci `/users`).
- Usunieto z podstron ustawien blok naglowkowy `Ustawienia` + opis, aby zwiekszyc obszar roboczy.
- Rozszerzono `bin/deploy_and_seed_orders.php` o parametr `--profile=default|realistic`.
- Dodano realistyczny profil seedowania:
  - wazone losowanie statusow i metod platnosci,
  - spojne mapowanie `external_status_id` -> `payment_status` i `total_paid`,
  - bardziej realne reguly tworzenia wpisow `order_payments`, `order_shipments`, `order_documents`,
  - historia statusow oparta na logicznych sciezkach przejsc (zamiast losowych skokow).
- Wykonano ponowne wdrozenie draftu i seed z profilem realistycznym:
  - komenda: `C:\xampp\php\php.exe bin/deploy_and_seed_orders.php --use-remote --count=30 --profile=realistic`,
  - wynik: `orders=30`, `order_items=94`, `order_status_history=81`.
- Dodano glowna sekcje panelu `Zamowienia` z podzakladka `Lista zamowien`.
- Wdrozone endpointy:
  - `GET /orders` (redirect do `/orders/list`),
  - `GET /orders/list` (widok listy).
- Dodano modul aplikacyjny:
  - `App\Modules\Orders\OrdersController`,
  - `App\Modules\Orders\OrdersRepository`.
- Widok listy zamowien opiera sie o aktualna baze (`orders`, `order_addresses`, `order_items`, `order_shipments`, `order_documents`) i udostepnia:
  - filtry (fraza, zrodlo, status, status platnosci, zakres dat),
  - sortowanie i paginacje,
  - kompaktowe komorki (referencje, klient, status+platnosc, pozycje, kwoty, wysylka, daty),
  - skrócone statystyki (`wszystkie`, `oplacone`, `wyslane`).
- Rozszerzono liste zamowien o podglad produktow w zamowieniu:
  - nazwa produktu,
  - miniatura (z `order_items.media_url`, fallback bez obrazu),
  - ilosc sztuk per pozycja,
  - licznik dodatkowych pozycji poza limitem podgladu.
- Miniatury produktow na liscie zamowien zostaly powiekszone o 100% (uklad bardziej czytelny).
- Dodano modal podgladu zdjecia po kliknieciu miniatury produktu na liscie zamowien.
- Status w kolumnie statusow jest prezentowany jako nazwa biznesowa (np. `Nowe`, `W realizacji`) bez technicznego kodu.
- Dodano skrypt serwisowy `bin/fill_order_item_images.php` do uzupelniania pustych `order_items.media_url`
  losowymi URL (`picsum.photos`) i wykonano go na bazie zdalnej (`--use-remote`, zaktualizowano 94 rekordy).
- Rozszerzono sidebar o grupe `Zamowienia` z podlinkiem `Lista zamowien`.
- Dodano widok szczegolow zamowienia:
  - endpoint `GET /orders/{id}`,
  - link do szczegolow po kliknieciu numeru zamowienia na liscie,
  - uklad sekcji inspirowany widokiem Apilo: pozycje, dane zamowienia, platnosc/wysylka, adresy, notatki, historia.
- Dopracowano widok `GET /orders/{id}` do ukladu bardziej zblizonego do Apilo:
  - lewy panel statusow z licznikami,
  - prawa kolumna szczegolow z paskiem akcji i tabami sekcji,
  - aktywne wyroznienie biezacego statusu zamowienia.
- Dodano taki sam lewy panel statusow na `GET /orders/list`:
  - grupy statusow z licznikami,
  - klikniecie statusu filtruje liste zamowien po `status`,
  - kolorowe liczniki per status (info/warn/success/danger).
- Poprawiono zrodlo panelu statusow (lista + szczegoly):
  - podzial na grupy i nazwy statusow sa pobierane dynamicznie z `order_status_groups` + `order_statuses`,
  - kolory pochodza z `order_status_groups.color_hex`,
  - dla statusow nieprzypisanych do konfiguracji dodawana jest sekcja `Pozostale`.
- Ujednolicono render panelu statusow jako jeden widget widoku:
  - nowy komponent `resources/views/components/order-status-panel.php`,
  - komponent jest wspolnie uzywany przez `orders/list.php` i `orders/show.php`,
  - statusy w szczegolach zamowienia sa klikalne (przejscie do listy z odpowiednim filtrem).
- Dodano klikalne taby w `orders/show.php`:
  - przelaczanie sekcji bez przeladowania strony (JS),
  - aktywny panel `Szczegoly zamowienia`,
  - pozostale panele (`Historia zmian`, `Przesylki`, `Platnosci`, `Dokumenty`) zawieraja tymczasowe puste boksy.
- Zmieniono seed zamowien (`bin/deploy_and_seed_orders.php`):
  - `external_status_id` jest losowany z aktywnych statusow z tabeli `order_statuses` (zgodnie z konfiguracja w `Ustawienia > Statusy`),
  - dodano fallback do listy domyslnej, jesli tabela jest pusta/niedostepna,
  - profil `realistic` ma fallback reguly finansowej dla niestandardowych statusow.
- Dodano skrypt serwisowy `bin/randomize_order_statuses.php`:
  - losowo podmienia `orders.external_status_id` dla juz istniejacych zamowien na aktywne statusy z `order_statuses`,
  - aktualizuje tez `is_canceled_by_buyer` dla statusu `cancelled`,
  - wspiera `--use-remote` i `--dry-run`.
- Wykonano podmiane statusow na bazie zdalnej (`--use-remote`): zaktualizowano 30 zamowien.





