Otwartoźródłowy klient PHP dla DPD Cloud Service Webservice (DPD Deutschland): nadawanie przesyłek i etykiety, walidacja lokalna i po stronie DPD, dwa modele śledzenia, wyszukiwarka ParcelShop i zasady odbiorów, przez SOAP i REST.
DPD to jedna z największych sieci kurierskich w Europie, a niemiecki DPD udostępnia swoją platformę nadawczą przez DPD Cloud Service Webservice - interfejs stojący za drukiem etykiet, śledzeniem paczek, wyszukiwaniem punktów ParcelShop i harmonogramem odbiorów dla niemieckich kont firmowych.
dpd-de-php to otwartoźródłowy klient PHP dla tej usługi. Obsługuje wszystkie pięć operacji przez oba transporty oferowane przez DPD - SOAP i REST - za jednym, identycznym API; waliduje zlecenia lokalnie według własnego załącznika z kodami błędów DPD, zanim cokolwiek zostanie wysłane; i jest otypowany do poziomu PHPStan 8, od danych logowania po kamienie milowe śledzenia.
W integracji z DPD łatwo nie docenić nie tego, co działa od razu, lecz dwóch par danych uwierzytelniających, dwóch zupełnie różnych modeli śledzenia, pól, które WSDL nazywa opcjonalnymi, a API odrzuca jako brakujące, oraz danych do sandboxa, których nie ma tam, gdzie wskazuje oficjalna dokumentacja. Wszystko to jest w paczce obsłużone i opisane.
Wszystkie operacje DPD Cloud Service, każda dostępna przez SOAP (domyślnie, zgodnie z żywym WSDL) oraz przez REST.
isParcelLocker().Nadanie zwraca numer paczki i PDF etykiety w tej samej odpowiedzi. Rozmiar etykiety, pozycja startowa i format wydruku są konfigurowalne per zlecenie przez typowane ustawienia.
Classic, Predict, zwroty, doręczenie i zwrot przez ParcelShop, cała rodzina Express od 8:30 do 18:00 wraz z wariantami sobotnimi, Express International oraz wycofane produkty za pobraniem zachowane dla kompletności - wszystko jako jeden enum.
DPD utrzymuje dwie niezależne usługi śledzenia i żadna nie zastępuje drugiej. Zaimplementowane są obie: strukturalna do maszyn stanów i zapisu kamieni milowych, tekstowa do wyrenderowania strony dla klienta.
Punkty odbioru po adresie albo współrzędnych, z danymi potrzebnymi, żeby je faktycznie pokazać: odległość, godziny otwarcia, zamknięcia świąteczne i usługi dostępne w danym punkcie.
Długości pól, limity wagi i reguły biznesowe DPD sprawdzane przed wywołaniem, liczone w znakach, a nie w bajtach - dokładnie tak, jak liczy je DPD - więc 35-znakowy ciąg z umlautami nie zostanie fałszywie odrzucony.
Transport przełącza się argumentem konstruktora. Kontraktu REST nie ma w PDF-ie DPD w ogóle; został odtworzony z przykładów kodu w portalu, razem z dwiema regułami budowy URL-i, których pominięcie po cichu kończy się kodem 404.
DPD egzekwuje limit wywołań na konto z dziesięciominutową karencją. Ma on własny typ wyjątku z metodą retryAfterSeconds() i celowo nie jest błędem uwierzytelniania - właściwą reakcją jest odczekanie, a nie szukanie nowych danych logowania.
Typowane DTO, enumy i udokumentowana hierarchia wyjątków od początku do końca, plus interfejs transportu, dzięki któremu cały klient da się przetestować bez ani jednego wywołania sieciowego.
Każde nadanie jest sprawdzane lokalnie wobec ograniczeń z załącznika z kodami błędów w dokumentacji DPD, a każda kontrola wskazuje błąd, któremu zapobiega. Reguły pól obejmują wagę (0-31,5 kg), limity 35 znaków dla zawartości i referencji oraz zasady adresowe DPD dla firmy, nazwiska, formy grzecznościowej, ulicy, numeru domu, miasta, kodu pocztowego, telefonu, e-maila i regionu.
Reguły biznesowe to te, które przy pierwszym spotkaniu potrafią zająć pół dnia:
Content, YourInternalID i Reference1 są w praktyce obowiązkowe, choć WSDL oznacza je jako opcjonalneUS po United StatesfindParcelShops()Walidacja lokalna jest najlepszym możliwym odwzorowaniem, a nie zamiennikiem walidacji DPD. Nie wie, czy adres istnieje ani czy produkt jest dostępny na danej relacji - od tego jest checkOrderData() i dlatego w bibliotece są obie.
DPD Cloud Service uwierzytelnia dwiema parami danych: dane partnera identyfikują samą integrację, a dane użytkownika - konto klienta DPD. Obie wydawane są osobno dla każdego środowiska, a para produkcyjna użyta wobec systemu testowego kończy się dokładnie tak samo jak nieprawidłowa.
Zdobycie dostępu do sandboxa to moment, w którym oficjalna dokumentacja aktywnie wprowadza w błąd. Strona portalu, na którą wskazuje zarówno PDF, jak i wsparcie DPD, wydaje dane do innego API - DPD Web Connect - którego formatu nie da się przełożyć na dane Cloud. Prawdziwe konto sandboxowe Cloud jest wypełnione w przykładach kodu w portalu, na stronie nieosiągalnej zwykłą nawigacją bez konkretnego parametru w adresie. README biblioteki opisuje tę drogę, żeby nikt nie musiał tracić na to dnia po raz drugi.
composer require very-code-com/dpd-de-php
$client = DpdCloudClient::sandbox('DPD Sandbox', $partnerToken, $userId, $userToken);
$result = $client->createShipment(new OrderItem(
shipAddress: new Address(
name: 'Max Mustermann', street: 'Musterstr.', houseNo: '1',
zipCode: '12345', city: 'Berlin', country: 'DE',
),
parcelShopId: 0,
parcel: new Parcel(
ShipService::Classic,
weightKg: 2.5,
content: 'Testware',
yourInternalId: 'ORDER-1',
reference1: 'ORDER-1',
),
));
echo $result->firstParcelNo(); // 01234567890123
file_put_contents('label.pdf', $result->labelPdf); // juz zdekodowany
Konfiguracja może równie dobrze pochodzić ze zmiennych środowiskowych albo z tablicy konfiguracyjnej frameworka, a klient przyjmuje własny transport i logger PSR-3 na potrzeby wstrzykiwania zależności i testów.
Sześć typów wyjątków odpowiada sześciu różnym reakcjom: walidacja lokalna, odrzucone dane logowania, limit wywołań z własną podpowiedzią czasu ponowienia, błąd biznesowy DPD niosący strukturalne identyfikatory i kody, awaria transportu oraz nieparsowalna odpowiedź. Każdy udostępnia surową odpowiedź i pełny raport diagnostyczny, gdy włączony jest tryb debug.
Continuous integration uruchamia testy jednostkowe na PHP 8.2, 8.3 i 8.4 z PHPStan na poziomie 8 przy każdym pushu i sprawdza składnię każdego przykładu. Osobny nocny workflow przepuszcza wszystkie pięć operacji przez oba transporty na żywym systemie testowym DPD, łącznie z prawdziwym nadaniem wydającym etykietę. Celowo nie jest częścią bramki na pull requestach: limit wywołań na konto zostałby przekroczony w obrębie jednego przebiegu macierzy.
Jedno ograniczenie DPD warto znać, zanim zaprojektuje się wokół niego system: nie istnieje operacja ponownego pobrania etykiety po numerze paczki. PDF zwrócony przy nadaniu to jedyny egzemplarz, jaki API kiedykolwiek wyda - więc trzeba go zapisać. Biblioteka to dokumentuje, zamiast udawać, że istnieje obejście.
Dla zespołów PHP nadających paczki przez niemieckiego DPD - sklepu drukującego etykiety przy pakowaniu, systemu ERP zamawiającego odbiory hurtowo, marketplace'u pokazującego klientom, gdzie jest paczka, albo portalu zwrotów podpowiadającego punkty nadania. Zamiast ręcznie sklejanej koperty SOAP i folderu notatek z prób i błędów, integracja staje się otypowaną paczką Composera z opisanymi kwiatkami przewoźnika.