Phase 113 complete (v3.7 Invoices): - DB: invoices, invoice_configs, invoice_number_counters, fakturownia_integration_settings + orders.invoice_requested - FakturowniaIntegrationRepository (multi-account via integrations.type='fakturownia') - FakturowniaApiClient (testConnection; createInvoice/downloadPdf STUBs) - IntegrationsRepository::updateTestResult() (reusable test-result writer) - /settings/integrations/fakturownia (list + edit + test + delete) - Karta Fakturownia w hubie /settings/integrations Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 KiB
12 KiB
Technical Changelog
2026-05-10 - Phase 113 Plan 01: Fakturownia Integration Foundation
Co zrobiono:
- Migracje SQL:
20260510_000104_create_invoices_tables.sql- cztery nowe tabele:invoice_configs,invoices,invoice_number_counters,fakturownia_integration_settings(multi-account,integration_id UNIQUE FK->integrations).20260510_000105_add_invoice_requested_to_orders.sql-orders.invoice_requested TINYINT(1) NOT NULL DEFAULT 0+ indexidx_orders_invoice_requested.20260510_000106_seed_fakturownia_integration_type.sql- no-op placeholder dokumentujacy uznanieintegrations.type='fakturownia'jako oficjalnie wspieranego.
FakturowniaIntegrationRepository- CRUD kont Fakturowni z resolved encryption (integrations.api_key_encryptedjako zrodlo prawdy,settings.api_token_encryptedjako cache).findAll/findByIntegrationId/save/delete/getDecryptedToken.FakturowniaApiClient::testConnection()- GEThttps://{prefix}.fakturownia.pl/account.json?api_token=...z cURL +SslCertificateResolver.createInvoice/downloadPdfjako STUB-y rzucajaceRuntimeException(do implementacji w kolejnym planie).IntegrationsRepository::updateTestResult()- nowa publiczna metoda do zapisulast_test_status / last_test_http_code / last_test_message / last_test_at. Wykorzystywana przezFakturowniaIntegrationController::test().FakturowniaIntegrationController- lista (/settings/integrations/fakturownia), edycja (/edit,/new), save, test, delete. CSRF via_token, flashfakturownia.save/.test/.error.- Widoki
resources/views/settings/fakturownia.php(lista z badge'ami) iresources/views/settings/fakturownia-edit.php(form: name, account_prefix, api_token, department_id, default_kind, default_payment_to_days, is_active). IntegrationsHubController::buildFakturowniaRow()- karta Fakturowni w hubie/settings/integrationsz agregowanym statusem wszystkich kont.- Routy w
routes/web.php(get /index,get /new,get /edit,post /save,post /test,post /delete) + DI wiring ($fakturowniaIntegrationRepository,$fakturowniaApiClient,$fakturowniaIntegrationController). - Dokumentacja:
db_schema.md(sekcja "Invoices" +fakturownia_integration_settings+ kolumnaorders.invoice_requested, total tables 55 -> 59),architecture.md(sekcja "Phase 113").
Dlaczego:
- v3.7 Invoices wprowadza wystawianie faktur dla klientow wymagajacych dokumentu z NIP (clarifications:
orders.invoice_requestedz importera + manual override). Bez fundamentu DB i konfiguracji konta Fakturowni zaden kolejny plan v3.7 (CRUD configs, wystawianie, lista) nie ma sensu. - Multi-account przez
integrations.type='fakturownia'zachowuje spojnosc z Allegro/shopPRO (rozne instancje) i pozwala na rozne konta Fakturowni dla roznych marek/oddzialow. is_delegatedflag winvoice_configsumozliwia w przyszlym planie dwa tryby: lokalna numeracja+PDF dompdf (default) lub delegacja do Fakturowni (numer+PDF z API).- STUB-y
createInvoice/downloadPdfcelowo rzucaja exception zamiast "TODO" - kazda przedwczesna probaba uzycia rzuci jasny blad zamiast cichego no-op. IntegrationsRepository::updateTestResult()jest reusable - przyszle integracje (np. kolejne API) beda mogly korzystac z tej samej metody zamiast inline UPDATE.
BREAKING:
- Brak zmian breaking.
IntegrationsHubControllerma nowy parametr konstruktora (FakturowniaIntegrationRepository) - wszystkie miejsca wywolania zaktualizowane.
2026-05-07 - Phase 112 Plan 01: Re-import Data Protection
Co zrobiono:
OrderImportRepository::upsertOrderAggregate- rozdzielono sciezkecreated(pierwszy import) odelse(re-import).replaceAddresses,replaceItems,replaceNotes,replacePayments,replaceShipments,replaceStatusHistorywywolywane sa teraz wylacznie przy pierwszym imporcie. LogikapaymentTransition/statusOverwriteAllowed(Phase 111) i preservacjastatus_code(Phase 62) bez zmian.OrderImportRepository::updateOrderDelta()- nowa prywatna metoda zastepujacaupdateOrder(). Aktualizuje wylaczniestatus_code,payment_status,total_paid,is_canceled_by_buyer,source_updated_at,payload_json,fetched_at,updated_at. Pozostale kolumny zamowienia nie sa nadpisywane przez re-import.- Propagacja anulowania: gdy
is_canceled_by_buyer=1ze zrodla LUB zmapowany pullstatus_code='anulowane'(Phase 75/83), wymuszone jestorders.status_code='anulowane'niezaleznie odstatusOverwriteAllowed. - Identical-payload guard: porownanie znormalizowanego
payload_json(nowy vs aktualny w DB). Identyczny payload + brakpaymentTransition/statusOverwriteAllowed/cancelledBySource-> commit transakcji bez wywolywania UPDATE;fetched_atiupdated_atpozostaja niezmienione. OrderImportRepository::getCurrentOrderState()- rozszerzeniegetCurrentStatusAndPaymentStatus()o kolumnepayload_json(jeden SELECT zamiast dwoch).OrderImportRepository::normalizePayloadJson()- nowy helper deserializujacy/reserializujacy payload do porownywalnej formy (JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).
Dlaczego:
- Bug case #882: po re-imporcie zamowienia produkty w
/orders/{id}wyswietlaly badge "Brak projektu" mimo wczesniej wygenerowanych projektow PSD. Przyczyna:replaceItems()wykonywal DELETE+INSERT naorder_itemsprzy kazdym re-imporcie, co (a) zerowalo flagiproject_generated/project_generated_at(Phase 97) na default 0/NULL i (b) zmienialoorder_items.id, co lamie referencje skryptu batchtools/generowanie/_batch_run.sh(UPDATE ... WHERE id IN (...)). - Phase 111 dodala emisje
payment.status_changedprzy re-imporcie z tranzycja platnosci, wiec re-import istniejacych zamowien stal sie regularny - problem #882 stal sie regresja systemowa, nie krawedziem. - Zamowienia (orderPRO jako narzedzie zarzadzania) sa edytowane w aplikacji, nie w zrodle (Allegro/shopPRO). Re-import ze zrodla powinien aktualizowac wylacznie stan platnosci, anulowanie i znaczniki synchronizacji - reszta jest stanem lokalnym.
- Identical-payload guard eliminuje niepotrzebne write'y do binloga/replikacji oraz sztuczne odswiezanie
updated_atprzy cyklicznym imporcie tych samych zamowien.
BREAKING:
- Brak zmian breaking dla istniejacego API/UI/automatyzacji. Wewnetrznie usunieto
updateOrder()igetCurrentStatusAndPaymentStatus()(oba private) - referencje zewnetrzne nie istnialy. - Backfill zamowien z resetowanymi flagami
project_generated(np. #882) wykonywany recznie przez operatora poza zakresem planu.
2026-05-05 - Phase 111 Plan 01: Payment Transition Event
Co zrobiono:
OrderImportRepository::upsertOrderAggregate- rozszerzona detekcjapayment_transition. Teraz porownuje poprzednipayment_statusz nowym (warunek0/1 -> 2) zamiast polegac wylacznie nastatus_code='nieoplacone'. Logika preservacji status_code z Phase 62 (statusOverwriteAllowed) zostala wydzielona jako osobna decyzja.OrderImportRepository::getCurrentStatusAndPaymentStatus()- nowa metoda pomocnicza zastepujacagetCurrentStatus(), zwraca i status_code, i payment_status w jednym SELECT.AllegroOrderImportService::importSingleOrder- dodaje emitpayment.status_changedgdypayment_transition && !$wasCreated.ShopproOrdersSyncService::importOneOrder- analogiczny emitpayment.status_changed.bin/backfill_payment_transition_111.php- jednorazowy CLI dla zamowien zpayment_status=2 && status_code='nieoplacone'(allegro + shoppro), idempotentny, wzorzec z Phase 98.
Dlaczego:
- Zamowienie #864 (Allegro) zaimportowane 10s po zlozeniu, gdy Allegro jeszcze nie potwierdzilo platnosci. Re-import 2 minuty pozniej zaktualizowal payment_status na 2, ale
order.importedjest gated przez$wasCreated(Phase 98), wiec automatyzacja "Zmien status na w realizacji (allegro)" nigdy nie odpalila. - Allegro nie mial odpowiednika
ShopproPaymentStatusSyncService, wiec tranzycja platnosci znikala cicho. ShopPRO mial analogiczna luke wShopproOrdersSyncService(flagapayment_transitionbyla wykrywana, ale nie emitowala eventu). - Regula automatyzacji #7 (
payment.status_changed->update_order_statusnaw_realizacji) nie ma warunku integration_id, wiec po wyemitowaniu eventu obejmie zarowno Allegro jak i shopPRO. - Idempotencja zalatwiona przez logike repo: po pierwszej tranzycji DB ma
payment_status=2, kolejny re-import widzi old=2/new=2 ipayment_transition=false. Brak duplikatow eventow.
2026-04-28 - Phase 110 Plan 01: Statistics Summary
Co zrobiono:
/statistics/summary- nowy widok podsumowania w menuStatystyki -> 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_groupsiorder_statuses, wiec migracja DB nie jest potrzebna. - Seria
Razemjest 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 przezfilemtime().resources/views/statistics/orders.php- filtrychannels[]istatus_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_statusi akcjiupdate_shipment_statusładuje statusy z DB przezDeliveryStatus::getAllOptions() - Walidacja w
parseConditionValue()iparseActionConfig()używaDeliveryStatus::getAllStatuses() AutomationService— usunięto stałąSHIPMENT_STATUS_OPTION_MAP; ewaluacjaevaluateShipmentStatusCondition()porównuje klucze bezpośrednioresolveStatusFromActionKey()— 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-statusesi jest on od razu dostępny w dropdownach automatyzacji bez deploymentu - Eliminacja kolizji semantycznej: stary klucz grupowy
picked_upmapował nadelivered(paczka odebrana przez klienta), nowy klucz DBpicked_upto "Odebrana przez kuriera" (od nadawcy) - BREAKING: stare reguły z grupowymi kluczami (
registered,courier_pickup,dropped_at_point,unclaimed,picked_up_return, orazpicked_up/ready_for_pickup/cancelledw 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_statusesz seedem 11 statusów (migracja20260427_000103) DeliveryStatusRepository— CRUD + per-request cacheDeliveryStatus.php— dynamiczne ładowanie statusów z DB (setRepository())- Panel
/settings/delivery-statusesz 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-colordla 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