Search by

tietge / silverstripe-shipping-dpd

moritz-sauer-13

DPD-Paketdienst für tietge/silverstripe-shipping — Etiketten über die SOAP-Webdienste von DPD Deutschland.

Package info

git.innomedia.de/Tietge/silverstripe-shipping-dpd

Type:silverstripe-vendormodule

pkg:composer/tietge/silverstripe-shipping-dpd

Statistics

Installs: 1

Dependents: 0

Suggesters: 1

1.0.0 2026-10-13 13:05 UTC

This package is auto-updated.

Last update: 2026-10-14 11:26:59 UTC


README

DPD Deutschland für tietge/silverstripe-shipping — Etiketten über die SOAP-Webdienste (Web Connect), ShipmentService/V4_5 und LoginService/V2_0.

Handgeschrieben: Es gibt kein offizielles SDK, die brauchbaren Community-Pakete sind winzig oder aufgegeben. Der Client deckt genau zwei Aufrufe ab — getAuth und storeOrders.

Status in diesem Projekt: vollständig gebaut und gegen die Stage-Umgebung verifiziert (Anmeldung, Depot, echtes Etikett mit !DEMO! und korrektem Gewicht). Produktiv fehlt allein die Kundennummer. Da der Versand auf UPS umgestellt wurde, ruht das Modul — es meldet sich nur an, wenn Zugangsdaten gepflegt sind, und steht sonst nirgends im Weg.

Installation

composer require tietge/silverstripe-shipping-dpd
vendor/bin/sake db:build --flush

Braucht ext-soap und ext-iconv.

Zugangsdaten

Tietge\Shipping\Dpd\DpdCarrier:
  sandbox: true
  delis_id: ''           # 8–10 Zeichen
  password: ''
  customer_number: ''    # Versender-Kundennummer, numerisch
  products: ['CL']
  message_language: 'de_DE'
  • DelisID und Passwort für die Sandbox stehen im Entwicklerportal (esolutions.dpd.com/entwickler/dpdwebservices.aspx) unter „Benutzerdaten ändern". Kein Antrag nötig.
  • Produktive Zugangsdaten über cit@dpd.de — und das ist keine Datenanfrage, sondern eine Abnahme: „Each development using the DPD Web Connect service must be validated and approved by DPD." Erst gegen Stage fertig werden, dann beantragen.
  • Kundennummer ≠ DelisID. Wer hier die DelisID einträgt, bekommt keinen Anmeldefehler — der Auftrag wird erst beim ersten Etikett abgelehnt.
  • Die Depotnummer wird nicht konfiguriert. Sie kommt aus der Anmeldeantwort und taucht als Präfix der Paketscheinnummer wieder auf.

Wer die Zugangsdaten aus der YAML heraushalten will, legt sie in die .env und verweist darauf — wahlweise mit Backticks oder einem _env-Schlüssel:

Tietge\Shipping\Dpd\DpdCarrier:
  delis_id: '`SS_DPD_DELIS_ID`'
  password: '`SS_DPD_PASSWORD`'
  customer_number_env: 'SS_DPD_CUSTOMER_NUMBER'
SS_DPD_DELIS_ID="…"
SS_DPD_PASSWORD="…"
SS_DPD_CUSTOMER_NUMBER="…"

Das gilt für delis_id, password und customer_number; ein <name>_env-Schlüssel hat Vorrang. Aufgelöst wird über EnvironmentConfigTrait des Basismoduls (ab 1.1) mit Environment::getEnv() — Silverstripe selbst ersetzt Backticks nur in Injector-Definitionen, nicht in der Config-API. Vorher ging die Zeichenkette samt Backticks deshalb wörtlich als Passwort an DPD. Ist die Variable nicht gesetzt, gilt die Einstellung als fehlend; der Unterreiter „DPD" nennt dann die Variable.

Ausführlich: docs/versandmodul-dpd-einrichtung.md.

Test und Produktion haben getrennte Nutzerverwaltungen: public-ws-stage.dpd.com gegenüber public-ws.dpd.com. Testetiketten tragen einen !DEMO!-Wasserdruck.

Betriebsregeln, die im Code stecken

DPDs API Developer Guidelines sind mit Sanktion formuliert: „Failure to follow these guidelines may cause an application ban." Drei Regeln schlagen unmittelbar durch:

