TailorFitWMS — System zarządzania magazynem

Szyty na miarę system magazynowy dla Cookinglife: od przyjmowania zamówień i kompletacji po zarządzanie stanami, etykiety wysyłkowe i synchronizację z ERP NetSuite — blisko dwa lata ciągłej produkcji i utrzymania.

Zarządzanie magazynem
Migracja PHP → Laravel
NetSuite ERP
Wysyłka multi-carrier

Rola & zakres

Cookinglife (sklep internetowy z artykułami kuchennymi, wraz ze sklepami stacjonarnymi) prowadzi cały proces magazynowy na systemie, który zbudowałem i od tego czasu rozwijam: przyjmowanie zamówień, kompletacja (pojedyncza, wsadowa, wózkowa i wielopoziomowa), zarządzanie stanami i lokalizacjami, pakowanie, etykiety wysyłkowe oraz synchronizacja z NetSuite jako ERP. Obok bieżącego utrzymania trwa migracja istniejącej platformy PHP na Laravel, moduł po module, bez przestojów.

  • Od przyjęcia zamówienia po wysyłkę: jeden system dla całego procesu fulfilmentu, spięty z NetSuite jako źródłem prawdy dla zamówień i stanów.
  • Kilka metod kompletacji (pojedyncza, wsadowa, wózkowa, wielopoziomowa) i skanowanie kodów kreskowych na hali przez OnScan.js.
  • Etykiety wysyłkowe multi-carrier przez Sendcloud, z własnym zadaniem zbierającym, które pobiera etykiety, gdy tylko NetSuite utworzy je po statusie „packed”.
  • Integracje z Shopify i Magento oraz normalizacja adresów i numerów telefonów przez Alumio.
  • Migracja na Laravel bez przestoju: moduł po module (zamówienia, kompletacja, stany, wysyłka, NetSuite, admin) przez routing nginx, z natychmiastowym rollbackiem każdego modułu.
Zobacz platformę na żywo

Efekty

  • Jeden system dla całego procesu fulfilmentu zamiast osobnych narzędzi do kompletacji, stanów i wysyłki.
  • Rozwiązano strukturalny błąd NetSuite przy zamówieniach zestawów (produktów złożonych z kilku elementów) — stan jest teraz alokowany automatycznie na wiele lokalizacji, zamiast wymagać, by wszystko leżało w jednej.
  • Usunięto race condition między utworzeniem a pobraniem etykiet wysyłkowych dzięki cyklicznemu zadaniu synchronizacji, więc etykiety przestały się od czasu do czasu gubić.
  • Zapasowa ścieżka wysyłki na wypadek awarii WMS poza godzinami pracy, z uzgadnianiem danych, żeby zamówienia nie pojawiały się podwójnie w kolejce kompletacji.
  • Blisko dwa lata ciągłej produkcji (848 commitów od sierpnia 2024) — nie projekt greenfield, lecz system, który rośnie razem z firmą.

Architektura

Trzy warstwy: wspólny Core, sam moduł TailorFitWMS oraz Overwrites per klient — dzięki czemu zmiany specyficzne dla firmy nie trafiają do rdzenia. Funkcje są zbudowane jako moduły-wtyczki, włączane i wyłączane per firma, z punktami rozszerzeń opartymi na zdarzeniach. Dane leżą w MySQL (dane transakcyjne), MongoDB (dokumenty) i Redis (cache i sesje); praca w tle (synchronizacja etykiet, zadania NetSuite) idzie przez Laravel Horizon, w tempie 100–500 zadań na godzinę. Trwająca migracja istniejącej platformy PHP na Laravel odbywa się moduł po module przez bloki location w nginx, więc każdą część można wdrożyć i wycofać osobno, nie ruszając reszty.

Wybór modelu

Żadnego AI/LLM w rdzeniu tej platformy — logika fulfilmentu (stany, kompletacja, wysyłka, synchronizacja z ERP) wymaga przewidywalności i możliwości prześledzenia, a nie elastyczności modelu językowego. Najważniejszy „wybór modelu” jest tu architektoniczny, nie związany z AI: przejście z istniejącego autorskiego frameworka PHP na Laravel dla większego ekosystemu narzędzi i lepszej utrzymywalności, ale stopniowo i moduł po module zamiast przepisania big-bang, żeby ograniczyć ryzyko w systemie sterującym magazynem przez całą dobę.

Koszty & opóźnienia

  • Środowisko produkcyjne działa na 5 usługach Dockera, każda z przydzielonymi 8 CPU / 8 GB — wymiarowanie pod system przetwarzający ruch zamówień i NetSuite bez przerwy, a nie tylko szczyty.
  • Etykiety wysyłkowe są celowo asynchroniczne: NetSuite tworzy etykietę dopiero po statusie „packed”, więc system nie musi czekać — zadanie zbierające pobiera etykiety co 3 minuty zamiast odpytywać każde zamówienie.
  • Integracja z NetSuite (OAuth1 TBA, SOAP + RESTlet + REST) jest najwolniejszym ogniwem łańcucha; lokalne operacje magazynowe, jak skanowanie i kompletacja, działają od niej niezależnie.

Wnioski

Zamówienia zestawów (produktów złożonych z kilku elementów) wykładały się na błędzie NetSuite VALID_LINE_ITEM_REQD, bo stan komponentów był rozrzucony po wielu lokalizacjach, a NetSuite oczekiwał jednej lokalizacji na linię. Rozwiązane przez przepisanie integracji RESTlet tak, by stan alokował się automatycznie na wiele lokalizacji. Etykiety wysyłkowe co jakiś czas ginęły przez race condition między momentem, w którym NetSuite tworzy etykietę, a momentem, w którym system ją pobiera; cykliczne zadanie zbierające co 3 minuty rozwiązało to strukturalnie zamiast jednorazową łatką. A na wieczory i weekendy, gdy pada sam WMS, istnieje zewnętrzna ścieżka awaryjna pozwalająca dalej wysyłać — z logiką uzgadniania, która nie dopuszcza, by te same zamówienia pojawiły się podwójnie w kolejce kompletacji po powrocie systemu.