Magazynier, który potwierdza przyjęcie palety na terminalu, nie zna kodów transakcji SAP i nie musi ich znać. Za jego skanem stoi jednak konkretne wywołanie: odczyt stanu, kontrola zamówienia zakupu albo zaksięgowanie ruchu materiałowego. Aplikacja WMS wykonuje je jako funkcję SAP, a nie jako sekwencję ekranów.

Poniżej opisano, czym różni się transakcja od wywołania RFC i od funkcji BAPI oraz jak odczytać parametry funkcji przed jej użyciem. Dalej znajduje się katalog funkcji według obszaru procesu, zasady zatwierdzania zmian i sposób ponawiania wywołań po błędzie. Sposób nawiązania połączenia i konfigurację kanału opisuje osobna strona o połączeniu aplikacji z systemem SAP.

Różnica między transakcją SAP a funkcją BAPI

Transakcja SAP, na przykład MMBE albo MB52, to zestaw ekranów dla człowieka pracującego w SAP GUI. RFC (Remote Function Call) jest protokołem, który pozwala programowi zewnętrznemu uruchomić moduł funkcyjny ABAP oznaczony jako dostępny zdalnie. BAPI jest wąskim, udokumentowanym podzbiorem takich modułów: każdy reprezentuje metodę obiektu biznesowego, na przykład zamówienia zakupu albo dokumentu materiałowego.

Sposób dostępuWarstwaKontrole biznesoweTypowe użycie w integracji z WMS
Transakcja SAP GUIekrany dialogowewykonywane w dialogu z użytkownikiempraca ręczna administratora lub księgowego
Moduł funkcyjny RFCfunkcja ABAP wywołana zdalniezależą od autora funkcji i nie mają gwarancjiodczyty raportowe, na przykład RFC_READ_TABLE
BAPImetoda obiektu biznesowegote same co w transakcji, wykonywane w tleksięgowanie ruchów i tworzenie dokumentów

RFC_READ_TABLE odczytuje dowolną tabelę, ale zwraca wiersz w polu o ograniczonej szerokości i omija logikę biznesową. Nadaje się do jednorazowego raportu. Do operacji, które zmieniają dane, wybiera się BAPI, ponieważ wywołanie przechodzi przez te same walidacje co ręczne księgowanie.

Reguła: dane w SAP zapisuje się wyłącznie przez BAPI albo przez inny udokumentowany interfejs biznesowy. Bezpośredni zapis do tabel omija kontrole i może zostawić niespójny dokument.

Jak odczytać parametry funkcji przed wywołaniem

Definicję funkcji ogląda się w transakcji SE37 (Function Builder), a listę BAPI pogrupowaną według obiektów biznesowych w BAPI Explorer, który uruchamia się transakcją BAPI. Zakładki definicji pokazują cztery rodzaje parametrów, a każdy ma inne znaczenie dla programisty aplikacji WMS.

  • Import - wartości wysyłane do funkcji, na przykład numer materiału i ilość; część pól jest obowiązkowa.
  • Export - wartości zwracane przez funkcję, na przykład numer dokumentu materiałowego i rok dokumentu.
  • Changing - parametry przekazywane w obie strony; funkcja może zmienić ich wartość.
  • Tables - tabele wewnętrzne wysyłane i odbierane razem, w tym pozycje dokumentu oraz obowiązkowa tabela RETURN.

Wywołanie z zewnątrz najlepiej najpierw wykonać ręcznie w SE37, klawiszem F8, na danych testowych. Programista widzi wtedy dokładnie te typy pól i formaty, których oczekuje SAP, na przykład numer materiału z zerami wiodącymi. Oficjalny opis obiektów i metod udostępnia portal dokumentacji SAP Help Portal, a dokładna nazwa i dostępność funkcji zależą od wersji systemu, więc każdą z nich sprawdza się w SE37 przed użyciem.

Odczyt stanów i danych podstawowych z poziomu WMS

