Awizacje dostaw w jednym widoku - lista i statusy
Przy kilkudziesięciu dostawach dziennie pojedyncza awizacja przestaje być obiektem, na którym pracuje planista. Pracuje on na zbiorze rekordów, który filtruje, a potem zmienia zbiorczo. Ten tekst dotyczy właśnie takiej pracy na wielu awizacjach dostaw naraz.
Punktem wyjścia jest lista z jasnym statusem każdego rekordu. W bazie VSS.net kolumna statusu oznacza bufor wartością 0 i zatwierdzenie wartością 1, a anulowanie lub usunięcie literą X. To jednak status rekordu, a nie wizyty. Przebieg samej wizyty na terenie zakładu opisuje osobny cykl, w którym pojazd przechodzi przez kolejne etapy.
| Status wizyty | Znaczenie | Kto zmienia |
|---|---|---|
| zatwierdzona | okno zarezerwowane, pojazd oczekiwany | planista albo system po kontroli |
| na terenie | pojazd wjechał przez bramę | ochrona lub skan kodu |
| w rozładunku | pojazd stoi przy rampie | brygadzista przyjęć |
| zakończona | rozładunek zamknięty, pojazd wyjechał | ochrona lub system przy wyjeździe |
| anulowana | rezerwacja zwolniona, okno wraca do puli | planista lub przewoźnik |
Reguła: status wizyty można zmienić tylko na następny dozwolony etap, a każda zmiana zostawia w historii godzinę i użytkownika.
Tę regułę najprościej wyrazić jako tabelę dozwolonych przejść. Poniższy fragment C# opisuje ją w słowniku i sprawdza zmianę jednym wywołaniem. Nazwy typów są przykładowe.
enum StatusWizyty { Zatwierdzona, NaTerenie, Rozladunek, Zakonczona, Anulowana }
static readonly Dictionary<StatusWizyty, StatusWizyty[]> Dozwolone = new()
{
[StatusWizyty.Zatwierdzona] = new[] { StatusWizyty.NaTerenie, StatusWizyty.Anulowana },
[StatusWizyty.NaTerenie] = new[] { StatusWizyty.Rozladunek },
[StatusWizyty.Rozladunek] = new[] { StatusWizyty.Zakonczona },
};
static bool MoznaZmienic(StatusWizyty z, StatusWizyty na) =>
Dozwolone.TryGetValue(z, out var cele) && Array.IndexOf(cele, na) >= 0;
Dzięki takiemu rozwiązaniu nie da się oznaczyć rozładunku jako zakończonego dla pojazdu, który nigdy nie wjechał. Typy wyliczeniowe w C# opisuje dokumentacja Microsoft Learn.
Kalendarz i filtry przy dużej liczbie awizacji
Lista dobrze pokazuje szczegóły, ale nie pokazuje rozkładu w czasie. Do tego służy kalendarz: oś godzin i rampy jako kolumny, a każda awizacja jako blok o długości okna. Kolizje i luki widać od razu, bez porównywania godzin w tabeli. Funkcje widoków opisuje artykuł o kalendarzach w VSS.net, a sam mechanizm rezerwacji z poziomu kalendarza - tekst o aplikacji kalendarz do awizacji dostaw.

