239 lines
18 KiB
Markdown
239 lines
18 KiB
Markdown
# 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`.
|
|
|
|
## 2026-05-12 - Phase 122 Plan 01: SMSPLANET Default SMS Footer
|
|
|
|
**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
|