Apilo
Case Study
E-commerce
Logistyka
InPost
Automatyzacja

Apilo i paczki dużych gabarytów — case study

Jak hurtownia pasz przestała ręcznie dzielić worki na paczki i klikać etykiety pojedynczo — i dlaczego waga jest tu najmniejszym problemem.

Mateusz KozłowskiMateusz Kozłowski12 min czytania
Wszystkie zrzuty w tym wpisie pochodzą z trybu demo systemu — zamówienia i dane klientów są fikcyjne.
W tym artykule

Co z tego wyszło

Hurtownia pasz i akcesoriów dla zwierząt sprzedaje przez Allegro i własny sklep, a zamówienia zbiera w Apilo. Towar to worki od 2 do 25 kg, więc prawie każda paczka ociera się o limit przewoźnika. Zbudowaliśmy nadbudowę nad Apilo, która sama dzieli zamówienie na paczki, sama dobiera gabaryt skrytki, drukuje etykiety całą partią — i uczy się od operatorki za każdym razem, gdy ta poprawi jej propozycję.

  • 1

    Podział na paczki liczy jeden algorytm

    Podgląd pojedynczego zamówienia i druk zbiorczy wołają tę samą funkcję. Wcześniej druk zbiorczy szedł własną regułą „1 sztuka = 1 paczka” i kupował więcej przesyłek, niż trzeba było.

  • 2

    Limity przewoźników w konfiguracji, nie w kodzie

    Waga i wymiary per kategoria (paczkomat, punkt odbioru, kurier) siedzą w jednym pliku JSON. Nowy przewoźnik albo zmiana limitu to wpis, nie zmiana logiki.

  • 3

    System uczy się od operatorki

    Ręczna korekta podziału zapisuje się jako wzór dla identycznego zestawu pozycji. Kolejne takie zamówienie pakuje się samo — również w druku zbiorczym.

  • 4

    Nic nie idzie do druku bez dowodu

    Przed partią panel sprawdza, które zamówienia mają już etykietę w Apilo. Każda utworzona przesyłka jest płatna u kuriera i nieodwracalna z poziomu integracji.

Poniedziałek: 80 etykiet i worki paszy

Zamówienia z Allegro i ze sklepu spływają do Apilo. Apilo dobrze zbiera je w jednym miejscu i potrafi utworzyć przesyłkę u kuriera, ale wciąż jest to praca na jednym zamówieniu naraz: otwórz, sprawdź, co w środku, zdecyduj, ile paczek, wpisz wagę, wybierz gabaryt, utwórz przesyłkę, wydrukuj. Przy dwudziestu zamówieniach da się to przeżyć. W poniedziałek rano bywa ich osiemdziesiąt.

Drugi problem to asortyment. Sklep z paszami nie sprzedaje pudełek 20×15×10 cm. Sprzedaje worki 10, 20 i 25 kg — towar, który przy każdym zamówieniu ociera się o limit wagowy albo wymiarowy przewoźnika. Ta sama pozycja raz mieści się w paczkomacie, a raz musi jechać kurierem.

Lista zamówień zaciągana z Apilo na żywo. Filtr po SKU, przewoźniku i statusie to punkt wyjścia do skompletowania partii druku.

Trzeci problem jest najdroższy: każda przesyłka utworzona w Apilo jest płatna u kuriera i nie da się jej cofnąć z poziomu integracji. Pomyłka nie kończy się komunikatem o błędzie, tylko fakturą. Dlatego cała ta automatyzacja jest zbudowana wokół pytania „czy na pewno wolno to utworzyć”, a nie wokół „jak zrobić to szybciej”.

Dlaczego „podziel na paczki” to nie jest suma wag