Odczyt jest bezpieczniejszy od zapisu, bo nie zmienia danych i nie wymaga zatwierdzania. Integrację zwykle zaczyna się więc od odczytu kartotek materiałów i stanów. Aplikacja magazynowa pobiera dane w chwili, gdy operator ich potrzebuje, więc nie opiera się na kopii z ostatniej synchronizacji.

Stany magazynowe i dostępność towaru

Listę stanów magazynowych dla wskazanych miejsc składowania zwraca funkcja BAPI_WHSE_STOCK_GET_LIST. Zestawienie zapotrzebowań i zapasów dla materiału daje BAPI_MATERIAL_STOCK_REQ_LIST, a dostępność do sprzedaży sprawdza BAPI_MATERIAL_AVAILABILITY, która uwzględnia rezerwacje oraz otwarte zamówienia. Te trzy wyniki odpowiadają na różne pytania i nie należy ich porównywać jak jednej liczby.

Stan fizyczny mówi, ile sztuk leży w lokalizacji. Dostępność mówi, ile z nich można jeszcze obiecać klientowi. Operator kompletacji potrzebuje pierwszej wartości, a planista zamówień drugiej, więc aplikacja pokazuje każdą osobno i podpisuje ją jednostką miary z odpowiedzi SAP.

Ilustracja do tematu stanów magazynowych odczytywanych z systemu SAP w aplikacji WMS
Stan fizyczny i dostępność pobrane osobnymi wywołaniami funkcji; wynik wyświetla się operatorowi w interfejsie magazynowym.

Kartoteki materiałów

Dane podstawowe materiału zapisuje i zmienia BAPI_MATERIAL_SAVEDATA, a szczegóły odczytuje BAPI_MATERIAL_GET_ALL. Funkcja zapisu przyjmuje osobne struktury dla każdego widoku materiału, na przykład danych ogólnych i danych zakładu, wraz z równoległymi strukturami znaczników zmiany (pola X). SAP zmienia tylko te pola, które mają znacznik, więc pominięty znacznik oznacza brak zapisu, a nie błąd.

Formaty pól i jednostki miary

Funkcje SAP oczekują wartości w formacie wewnętrznym, który różni się od tego, co skanuje magazynier. Numer materiału bywa uzupełniany zerami wiodącymi do stałej długości, data ma postać RRRRMMDD, a jednostka miary występuje w kodzie wewnętrznym (ST dla sztuki) i osobno w kodzie ISO (PCE). Warstwa integracyjna zamienia te formaty w obie strony, zwykle przez moduły konwersji SAP (CONVERSION_EXIT_*), żeby aplikacja WMS nie musiała ich znać.

Pominięta konwersja daje objaw mylący dla programisty: funkcja odczytu nie zgłasza błędu, tylko zwraca pustą listę, bo materiał o numerze bez zer wiodących w SAP nie istnieje. Przy pierwszym teście warto więc porównać dokładny łańcuch znaków wysłany do SAP z tym, który widać w SE37.

Księgowanie ruchów magazynowych funkcją BAPI_GOODSMVT_CREATE

Każdy ruch towaru, który ma zmienić stan w SAP, przechodzi przez BAPI_GOODSMVT_CREATE. Funkcja przyjmuje nagłówek z datami oraz kod ruchu (GM_CODE), a do tego pozycje z materiałem i ilością oraz rodzajem ruchu. Zwraca numer i rok utworzonego dokumentu materiałowego.

Operacja w WMSGM_CODERodzaj ruchuWymagane pola pozycji
przyjęcie do zamówienia zakupu01101PO_NUMBER, PO_ITEM, MVT_IND
wydanie na zlecenie produkcyjne03261ORDERID
wydanie na centrum kosztów03201COSTCENTER
przesunięcie między lokalizacjami04311STGE_LOC, MOVE_STLOC

