Program do zarządzania dostawami - od zamówienia zakupu do przyjęcia

Dostawa zaczyna się w ERP jako zamówienie zakupu, a kończy w magazynie jako dokument przyjęcia. Między tymi punktami działa program do zarządzania dostawami, który pilnuje terminu i statusu dostawy. Bez niego odpowiedź na pytanie, gdzie jest towar z zamówienia, wymaga telefonu do dostawcy.

Z punktu widzenia danych dostawa ma cztery daty, które rzadko się pokrywają. Rozbieżność między nimi jest najcenniejszą informacją, bo pokazuje opóźnienie, zanim pojazd stanie pod bramą.

  • Data zamówiona - termin z zamówienia zakupu, który ustala dział zakupów.
  • Data potwierdzona - termin, który obiecał dostawca po przyjęciu zamówienia.
  • Okno awizowane - rezerwacja czasu na rampie, którą zatwierdza logistyka magazynu.
  • Czas przyjazdu - moment zarejestrowany przy bramie, czyli rzeczywisty początek obsługi.
EtapZdarzenieŹródło danychStatus w programie
Zamówienieutworzenie zamówienia zakupuERPzaplanowana
Awizacjazatwierdzenie okna na rampiedostawca lub logistykaawizowana
Przyjazdwjazd pojazdu na terenbrama, ochronana terenie
Rozładunekrozpoczęcie obsługi przy rampiemagazynierw rozładunku
Przyjęciezamknięcie dokumentu PZWMSprzyjęta

Reguła: status dostawy zmienia się wyłącznie przez zdarzenie, a nie przez ręczną edycję pola.

Reguła wynika z konieczności odtworzenia historii. Gdy status jest polem edytowanym, po sporze z przewoźnikiem nie wiadomo, kto i kiedy go zmienił. Gdy status wynika z dziennika zdarzeń, każda zmiana ma czas i autora.

System zarządzania dostawami - statusy i zdarzenia

System zarządzania dostawami przechowuje dziennik zdarzeń zamiast jednego pola statusu. Każde zdarzenie to osobny wiersz z typem zdarzenia i czasem, a autor zapisuje się w osobnej kolumnie. Aktualny status jest po prostu ostatnim zdarzeniem dostawy, a historia pozostaje nienaruszona.

CREATE TABLE dbo.DeliveryEvent (
    EventId     BIGINT IDENTITY(1,1) PRIMARY KEY,
    DeliveryId  INT          NOT NULL,
    EventType   VARCHAR(20)  NOT NULL,   -- PLANNED, ARRIVED, UNLOADING, RECEIVED, CANCELLED
    EventAt     DATETIME2(0) NOT NULL DEFAULT SYSUTCDATETIME(),
    UserName    NVARCHAR(60) NULL
);
CREATE INDEX IX_DeliveryEvent_Delivery
    ON dbo.DeliveryEvent (DeliveryId, EventId) INCLUDE (EventType, EventAt);

SELECT d.DeliveryId, e.EventType AS CurrentStatus, e.EventAt
FROM dbo.Delivery AS d
CROSS APPLY (
    SELECT TOP (1) EventType, EventAt
    FROM dbo.DeliveryEvent
    WHERE DeliveryId = d.DeliveryId
    ORDER BY EventId DESC
) AS e;

Przykład ma charakter poglądowy, a nazwy tabel są przykładowe. Indeks złożony zaczyna się od kolumny DeliveryId, więc dla każdej dostawy SQL Server wykonuje jedno wyszukiwanie i czyta ostatni wpis. Kolumny w klauzuli INCLUDE sprawiają, że zapytanie nie sięga do indeksu klastrowego, co przy tysiącach dostaw dziennie robi różnicę w czasie odpowiedzi.

Zapis zdarzenia i zmiana dokumentu powiązanego, na przykład utworzenie przyjęcia w WMS, powinny odbyć się w jednej transakcji. Gdy oba zapisy przebiegają osobno, po awarii między nimi dostawa ma status przyjętej, a magazyn nie ma dokumentu. Szczegółowy model statusów awizacji od strony przewoźnika opisuje artykuł awizacja transportu - statusy, zmiany, API.

Planowanie dostaw na podstawie zamówień zakupu

Planowanie dostaw zaczyna się od zamówień, które jeszcze nie mają okna. Program tworzy z nich listę propozycji z liczbą palet i przewidywanym czasem rozładunku. Dostawca wybiera termin z wolnych okien, a długość rezerwacji wynika z ładunku, a nie z jego deklaracji.