Przy setkach rekordów sam kalendarz też przestaje wystarczać, bo blok zasłania blok. Potrzebne są filtry, które zawężają widok do jednego pytania. Zestawienie poniżej pokazuje cztery najczęściej używane.
| Filtr | Pytanie, na które odpowiada | Typowy użytkownik |
|---|---|---|
| rampa | co dzieje się przy konkretnej bramie | brygadzista przyjęć |
| przewoźnik | jak często dana firma się spóźnia | dział logistyki |
| status | które awizacje czekają w buforze | planista |
| zakres dat | czy przyszły tydzień jest przeciążony | kierownik magazynu |
Po stronie bazy danych filtry opcjonalne zapisuje się jednym zapytaniem z parametrami dopuszczającymi wartość pustą. Aby optymalizator nie użył planu zbudowanego dla innego zestawu parametrów, dodaje się OPTION (RECOMPILE). Wskazówki zapytań opisuje dokumentacja Query Hints.
SELECT a.Id, a.OknoOd, a.OknoDo, a.RampaId, a.PrzewoznikId, a.Ach
FROM dbo.Awizacja AS a
WHERE a.OknoOd >= @od AND a.OknoOd < @do
AND (@rampa IS NULL OR a.RampaId = @rampa)
AND (@przewoznik IS NULL OR a.PrzewoznikId = @przewoznik)
AND (@ach IS NULL OR a.Ach = @ach)
ORDER BY a.OknoOd
OPTION (RECOMPILE);
Indeks na zakres dat i status skraca odczyt, ale zapytanie musi zostać czytelne dla ludzi utrzymujących kod. Jedno zapytanie z filtrami opcjonalnymi zwykle wystarcza, dopóki tabela nie urośnie do milionów wierszy.
Masowe zmiany terminów i anulowanie serii
Awaria bramy o siódmej rano dotyka kilkunastu awizacji naraz. Dyspozytor nie powinien dzwonić do każdego przewoźnika z osobna ani poprawiać rekordów jeden po drugim. Zarządzanie awizacjami z jednego panelu pozwala zmienić termin lub przenieść wizytę na inną bramę. Anulowanie rezerwacji także odbywa się zbiorczo, a system powiadamia zainteresowanych.
Zmiana zbiorcza ma sens tylko wtedy, gdy jest bezpieczna. Zanim rekordy zostaną zapisane, system musi sprawdzić, czy przesunięcie nie stworzy kolizji z innymi wizytami. Poniższy przykład przesuwa wszystkie zatwierdzone awizacje jednej rampy o zadaną liczbę minut i wycofuje zmianę, gdy któreś okna zaczną się nakładać. Przykład zakłada jedną wizytę na rampę w danym czasie.
BEGIN TRAN;
UPDATE a
SET OknoOd = DATEADD(MINUTE, @minuty, a.OknoOd),
OknoDo = DATEADD(MINUTE, @minuty, a.OknoDo)
FROM dbo.Awizacja AS a
WHERE a.RampaId = @rampa AND a.Ach = '1'
AND a.OknoOd >= @od AND a.OknoOd < @do;
IF EXISTS (SELECT 1
FROM dbo.Awizacja AS x
JOIN dbo.Awizacja AS y
ON y.RampaId = x.RampaId AND y.Id > x.Id AND y.Ach = '1'
AND x.OknoOd < y.OknoDo AND y.OknoOd < x.OknoDo
WHERE x.RampaId = @rampa AND x.Ach = '1')
ROLLBACK;
ELSE
COMMIT;
Funkcję dodającą minuty do daty opisuje dokumentacja DATEADD. Wszystkie zmiany odbywają się w jednej transakcji, więc częściowo przesunięty harmonogram nigdy nie zostaje zapisany.
- Podgląd przed zapisem - lista rekordów, których zmiana dotknie, z podświetlonymi kolizjami.
- Jedna transakcja - albo przesuwają się wszystkie wybrane awizacje, albo żadna.
- Powiadomienia po zatwierdzeniu - wiadomość do przewoźników wysyłana dopiero po udanym zapisie.
- Dziennik zmian - zapis, kto i kiedy przesunął okna oraz z jakim uzasadnieniem.
Anulowanie serii działa podobnie, ale zamiast przesuwać okna oznacza rekordy statusem X i zwalnia pojemność. Zwolnione sloty wracają do puli i mogą zostać zaproponowane transportom z listy rezerwowej. Proces zmian z perspektywy przewoźnika, w tym statusy i integrację przez API, opisuje artykuł o awizacji transportu.
Awizacje cykliczne dla stałych przewoźników
Część dostaw powtarza się bez zmian: kurierzy odbierają towar kilka razy w tygodniu o tej samej godzinie, a dostawcy komponentów przyjeżdżają według stałego grafiku. Ręczne zgłaszanie każdego wystąpienia oznaczałoby setki niepotrzebnych operacji miesięcznie. Kalendarz awizacji VSS.net pozwala tworzyć cykliczne rezerwacje okien czasowych w ustawionym interwale.
Seria a pojedyncze wystąpienie
Podstawowa decyzja przy każdej zmianie dotyczy zakresu: jedno wystąpienie albo cała seria od wskazanej daty. Przesunięcie jednej dostawy z powodu święta nie powinno zmieniać grafiku na kolejne miesiące. Odwrotnie, zmiana trasy przewoźnika dotyczy całej serii od wskazanej daty.
Technicznie seria jest regułą powtarzania, z której system generuje konkretne rekordy na okres z wyprzedzeniem. Wyjątek od reguły zapisuje się jako osobny rekord, który ma pierwszeństwo przed wygenerowanym. Dzięki temu edycja jednego wystąpienia nie zmienia pozostałych.
Powiadomienia SMS i e-mail należą do standardowych funkcji kalendarza i ograniczają liczbę telefonów do dyspozytora w dniu dostawy. Porządek okien w takim harmonogramie opisuje tekst o oknach czasowych, a ogólną ideę harmonogramu online - artykuł o harmonogramie online w zarządzaniu transportem.
Widoczność awizacji dla przewoźników i najemców
Przy wielu awizacjach różne osoby powinny widzieć różne podzbiory. Przewoźnik ogląda wyłącznie własne zgłoszenia. W centrum logistycznym obsługującym kilku najemców każdy z nich ma osobny harmonogram i nie widzi rezerwacji pozostałych. Planista przegląda całość, a ochrona tylko pojazdy oczekiwane danego dnia.
| Rola | Zakres widoczności | Typowe operacje |
|---|---|---|
| przewoźnik | awizacje własnej firmy | zgłoszenie, zmiana terminu, anulowanie |
| najemca w centrum logistycznym | własny harmonogram i własne rampy | rezerwacje w ramach umowy |
| planista magazynu | wszystkie awizacje obiektu | zmiany zbiorcze, rezerwa pojemności |
| ochrona | pojazdy oczekiwane danego dnia | rejestracja wjazdu i wyjazdu |
Ograniczenie widoczności musi działać w bazie danych, a nie tylko w interfejsie. Jeśli filtr po firmie istnieje wyłącznie w przeglądarce, wystarczy zmienić parametr żądania, żeby zobaczyć cudze dane. Najprościej wymusić go funkcją tabelaryczną, z której korzystają wszystkie zapytania użytkowników zewnętrznych.
CREATE FUNCTION dbo.AwizacjeFirmy (@firmaId INT)
RETURNS TABLE
AS
RETURN
SELECT a.Id, a.OknoOd, a.OknoDo, a.RampaId, a.Ach
FROM dbo.Awizacja AS a
WHERE a.FirmaId = @firmaId;
Od SQL Server 2016 dostępna jest też wbudowana ochrona na poziomie wierszy, opisana w dokumentacji Row-Level Security. Reguła filtrująca jest wtedy dołączana do każdego zapytania automatycznie, co ogranicza ryzyko pominięcia filtra w nowym raporcie.
Czas postoju pojazdu jako wskaźnik
Czas postoju obejmuje okres od wjazdu pojazdu na teren zakładu do jego wyjazdu. Jest to najprostszy wskaźnik pokazujący, ile realnie zyskuje firma po uruchomieniu awizacji. Przed wdrożeniem warto więc zmierzyć obecny czas oczekiwania przed bramą, żeby porównanie miało punkt odniesienia.
Sam wskaźnik składa się z etapów, które mają różnych właścicieli. Wyodrębnienie ich pozwala wskazać, gdzie tracony jest czas, zamiast dyskutować o średniej.
| Etap postoju | Znacznik czasu | Kto wpływa na wynik |
|---|---|---|
| oczekiwanie przed bramą | przyjazd i wjazd na teren | planista i portiernia |
| ważenie | waga przy wjeździe i wyjeździe | ochrona |
| oczekiwanie na rampę | wjazd i podstawienie pod rampę | plac i planista |
| rozładunek | początek i koniec obsługi | zespół przyjęć |
Największy udział w postoju ma zwykle oczekiwanie, a nie sam rozładunek. Kierowca, który dotrze przed wyznaczoną godziną, powinien zostać skierowany na miejsce postojowe zamiast czekać w kolejce przy bramie. Zajętość miejsc pokazuje artykuł o wizualizacji miejsc parkingowych, a dalszy przebieg przyjęcia opisuje tekst o awizacjach dostaw do magazynu.
Integracja z wagami samochodowymi rejestruje masę pojazdu przy wjeździe i wyjeździe bez ręcznego przepisywania odczytów. Znacznik czasu ważenia jest wtedy dodatkową, wiarygodną datą w historii wizyty. Szczegóły opisuje strona o wagach samochodowych w systemie awizacji.