Pierwsza intuicja — zsumuj wagi pozycji i podziel przez limit przewoźnika — wywraca się na trzech rzeczach naraz:

  • Paczkomat ma gabaryty, nie tylko wagę. Skrytka A ma 8 cm wysokości, B — 19 cm, C — 41 cm. Worek 10 kg jest lekki w stosunku do limitu 25 kg, ale jest pękaty i do gabarytu B nie wejdzie.
  • Ta sama zawartość, inny przewoźnik, inny podział. Dwa worki po 10 kg mieszczą się w jednej przesyłce paczkomatowej (20 ≤ 25 kg), w punkcie odbioru z limitem 20 kg są dokładnie na granicy, a u kuriera (31,5 kg) można dorzucić trzeci.
  • Podział przekłada się wprost na koszt. Każda dodatkowa paczka to dodatkowa, płatna przesyłka. Reguła „jedna sztuka = jedna paczka” jest bezpieczna i systematycznie przepłaca.

Dlatego podział liczy algorytm pakowania (first-fit decreasing) z limitem wagowym kategorii przewoźnika, a gabaryt wybiera najbardziej wymagająca sztuka w paczce, a nie suma wag. Worek od 10 kg w górę wymusza gabaryt C, nawet jeśli waga zmieściłaby się w mniejszej skrytce.

Trzy worki po 10 kg do paczkomatu: system proponuje dwie paczki (20/25 kg i 10/25 kg) i gabaryt C dla obu. Operatorka może przenieść pozycję do innej paczki — a ta korekta zostaje zapamiętana.

Skąd system w ogóle wie, ile waży worek

Apilo zwraca pozycje zamówienia z nazwą, SKU, ilością i ceną. Nie zwraca wagi — najczęściej po prostu nie ma jej w kartotece sprzedażowej. Ratuje nas branża: waga jest w nazwie produktu („Pasza dla koni 25kg”, „Granulat dla drobiu 10kg”). Wagę czyta więc parser nazwy — i to jest dokładnie ten kawałek kodu, który potrafi po cichu kosztować pieniądze.

„Worek 22,5 kg"   → regex z samą kropką → 5 kg     ❌ zaniżona deklaracja → dopłata od kuriera
„Mieszanka 1,25kg" → regex z samą kropką → 25 kg    ❌ fałszywa blokada limitu
„Worek 22,5 kg"   → regex z przecinkiem → 22,5 kg  ✅

Wyrażenie regularne, które uznaje tylko kropkę dziesiętną, z „Worek 22,5 kg” robi 5 kg, a z „Mieszanka 1,25kg” — 25 kg. Pierwszy błąd to zaniżona deklaracja i dopłata od przewoźnika po fakcie; drugi to fałszywa blokada limitu na czymś, co waży kilogram. Oba wyglądają w panelu zupełnie normalnie.

Limity przewoźników: waga to połowa problemu

Pierwsza wersja wysyłała do Apilo sztywne wymiary 60×40×40 cm dla każdej przesyłki. U kuriera przechodziło. Aż do pierwszej Orlen Paczki:

422 DIMENSIONS_VALIDATION_ERROR
packages.dimensions  Podane wymiary wykraczają poza limit 64 x 41 x 38 cm

Wysokość 40 cm przy limicie 38 cm wywracała całą przesyłkę, a komunikat wracał do operatorki jako surowy błąd 422. Naprawa polegała na przeniesieniu limitów z kodu do konfiguracji — jeden plik carrier-limits.json trzyma i wagę, i wymiary per kategoria przewoźnika:

{
  "id": "inpost_paczkomat", "label": "InPost Paczkomat",
  "match": ["paczkomat"], "maxKg": 25,
  "maxDims":     { "l": 64, "w": 38, "h": 41 },
  "defaultDims": { "l": 60, "w": 35, "h": 38 }
},
{
  "id": "locker_or_point", "label": "Automat / punkt odbioru",
  "match": ["automat", "punkt", "orlen paczka", "żabka"], "maxKg": 20,
  "maxDims":     { "l": 64, "w": 41, "h": 38 },
  "defaultDims": { "l": 60, "w": 40, "h": 30 }
}
Ten sam worek 10 kg, ale wysyłka do punktu odbioru: inny limit wagi (20 kg) i inne wymiary (64×41×38). Panel pokazuje limit, zanim ktokolwiek kliknie „Generuj”.

Kategorię rozpoznajemy po czytelnej nazwie metody wysyłki („ORLEN Paczka — odbiór w punkcie”), a nie po kodzie metody — kody bywają identyfikatorami platformy sprzedażowej i nie da się ich dopasować do reguł. Dodanie przewoźnika albo zmiana limitu to dziś edycja JSON-a; domyślne wymiary są przycinane do limitu, żeby zamiast błędu 422 poszła mniejsza paczka.