RegelGrenzeWie das Modul damit umgeht
Anmeldungen10 pro DelisID und Tag, „calling the login service in combination with each shipment service … is specifically prohibited"Sitzung im PSR-16-Cache; das Modul zählt mit und verweigert die elfte, statt eine Sperre zu riskieren
Neuanmeldungnur bei LOGIN_5 / LOGIN_6genau diese beiden Codes lösen einen einmaligen zweiten Versuch aus
Token-Laufzeitein Geschäftstag, endet gegen 3 UhrCache läuft passend zum Geschäftstag ab; der Tageszähler ebenfalls, damit er nicht um Mitternacht zehn zusätzliche Anmeldungen freigibt
Versandaufrufe1/Sekunde, 60/Minute, 3.600/Stunde, immer nacheinanderDrossel im Client, damit eine spätere Sammelaktion sie nicht umgehen kann

Praktische Folge: Nie „Verbindung testen" in Serie drücken. Jeder Test verbraucht eine Anmeldung.

Fallstricke, die den Code prägen

Gewicht in 10-Gramm-Einheiten. 300 bedeutet 3 kg. Aus der Schemadoku: „Parcel weight in grams rounded in 10 gram units without decimal point." Ein naives „Gramm einsetzen" bucht das Zehnfache — und das fällt erst auf der Frachtrechnung auf. Am gedruckten Etikett gegengeprüft: 2450 g gesendet als weight: 245, gedruckt „2,45 kg".

HTTP 200 bedeutet nicht Erfolg. DPD legt Beanstandungen als faults in eine formal erfolgreiche Antwort — bis zu drei je Auftrag. Es kann dabei eine Paketscheinnummer ohne PDF zurückkommen; die Nummer ist dann verbraucht. Der Adapter prüft deshalb beides: keine faults und ein vorhandenes Dokument. Die verbrauchte Nummer steht in der Fehlermeldung, damit niemand später eine Sendung sucht, die es nie gab.

Elementreihenfolge ist bindend. Alles ist xsd:sequence; ein Feld an falscher Stelle liefert keinen Fachfehler, sondern einen rohen cvc-complex-type-Fault. Die Reihenfolge ist im Adapter fest kodiert, nicht aus einer Wertetabelle erzeugt.

Feldlängen: Schema ≠ Fachregel. name1, street und city erlauben im XSD 50 Zeichen, die Fachregel nennt 35 — die Schemadoku sagt es selbst. Gekürzt wird auf 35, sonst COMMON_3.

Nur ISO 8859-1 für Adressdaten. „Łódź" wird zu „Lódz", bevor es ins Envelope geht; sonst lehnt DPD mit COMMON_4 ab. Umlaute und nordische Zeichen bleiben, Latin-1 kennt sie — das ó überlebt deshalb, nur ł und ź werden umgeschrieben. Daten, die gar kein gültiges UTF-8 sind, werden vorher als Latin-1 gelesen; sonst fiele das Feld leer aus und DPD meldete einen Schemafehler statt eines Adressfehlers.

splitByParcel=true, damit das PDF immer unter parcelInformation[].output steht — ohne den Schalter liegt es je nach Fall an zwei verschiedenen Stellen im Antwortbaum.

Was DPD nicht kann

  • Kein Storno. Die deutsche ShipmentService hat in allen Fassungen (V3_2, V4_4, V4_5) genau eine Operation: storeOrders. Aus der WSDL ausgelesen, nicht vermutet. Ein Etikett verfällt, wenn das Paket nie eingeliefert wird — supportsCancellation() meldet deshalb false, und der Storno-Knopf erscheint bei DPD-Sendungen gar nicht erst.
  • Kein REST für den Versand. „The shipment service is not available via the REST interface."

Kaufmännisch offen: ob DPD je erzeugtem Etikett oder je eingeliefertem Paket abrechnet. Üblich ist Letzteres, belegt ist es nicht — und weil es kein Storno gibt, ist das der Unterschied zwischen „Fehldruck kostet nichts" und „Fehldruck kostet".

Produktkatalog

CL (DPD CLASSIC) ist der Standardfall. Gültig in V4_5: CL, E830, E12, E18, IE2, PL, MAIL, MAX. E10 und PM4 gibt es nicht mehr — die standen nur bis V4_4 im Enum.

Etikettenformat (A4 oder A6) im CMS unter Website-Einstellungen → Shop → Versand → DPD.