Do raportu lepiej nadaje się mediana i wysoki percentyl niż średnia. Kilka bardzo długich postojów po awarii zawyża średnią, więc typowy przebieg znika z raportu. Poniższe zapytanie liczy oba wskaźniki dla każdej rampy. Funkcję percentyla opisuje dokumentacja PERCENTILE_CONT.
SELECT DISTINCT a.RampaId,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY DATEDIFF(MINUTE, a.Wjazd, a.Wyjazd))
OVER (PARTITION BY a.RampaId) AS Mediana,
PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY DATEDIFF(MINUTE, a.Wjazd, a.Wyjazd))
OVER (PARTITION BY a.RampaId) AS P90
FROM dbo.Awizacja AS a
WHERE a.Wyjazd IS NOT NULL AND a.Wjazd >= @od;
Punktualność przewoźników w raporcie
Drugi wskaźnik dotyczy zachowania dostawców. Punktualność określa, czy pojazd przyjechał w oknie z ustaloną tolerancją. Przyjazd w tolerancji liczy się jako punktualny, a wcześniejszy lub późniejszy jako odchylenie. Magazyn musi zdecydować, jak traktuje przyjazd zbyt wczesny, bo zajmuje on miejsce na placu równie skutecznie jak spóźniony.
| Kategoria | Warunek | Skutek na placu |
|---|---|---|
| przyjazd zbyt wczesny | przed początkiem tolerancji | pojazd zajmuje miejsce postojowe, rampa jeszcze zajęta |
| przyjazd punktualny | w oknie z tolerancją | brak zakłóceń w harmonogramie |
| przyjazd spóźniony | po końcu tolerancji | przesunięcie kolejnych okien albo utrata rezerwacji |
Każda awizacja zostawia ślad w bazie danych, więc dane do raportu powstają same. Planowany i rzeczywisty czas przyjazdu gromadzą się bez dodatkowej pracy, podobnie jak czas rozładunku. Raport terminowości wskazuje przewoźników, którzy regularnie się spóźniają, i staje się argumentem w rozmowach kontraktowych.
SELECT p.Nazwa AS Przewoznik,
COUNT(*) AS Wizyty,
SUM(CASE WHEN a.Przyjazd BETWEEN DATEADD(MINUTE, -@tol, a.OknoOd)
AND DATEADD(MINUTE, @tol, a.OknoOd)
THEN 1 ELSE 0 END) AS WTolerancji,
100.0 * SUM(CASE WHEN a.Przyjazd BETWEEN DATEADD(MINUTE, -@tol, a.OknoOd)
AND DATEADD(MINUTE, @tol, a.OknoOd)
THEN 1 ELSE 0 END) / COUNT(*) AS ProcentPunktualnych
FROM dbo.Awizacja AS a
JOIN dbo.Przewoznik AS p ON p.Id = a.PrzewoznikId
WHERE a.Przyjazd IS NOT NULL AND a.OknoOd >= @od
GROUP BY p.Nazwa
ORDER BY ProcentPunktualnych;
Raporty tego typu buduje się zwykle w narzędziu raportowym z zapytaniem SQL jako źródłem danych. Sposób przygotowania takich zestawień opisuje tekst o SQL Report Builder i raportach RDL. Wnioski z raportu przekłada się na parametry systemu, na przykład tolerancję i pojemność okien.
Dostosowanie okien na podstawie wskaźników
Oba wskaźniki mają sens dopiero wtedy, gdy prowadzą do zmiany parametrów. Jeśli mediana czasu rozładunku dla dostaw wielkogabarytowych wynosi 40 minut, a okno zaplanowano na 30, każda taka dostawa przesuwa kolejne. Wystarczy wtedy wydłużyć okno dla tej grupy asortymentu, zamiast dokładać rampy.
Odwrotna sytuacja występuje przy przewoźnikach o niskiej punktualności. Rezerwacja, z której korzystają rzadko, blokuje pojemność, więc skrócenie tolerancji albo wprowadzenie rezerwy zwalnianej po kwadransie zwykle poprawia wykorzystanie ramp. Zmiany wprowadza się stopniowo i sprawdza w kolejnych tygodniach, bo skutki widać dopiero w danych.
Pełny obraz obejmuje też pojazdy, które przyjechały bez zgłoszenia. Ich udział w ruchu opisuje artykuł o transporcie nieawizowanym. Planowanie obłożenia ramp i zgodność zgłoszeń z zamówieniami omawia tekst o awizacji dostawy jako planie dnia, a zarządzanie całym procesem prezentuje strona zarządzanie awizacjami na portalu awizacji.