Jeden mózg pakowania — i nauka z druku zbiorczego

Najgorsza wersja takiego systemu to ta, w której podgląd pokazuje co innego niż druk. Mieliśmy to przez chwilę: podgląd zamówienia liczył paczki algorytmem, a druk zbiorczy szedł regułą „1 sztuka = 1 paczka”. Operatorka widziała jedną paczkę, a partia kupowała dwie przesyłki. Dziś obie ścieżki wołają tę samą funkcję, a kolejność źródeł decyzji jest jawna:

  • 1

    Ręczna korekta z tego zamówienia

    Jeśli operatorka poprzestawiała pozycje w podglądzie, jej podział wygrywa ze wszystkim innym.

  • 2

    Zapamiętany wzór

    Odcisk zamówienia to kategoria przewoźnika plus zestaw SKU z ilościami. Trafienie znaczy, że dokładnie taki komplet ktoś już kiedyś spakował ręcznie.

  • 3

    Algorytm pakowania

    Dopiero gdy nie ma ani korekty, ani wzoru, liczy first-fit decreasing z limitem wagowym kategorii i regułą gabarytu.

Wzór jest odciskiem całego zamówienia, nie pojedynczej pozycji: kategoria_kuriera::sku:ilość, posortowane. Inna ilość tego samego SKU to inny wzór, bo inaczej się go pakuje. Inny typ przewoźnika też, bo ma inny limit.

Druk zbiorczy też uczy się — a to była większa zmiana, niż wygląda. Wcześniej wzory powstawały wyłącznie w podglądzie pojedynczego zamówienia, czyli w ścieżce, którą operatorka chodzi najrzadziej. Cały główny ruch szedł partiami i nie uczył systemu niczego.

Partia druku: koszyk, pre-flight, przegląd wag

Zamówienia trafiają do koszyka zapisanego w bazie, a nie w zakładce przeglądarki. Dzięki temu partię można zacząć kompletować przed południem, wrócić do niej po obiedzie i zobaczyć na liście, że koleżanka wrzuciła te same zamówienia do swojego koszyka.

Pre-flight przed generowaniem: osiem zamówień gotowych, jedno nierozstrzygnięte. „Nierozstrzygnięte” nie znaczy „bez etykiety” — takiego zamówienia nie wolno wpuścić do partii.

Zanim powstanie choćby jedna przesyłka, panel odpowiada na pytanie „które z tych zamówień ma już etykietę w Apilo”. Dowód zbiera z trzech źródeł:

  • lustro przesyłek w naszej bazie, odświeżane synchronizacją godzinową,
  • status zamówienia w Apilo („Wysłane”, „Doręczone”) — jest na liście, więc nie kosztuje ani jednego dodatkowego zapytania,
  • tag „Etykieta utworzona” — najpewniejszy, ale wymaga osobnego zapytania na każde zamówienie, więc pytamy o niego punktowo.

Werdykt jest trójstanowy: ma etykietę, nie ma, albo nie wiadomo. Zwinięcie „nie wiadomo” do „nie ma” kosztuje jedną płatną przesyłkę na każde nierozstrzygnięte zamówienie — dlatego takie zamówienia po prostu wypadają z partii z czytelnym komunikatem. Z tego samego powodu koszyk ma dwie różne akcje: „Generuj etykiety” (tworzy, płatne, pomija te z etykietą) i „Drukuj wszystkie etykiety” (czysty odczyt, wolno klikać do skutku).

Przegląd wag przed nadaniem partii. Produkty są deduplikowane po SKU — w partii ten sam worek wraca w kilkunastu zamówieniach, więc operatorka poprawia wagę raz.

Ostatni krok przed nadaniem to przegląd wag. Produkty są deduplikowane po SKU, więc operatorka poprawia wagę raz na towar, a nie raz na zamówienie; brak wagi blokuje przycisk, a waga ponad limit kategorii dostaje ostrzeżenie, zanim odrzuci ją Apilo. Partia jest ograniczona do dwudziestu zamówień — powyżej tego równoległe wywołania API przestają być grzeczne.

