Jeden z najbardziej upierdliwych efektów ubocznych integracji między systemami to duplikaty. Ta sama faktura zaksięgowana dwa razy, to samo zamówienie wysyłane dwa razy, ten sam klient w CRM w trzech kartotekach. Wygląda banalnie — dopóki nie zaczniesz liczyć godzin marnowanych na sprzątanie i pieniędzy na dodatkowe kuriery.
Duplikaty nie biorą się z tego, że „system się głupio pomylił". Biorą się z bardzo konkretnego mechanizmu, o którym nikt nie mówi na demo. I na szczęście da się je wyeliminować bez wymiany całej integracji — pod warunkiem, że rozumiesz, skąd tak naprawdę wychodzą.
Dlaczego integracje robią duplikaty
Klasyczna integracja między dwoma systemami — powiedzmy sklepem internetowym i ERP — działa mniej więcej tak: sklep wysyła do ERP komunikat „mam nowe zamówienie nr 12345". ERP potwierdza „przyjąłem". Jedno zamówienie, jedno potwierdzenie, koniec tematu.
Problem zaczyna się, kiedy potwierdzenie nie dotrze. Sieć chrupnęła na sekundę, ERP przez chwilę nie odpowiadał, timeout, cokolwiek. Sklep nie wie, czy zamówienie zostało przyjęte, czy nie. Ma dwa wyjścia: albo uznać, że nie zostało (i wysłać jeszcze raz), albo uznać, że zostało (i zostawić w spokoju). Prawie zawsze wybiera to pierwsze — bo lepiej wysłać dwa razy niż zgubić zamówienie klienta.
I tu robi się duplikat. ERP tak naprawdę przyjął pierwszą próbę — tylko odpowiedź nie dotarła. Druga próba trafia do niego jak zupełnie nowe zamówienie. Nic go nie powstrzymuje przed zapisaniem obu.
Ten sam mechanizm potrafi zadziałać na dowolnym styku systemów: bank → ERP, ERP → WMS, kurier → sklep, POS → księga. Wszędzie tam, gdzie „ktoś wysyła, ktoś odbiera, a między nimi jest sieć", która czasami się dławi.
Klucz idempotencyjny — koncept w trzech zdaniach
Rozwiązanie ma techniczną nazwę — idempotencja — i brzmi trudniej niż jest w praktyce. Chodzi o to, żeby wysłać tę samą operację dziesięć razy i mieć pewność, że efekt będzie taki, jakbyś wysłał ją raz. Jak włącznik światła: pierwsze naciśnięcie zapala, kolejne dziewięć nic nie zmieniają.
W praktyce robi się to tak: nadawca (sklep, kurier, bank) dokleja do każdej operacji unikalny numer — nazywamy go kluczem idempotencyjnym. Odbiorca (ERP, WMS) zapamiętuje, że taki klucz już widział. Jeśli przyjdzie drugi raz — po prostu odpowiada „mam, dzięki" i nic nie duplikuje. Ten sam mechanizm stosuje np. Stripe czy PayU do transakcji płatniczych.
To jedna z tych rzeczy, które trzeba zaprojektować przy budowie integracji — dopisanie tego po fakcie kosztuje więcej. Ale wykonalne jest zawsze.
Przykład: hurtownia części motoryzacyjnych
U jednego z naszych klientów — 22-osobowej hurtowni części motoryzacyjnych z Wielkopolski — sytuacja wyglądała tak. Comarch Optima jako ERP, BaseLinker jako most do Allegro i sklepu Shoper, prosty WMS na magazynie. Zamówienia z Allegro szły do Optimy przez BaseLinker, a z Optimy schodziły na magazyn do wysyłki.
Średnio 14 duplikatów zamówień miesięcznie. Nie tragedia w skali obrotu, ale konkretny problem operacyjny. Księgowa spędzała ok. 6 godzin miesięcznie na wyszukiwaniu i stornowaniu duplikatów. Magazynier co jakiś czas wysyłał tę samą paczkę dwa razy — koszt kuriera plus czas na odzyskanie towaru od klienta plus rozmowa telefoniczna „bardzo przepraszamy". Klienci dwa razy widzieli obciążenie karty i chwytali za telefon. W skali roku uzbierało się kilkanaście godzin pracy zarządu poświęconych na przeprosiny.
Diagnoza zajęła nam pół dnia z logów. BaseLinker wysyłał zamówienia do Optimy przez pośrednika (własne middleware, które ktoś napisał 4 lata wcześniej i odszedł z firmy). Middleware przy timeoutach powtarzało próbę — bez żadnego znacznika, że to ta sama operacja. Optima z chęcią przyjmowała drugą kopię.
Poprawka była nudna: do middleware dodaliśmy klucz idempotencyjny oparty o id_zamowienia_BaseLinker + data_utworzenia. Optima dostała prosty widok bazodanowy, który sprawdzał, czy taki klucz już przeszedł. Do tego — jako bezpiecznik na wcześniejsze grzechy — nocny job szukający identycznych zamówień w oknie 24 godzin i wysyłający alert.
Przez kolejne 3 miesiące — 0 duplikatów. Nudne, ale skuteczne.
Co możesz zrobić w tym tygodniu
Nawet jeśli nie masz jeszcze budżetu na zmianę integracji, można ograniczyć szkody prostymi krokami:
- Zmierz skalę problemu. Zapytaj księgowość, ile stornowanych faktur i zamówień było w ostatnim kwartale. Dopóki nie masz liczby, nikt tego nie potraktuje poważnie.
- Włącz alerty. Zwykły raport „zamówienia od tego samego klienta na tę samą kwotę w oknie 15 minut" wychwyci większość duplikatów zanim schodzą na magazyn. Da się to postawić w Optimie/enova/Subiekcie na raporcie w SQL.
- Ustaw regułę w BaseLinkerze/Selly/podobnych. Wiele mostów ma ustawienie „nie wysyłaj tego samego zamówienia ponownie przez X minut". Domyślnie bywa wyłączone.
- Zapytaj dostawcę middleware o klucz idempotencyjny. Jeśli integrację robił ktoś zewnętrzny, to jest jedno pytanie: „czy w waszym kodzie jest idempotency key na tej integracji?". Jeśli usłyszysz „a co to jest?", masz odpowiedź, dlaczego macie duplikaty.
- Nie próbuj naprawiać tego w ERP. To warstwa middleware/mostu jest odpowiedzialna za jednorazowe dostarczenie. Wtykanie logiki dedu do ERP kończy się bałaganem w regułach księgowych.
Kiedy zawołać kogoś od integracji
Jeśli po tych krokach nadal wpadają duplikaty — albo integracja robi cały ciąg pochodnych szkód (podwójne rezerwacje magazynowe, podwójne wysyłki, podwójne noty korygujące) — to znak, że warto dołożyć klucz idempotencyjny na dobre. To nie jest rewolucja: dla większości integracji między popularnymi systemami (Comarch Optima, enova365, Subiekt GT, Microsoft Dynamics AX, BaseLinker, Shoper, WooCommerce) da się to zrobić w kilka dni roboczych, bez dotykania samych systemów źródłowych.
Duplikaty są nudne. Ale koszt ich obsługi rośnie wraz z obrotem — i w pewnym momencie kosztują więcej niż zbudowanie integracji od nowa.
Idempotencja to jedna z tych rzeczy, o których nie mówi się na demo, a które decydują, czy Twoja integracja rok później będzie zbawieniem, czy stałym źródłem korekt.