Okno czasowe ma pojemność, czyli największą liczbę pojazdów obsługiwanych jednocześnie na rampie. Gdy dostawcy rezerwują ostatnie wolne miejsce w tej samej sekundzie, zapis wymaga blokady zakresu, inaczej obaj dostają potwierdzenie. Zasady doboru długości okien omawia artykuł o oknach czasowych, a ogólne podejście do harmonogramu dostaw przedstawia strona planowanie dostaw.

Celem planowania jest płaski rozkład obciążenia. Jeżeli wszystkie dostawy z zamówień tygodnia przyjeżdżają w poniedziałek rano, rampy stoją puste od środy. Przesunięcie części dostawców na słabsze dni jest tańsze niż dodatkowa zmiana na przyjęciach.

Parametr planowaniaSkąd pochodziSkutek dla okna
Liczba paletzamówienie zakupu lub awizo ASNdługość rezerwacji
Rodzaj pojazduzgłoszenie dostawcydobór rampy i sprzętu
Wymagana temperaturakarta towarurampa z uszczelnieniem
Godziny pracy magazynuustawienia obiektugranice dostępnych okien
Tablet z kolorową mapą obciążenia na tle regałów magazynowych, w tle biała ciężarówka przy rampie
Plan obciążenia ramp na tablecie - rozkład dostaw w ciągu dnia widać jeszcze przed przyjazdem pojazdów

Dostawców cyklicznych warto obsługiwać szablonem. Dostawca, który przyjeżdża co wtorek i piątek o tej samej porze, nie zakłada każdej wizyty osobno, a system rezerwuje okna w wybrane dni tygodnia na kolejne tygodnie z góry.

Moduł awizacji w Studio VSS.net pozwala dostawcy zarezerwować okno przez przeglądarkę lub aplikację na smartfonie, a magazynowi oglądać zajętość w kalendarzu ramp. Zasady tej sekcji opisuje serwis producenta na stronie planowanie dostaw do magazynu, a szczegóły modułu znajdują się w artykule o oprogramowaniu do zarządzania dostawami VSS.net.

Oprogramowanie do zarządzania dostawami - śledzenie i opóźnienia

Oprogramowanie do zarządzania dostawami klasyfikuje każdą dostawę względem okna. Dostawa bez przyjazdu po zakończeniu okna jest spóźniona, dostawa z przyjazdem poza oknem jest po terminie, a przyjazd przed oknem oznacza pojazd, który musi poczekać. Klasyfikację najlepiej liczyć w bazie. Wtedy raporty i ekran dyspozytora dostają ten sam wynik.

SELECT DeliveryId, PlannedFrom, PlannedTo, ArrivedAt,
       CASE
         WHEN ArrivedAt IS NULL AND SYSUTCDATETIME() > PlannedTo THEN N'spóźniona'
         WHEN ArrivedAt > PlannedTo   THEN N'po terminie'
         WHEN ArrivedAt < PlannedFrom THEN N'przed oknem'
         WHEN ArrivedAt IS NOT NULL   THEN N'w oknie'
         ELSE N'oczekiwana'
       END AS Punctuality
FROM dbo.Delivery
WHERE PlannedFrom >= CAST(SYSUTCDATETIME() AS DATE);
KlasyfikacjaWarunekReakcja logistyki
oczekiwanaokno jeszcze trwa, brak przyjazdubrak, obserwacja
spóźnionaokno minęło, brak przyjazdukontakt z dostawcą i zwolnienie okna
po terminieprzyjazd po końcu oknanowe okno lub obsługa w miarę możliwości rampy
przed oknemprzyjazd przed początkiem oknaoczekiwanie na placu lub wcześniejsza obsługa

Wszystkie znaczniki czasu zapisuje się w UTC, a na czas lokalny przelicza się dopiero przy wyświetlaniu. Pozwala to uniknąć błędów przy zmianie czasu z letniego na zimowy, kiedy jedna godzina w nocy pojawia się dwa razy. Do przeliczenia służy klauzula AT TIME ZONE opisana w dokumentacji AT TIME ZONE w Microsoft Learn.

Po stronie przeglądarki ekran dyspozytora odświeża się przez zapytanie AJAX. Poniższy przykład w jQuery pobiera dzisiejsze dostawy co minutę i buduje wiersze tabeli przez metodę text(), dzięki czemu nazwa dostawcy z apostrofem lub znacznikiem nie zepsuje strony. Adres interfejsu jest przykładowy.

function refreshDeliveries() {
  $.getJSON('/api/deliveries/today').done(function (rows) {
    var $body = $('#deliveries tbody').empty();
    $.each(rows, function (i, r) {
      $('<tr>').addClass(r.punctuality)
        .append($('<td>').text(r.supplier))
        .append($('<td>').text(r.plannedFrom))
        .append($('<td>').text(r.status))
        .appendTo($body);
    });
  });
}
setInterval(refreshDeliveries, 60000);

