Integracja ze Stockly
Stockly jest zbudowany tak, żeby dało się nim sterować z zewnątrz. Moduł przewoźnika, ERP trzymający wagi, desktopowe narzędzie do etykiet, program obsługujący drukarkę niewidoczną dla serwera, 3PL robiący własną kartonizację, system księgujący towar na półki. Żadne z nich nie potrzebuje zmiany w Stockly, żeby z nim współpracować.
Metody są cztery. Wybór właściwej przesądza o kształcie całej integracji.
Cztery metody integracji
Dział zatytułowany „Cztery metody integracji”| Metoda | Kiedy | Gdzie działa |
|---|---|---|
| Nazwane zdarzenia | Twój kod żyje w tej samej instalacji Shopware | w procesie |
| Endpointy HTTP | Twój kod żyje gdzie indziej | przez Admin API |
| Encje DAL | wypychasz dane podstawowe albo czytasz do raportu | przez API albo w procesie |
| Punkty rozszerzeń | dokładasz zdolność: przewoźnika, strategię podziału | w procesie |
Od czego zacząć
Dział zatytułowany „Od czego zacząć”| Twoje zadanie | Zacznij od |
|---|---|
| położyć towar w binie, zdjąć go, przewieźć | Jak położyć zapas w binie |
| zapytać, co leży na półkach | Odczyt zapasu |
| policzyć, zasilić magazyn, przelać jeden w drugi | Korekty i zadania masowe |
| dowiadywać się, gdy coś się zmienia | Zdarzenia |
| zdecydować coś zamiast Stockly | Punkty decyzyjne |
| masz już stany w innym systemie | Obce zapisy |
| wysyłać, pakować, drukować | ta strona i API pakowania |
Niezależnie od zadania zacznij od modelu zapasu: prawie każdy błąd integracji w historii tego modułu brał się z niezrozumienia, która liczba wynika z której.
Nazwane zdarzenia
Dział zatytułowany „Nazwane zdarzenia”Nazwane napisem, żeby nasłuchujący nigdy nie musiał importować naszej klasy, i taki jest cel tego nazewnictwa: moduł, który psuje się przy braku Stockly, jest zależnością, a nie integracją.
| Zdarzenie | Znaczenie |
|---|---|
p2lab.stockly.parcels.plan | prosi o propozycję; nic nie zapisuje |
p2lab.stockly.parcels.commit | zapisuje podział |
p2lab.stockly.parcel.tracking | zgłasza numer przesyłki dla jednej paczki |
p2lab.stockly.parcel.registered | paczka dostała numer przesyłki |
p2lab.stockly.parcel.failed | zamówienie przesyłki nie doszło do skutku, z powodem |
p2lab.stockly.label.print | oddaje gotową etykietę do kolejki druku; odsyła jobId |
p2lab.stockly.label.preferred_format | pyta, w jakim formacie zamówić etykietę u przewoźnika |
p2lab.stockly.print.job.printed | zadanie wydrukowane; argumenty jobId, printerId |
p2lab.stockly.print.job.failed | zadanie nie powiodło się; argumenty jobId, error |
Dwa ostatnie to raporty, a nie pytania: niosą dane w argumentach zdarzenia, jak reszta tej listy, ale nic nie jest z nich odczytywane z powrotem.
Fakty, które moduł ogłasza później, nazywają się odwrotnie, z podkreśleniem po nazwie dostawcy
(p2lab_stockly.…), bo to zdarzenia biznesowe Shopware, a nie hooki, na które udziela się
odpowiedzi. Obejmują płaszczyzny popytu, zamówień oczekujących, towaru, zapasu, pracy, wysyłki,
zwrotów i spójności; mają własny katalog.
Większość faktów jest też dostępna we Flow Builderze, więc sklep może powiesić na nich mail, tag czy zmianę stanu bez pisania kodu.
Endpointy HTTP
Dział zatytułowany „Endpointy HTTP”Wszystkie pod /api/_action/p2lab-stockly/, uwierzytelniane jak każde wywołanie Admin API i pilnowane
tymi samymi uprawnieniami co ekrany.
Wysyłka — shipping/…
| Metoda | Ścieżka | Co robi |
|---|---|---|
POST | shipping/parcels/plan | propozycja, nic nie zapisuje |
POST | shipping/parcels/commit | zapisuje podział |
POST | shipping/parcels/request | prosi przewoźnika o przesyłki |
POST | shipping/parcels/packed | zgłasza, że ekran pakowania skończył |
POST | shipping/parcels/of-order | zapisane paczki zamówienia |
POST | shipping/parcels/{parcelId}/tracking | zgłasza numer przesyłki |
POST | shipping/parcels/{parcelId}/cancel | anuluje jedną paczkę |
POST | shipping/parcels/close | nic więcej z tego zamówienia nie wyjedzie |
GET | shipping/profiles | zainstalowani przewoźnicy i strategie podziału |
GET | shipping/batches/eligible | paczki czekające na przekazanie kierowcy |
POST | shipping/batches/close | zamyka przekazanie; zwraca id zadania |
GET | shipping/batches/{batchId}/list | lista do podpisu przez kierowcę, jako PDF |
Dane pakowania — packaging/…
| Metoda | Ścieżka | Co robi |
|---|---|---|
GET | packaging/resolve | czego system użyje dla tych artykułów, wraz z pochodzeniem |
GET | packaging/coverage | jak kompletny jest katalog i co poprawić najpierw |
GET | packaging/collisions | artykuły zgarniane przez dwie reguły o równej randze |
GET | packaging/variance | gdzie przewidywanie nie zgadza się z wagą |
Druk — printing/…
| Metoda | Ścieżka | Co robi |
|---|---|---|
POST | print-job | przyjmuje gotową etykietę spoza Shopware; zwraca jobId |
POST | printing/print-jobs/next | wydaje stanowisku następne zadanie; null, gdy nie ma pracy |
POST | printing/print-jobs/{jobId}/ack | potwierdza wydruk albo zgłasza porażkę |
POST | printing/jobs/{jobId}/retry | ponawia zadanie |
POST | printing/jobs/{jobId}/cancel | porzuca zadanie |
GET | printing/station-devices | czy instalacja ma drukarki obsługiwane przez przeglądarkę |
GET | printing/profiles | znane typy drukarek i ich formaty |
Encje DAL
Dział zatytułowany „Encje DAL”Zwykłe encje Shopware, więc /api/search/… i /api/… działają tak jak wszędzie indziej.
| Encja | Trzyma |
|---|---|
p2lab_stockly_parcel | jedna paczka: waga, numer przesyłki, stanowisko, karton, notatki |
p2lab_stockly_parcel_line | co jest w paczce |
p2lab_stockly_parcel_batch | jedno przekazanie kierowcy |
p2lab_stockly_packaging_material | katalog pudeł |
p2lab_stockly_packaging_profile | zbiorcze reguły pakowania |
p2lab_stockly_product_packaging | nadpisania per artykuł |
p2lab_stockly_packaging_rule | jedna reguła na metodę dostawy |
p2lab_stockly_printer | jedno urządzenie: sposób podłączenia, format, rozmiar etykiety |
p2lab_stockly_print_job | jedno zadanie druku: dane, status, próby |
p2lab_stockly_print_document_rule | który dokument Shopware jest przechwytywany i dokąd trafia |
p2lab_stockly_print_rule | która praca co drukuje, dla kogo i z jakim priorytetem |
p2lab_stockly_printer_default | urządzenie domyślne dla stanowiska, operatora albo magazynu |
p2lab_stockly_print_media | nośniki, którymi urządzenie może być załadowane |
Encje magazynowe — półki, biny, ruchy, loty, nośniki — wymienia model zapasu. Czytaj je do woli, ale zapisuj przez endpointy.
Punkty rozszerzeń
Dział zatytułowany „Punkty rozszerzeń”Interfejsy do zaimplementowania, rejestrowane tagiem usługi.
| Interfejs | Dokłada |
|---|---|
ParcelSplitStrategyInterface | sposób rozkładania towaru na paczki |
CarrierProfileInterface | przewoźnika: jego limity, produkty i walidacje |
CarrierManifestGatewayInterface | powiadomienie przewoźnika o zamknięciu przekazania |
ExtractionEngineInterface | silnik odczytu dokumentów dla importu |
Kolejka druku to ścieżka osobna od wysyłki i wpuszcza trzy różne rodzaje programów. Ekrany opisuje rozdział o druku; tutaj jest to, co musi wiedzieć kod.
Etykieta z wtyczki w tej samej instalacji
Dział zatytułowany „Etykieta z wtyczki w tej samej instalacji”p2lab.stockly.label.print przyjmuje gotową etykietę. Dane jadą w argumentach zdarzenia, nie w
jego podmiocie, bo tą samą drogą wraca odpowiedź:
$event = new GenericEvent(null, [ 'payload' => $labelBytes, 'format' => 'zpl', 'source' => 'AcmeCarrier', 'externalId' => $parcelNumber, 'orderId' => $orderId, 'context' => $context,]);
$dispatcher->dispatch($event, 'p2lab.stockly.label.print');
// Dopisane przez kolejkę — do zapisu przy przesyłce albo do anulowania zadania.$jobId = $event->getArgument('jobId');Przed zamówieniem etykiety u przewoźnika należy zapytać p2lab.stockly.label.preferred_format o
format: argumenty role, format (własny domyślny) i context, odpowiedź pod format. To format
urządzenia, na które zadanie i tak trafi, więc drukarka używająca ZPL dostanie ZPL zamiast PDF-a
przerabianego po drodze.
Zdarzenie nie wypuszcza wyjątku na zewnątrz. Wołający jest w środku zakładania przesyłki u przewoźnika, gdzie numer paczki już został wydany; nieosiągalna drukarka nie może z problemu druku zrobić problemu wysyłki.
Etykieta z programu spoza Shopware
Dział zatytułowany „Etykieta z programu spoza Shopware”POST /api/_action/p2lab-stockly/print-job robi dokładnie to samo co zdarzenie, tyle że przez API:
{ "source": "acme-desktop", "externalId": "1Z999AA10123456784", "format": "zpl", "payload": "<base64>", "copies": 1, "orderId": "0189…", "printerId": "0189…" }Odpowiedź to {"jobId": "…"}. Zamiast payload można podać mediaId. Bez printerId kolejka wybiera
urządzenie sama, tak jak dla etykiety z wysyłki.
Program, który sam drukuje
Dział zatytułowany „Program, który sam drukuje”Drukarka podłączona przez lokalnego agenta albo przez przeglądarkę nie jest osiągalna dla serwera, więc to stanowisko pyta o pracę:
POST /api/_action/p2lab-stockly/printing/print-jobs/nextAuthorization: Bearer <token>Content-Type: application/json
{"stationId": "0189…", "drivers": ["agent"]}Odpowiedź niesie job i counts. job bywa null i to jest stan normalny: stanowisko pakowania
częściej nie ma nic do druku, niż ma. Zadanie zawiera format (zpl, epl, pdf), copies,
driver, tyle o urządzeniu, ile trzeba, żeby je odnaleźć (host, deviceUid, usbVendorId,
usbProductId), oraz payload w base64: należy go zdekodować i przepisać bajty bez zmian.
Po wydruku:
POST /api/_action/p2lab-stockly/printing/print-jobs/<jobId>/ackContent-Type: application/json
{"printed": true}{"printed": false, "error": "Printer offline"}Trzy rzeczy kosztują tu najwięcej czasu:
Pobranie rezerwuje zadanie. Bez ack stoi na Sending, dopóki nie zwolni go czas z
ustawień druku, domyślnie pięć minut.
Zgłoszona porażka jest ostateczna. Zadania przypiętego do jednego stanowiska nie ma kto przejąć, więc kolejka nie ponawia go sama; ponowienie jest decyzją człowieka albo programu wywołującego.
source razem z externalId daje idempotencję. Powtórzone przyjęcie tej samej pary zwraca
istniejące jobId zamiast drugiej etykiety, więc ponowienie po upływie limitu czasu jest bezpieczne. Wołający nie
odróżni jednego od drugiego i takie jest założenie.
Uprawnienia: p2lab_stockly_print_job:create dla oddania etykiety, p2lab_stockly_print_job:update
dla pętli agenta, p2lab_stockly_printer:read dla printing/station-devices.
Trzy zasady obowiązujące w całym module
Dział zatytułowany „Trzy zasady obowiązujące w całym module”Null to nie zero. Wszędzie w danych o pakowaniu brak liczby znaczy „pytaj wyżej”, a zero jest
twierdzeniem. Wysłanie 0 jako wagi opakowania oznacza, że artykuł jedzie bez opakowania, i nic
niżej tego nie poprawi.
Pochodzenie podróżuje razem z liczbami. packaging/resolve podaje nie tylko wartość, ale i jej
źródło: product, parent, profile, global albo none. Integracja, która pokazuje none swoim
użytkownikom, wyłapuje braki w danych po kilku dniach, a nie po kilku kwartałach.
Do rejestru zapasu się dopisuje, nigdy się go nie poprawia. Wiersz ruchu nie jest edytowany; korekta to nowy wiersz z własnym powodem. Wszystko, co magazyn odnotowuje o tym, dlaczego w binie leżą cztery sztuki, zbudowane jest z wierszy, i dlatego żadnego nie wolno po cichu zmienić.
- Model zapasu — do czego przypięta jest ilość
- Jak położyć zapas w binie — magazynowa ścieżka zapisu
- Zdarzenia — pełny katalog
- API pakowania w szczegółach — kształty żądań i odpowiedzi
- Kolejka druku — co się dzieje z przekazanym zadaniem
- Przykłady — integracje od początku do końca