Wartości w tabeli pokazują typowe ustawienia, a konkretne rodzaje ruchu zależą od konfiguracji SAP w danej firmie. Osobno uzgadnia się z konsultantem, które z nich są dopuszczone dla konta integracyjnego. Powstały dokument materiałowy odpowiada dokumentom magazynowym widocznym w WMS, na przykład PZ albo WZ, więc jego numer trafia z powrotem do rekordu operacji.

Zatwierdzanie i wycofanie zmian po tabeli RETURN

Funkcja księgująca nie zatwierdza transakcji bazy danych sama. Po wywołaniu aplikacja sprawdza tabelę RETURN, w której każdy komunikat ma typ: S (sukces), I (informacja), W (ostrzeżenie), E (błąd) albo A (przerwanie). Przy typie E lub A wywołuje się BAPI_TRANSACTION_ROLLBACK, a przy pozostałych BAPI_TRANSACTION_COMMIT z parametrem WAIT ustawionym na X, żeby wywołanie wróciło dopiero po zapisie do bazy.

Reguła: commit i wywołanie księgujące muszą przebiegać w tej samej sesji RFC. Commit wysłany osobnym połączeniem nie zatwierdzi niczego, a dokument nie powstanie mimo pozornie poprawnej odpowiedzi.

// Przykład poglądowy: interfejs IRfcSession jest umowny, nie pochodzi z biblioteki SAP.
public interface IRfcSession
{
    IDictionary<string, object> Call(string function, IDictionary<string, object> input);
}

public static string PostGoodsReceipt(IRfcSession session, string operationId,
    string material, string plant, string storageLoc, decimal qty, string po, string poItem)
{
    var input = new Dictionary<string, object>
    {
        ["GOODSMVT_HEADER"] = new Dictionary<string, object>
        {
            ["PSTNG_DATE"] = DateTime.Today,
            ["DOC_DATE"] = DateTime.Today,
            ["REF_DOC_NO"] = operationId          // numer operacji WMS w nagłówku
        },
        ["GOODSMVT_CODE"] = new Dictionary<string, object> { ["GM_CODE"] = "01" },
        ["GOODSMVT_ITEM"] = new[]
        {
            new Dictionary<string, object>
            {
                ["MATERIAL"] = material, ["PLANT"] = plant, ["STGE_LOC"] = storageLoc,
                ["MOVE_TYPE"] = "101", ["ENTRY_QNT"] = qty, ["PO_NUMBER"] = po,
                ["PO_ITEM"] = poItem, ["MVT_IND"] = "B"
            }
        }
    };

    var result = session.Call("BAPI_GOODSMVT_CREATE", input);
    var errors = ((IEnumerable<IDictionary<string, object>>)result["RETURN"])
        .Where(r => (string)r["TYPE"] == "E" || (string)r["TYPE"] == "A");

    if (errors.Any())
    {
        session.Call("BAPI_TRANSACTION_ROLLBACK", new Dictionary<string, object>());
        throw new InvalidOperationException((string)errors.First()["MESSAGE"]);
    }

    session.Call("BAPI_TRANSACTION_COMMIT", new Dictionary<string, object> { ["WAIT"] = "X" });
    return (string)result["MATERIALDOCUMENT"];
}

Jedno wywołanie na dokument, nie na pozycję

Każde wywołanie RFC niesie narzut sieciowy i tworzy osobną sesję kontroli w SAP. Dokument z kilkudziesięcioma pozycjami wysyła się więc jednym wywołaniem, z całą tabelą GOODSMVT_ITEM, a nie w pętli po pozycjach. Zmniejsza to liczbę zapytań i daje jeden numer dokumentu materiałowego, który łatwo przypisać do zlecenia w WMS. Wadą jest to, że błąd w jednej pozycji odrzuca cały dokument, więc aplikacja pokazuje operatorowi numer pozycji z komunikatu RETURN.

Symulacja przed księgowaniem

BAPI_GOODSMVT_CREATE ma parametr TESTRUN. Ustawiony na X uruchamia wszystkie kontrole i zwraca komunikaty, ale nie tworzy dokumentu. Warstwa integracyjna może więc wywołać symulację, gdy operator jeszcze skanuje pozycje, i pokazać błąd, na przykład brak zamówienia albo zablokowany materiał, zanim operator zeskanuje kolejne palety.