Metoda opisana w dokumentacji jQuery.getJSON zwraca obiekt jqXHR z metodami done() i fail(), więc błąd sieci obsługuje się w osobnym wywołaniu. Powiadomienie o opóźnieniu trafia do kierowcy i dostawcy jako wiadomość SMS lub e-mail, a dyspozytor widzi pojazd na mapie placu opisanej w artykule o wizualizacji zajętości miejsc parkingowych.

Dane dostawy i dokument przyjęcia

Dostawa niesie dane, które magazyn wykorzysta przy przyjęciu: numer zamówienia, listę pozycji z ilościami i numery jednostek logistycznych. Jeżeli dostawca wysyła awizo wysyłki w formacie DESADV, program tworzy z niego awizację bez ręcznego przepisywania. Przy przyjęciu skaner porównuje odczytane numery SSCC z listą z awizacji, a wynik trafia do dokumentu PZ.

RozbieżnośćJak jest wykrywanaTypowa reakcja
Brak palety z listynumer SSCC z awizacji nie został zeskanowanyprzyjęcie niepełne i reklamacja ilościowa
Paleta spoza listyzeskanowany numer nie występuje w awizacjiwstrzymanie jednostki do wyjaśnienia
Inny indeks towarukod na etykiecie różni się od pozycji zamówieniaodrzucenie pozycji lub korekta zamówienia
Uszkodzenie opakowaniauwaga magazyniera przy pozycjiprotokół rozbieżności ze zdjęciem
Ciężarówka załadowana paletami owiniętymi folią przy wózku widłowym, obok pracownik w pomarańczowej kamizelce
Rozładunek pojazdu przy rampie - w tym punkcie lista z awizacji jest porównywana z odczytem skanera

Obsługę przyjęcia po stronie magazynu opisuje artykuł o awizacjach dostaw do magazynu. Skanowanie na terminalu z systemem Android omawia tekst o aplikacji magazynowej na Androida. W obu miejscach zasada jest ta sama: rozbieżność zapisuje się w chwili wykrycia, a nie po zakończeniu rozładunku.

Zasada: przyjęcie zamyka się na liczbach ze skanera, a nie na liczbach z awizacji.

Osobnego traktowania wymaga pojazd bez awizacji. Ochrona rejestruje go jako wjazd nieawizowany, a logistyka decyduje, czy dla niego znajdzie się okno, czy dostawca ma poczekać. Taki wpis też trafia do historii, więc raport pokazuje, jaki odsetek ruchu omija kalendarz i którzy dostawcy robią to najczęściej.

Dostawy częściowe i pozycje zamówienia

Jedno zamówienie zakupu rzadko dociera jednym pojazdem. Dostawca dzieli ilość na kilka dostaw, część pozycji przychodzi z opóźnieniem, a część zostaje anulowana. Program musi więc łączyć dostawy z zamówieniem na poziomie pozycji, a nie nagłówka.

Saldo pozycji liczy się jako różnica między ilością zamówioną a sumą ilości przyjętych we wszystkich dostawach. Poniższe zapytanie zwraca pozycje z niedoborem i jest podstawą listy do ponaglenia dostawcy. Nazwy tabel są przykładowe.

SELECT ol.OrderId, ol.LineNo, ol.QtyOrdered,
       ISNULL(SUM(dl.QtyReceived), 0) AS QtyReceived,
       ol.QtyOrdered - ISNULL(SUM(dl.QtyReceived), 0) AS QtyOpen
FROM dbo.PurchaseOrderLine AS ol
LEFT JOIN dbo.DeliveryLine AS dl
       ON dl.OrderId = ol.OrderId AND dl.LineNo = ol.LineNo
GROUP BY ol.OrderId, ol.LineNo, ol.QtyOrdered
HAVING ol.QtyOrdered > ISNULL(SUM(dl.QtyReceived), 0);

Złączenie LEFT JOIN zachowuje pozycje bez żadnej dostawy, które przy INNER JOIN zniknęłyby z wyniku. To najczęstszy błąd w raportach otwartych zamówień: pozycja, której dostawca jeszcze nie wysłał, wypada z zestawienia i wygląda jak zrealizowana.

Role i powiadomienia w programie do dostaw

Dostawca powinien widzieć tylko własne dostawy, a magazyn wszystkie. Uprawnienia przypisuje się rolom, a nie osobom, bo konta przewoźników zmieniają się częściej niż zakres ich pracy. Konfigurację ról opisuje artykuł o awizacjach VSS.net.