Zamówienie anulowane po wydrukowaniu etykiety

Synchronizacja z Apilo chodzi co godzinę. Operatorka kompletuje partię w kilkanaście minut. To wystarczy, żeby zamówienie anulowane o 10:05 dostało płatną etykietę o 10:20 — i żeby nikt nie zauważył tego aż do rozliczenia z kurierem.

Dlatego anulowanie nie czeka na synchronizację, tylko przychodzi z Apilo natychmiast, regułą automatyzacji wywołującą nasz adres URL. Zapis trafia do osobnej tabeli, a strażnik po stronie serwera odrzuca próbę utworzenia przesyłki dla anulowanego zamówienia. To jedyna blokada, której nie da się ominąć przyciskiem „generuj mimo to”: drugą etykietę operatorka czasem chce świadomie, etykiety dla anulowanego — nigdy.

Co to zmieniło (i czego nie rozwiązuje)

Codzienna praca wygląda dziś tak:

  • Kompletowanie partii zamiast klikania zamówień. Filtr po SKU i przewoźniku, koszyk, jeden przegląd wag, jeden zbiorczy PDF do drukarki.
  • Podział na paczki jest decyzją systemu, a gdy operatorka go poprawi, kolejne identyczne zamówienie jest już spakowane dobrze.
  • Limity przewoźnika widać przed drukiem, a nie w postaci błędu 422 z Apilo po fakcie.
  • Anulowane i już oetykietowane zamówienia wypadają z partii same.

Nie podaję tu procentów oszczędności, bo uczciwa liczba bierze się z pomiaru, a nie z prezentacji. System zbiera własną telemetrię: ile podziałów przyjęto bez zmian, ile poprawiono, skąd wzięła się podpowiedź (zapamiętany wzór czy algorytm) i jak często waga jest nieznana. Zakładka Trafność AI pokazuje to jako serię w czasie — i to jest jedyna wersja zwrotu z inwestycji, którą warto pokazywać klientowi.

Wnioski dla twojego magazynu

  • 1

    Zacznij od tego, co kosztuje pieniądze

    W wysyłce najdroższy nie jest czas kliknięcia, tylko nadmiarowa przesyłka, dopłata za zaniżoną wagę i etykieta dla anulowanego zamówienia. Automatyzuj wokół tych trzech, a nie wokół „szybciej”.

  • 2

    Jedna ścieżka decyzji, nie dwie

    Jeśli podgląd i wykonanie liczą to samo dwoma kawałkami kodu, prędzej czy później rozjadą się w sposób, który pierwszy zobaczy klient.

  • 3

    Limity i reguły do konfiguracji

    Tabela limitów przewoźników zmienia się częściej niż logika. Trzymana w kodzie, starzeje się od razu w dwóch kopiach.

  • 4

    Pomiar od pierwszego dnia

    Telemetria „ile system zrobił sam, a ile poprawił człowiek” kosztuje kilka linijek przy każdej operacji, a po miesiącu jest jedyną twardą odpowiedzią na pytanie, czy to się opłaciło.

Jeśli interesuje cię strona techniczna — pułapki samego API Apilo: tokeny, cichy limit 512 rekordów, metody przewoźników, tagi i webhooki — opisałem je w osobnym wpisie.


Mateusz Kozłowski

Mateusz Kozłowski

Założyciel flowbiz · Ekspert automatyzacji procesów

Wdrażam automatyzacje, integracje i AI w średnich firmach na Pomorzu i w Kujawsko-Pomorskiem.

Mateusz z flowbiz - ekspert automatyzacji

Bezpłatna Konsultacja

Odzyskaj 40 godzin tygodniowo

Przeprowadzę Cię przez proces automatyzacji krok po kroku. Bez technicznego żargonu, bez ukrytych kosztów - tylko konkretne rozwiązania dla Twojej firmy.

Bezpłatny audyt procesów - znajdziemy największe wąskie gardła

Konkretny plan oszczędności - pokażemy ile zaoszczędzisz

Szybkie wdrożenie - pierwsze efekty już w tygodniu