Przejdź do treści

Punkty dostępowe API

Konektor udostępnia w sieci lokalnej jeden, wspólny dla wszystkich programów ERP interfejs HTTP/JSON pod ścieżkami /api/v1/*. Ta strona opisuje go dla integratora budującego własnego klienta.

Kontrakt jest celowo identyczny dla wszystkich trzech konektorów. To jedyny powód, dla którego terminal i panel MobiSkan nie wymagają żadnych zmian przy przełączeniu klienta na inny program ERP. Konektor tłumaczy schemat swojego ERP na te struktury, a klient nie wie, z jakim programem rozmawia.

Transport

Element Wartość
Protokół wyłącznie HTTPS, bez nasłuchu HTTP
Port domyślny 5443 dla Subiekta GT, 5444 dla Subiekta nexo, 5445 dla PC-Marketu
Certyfikat samopodpisany, klient nie weryfikuje łańcucha ani nazwy hosta, tylko przypina odcisk certyfikatu przy pierwszym połączeniu
Format JSON, nazwy pól w notacji camelCase
Wartości wyliczeniowe przesyłane jako liczby, nie jako tekst
Zasięg sieć lokalna, interfejs nie jest przeznaczony do wystawiania w internecie

Konektor jest osiągany po adresie IP, dlatego nazwa hosta w certyfikacie nie jest weryfikowana. Tożsamości dowodzi przypięty odcisk. Wymiana certyfikatu na maszynie z konektorem wymaga ponownego zaufania po stronie klienta.

Uwierzytelnianie

Każde żądanie poza sondą stanu musi nieść nagłówek:

Authorization: Bearer <token parowania>

Token parowania jest współdzielonym sekretem ustalanym przy instalacji konektora. Nie jest tokenem sesji: nie wygasa i nie podlega odnawianiu. Konektor porównuje go w stałym czasie, żeby czas odpowiedzi nie zdradzał kolejnych znaków tokenu.

Dwa świadome wyjątki od tej reguły:

  • Sonda stanu nie wymaga tokenu. Terminal musi móc sprawdzić konektor, zanim się z nim sparuje.
  • Pusty token w konfiguracji wyłącza uwierzytelnianie w całości. To ułatwienie na czas prac deweloperskich. Instalacja produkcyjna musi mieć token ustawiony, inaczej cały katalog i wszystkie dokumenty są dostępne dla dowolnego hosta w sieci lokalnej bez żadnego uwierzytelnienia.

Nieprawidłowy token skutkuje odpowiedzią 401.

Zestawienie punktów dostępowych

Kolumny mówią, który konektor ma daną operację zaimplementowaną.

Metoda i ścieżka Do czego Subiekt GT Subiekt nexo PC-Market
GET /api/v1/health sondowanie i parowanie, zwraca rodzaj konektora, identyfikator instalacji, wersję i stan połączenia z bazą ERP tak tak tak
GET /api/v1/catalog?since=<token> katalog towarów, pusty parametr oznacza pełny zrzut, podany token oznacza zmiany od tego punktu tak tak tak
GET /api/v1/catalog/products/{id}/photo zdjęcie główne towaru jako bajty JPEG tak nie nie
GET /api/v1/business-partners kontrahenci, zawsze pełny stan tak tak tak
GET /api/v1/warehouses magazyny, zawsze pełny stan tak tak tak
GET /api/v1/stock stany magazynowe, zawsze pełny stan tak tak tak
GET /api/v1/documents?type=PZ\|WZ\|MM\|PW\|RW dokumenty magazynowe wskazanego typu wraz z pozycjami tak tak, bez MM tak
GET /api/v1/documents/mm/{id}/warehouses para magazynów dokumentu MM tak nie nie
POST /api/v1/catalog/products utworzenie lub aktualizacja towaru w ERP tak tak tak, zawsze niedostępne
POST /api/v1/documents/complete zapis wyniku kompletacji dokumentu tak tak tak, zawsze niedostępne

Operacja, której dany ERP nie obsługuje, ma swoją ścieżkę i odpowiada kodem 503 z informacją, że jest niedostępna. Nie jest to 404 ani brak ścieżki, ponieważ klient nie odróżniłby tego od zepsutego albo starszego wdrożenia i ponawiałby żądanie bez sensu.

Parametr type jest wymagany przy pobieraniu dokumentów i nie rozróżnia wielkości liter. Inna wartość skutkuje odpowiedzią 400.

Zapytania o kontrahentów, magazyny i stany nie przyjmują żadnych parametrów i zwracają komplet danych. Przyrostowość jest dostępna wyłącznie dla katalogu towarów i tylko wtedy, gdy dany ERP ma czym ją obsłużyć.

Kształt odpowiedzi odczytu

Poniżej pola najwyższego poziomu w kolejności, w jakiej występują w kontrakcie.

HealthResult        : connectorType, instanceId, version, erpConnected, znacznik czasu UTC
CatalogResult       : token, full, products[], deactivated[]
ProductDto          : externalId, symbol, name, unitShortName, priceNet, currencyCode,
                      active, barcodes[], rowVersion, vatExempt, vatRatePercent, attributes{}
BusinessPartnerDto  : externalId, nip, companyName, country, address, city, postcode, phone, email
WarehouseDto        : externalId, symbol, name, isMain
StockLevelsResult   : items[] -> externalProductId, externalWarehouseId, quantity
DocumentsResult     : documents[]
DocumentDto         : externalId, type, isAutoGenerated, fullNumber, issueDate,
                      warehouseExternalId, payerPartnerExternalId,
                      recipientPartnerExternalId, rawStatus, rawStatusBlock, positions[]
DocumentPositionDto : externalId, productExternalId, quantity, unit, warehouseExternalId,
                      destinationWarehouseExternalId

Dwie zasady utrzymujące ten kontrakt niezależnym od konkretnego ERP:

  • externalId jest identyfikatorem w programie ERP, nie w MobiSkan. Klient dopasowuje dane po parze złożonej ze źródła i tego identyfikatora i nigdy nie zakłada jego formatu. W jednym programie to liczba, w innym symbol tekstowy.
  • rowVersion i token niosą przyrostowość i są dla klienta nieprzezroczyste. Konektor decyduje, co w nich umieści, a klient jedynie zapamiętuje wartość i odsyła ją bez zmian w kolejnym zapytaniu o katalog.

Pola rawStatus i rawStatusBlock niosą surowe kody statusu z programu ERP, celowo nieprzetłumaczone na własną enumerację. Ich znaczenie jest specyficzne dla konkretnego programu i klient nie powinien na nich polegać poza diagnostyką.

Wartości pola type dokumentu: 0 dla PZ, 1 dla WZ, 2 dla MM, 3 dla PW, 4 dla RW.

Zapis: odróżnienie braku możliwości od nieudanej próby

To jest najważniejszy element kontraktu dla integratora.

Operacje zapisu nie zgłaszają błędów wyjątkiem ani samym kodem HTTP. Zwracają rekord z trzema polami rozstrzygającymi, co się stało:

Pole Znaczenie
available czy ten konektor w ogóle potrafi wykonać tę operację, gdzie false oznacza brak dodatku producenta, brak licencji albo brak mechanizmu zapisu w danym programie ERP
success czy próba zapisu się powiodła
error powód, gdy available albo success ma wartość false

Odwzorowanie na kody HTTP:

Sytuacja Kod Ciało odpowiedzi
Zapisano 200 available: true, success: true
Konektor tego nie potrafi 503 available: false wraz z powodem
Zapis odrzucony przez ERP 502 available: true, success: false wraz z komunikatem
Brak wymaganych pól w żądaniu 400 komunikat o błędnym żądaniu

Rozdzielenie sytuacji "ten konektor tego nie potrafi" od "próbowałem i się nie udało" jest częścią kontraktu, a nie szczegółem implementacji. Klient powinien reagować na nie inaczej:

  • Przy 503 funkcja jest niedostępna trwale dla tej instalacji. Właściwą reakcją jest ukrycie albo wyszarzenie jej w interfejsie, a nie ponawianie próby. Taką odpowiedź daje między innymi konektor PC-Marketu na każdą próbę zapisu towaru oraz konektory Subiekt bez aktywnego dodatku producenta.
  • Przy 502 operacja jest wspierana, ale konkretna próba się nie powiodła. Właściwą reakcją jest pokazanie komunikatu z pola error i umożliwienie ponowienia.

Gdyby oba przypadki zwracały jeden kod, klient musiałby zgadywać po treści komunikatu.

Ta sama trójstanowa odpowiedź obowiązuje dla zapytania o parę magazynów dokumentu MM.

Żądania zapisu

Operacja Pola żądania
Zapis towaru symbol, name, opcjonalnie priceLevelName wraz z netPrice (podawane razem albo wcale). Konektor Subiekt nexo nie obsługuje ceny i dodatkowo przyjmuje opcjonalne supplierNip
Zapis wyniku kompletacji type, documentExternalId oraz positions[] z polami positionExternalId i completedQuantity, a dodatkowo opcjonalne requestId

Odpowiedź na zapis towaru niesie poza polami rozstrzygającymi także created, mówiące czy towar powstał, czy został zaktualizowany, oraz externalId rekordu w ERP.

Odpowiedź na zapis kompletacji niesie fullyCompleted oraz differentialDocumentExternalId. Przy pełnej zgodności ilości nic nie jest zapisywane, fullyCompleted ma wartość true, a identyfikator dokumentu różnicowego pozostaje pusty. Przy kompletacji częściowej powstaje nowy dokument różnicowy, a jego identyfikator wraca w tym polu.

Pole requestId jest kluczem powtórzenia. Klient, który ponawia wysyłkę po przekroczeniu limitu oczekiwania, wysyła przy każdej próbie tę samą wartość, a konektor odsyła wtedy wynik pierwszego zapisu zamiast tworzyć w programie ERP kolejny dokument różnicowy. Odpowiedź na powtórzenie jest nieodróżnialna od pierwszej. Pole pozostaje opcjonalne ze względu na starsze wersje aplikacji, ale każdy klient, który ponawia żądania, powinien je wysyłać.

Pozycja, której positionExternalId nie ma odpowiednika w dokumencie źródłowym, jest błędem 502 i nic nie zostaje zapisane w programie ERP. Taka rozbieżność oznacza, że dokument zmieniono w programie ERP już po pobraniu go przez klienta, więc ciche pominięcie takiej pozycji gubiłoby skompletowany towar.

Wysyłanie danych z konektora do panelu

Poza opisanym wyżej odpytywaniem konektor sam wysyła katalog i dokumenty magazynowe do panelu MobiSkan WMS. Jest to jednak powierzchnia serwera panelu, a nie konektora, i nie należy do interfejsu opisanego na tej stronie.

Wymagania wobec nowego klienta

Minimum, żeby własny klient działał z konektorem:

  1. Obsłuż sondę stanu bez tokenu oraz pobranie katalogu z tokenem. To wystarcza do sparowania i pierwszej synchronizacji.
  2. Zachowaj wielkość liter w nazwach pól - JSON jest w notacji camelCase.
  3. Traktuj token katalogu jako ciąg nieprzezroczysty i odsyłaj go bez zmian.
  4. Rozróżniaj 503 od 502 przy operacjach zapisu.
  5. Przypnij odcisk certyfikatu przy pierwszym połączeniu i odrzucaj inny certyfikat pod tym samym adresem.

Dalej