Funkcje BAPI według obszarów procesu

Poza ruchami materiałowymi integracja WMS z SAP obejmuje sprzedaż i zakupy, a także dostawy. Zestawienie poniżej grupuje funkcje według dokumentu, który tworzą lub odczytują.

ObszarFunkcjeZastosowanie w WMS
zlecenia sprzedażyBAPI_SALESORDER_CREATEFROMDAT2, BAPI_SALESORDER_CHANGE, BAPI_SALESORDER_SIMULATEutworzenie i zmiana zlecenia oraz symulacja bez zapisu
zamówienia zakupuBAPI_PO_CREATE1, BAPI_PO_CHANGEutworzenie i zmiana zamówienia u dostawcy
dostawy przychodząceBAPI_INB_DELIVERY_SAVEREPLICAzapis dostawy związanej z awizacją
dostawy wychodząceBAPI_OUTB_DELIVERY_CREATE_SLS, BAPI_OUTB_DELIVERY_CREATE_STO, BAPI_OUTB_DELIVERY_CHANGEdostawa do zlecenia sprzedaży lub zamówienia przesunięcia
dokumenty transportoweBAPI_SHIPMENT_CREATE, BAPI_SHIPMENT_CHANGEgrupowanie dostaw w transport
zlecenia przeniesienia WMBAPI_WHSE_TO_GET_LIST, BAPI_WHSE_TO_GET_DETAILlista zleceń i szczegóły pojedynczego zlecenia

Dostawa przychodząca opisuje towar, który ma dotrzeć od dostawcy, więc jej dane wykorzystuje się przy przyjęciu do magazynu, zanim ruch zostanie zaksięgowany. Dostawy wychodzące tworzą punkt wyjścia dla ewidencji wydań: kompletacja realizuje pozycje dostawy, a księgowanie wydania następuje po jej potwierdzeniu.

Inwentaryzacja jako sekwencja wywołań BAPI

Spis z natury w SAP przechodzi trzy etapy i każdy ma własną funkcję. Najpierw powstają dokumenty inwentaryzacyjne, potem wpisuje się do nich wyniki liczenia, a na końcu księguje się różnice. Aplikacja na terminalu pokrywa środkowy etap, bo to na hali pada liczba, którą trzeba przenieść do SAP.

EtapFunkcjaSkutek w SAPZatwierdzenie
utworzenie dokumentówBAPI_MATPHYSINV_CREATE_MULTdokumenty inwentaryzacyjne z blokadą pozycjiBAPI_TRANSACTION_COMMIT
wpisanie wyników liczeniaBAPI_MATPHYSINV_COUNTilości policzone przypisane do pozycjiBAPI_TRANSACTION_COMMIT
zaksięgowanie różnicBAPI_MATPHYSINV_POSTDIFFkorekta stanu i dokument materiałowyBAPI_TRANSACTION_COMMIT

Szerszy opis samego liczenia oraz spisów cyklicznych zawiera tekst o inwentaryzacji zapasów w programie magazynowym. Tutaj istotne jest to, że każdy etap zatwierdza się osobno, więc błąd na trzecim nie cofa wyników wpisanych na drugim.

Ilustracja do tematu transakcji i zatwierdzania zmian w systemie SAP po wywołaniu funkcji BAPI
Każde wywołanie zapisujące kończy się osobnym zatwierdzeniem, dlatego etapy inwentaryzacji da się powtarzać niezależnie.

Transakcje SAP GUI a funkcje BAPI

Zestawienie łączy ręczną transakcję z funkcją o zbliżonym zakresie. Służy administratorowi, który porównuje wynik wywołania z tym, co widzi na ekranie SAP GUI podczas testów integracji.

