Files
orderPRO/DOCS/TECH_CHANGELOG.md

18 KiB

Technical Changelog

2026-05-16 - Phase 130 Plan 01: Erli Shipments + Labels

Co zrobiono:

  • Rozszerzono carrier_delivery_method_mappings o source_service_id i source_vendor_code, zeby mapowanie Erli przechowywalo osobno metode marketplace i vendora wymaganego przez POST /shipping/external.
  • Dodano zakladke Dostawy w /settings/integrations/erli oraz ErliDeliveryMappingController do mapowania metod z zamowien Erli na lokalne uslugi InPost/Apaczka.
  • Rozszerzono ErliApiClient o slowniki shipping/delivery/vendor/cenniki i tworzenie paczek zewnetrznych przez POST /shipping/external.
  • ShipmentController uzywa mapowan Erli przy przygotowaniu przesylki i po uzyskaniu tracking number wywoluje ErliExternalShipmentService.
  • ErliExternalShipmentService rejestruje paczke zewnetrzna w Erli, zapisuje odpowiedz w shipment_packages.payload_json.erli_external_parcel i loguje bledy jako niekrytyczne.

Dlaczego:

  • Operator chce nadawac zamowienia Erli z orderPRO, ale bez wymuszania nadawania na umowie Erli. Etykiety pozostaja u lokalnych providerow, a Erli dostaje informację o zewnetrznej paczce/tracking number.

BREAKING / migracja:

  • Wymagana migracja 20260516_000117_extend_delivery_mappings_for_erli_shipping.sql.
  • Brak breaking changes w istniejacych mapowaniach Allegro/shopPRO; nowe kolumny sa opcjonalne.

2026-05-16 - Erli Settings Tabs UI Fix

Co zrobiono:

  • Ujednolicono /settings/integrations/erli z innymi integracjami przez dodanie zakladek Integracja, Statusy i Ustawienia.
  • Dodano obsluge aktywnej zakladki przez parametr tab oraz return_to w formularzach Erli, zeby po zapisie wracac do wlasciwego panelu.

Dlaczego:

  • Ekran Erli po Phase 129 mial wszystkie sekcje jedna pod druga, przez co odstawal od Allegro/shopPRO i byl trudniejszy do skanowania.

2026-05-16 - Phase 129 Plan 01: Erli Status Mapping + Sync

Co zrobiono:

  • Dodano migracje 20260515_000116_add_erli_status_mapping_sync.sql z tabelami erli_order_status_mappings, erli_order_status_pull_mappings, kolumna integration_order_sync_state.last_status_pushed_at, seedami statusow Erli oraz cronem erli_status_sync.
  • Rozszerzono ustawienia Erli o mapowania Erli -> orderPRO, orderPRO -> Erli, kierunek synchronizacji statusow i interwal crona.
  • Dodano ErliStatusMappingRepository, ErliPullStatusMappingRepository, ErliStatusSyncService oraz ErliStatusSyncHandler.
  • Rozszerzono ErliApiClient o PATCH /orders/{id}/status oraz ErliOrdersSyncService o discovery surowych statusow z inboxa.
  • ErliOrderMapper korzysta teraz z konfigurowalnych pull mappings, zachowujac fallbacki z Phase 128.
  • Dodano testy jednostkowe tests/Unit/ErliStatusSyncServiceTest.php i rozszerzono ErliOrderMapperTest.

Dlaczego:

  • Phase 128 importowala zamowienia Erli, ale statusy byly mapowane domyslnie. Operator potrzebuje kontrolowac pull/push statusow analogicznie do Allegro/shopPRO.
  • Push jest ograniczony do recznych zmian statusu (order_status_history.change_source='manual'), zeby uniknac petli po automatyzacjach i reimportach.

BREAKING / migracja:

  • Brak breaking changes. Nowy cron jest domyslnie wylaczony w migracji; zapis ustawien Erli wlacza go zgodnie z aktywnoscia integracji.
  • Manual smoke po wdrozeniu: php bin/migrate.php, sprawdz widok /settings/integrations/erli, zapisz mapowania, ustaw orderPRO -> Erli, zmien recznie status zamowienia Erli i uruchom cron erli_status_sync.

2026-05-15 - Phase 128 Plan 01: Erli Orders Import