RolaCo widzi i robiPowiadomienia
Dostawca lub przewoźnikwłasne dostawy, zakładanie awizacji, zmiana okna do terminu granicznegopotwierdzenie rezerwacji, zmiana terminu
Logistykazatwierdzanie i przesuwanie okien we wszystkich dostawachspóźnienia, dostawy bez awizacji
Ochronalista pojazdów oczekujących na wjazd, rejestracja przyjazdubrak
Magazyndostawy przypisane do ramp oraz rejestracja początku i końca rozładunkuzbliżająca się dostawa

Powiadomienia mają sens wtedy, gdy wynikają z reguły, a nie z każdego zdarzenia. Reguła typu spóźnienie ponad próg minut uruchamia wiadomość SMS lub e-mail do kierowcy i do logistyki, a próg ustala się w parametrach obiektu. Zbyt liczne komunikaty uczą odbiorców ich ignorowania.

Reguła: powiadomienie trafia do osoby, która może zareagować, a nie do wszystkich uczestników dostawy.

Wskaźniki terminowości dostaw

Program dostarcza wskaźniki dopiero wtedy, gdy zdarzenia mają znaczniki czasu. Podstawowym miernikiem jest odsetek dostaw przyjętych w oknie, a rozszerzeniem wskaźnik OTIF, czyli dostawa na czas i w pełnej ilości. Oba liczy się z dziennika zdarzeń i z dokumentów przyjęcia.

  • Terminowość okna - udział dostaw z przyjazdem mieszczącym się w awizowanym oknie.
  • Średni czas obsługi - różnica między rozpoczęciem a zakończeniem rozładunku na rampie.
  • Obciążenie bram w tygodniu - liczba dostaw na bramę w kolejnych dniach, podstawa do przesuwania dostawców.
  • Wjazdy nieawizowane - udział pojazdów, które ominęły kalendarz, liczony z historii wizyt.

Dwa czasy warto rozdzielać. Czas oczekiwania od wjazdu do przydzielenia rampy obciąża organizację placu, a czas rozładunku obciąża proces przyjęcia. Rozliczenie przestojów z przewoźnikiem opiera się na obu, dlatego znaczniki czasu z bramy i z rampy muszą pochodzić z zegara jednego serwera, a nie z urządzeń z rozjechanym czasem.

Wskaźniki mają sens per dostawca. Jedna średnia dla całego magazynu ukrywa dostawcę, który spóźnia się co tydzień, za średnią z dziesięciu punktualnych. Zestawienie miesięczne z listą dostawców posortowaną według odsetka spóźnień daje logistyce podstawę do rozmowy o zmianie okna lub umowy.

Integracja programu do dostaw z ERP i WMS

Program do zarządzania dostawami nie zastępuje ERP ani WMS, tylko łączy je w miejscu, gdzie żaden z nich nie sięga. ERP zna zamówienie, WMS zna przyjęcie, a pomiędzy nimi jest pojazd na placu. Awizacja może powstać z zamówienia zakupu albo z awizo wysyłki, a zatwierdzona trafia do WMS jako oczekujące zlecenie przyjęcia.

VSS.net wymienia dane z ERP przez API i EDI, a zmiany statusów w WMS, na przykład zakończenie rozładunku, wracają do awizacji i dalej do ERP. Mechanizm przedstawia artykuł o tym, jak VSS łączy się z WMS i ERP przy przyjęciach, a system magazynowy po drugiej stronie opisuje strona Studio WMS.net.

KierunekDaneWyzwalacz
ERP do programu dostawzamówienie zakupu lub awizo ASNzatwierdzenie zamówienia
Program dostaw do WMSzatwierdzona awizacja z pozycjamizatwierdzenie okna
WMS do programu dostawzakończenie rozładunku i przyjęciazamknięcie dokumentu PZ
Program dostaw do ERPstatus i czas zdarzeniakażde zdarzenie dostawy

Każdy komunikat powinien mieć identyfikator dokumentu źródłowego, bo ERP po przekroczeniu limitu czasu połączenia wysyła ten sam dokument ponownie. Unikalny indeks na parze system źródłowy i numer dokumentu zamienia drugie wysłanie w aktualizację istniejącej dostawy. Bez niego w kalendarzu pojawiają się duplikaty, które zajmują okna na rampach.

Druga część zabezpieczenia to ponawianie. Gdy interfejs ERP nie odpowiada, komunikaty zostają w kolejce, a łącznik ponawia próbę w rosnących odstępach, na przykład po minucie i po kwadransie. Po kilku nieudanych próbach komunikat trafia do listy błędów, którą przegląda administrator, a magazyn pracuje dalej na danych z ostatniej udanej wymiany.