Transakcja SAPFunkcja o zbliżonym zakresieModułZastosowanie
MMBE, MB52BAPI_WHSE_STOCK_GET_LISTMMprzegląd stanów materiału
MIGOBAPI_GOODSMVT_CREATEMMruchy towarowe w magazynie
VA01, VA02BAPI_SALESORDER_CREATEFROMDAT2, BAPI_SALESORDER_CHANGESDzlecenia sprzedaży
ME21N, ME22NBAPI_PO_CREATE1, BAPI_PO_CHANGEMMzamówienia zakupu
MI01, MI04, MI07BAPI_MATPHYSINV_CREATE_MULT, BAPI_MATPHYSINV_COUNT, BAPI_MATPHYSINV_POSTDIFFMMinwentaryzacja i różnice
Zakres orientacyjny

Funkcja i transakcja nie muszą zwracać identycznych pól. Mapowanie zatwierdza konsultant SAP, a diagnozę uprawnień ułatwia transakcja SU53, która pokazuje ostatni odrzucony obiekt autoryzacji.

Ślad wywołań i ponawianie w warstwie WMS

Sieć zawodzi częściej niż SAP. Jeśli odpowiedź na BAPI_GOODSMVT_CREATE nie wróci w limicie czasu, aplikacja nie wie, czy dokument powstał, więc ślepe ponowienie grozi podwójnym przyjęciem. Rozwiązaniem jest numer operacji WMS wpisany w polu REF_DOC_NO nagłówka: przed powtórzeniem wywołania warstwa integracyjna szuka w SAP dokumentu materiałowego z tym numerem odniesienia i wysyła ruch ponownie tylko wtedy, gdy go nie znajdzie.

Reguła: ponowienie wywołania księgującego jest dopuszczalne dopiero po sprawdzeniu, że dokument z danym numerem odniesienia nie istnieje w SAP.

Po stronie WMS każde wywołanie zostawia wiersz w dzienniku z nazwą funkcji i statusem wraz z komunikatem z tabeli RETURN. Tabela poniżej w T-SQL jest schematem przykładowym, a nie strukturą konkretnego produktu.

CREATE TABLE dbo.SapCallLog
(
    CallId        bigint IDENTITY(1,1) PRIMARY KEY,
    OperationId   varchar(40)   NOT NULL,   -- ten sam numer trafia do REF_DOC_NO
    FunctionName  varchar(60)   NOT NULL,
    Status        varchar(10)   NOT NULL,   -- OK, ERROR, TIMEOUT
    ReturnType    char(1)       NULL,       -- S, I, W, E, A
    ReturnMessage nvarchar(220) NULL,
    MaterialDoc   varchar(10)   NULL,
    CreatedAt     datetime2     NOT NULL DEFAULT SYSUTCDATETIME()
);

CREATE INDEX IX_SapCallLog_Retry
    ON dbo.SapCallLog (Status, CreatedAt)
    INCLUDE (OperationId, FunctionName);

Indeks na kolumnach Status i CreatedAt obsługuje zadanie, które co kilka minut wybiera wywołania oczekujące na ponowienie. Rozwiązanie SoftwareStudio wywołuje funkcje SAP bezpośrednio z aplikacji magazynowej, o czym opisuje strona o wywoływaniu funkcji SAP z poziomu WMS. Ogólne tryby wymiany danych (synchroniczny oraz wsadowy) porównuje tekst o integracji WMS z SAP, a produktowe ujęcie tematu zawiera opis wdrożenia WMS z integracją SAP dla magazynu chemicznego.

Ilustracja do tematu integracji systemu magazynowego z systemem SAP i warstwą wymiany danych
Warstwa integracyjna pośredniczy między aplikacją magazynową a SAP i prowadzi dziennik wywołań.

Szersze warianty architektury, w tym pośredników takich jak SAP PI/PO i Integration Suite, wyjaśnia strona integracja z SAP. Model, w którym kilka systemów wymienia dokumenty przez kolejkę i interfejs REST, opisuje tekst o integracji WMS z ERP.