Co zrobiono:

  • Dodano migracje 20260515_000115_add_erli_orders_import_schedule.sql, ktora zapewnia kolumny kursora w integration_order_sync_state i seeduje cron_schedules.job_type='erli_orders_import' jako disabled.
  • Rozszerzono ustawienia Erli o wlaczenie importu zamowien, date startu, interwal crona oraz reczna akcje POST /settings/integrations/erli/import.
  • Rozszerzono ErliApiClient o fetchInbox() (GET /inbox) oraz bezpieczny ACK markInboxRead() (POST /inbox/mark-read, body lastMessageId) potwierdzony z oficjalnego swaggera Erli.
  • Dodano ErliOrderMapper, ErliOrderSyncStateRepository, ErliOrdersSyncService i ErliOrdersImportHandler.
  • Import wspiera zdarzenia orderCreated, orderStatusChanged, orderSellerStatusChanged, zapisuje order aggregate przez OrderImportRepository, ustawia invoice_requested przy danych firmowych/NIP, zapisuje activity log i emituje order.imported oraz payment.status_changed.
  • Dodano testy jednostkowe tests/Unit/ErliOrderMapperTest.php.

Dlaczego:

  • Erli ma zaczac realnie dostarczac zamowienia do orderPRO po fundamencie konfiguracji z Phase 127.
  • /inbox jest rekomendowanym zrodlem zdarzen Erli; ACK jest wykonywany dopiero po bezblednym batchu, zeby nie zgubic zamowien przy czesciowej awarii.

BREAKING / migracja:

  • Brak breaking changes. Nowy cron jest domyslnie wylaczony do czasu wlaczenia importu w ustawieniach Erli.
  • Manual smoke po wdrozeniu: php bin/migrate.php, zapis aktywnej konfiguracji Erli, wlaczenie importu, klik Importuj zamowienia teraz, kontrola orders.source='erli' i licznikow importu.

2026-05-15 - Phase 127 Plan 01: Erli Integration Foundation

Co zrobiono:

  • Dodano migracje 20260515_000114_create_erli_integration_settings.sql z pojedyncza globalna konfiguracja erli_integration_settings i bazowym wpisem integrations.type='erli'.
  • Dodano ErliIntegrationRepository z szyfrowaniem klucza API przez IntegrationSecretCipher i zachowaniem sekretu przy pustym polu edycji.
  • Dodano ErliApiClient, ktory testuje polaczenie realnym GET https://erli.pl/svc/shop-api/inbox z naglowkiem Authorization: Bearer ... i User-Agent.
  • Dodano ErliIntegrationController, routes /settings/integrations/erli, /save, /test oraz widok resources/views/settings/erli.php.
  • Dodano Erli do hubu integracji /settings/integrations z informacja o konfiguracji, aktywnosci i ostatnim tescie.

Dlaczego:

  • Erli ma byc trzecim kanalem sprzedazy, ale potrzebuje najpierw bezpiecznego fundamentu konfiguracji i potwierdzenia dostepu do API.
  • Na podstawie decyzji operatora integracja startuje jako jedna globalna konfiguracja, bez przelacznika sandbox.
  • Test polaczenia realnie odpytuje API, ale nie importuje zamowien i nie oznacza inboxa jako przeczytanego.

BREAKING / migracja:

  • Brak breaking changes. Nowa tabela i nowy wpis integracji sa dodatkiem. Import zamowien, synchronizacja statusow, etykiety i tracking Erli sa odlozone do kolejnych faz v3.8.

2026-05-12 - SMSPLANET Inbound Webhook Fix

Co zrobiono:

  • Poprawiono dopasowanie przychodzacych SMSPLANET po telefonie: SmsMessageRepository::findLatestOrderIdByPhones() nie odwoluje sie juz do nieistniejacej w produkcyjnej bazie kolumny orders.buyer_phone, tylko do order_addresses.phone.
  • Dodano obsluge GET /webhooks/smsplanet/inbound obok POST, bo sekcja odbierania SMS 2WAY w dokumentacji SMSPLANET opisuje przekierowanie na URL bez jednoznacznego kontraktu metody.
  • SmsplanetWebhookController obsluguje format 2WAY POST application/x-www-form-urlencoded z parametrem message=<JSON>, scala JSON z body z parametrami requestu takze wtedy, gdy URL ma query string, i po sukcesie zwraca plain text OK.

Dlaczego:

  • Publiczny endpoint byl osiagalny jako POST, ale odpowiedz SMS nie mogla zostac zapisana przez blad SQL Unknown column 'o.buyer_phone'. GET na ten sam URL zwracal 404.

BREAKING / migracja:

  • Brak migracji. Zmiana usuwa bledne zalozenie o schemacie produkcyjnej tabeli orders.

Co zrobiono:

  • Dodano migracje 20260512_000111_smsplanet_default_footer.sql z kolumna smsplanet_integration_settings.default_footer.
  • Rozszerzono konfiguracje SMSPLANET o opcjonalna stopke SMS z limitem 300 znakow i zapisem oddzielnym od danych autoryzacji/nadawcy.
  • Testowa wysylka SMSPLANET oraz wysylka SMS z zamowienia dopinaja stopke przez pusta linie, waliduja finalna tresc w limicie 918 znakow i nie wywoluja API przy przekroczeniu limitu.
  • Historia sms_messages.body zapisuje finalna tresc wyslana do SMSPLANET, czyli razem ze stopka, gdy jest skonfigurowana.
  • Widok rozmowy SMS w zamowieniu pokazuje kompaktowa informacje, ze stopka zostanie dodana automatycznie.

Dlaczego:

  • Operator ma utrzymywac jeden wspolny podpis firmy bez recznego kopiowania go do kazdej wiadomosci SMS.

BREAKING / migracja:

  • Brak. Pusta stopka zachowuje dotychczasowe tresci SMS bez zmian.

2026-05-12 - Phase 121 Plan 01: SMSPLANET Conversation + Notifications

Co zrobiono:

  • Dodano migracje 20260512_000110_smsplanet_conversation_notifications.sql z tabelami sms_messages, notifications oraz polami sender_mode i sender_phone w smsplanet_integration_settings.
  • Rozszerzono SMSPLANET o wybor nadawcy: nadpis albo numer 2WAY, bez tymczasowego override testowego numeru.
  • Dodano publiczny webhook /webhooks/smsplanet/inbound, zapis przychodzacych SMS, dopasowanie do ostatniego zamowienia po telefonie i tworzenie globalnego powiadomienia.
  • Dodano zakladke SMS w szczegolach zamowienia z historia rozmowy i formularzem wysylki.
  • Dodano centrum powiadomien /notifications, API pollingu /api/notifications/unread, badge w topbarze i progresywne powiadomienia przegladarki.
  • Poprawiono migracje po pierwszej probie na bazie: rzeczywiste orders.id ma typ BIGINT UNSIGNED, wiec sms_messages.order_id i notifications.related_order_id tez musza miec BIGINT UNSIGNED.

Dlaczego:

  • Operator ma prowadzic dwukierunkowa rozmowe SMSPLANET bez opuszczania zamowienia, a nowe odpowiedzi klientow maja byc widoczne globalnie.

BREAKING / migracja:

  • Brak. Webhook SMSPLANET w tej fazie celowo nie weryfikuje podpisu.

2026-05-12 - SMSPLANET Test Sender Override

Co zrobiono:

  • Tymczasowo ustawiono testowa wysylke SMSPLANET na from=48532963363 w SmsplanetIntegrationController::test().
  • Zapis konfiguracji SMSPLANET pozostaje bez zmian; override dotyczy tylko endpointu /settings/integrations/smsplanet/test.

Dlaczego:

  • Operator sprawdza odbior odpowiedzi SMS z numeru 2WAY zamiast tekstowego nadpisu.

2026-05-12 - Phase 118 Plan 01: Fakturownia Single Instance

Co zrobiono:

  • Dodano migracje 20260512_000109_fakturownia_single_instance.sql, ktora wybiera aktywna instancje Fakturowni, przepina delegowane invoice_configs.integration_id na jeden globalny rekord i usuwa nadmiarowe konta Fakturowni po przepieciu zaleznosci.
  • Przebudowano FakturowniaIntegrationRepository na model jednej globalnej konfiguracji (getSettings(), saveSettings(), getIntegrationId(), getCredentials()), z kompatybilnym findAll() zwracajacym jeden element.
  • Uproszczono FakturowniaIntegrationController i widok /settings/integrations/fakturownia do pojedynczego formularza konfiguracji i testu polaczenia.
  • Hub integracji pokazuje Fakturownie jako jedna instancje, bez licznika kont.
  • Zapis delegowanej konfiguracji faktury ustawia invoice_configs.integration_id na globalny rekord Fakturowni; UI konfiguracji faktury nie pokazuje juz selecta kont.
  • Zaktualizowano DOCS/DB_SCHEMA.md i DOCS/ARCHITECTURE.md o kontrakt pojedynczej Fakturowni.

Dlaczego:

  • Operator chce obslugiwac Fakturownie tak jak HostedSMS/SMSPLANET: jedna konfiguracja globalna zamiast wielu instancji.
  • Zachowanie invoice_configs.integration_id ogranicza ryzyko regresji w InvoiceService i historii faktur, a jednoczesnie usuwa wieloinstancyjny wybor z UI.

BREAKING / migracja:

  • Po migracji nie ma juz wielu kont Fakturowni w UI. Jesli baza miala wiele rekordow integrations.type='fakturownia', zachowany zostaje aktywny rekord (fallback: uzywany przez konfiguracje faktur, potem najnizsze id), a pozostale sa usuwane.

2026-05-12 - Phase 117 Plan 01: SMSPLANET Integration Settings + Test SMS

Co zrobiono:

  • Dodano migracje 20260512_000108_create_smsplanet_integration_settings.sql z pojedyncza konfiguracja smsplanet_integration_settings i bazowym wpisem integrations typu smsplanet.
  • Dodano SmsplanetIntegrationRepository z obsluga metod autoryzacji token oraz key_password i szyfrowaniem sekretow przez IntegrationSecretCipher.
  • Dodano SmsplanetApiClient dla SMSPLANET (POST https://api2.smsplanet.pl/sms) z obsluga Bearer token oraz key + password.
  • Dodano SmsplanetIntegrationController i trasy /settings/integrations/smsplanet, /save, /test.
  • Dodano widok resources/views/settings/smsplanet.php z konfiguracja i realna wysylka testowego SMS z edytowalna trescia oraz panelem ostatniego testu (OK, HTTP, messageId).
  • Dodano SMSPLANET do hubu integracji /settings/integrations.
  • Poprawiono import IntegrationSecretCipher, aby rzucal istniejacy App\Core\Exceptions\IntegrationConfigException.

Dlaczego:

  • Operator potrzebuje drugiej bramki SMS analogicznej do HostedSMS, ale bez uruchamiania jeszcze automatyzacji lub historii wysylek.
  • SMSPLANET wspiera dwa warianty autoryzacji, wiec konfiguracja przechowuje wszystkie sekrety w formie szyfrowanej i waliduje wymagania zalezne od wyboru operatora.
  • Test uzywa rzeczywistej wysylki, bo celem tej fazy jest potwierdzenie realnej sciezki API.

2026-05-12 - Phase 116 Plan 01: HostedSMS Integration Settings + Test SMS

Co zrobiono:

  • Dodano migracje 20260512_000107_create_hostedsms_integration_settings.sql z pojedyncza konfiguracja hostedsms_integration_settings i bazowym wpisem integrations typu hostedsms.
  • Dodano HostedSmsIntegrationRepository z szyfrowaniem hasla przez IntegrationSecretCipher.
  • Dodano HostedSmsApiClient dla HostedSMS SimpleAPI (POST https://api.hostedsms.pl/SimpleApi).
  • Dodano HostedSmsIntegrationController i trasy /settings/integrations/hostedsms, /save, /test.
  • Dodano widok resources/views/settings/hostedsms.php z konfiguracja i realna wysylka testowego SMS z edytowalna trescia oraz czytelnym panelem ostatniego testu (OK, HTTP, MessageId).
  • Dodano HostedSMS do hubu integracji /settings/integrations.

Dlaczego:

  • Operator potrzebuje najpierw zapisac dane HostedSMS i sprawdzic realna wysylke SMS, zanim integracja zostanie wykorzystana w automatyzacjach lub komunikacji z klientami.
  • Test uzywa rzeczywistej wysylki, bo SimpleAPI nie udostepnia osobnego endpointu ping/test.
  • Haslo nie jest ujawniane po zapisie; UI pokazuje tylko status zapisanego sekretu.

2026-04-28 - Phase 110 Plan 01: Statistics Summary

Co zrobiono:

  • /statistics/summary - nowy widok podsumowania w menu Statystyki -> Podsumowanie.
  • OrdersStatisticsController::summary() - buduje miesieczny view-model dla wykresow liczby i wartosci zamowien.
  • OrdersStatisticsRepository::aggregateByMonth() - agreguje istniejace zamowienia po miesiacu i kanale/integracji.
  • public/assets/js/modules/statistics-summary-charts.js - renderer dwoch interaktywnych wykresow liniowych oparty o Chart.js 4.4.8 CDN.
  • resources/views/statistics/summary.php - filtry zgodne z raportem dziennym, dwa wykresy obok siebie na desktopie oraz dwie tabele fallback pod nimi.
  • Domyslny poczatek historii ustawiony na 2026-04-01 (04-2026) mimo starszych danych.

Dlaczego:

  • Operator potrzebuje szybkiego trendu miesiecznego przed przejsciem do szczegolowych dziennych statystyk.
  • Wykresy uzywaja obecnych tabel orders, integrations, order_status_groups i order_statuses, wiec migracja DB nie jest potrzebna.
  • Seria Razem jest liczona z tych samych danych co serie integracji, co ulatwia sprawdzenie sum miesiecznych.

2026-04-28 - Phase 109 Plan 01: Checkbox Multiselect Filters

Co zrobiono:

  • public/assets/js/modules/checkbox-multiselect.js - nowy vanilla JS enhancer dla natywnych <select multiple data-checkbox-multiselect>.
  • resources/views/layouts/app.php - globalne podpiecie modulu z cache busting przez filemtime().
  • resources/views/statistics/orders.php - filtry channels[] i status_groups[] oznaczone do progresywnego ulepszenia bez zmiany nazw pol formularza.
  • resources/scss/app.scss - kompaktowe style dropdownu z checkboxami i opcja "Wszystkie".

Dlaczego:

  • Natywne selecty multiple byly malo czytelne i zajmowaly za duzo miejsca w filtrach statystyk.
  • Zachowanie oryginalnego selecta w DOM utrzymuje obecny kontrakt GET i fallback bez JavaScript.
  • Brak zmian w schemacie DB i logice agregacji statystyk.

Chronologiczny log zmian technicznych — co i dlaczego.

2026-04-27 — Phase 108 Plan 02: Automation Dropdowns z DB

Co zrobiono:

  • AutomationController — usunięto stałą SHIPMENT_STATUS_OPTIONS (8 grupowych kluczy)
  • Dropdown statusów w warunku shipment_status i akcji update_shipment_status ładuje statusy z DB przez DeliveryStatus::getAllOptions()
  • Walidacja w parseConditionValue() i parseActionConfig() używa DeliveryStatus::getAllStatuses()
  • AutomationService — usunięto stałą SHIPMENT_STATUS_OPTION_MAP; ewaluacja evaluateShipmentStatusCondition() porównuje klucze bezpośrednio
  • resolveStatusFromActionKey() — bezpośredni klucz statusu z DB jako target (zamiast pierwszego z grupy)

Dlaczego:

  • Zamknięcie integracji z Plan 01 — operator dodaje status w /settings/delivery-statuses i jest on od razu dostępny w dropdownach automatyzacji bez deploymentu
  • Eliminacja kolizji semantycznej: stary klucz grupowy picked_up mapował na delivered (paczka odebrana przez klienta), nowy klucz DB picked_up to "Odebrana przez kuriera" (od nadawcy)
  • BREAKING: stare reguły z grupowymi kluczami (registered, courier_pickup, dropped_at_point, unclaimed, picked_up_return, oraz picked_up/ready_for_pickup/cancelled w starym znaczeniu) nie matchują — wymagają ręcznego odtworzenia z nowymi kluczami DB

2026-04-27 — Phase 108 Plan 01: Delivery Status Management

Co zrobiono:

  • Tabela delivery_statuses z seedem 11 statusów (migracja 20260427_000103)
  • DeliveryStatusRepository — CRUD + per-request cache
  • DeliveryStatus.php — dynamiczne ładowanie statusów z DB (setRepository())
  • Panel /settings/delivery-statuses z CRUD (zakładka "Statusy") i mapowaniem (zakładka "Mapowanie dostawy")
  • Sidebar: "Statusy" → "Statusy zamówień", nowe "Statusy przesyłek" z badge niezmapowanych
  • Badge przesyłek: inline CSS custom property --status-color dla niestandardowych statusów

Dlaczego:

  • Dodanie nowego statusu wymagało zmiany kodu + deploymentu; teraz z UI
  • Operator może definiować własne statusy znormalizowane bez ingerencji w kod