53 KiB
Entwicklungskonzept DHL Modul
Stand: 27.05.2026
Ziel
Diese Datei ist die aktuelle Arbeitsgrundlage fuer die Weiterentwicklung des DHL Moduls. Die bisherigen Markdown-Dateien in diesem Ordner dokumentieren abgeschlossene oder ueberholte Zwischenstaende, insbesondere den frueheren SDK-Ansatz, Paketinstallation, SSL/cURL-Fixes und einzelne abgeschlossene Entwicklungsschritte.
Aktuelle Anforderungen kommen aus docs/dhl/Anpassung DHL Modul.md:
- Internationaler Versand ausserhalb Deutschlands, insbesondere Oesterreich und Spanien.
- Freies Feld fuer Sendungsreferenz oder interne Hinweise wie "Nachlieferung".
- Adressvalidierung vor Labelerstellung, damit fehlerhafte Labels und kostenpflichtige Stornos vermieden werden.
- Storno im DHL Cockpit pruefen und stabilisieren.
- Gewicht von Kompensationsprodukten in das DHL-Paketgewicht einrechnen.
- Tracking-Mails auf Rhythmus, Ausloeser und Mehrfachversand pruefen.
- Tracking-Codes in Admin, User-Portal und User-N-Portal sichtbar machen.
- Tracking-Mail-Versand nur bei Statusaenderung.
- DHL-Umstellung von
V62WPWarenpost aufV62KPDHL Kleinpaket bis spaetestens 31.05.2026.
Aktueller technischer Stand
Das produktive Modul basiert auf dem Paket packages/acme-laravel-dhl und verwendet die DHL REST API ueber Acme\Dhl\Support\DhlClient. Die zentrale Tabelle ist dhl_package_shipments.
Wichtige produktive Einstiegspunkte:
app/Http/Controllers/DhlShipmentController.phpapp/Services/DhlShipmentService.phpapp/Services/DhlModalService.phpapp/Services/DhlDataHelper.phpapp/Services/DhlTrackingService.phppackages/acme-laravel-dhl/src/Services/ShippingService.phppackages/acme-laravel-dhl/src/Services/ReturnsService.phppackages/acme-laravel-dhl/src/Models/DhlShipment.phpconfig/dhl.php
Historische Dokumente erwaehnen teilweise alte Strukturen wie App\Models\DhlShipment, dhl_shipments oder einen konsolidierten DhlApiService. Diese Angaben sind nicht mehr massgeblich, ausser sie werden explizit in aktuellem Code noch referenziert. Aktuell gibt es genau dort noch Altlasten, die bereinigt werden muessen.
Offensichtliche Befunde
1. Produktkuerzel V62WP ist veraltet
V62WP ist weiterhin in Konfiguration, Admin-Settings, Validierung, Produktauswahl und Sprachdateien vorhanden. DHL verlangt die Umstellung auf V62KP.
Betroffene Stellen:
config/dhl.phpapp/Http/Controllers/SettingController.phpapp/Services/DhlModalService.phppackages/acme-laravel-dhl/src/Services/ShippingService.phpresources/lang/*/dhl.php
Risiko: Kleinpaket/Warenpost-Labels koennen nach der DHL-Frist abgelehnt werden.
2. Async Tracking verwendet veraltetes Model
app/Jobs/TrackShipmentJob.php importiert App\Models\DhlShipment, dieses Model existiert im aktuellen System nicht mehr. Die produktive DHL-Integration verwendet Acme\Dhl\Models\DhlShipment.
Risiko: Asynchrones Tracking bricht zur Laufzeit, sobald Queue-Tracking genutzt wird.
3. Statuswerte fuer Storno sind inkonsistent
Im Paket wird bei erfolgreichem Storno canceled gesetzt. Andere Stellen, Uebersetzungen und historische Dokumente verwenden cancelled.
Risiko: Filter, Badges, Terminal-Status, Uebersetzungen und Storno-Buttons verhalten sich uneinheitlich.
4. Storno ist technisch vorhanden, aber nicht robust genug
Storno laeuft ueber DELETE /parcel/de/shipping/v2/orders/{shipmentNumber}. Der Code prueft canCancel(), speichert aber Fehler nur begrenzt fachlich verwertbar. Produktspezifische Einschraenkungen wie Warenpost/Kleinpaket sind nicht sauber modelliert.
Risiko: Anwender sehen generische Fehler und koennen nicht erkennen, ob ein Storno produktbedingt, statusbedingt, API-bedingt oder wegen Sandbox/Production-Mismatch scheitert.
5. Internationaler Versand ist nur teilweise vorbereitet
V53PAK ist als internationales Produkt vorhanden, und einige Laender werden in 3-stellige ISO-Codes konvertiert. Dennoch gibt es keinen zentralen Produktentscheid je Zielland, keine harte Validierung nicht unterstuetzter Laender und einen gefaehrlichen Fallback auf DEU.
Risiko: Sendungen nach Oesterreich, Spanien oder weitere Laender koennen falsche Produktcodes, falsche Abrechnungsnummern oder falsche Laendercodes erhalten.
6. Adressvalidierung ist nur formal
Aktuell prueft das Modul Pflichtfelder, Hausnummern und einfache PLZ-Regeln. Eine echte Pruefung, ob Strasse, PLZ und Ort postalisch existieren, findet nicht statt.
Empfohlene Loesung: DHL/Post & DHL DATAFACTORY AUTOCOMPLETE 2.0 fuer DE/AT/CH pruefen und integrieren. Alternativen fuer breiteren Laenderumfang: Loqate, Google Address Validation oder HERE. Wichtig ist eine harte Sperre bei nicht versandfaehigen Adressen vor Labelerstellung.
7. Referenzfeld ist API-seitig vorhanden, aber nicht im Cockpit nutzbar
ShippingService kann reference nach refNo mappen. DhlDataHelper setzt aktuell automatisch Order-{id}.
Risiko: Admins koennen Hinweise wie "Nachlieferung" nicht strukturiert am Label/API-Auftrag hinterlegen.
8. Gewicht von Kompensationsprodukten fehlt
Kompensationsprodukte werden im Warenkorb mit Gewicht 0 abgelegt, damit die Kompensationslogik nicht beeinflusst wird. Das DHL-Gewicht kommt aus ShoppingOrder->weight und enthaelt dieses Produktgewicht dadurch nicht.
Risiko: DHL-Label wird mit zu geringem Paketgewicht erstellt.
9. Tracking-Mail-Logik ist grundsaetzlich brauchbar, muss aber abgesichert werden
Der Scheduler ruft stuendlich dhl:update-tracking --days=30 --send-emails auf. Statusabhaengige Intervalle verhindern zu viele API-Calls. Automatische Mails werden nur gesendet, wenn eine Sendung neu auf in_transit wechselt und noch keine Mail markiert wurde.
Risiko: Statusspruenge direkt auf out_for_delivery oder besondere DHL-Statuscodes koennen ohne Mail bleiben. Mehrere Sendungen einer Bestellung werden teils zusammengefasst, aber die fachliche Regel muss final bestaetigt werden.
Entwicklungskonzept
Phase 1: Pflichtkorrekturen vor DHL-Frist
V62WPvollstaendig aufV62KPmigrieren.- Neue Konfigurationskeys fuer
DHL_ACCOUNT_NUMBER_V62KP, Admin-Settingdhl_account_v62kp, Dimensionen und Uebersetzungen einfuehren. ShippingServiceValidierung umV62KPerweitern undV62WPentfernen oder nur noch als Legacy-Mapping fuer Altdaten anzeigen.- Bestehende Sendungen mit
V62WPhistorisch lesbar lassen, aber neue Labelerstellung blockieren. - Tests fuer Produktcode-Auswahl, Validierung und Payload-Erstellung schreiben.
Phase 2: Stabilisierung von Tracking und Storno
TrackShipmentJobauf aktuelles Model und aktuellenDhlTrackingServiceumstellen.- Statuswerte vereinheitlichen. Empfehlung: intern
canceledverwenden, Uebersetzung auf Deutsch "Storniert". TERMINAL_STATUSES, Badges, Filter und Sprachdateien entsprechend angleichen.- Storno-Fehler strukturiert speichern: HTTP-Status, DHL-Fehlercode, DHL-Detailtext, Zeitpunkt.
- Admin-Feedback verbessern: nicht stornierbar wegen Status, Produkt, API-Antwort oder nicht auffindbarer DHL-Sendung.
- Tests fuer erfolgreiche Stornierung, bereits stornierte Sendung, nicht stornierbare Sendung und API-Fehler.
Phase 3: Internationalisierung Versand
- Zentralen Service fuer Produkt-/Billing-Entscheidung einfuehren, z. B.
DhlProductResolver. - Zielland, Produktcode, Abrechnungsnummer und erlaubte Services dort validieren.
- Regeln initial:
DE:V01PAKoderV62KPAT,ESund weitere aktivierte Laender:V53PAK
- Fallback auf
DEUentfernen. Unbekannte Laender muessen mit klarer Fehlermeldung abbrechen. - Cockpit-Formular: Produkt anhand Zielland vorschlagen, aber Admin-Korrektur erlauben.
Phase 4: Adressvalidierung vor Labelerstellung
- Neuen serverseitigen Validierungsendpunkt fuer DHL-Adressen schaffen.
- Basisvalidierung behalten: Pflichtfelder, Land, PLZ-Format, Hausnummer, Packstation/Postnummer.
- DHL DATAFACTORY AUTOCOMPLETE 2.0 fuer DE/AT/CH evaluieren.
- Falls DHL fuer alle benoetigten Laender nicht ausreicht, externen Provider evaluieren.
- UI-Status einfuehren:
- gueltig: Labelerstellung erlaubt
- Warnung: Admin kann bewusst fortfahren
- Fehler: Labelerstellung gesperrt
- Validierungsergebnis optional am Shipment/Order protokollieren.
Phase 5: Referenzfeld und Admin-UX
- Neues Formularfeld
referenceodershipment_referenceim DHL Cockpit. - Wert an
DhlDataHelper::prepareOrderData()uebergeben. ShippingServicenutzt vorhandenes Mapping nachrefNo.- Referenz im Shipment speichern, damit spaeter nachvollziehbar ist, warum eine Sendung erstellt wurde.
- Laengenlimit der DHL API beachten, aktuell maximal 35 Zeichen.
Phase 6: DHL-Gewicht korrekt berechnen
- Separaten Gewichtsdienst fuer DHL einfuehren, z. B.
DhlShipmentWeightCalculator. - Basis:
ShoppingOrder->weight. - Fuer
shopping_order_itemsmitcomp > 0das Produktgewicht ausProduct->weightnachladen und addieren. - Nur DHL-Gewicht anpassen, nicht die bestehende Warenkorb-/Versandkostenlogik.
- Rundung und DHL-Grenzwerte je Produkt testen.
Phase 7: Tracking-Codes und Mails fachlich finalisieren
- Bestehende Admin-Anzeige pruefen und bei Bedarf vereinheitlichen.
- Tracking-Code-Anzeige in User-Portal und User-N-Portal ergaenzen.
- Mail-Regel final definieren:
- automatisch nur einmal pro Sendung
- nur bei relevanter Statusaenderung
- mehrere Sendungen einer Bestellung sinnvoll zusammenfassen
- Statusspruenge wie
createddirekt nachout_for_deliveryabdecken. - Command
dhl:update-trackingTests fuer Mailausloeser und Nicht-Ausloeser ergaenzen.
Phase 8: DHL-seitige Adressvalidierung ueber mustEncode / printOnlyIfCodable
Status: umgesetzt fuer deutsche Empfaengeradressen.
Ziel:
- Die bestehende formale Vorabpruefung bleibt erhalten.
- Bei der finalen DHL-Labelerstellung soll DHL selbst pruefen, ob die Adresse leitcodierbar bzw. versandfaehig ist.
- Dafuer soll der DHL-Query-Parameter
mustEncode=truegenutzt werden. printOnlyIfCodableist laut DHL-Spezifikation der Legacy-Name dieser Funktion.- Wenn DHL die Adresse ablehnt, wird kein Etikett erstellt.
- Die DHL-Fehlermeldung wird in das bestehende Modal zurueckgespiegelt, damit der Admin die Lieferadresse direkt korrigieren kann.
- Laut DHL-Beschreibung ist diese Pruefung nur fuer deutsche Empfaengeradressen relevant.
Geplanter Ablauf:
- Admin oeffnet das DHL-Erstellungsmodal.
- Die bestehende Vorabpruefung prueft weiterhin:
- Pflichtfelder
- PLZ-Format
- Produkt-/Zielland-Kombination
- Packstation-/Paketbox-Regeln
- einfache Plausibilitaet
- Beim Klick auf
Sendung jetzt erstellenwird die Sendung an DHL uebergeben. - Der DHL-Request enthaelt
mustEncode=true. - DHL erstellt das Label nur, wenn die Adresse codeable/leitcodierbar ist.
- Wenn DHL die Adresse ablehnt:
- es wird kein Shipment als erfolgreich erstellt markiert
- die DHL-Fehlermeldung wird normalisiert
- das Modal bleibt geoeffnet
- die Fehlermeldung erscheint unten in der Vorabpruefung
- der Admin kann die Adresse korrigieren und erneut pruefen/erstellen
Geplante technische Integrationspunkte:
packages/acme-laravel-dhl/src/Services/ShippingService.php- Create-Shipment-Request um den Query-Parameter
mustEncode=trueerweitern. - Legacy-Begriff
printOnlyIfCodablenur als Dokumentations-/Kompatibilitaetshinweis fuehren, nicht als neuen internen Optionsnamen verwenden. - DHL-Fehlerantworten fuer nicht codeable Adressen strukturiert auswerten.
- Create-Shipment-Request um den Query-Parameter
app/Services/DhlDataHelper.php- Option aus Konfiguration/Settings fuer die Request-Erstellung vorbereiten.
app/Services/DhlShipmentService.php- DHL-Adressfehler als fachliche Validierungsfehler behandeln, nicht als generischen Systemfehler.
app/Http/Controllers/DhlShipmentController.php- Fehlerantwort im JSON so zurueckgeben, dass das Modal sie anzeigen kann.
resources/views/admin/dhl/modal_create_shipment.blade.php- DHL-Fehler bei Labelerstellung in der bestehenden Vorabpruefungsbox anzeigen.
- Keine separate Browser-Alert-Meldung.
config/dhl.phpund/oder DHL-Settings- Einstellung z. B.
print_only_if_codeablevorbereiten. - Standard fachlich klaeren: fuer Produktion bevorzugt aktiv, fuer Tests/Sandbox ggf. konfigurierbar.
- Einstellung z. B.
Fachliche Entscheidung:
- Die formale Pruefung bleibt vor DHL bestehen, damit offensichtliche Fehler frueh im Modal sichtbar sind.
mustEncode=trueist die finale DHL-seitige Absicherung direkt bei der Labelerstellung.- Eine abgelehnte DHL-Adresse blockiert die Labelerstellung.
- Provider-Ausfall oder API-Fehler muss von einer fachlichen DHL-Adressablehnung unterscheidbar sein.
- Die Fehlermeldung soll fuer Admins handlungsorientiert sein, z. B.
DHL kann diese Adresse nicht leitcodieren. Bitte Straße, Hausnummer, PLZ und Ort pruefen. - Fuer nicht-deutsche Empfaengeradressen darf
mustEncodenicht als vollwertige externe Adressvalidierung dargestellt werden, solange DHL diese Einschraenkung in der API-Dokumentation nennt.
Offene Klaerung nach Implementierung:
- Verhalten in Sandbox und Produktion.
- Welche DHL-Status-/Fehlercodes fuer nicht codeable Adressen zurueckkommen.
- Ob
mustEncodefuer alle genutzten Produkte gilt:V01PAKV62KPV53PAK
- Ob internationale Sendungen ignoriert werden, Warnungen liefern oder anders behandelt werden.
- Ob bestehende manuelle Admin-Uebersteuerung fachlich erlaubt sein soll oder DHL-Ablehnung immer hart blockiert.
Empfohlene Reihenfolge
V62WP->V62KP, Statuswerte undTrackShipmentJobkorrigieren.- Storno stabilisieren und bessere Fehlermeldungen im Cockpit anzeigen.
- Internationalen Produktresolver einbauen.
- Referenzfeld und Gewichtskorrektur umsetzen.
- Adressvalidierung integrieren.
- Tracking-Anzeigen und Mailregeln final testen.
- DHL-seitige Adressvalidierung ueber
mustEncode=trueintegrieren, sobald API-Verhalten und Fehlerrueckgaben geklaert sind.
Teststrategie
- Feature-Tests fuer Controller-Endpunkte: Label erstellen, Storno, Tracking-Mail, Tracking-Update.
- Unit-Tests fuer Produktresolver, Gewichtskalkulation und Adressvalidierung.
- HTTP-Fakes fuer DHL API Responses inklusive Fehlerfaelle.
- Regression-Test fuer
V62KPPayload. - Command-Test fuer
dhl:update-tracking --send-emails.
Entwicklungsprotokoll
Dieser Abschnitt dokumentiert die tatsaechlich umgesetzten Entwicklungsschritte. Jede Phase wird hier nach Abschluss mit Ziel, betroffenen Dateien, fachlicher Entscheidung und Verifikation ergaenzt.
27.05.2026 - Phase 1: Pflichtkorrekturen vor DHL-Frist
Status: abgeschlossen.
Ziel:
- Neue DHL-Labels duerfen nicht mehr mit
V62WPWarenpost erstellt werden. V62KPDHL Kleinpaket wird als neues Produkt fuer nationale Kleinpaket-Sendungen eingefuehrt.- Historische Sendungen mit
V62WPbleiben im System lesbar.
Umsetzung:
config/dhl.phpDHL_ACCOUNT_NUMBER_V62KPals neuer Konfigurationskey eingefuehrt.V62KPinaccount_numbersunddimensionsaufgenommen.V62WPaus der produktiven Konfiguration fuer neue Label entfernt.
app/Http/Controllers/SettingController.php- DHL-Konfiguration liefert nun
account_numbers.V62KPunddimensions.V62KP. - Altes Datenbank-Setting
dhl_account_v62wpwird nur noch als Fallback genutzt, fallsdhl_account_v62kpnoch nicht gepflegt ist. - Altes Default-Produkt
V62WPwird beim Lesen aufV62KPnormalisiert.
- DHL-Konfiguration liefert nun
resources/views/admin/settings/index.blade.php- Admin-Auswahl fuer Standard-Produkt von
V62WP - Warenpost NationalaufV62KP - DHL Kleinpaketumgestellt. - Admin-Feld
dhl_account_v62kpeingefuehrt. - Bestehender Wert aus
dhl_account_v62wpwird im Formular als Fallback angezeigt, damit Bestandskonfigurationen nicht leer starten.
- Admin-Auswahl fuer Standard-Produkt von
app/Services/DhlModalService.php- Produktauswahl im DHL-Cockpit bietet
V62KP - DHL KleinpaketstattV62WP - DHL Warenpost Nationalan. - Fallback-Produktsatz ebenfalls auf
V62KPumgestellt.
- Produktauswahl im DHL-Cockpit bietet
packages/acme-laravel-dhl/src/Services/ShippingService.php- Validierung fuer neue Label erlaubt
V62KP. V62WPwird fuer neue Label abgelehnt.- Billing-Nummer-Aufloesung nutzt automatisch den neuen Setting-Key
dhl_account_v62kp.
- Validierung fuer neue Label erlaubt
resources/lang/de/dhl.php,resources/lang/en/dhl.php,resources/lang/es/dhl.php,resources/lang/fr/dhl.phpV62KPals DHL Kleinpaket ergaenzt.V62WPals Legacy-Anzeige belassen, damit historische Sendungen weiterhin verstaendlich dargestellt werden.
tests/Pest.php- TestCase-Bootstrapping fuer
tests/Unit/Dhlregistriert.
- TestCase-Bootstrapping fuer
tests/Unit/Dhl/ShippingServiceProductCodeTest.php- Neuer Regression-Test fuer Phase 1 ergaenzt.
Fachliche Entscheidung:
V62WPwird nicht hart aus allen Anzeigen entfernt, weil bestehende DHL-Sendungen mit diesem Produktcode historisch nachvollziehbar bleiben muessen.- Neue Labelerstellung blockiert
V62WPbewusst ueber dieShippingService-Validierung. - Eine Datenmigration fuer bestehende Settings wurde noch nicht angelegt. Stattdessen wird
dhl_account_v62wptemporaer als Fallback verwendet. Eine spaetere Migration kann den Wert dauerhaft nachdhl_account_v62kpueberfuehren.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl/ShippingServiceProductCodeTest.php- Ergebnis: 3 Tests bestanden, 5 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
Offene Folgepunkte:
- Phase 2:
TrackShipmentJobauf aktuelles DHL-Model und aktuellenDhlTrackingServiceumstellen. Erledigt am 27.05.2026. - Phase 2: Storno-Statuswerte zwischen
canceledundcancelledvereinheitlichen. Erledigt am 27.05.2026. - Optional: Migration oder Admin-Hinweis fuer das alte Setting
dhl_account_v62wp, sobald die Fallback-Phase beendet werden soll.
27.05.2026 - Phase 2: Tracking-Job und Storno-Status stabilisiert
Status: abgeschlossen fuer Tracking-Job, Statusvereinheitlichung und strukturierte Storno-Fehlerbasis.
Ziel:
- Asynchrones Tracking darf nicht mehr auf das alte, nicht mehr produktive DHL-Model
App\Models\DhlShipmentzugreifen. - Storno-Statuswerte werden intern auf
canceledvereinheitlicht. - Alte Daten mit
cancelledbleiben lesbar und filterbar. - Storno-Fehler werden fachlich verwertbarer im Shipment protokolliert.
Umsetzung:
app/Jobs/TrackShipmentJob.php- Import von
App\Models\DhlShipmentaufAcme\Dhl\Models\DhlShipmentumgestellt. - Abhaengigkeit auf den alten
DhlApiServiceentfernt. - Job nutzt nun
DhlTrackingService::updateTrackingNow()ueber Laravel-Dependency-Injection imhandle()-Methodenparameter. - Queue-Tracking fuehrt dadurch synchron innerhalb des Jobs aus und dispatcht nicht erneut rekursiv in dieselbe Queue.
- Logging verwendet jetzt
dhl_shipment_nostatt des alten/inkonsistententracking_number.
- Import von
app/Services/DhlTrackingService.phpupdateTrackingNow()ergaenzt, um Tracking bewusst ohne Queue-Dispatch auszufuehren.- Bestehender Controller-/Service-Pfad
updateTracking()bleibt unveraendert und entscheidet weiterhin anhand der DHL-Konfiguration zwischen sync/async.
packages/acme-laravel-dhl/src/Models/DhlShipment.phpcancelledals Legacy-Alias fuercanceledeingefuehrt.- Statusuebersetzung und Badge-Klasse normalisieren alte
cancelled-Werte aufcanceled. - Terminal-Statusliste enthaelt
canceledundcancelled, damit Alt-Datensaetze nicht weiter getrackt werden.
packages/acme-laravel-dhl/src/Services/ShippingService.php- Erfolgreiche Stornierung setzt weiterhin intern
status = canceled. - Erfolgreiche Storno-Antwort wird unter
api_response_data.cancellationgespeichert. - Fehlgeschlagene Stornos werden unter
api_response_data.cancellation_errorstrukturiert gespeichert:statushttp_statusdhl_codedetailexception_classoccurred_at
- Erfolgreiche Stornierung setzt weiterhin intern
app/Services/DhlShipmentService.php- Lokale Storno-Validierungsfehler wie fehlende DHL-Sendungsnummer oder nicht stornierbarer Status werden ebenfalls in
api_response_data.cancellation_errorprotokolliert. - Admin-Feedback fuer nicht stornierbaren Status nutzt die uebersetzte Statusbezeichnung.
- Lokale Storno-Validierungsfehler wie fehlende DHL-Sendungsnummer oder nicht stornierbarer Status werden ebenfalls in
app/Http/Controllers/DhlShipmentController.php- Statusfilter normalisiert
cancelledaufcanceled. - Bei Filter
canceledwerden neuecanceled- und altecancelled-Sendungen gemeinsam gefunden. - DataTable-Badges verwenden intern
canceled.
- Statusfilter normalisiert
resources/views/admin/dhl/cockpit.blade.php- Statusfilter zeigt
canceledals neuen Wert fuer "Storniert". - Alte URL-/Request-Werte mit
cancelledbleiben im Select kompatibel.
- Statusfilter zeigt
resources/views/admin/dhl/show.blade.php- Detailansicht behandelt
canceledundcancelledgleich. - Aktionsbereich wird fuer beide Storno-Statuswerte ausgeblendet.
- Detailansicht behandelt
resources/views/public/tracking.blade.php- Public-Tracking behandelt
canceledundcancelledgleich.
- Public-Tracking behandelt
resources/lang/de/dhl.php,resources/lang/en/dhl.php,resources/lang/es/dhl.php,resources/lang/fr/dhl.php- Neuer Statuskey
canceledergaenzt. - Legacy-Key
cancelledbleibt erhalten.
- Neuer Statuskey
tests/Unit/Dhl/DhlShipmentStatusTest.php- Neue Tests fuer Statusnormalisierung, Uebersetzung und Badge-Klasse.
tests/Unit/Dhl/TrackShipmentJobTest.php- Neuer Test, dass der Queue-Job den aktuellen
DhlTrackingServicenutzt.
- Neuer Test, dass der Queue-Job den aktuellen
Fachliche Entscheidung:
- Intern gilt ab jetzt
canceledals kanonischer DHL-Storno-Status. cancelledwird nicht migriert oder entfernt, weil es in bestehenden Daten/URLs/Views vorkommen kann und weiterhin verstaendlich angezeigt werden soll.- Storno-Fehler werden zunaechst in
api_response_datagespeichert, um keine neue Datenbankmigration fuer den ersten Stabilisierungsschritt zu erzwingen. Falls spaeter gezielte Admin-Auswertungen gebraucht werden, koennen dedizierte Spalten oder eine eigene Fehler-Tabelle folgen.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 6 Tests bestanden, 12 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
Offene Folgepunkte:
- Phase 2 Rest: Tests fuer echte Storno-API-Fehler mit HTTP-Fakes/Mocking weiter ausbauen.
- Phase 2 Rest: Admin-Detailanzeige fuer gespeicherte
api_response_data.cancellation_errorbei Bedarf sichtbar machen. - Phase 3: Internationalen Produkt-/Billing-Resolver einfuehren. Erledigt am 27.05.2026.
27.05.2026 - Phase 3: Internationaler Produkt- und Laenderresolver
Status: abgeschlossen fuer zentrale Produkt-/Laenderentscheidung, initiale Laenderfreigabe und harten Zielland-Fallback-Stopp.
Ziel:
- Produktcode, Zielland und DHL-Laendercode werden zentral entschieden.
- Deutschland nutzt fuer neue Label nur erlaubte nationale Produkte
V01PAKoderV62KP. - Oesterreich und Spanien nutzen initial
V53PAK. - Unbekannte oder nicht freigegebene Ziellaender duerfen nicht mehr still auf
DEUfallen. - Das DHL-Cockpit schlaegt den Produktcode anhand des Ziellands vor, laesst aber erlaubte Admin-Korrekturen zu.
Umsetzung:
app/Services/DhlProductResolver.php- Neuer zentraler Resolver fuer DHL-Produkt- und Laenderentscheidungen.
- Regeln initial:
DE: erlaubtV01PAK,V62KPAT: erlaubtV53PAKES: erlaubtV53PAK
- DHL-Laendercode-Konvertierung zentralisiert, z. B.
DE -> DEU,AT -> AUT,ES -> ESP. - Unbekannte Laendercodes loesen eine klare Exception aus statt auf Deutschland zurueckzufallen.
- Explizit falsch gewaehlte Produkt-/Laender-Kombinationen werden abgelehnt.
- Fehlende Billing-Nummern werden ueber
assertBillingNumber()fachlich klar abgebrochen.
app/Services/DhlDataHelper.php- Empfaengerland ist jetzt Pflicht fuer die DHL-Datenaufbereitung.
- Produktcode wird ueber
DhlProductResolver::resolveForShipment()bestimmt. - Der alte Empfaengerland-Fallback auf
DEwurde entfernt. - Dimensionen werden anhand des aufgeloesten Produktcodes gelesen.
packages/acme-laravel-dhl/src/Services/ShippingService.php- Payload-Erstellung nutzt den Resolver fuer Zielland und Produktcode.
- Billing-Nummer wird gegen den aufgeloesten Produktcode validiert.
convertCountryCode()nutzt den Resolver und gibt keinenDEU-Fallback mehr zurueck.- Normale Empfaengeradressen und Packstation/Paketbox-Payloads verwenden die gleiche harte Laendercode-Validierung.
app/Services/DhlModalService.php- Modal-Daten enthalten nun
productSuggestionsundselectedProductCode. - Initialer Produktvorschlag wird aus dem Zielland abgeleitet.
- Servervalidierung prueft Produkt-/Zielland-Kombinationen ueber den Resolver.
- Modal-Daten enthalten nun
resources/views/admin/dhl/modal_in_order_shipment.blade.php- Produktauswahl markiert den vorgeschlagenen Produktcode.
- Laenderoptionen tragen den ISO-Code als
data-country-code. - Hinweistext ergaenzt, dass der Produktcode anhand des Ziellands vorgeschlagen wird.
resources/views/admin/dhl/modal_create_shipment.blade.php- Bei Ziellandwechsel wird der passende Produktvorschlag automatisch gesetzt.
app/Http/Controllers/ModalController.php- Fallback-Daten fuer das DHL-Modal um Produktvorschlaege und Default-Produkt ergaenzt.
tests/Unit/Dhl/DhlProductResolverTest.php- Neue Tests fuer Deutschland, Oesterreich, Spanien, nicht freigegebene Laender, unbekannte Laendercodes und fehlende Billing-Nummern.
tests/Unit/Dhl/ShippingServiceProductCodeTest.php- Payload-Test fuer internationales Paket nach Oesterreich ergaenzt.
- Regression-Test ergaenzt, dass nicht freigegebene Laender nicht auf Deutschland fallen.
Fachliche Entscheidung:
DE,ATundESsind die initial freigegebenen DHL-Versandlaender fuer diese Phase.- Weitere Laender werden nicht implizit erlaubt, auch wenn eine ISO-Konvertierung technisch bekannt ist. Sie muessen fachlich freigegeben und im Resolver ergaenzt werden.
- Falls im Backend kein Produktcode explizit uebergeben wird, kann der Resolver fuer
AT/ESautomatischV53PAKvorschlagen. Wenn ein Admin explizit ein nicht erlaubtes Produkt waehlt, wird die Labelerstellung serverseitig abgelehnt. - Der alte
DEU-Fallback wurde bewusst entfernt, weil ein falsches Zielland zu falschen Labels und kostenpflichtigen Stornos fuehren kann.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 15 Tests bestanden, 32 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
Offene Folgepunkte:
- Phase 3 Erweiterung: Weitere Laender erst nach fachlicher Freigabe in
DhlProductResolveraufnehmen. - Phase 3 Erweiterung: Optional Admin-Setting fuer freigegebene internationale Ziellaender einfuehren.
- Phase 4: Adressvalidierung vor Labelerstellung integrieren. Erledigt als formale Basisvalidierung am 27.05.2026.
27.05.2026 - Phase 4: Formale Adressvalidierung vor Labelerstellung
Status: abgeschlossen fuer serverseitige Basisvalidierung, Warn-/Fehlerstatus und Cockpit-Vorpruefung. Externe postalische Validierung ist noch offen.
Ziel:
- Vor der Labelerstellung wird eine DHL-Adresse serverseitig bewertet.
- Offensichtlich nicht versandfaehige Adressen blockieren die Labelerstellung.
- Pruefbeduerftige Adressen erzeugen Warnungen und muessen im Cockpit bewusst bestaetigt werden.
- Packstation/Paketbox-Faelle werden strenger validiert.
- Die bestehende Labelerstellung bleibt auch serverseitig abgesichert, falls die UI-Pruefung umgangen wird.
Umsetzung:
app/Services/DhlAddressValidator.php- Neuer zentraler Validator fuer formale DHL-Adresspruefung.
- Rueckgabeformat:
status:valid,warningodererrorcan_create_label: true/falseerrorswarningsnormalized
- Blockierende Pruefungen:
- Pflichtfelder fuer Strasse, PLZ, Ort und Land.
- Name/Firma muss vorhanden sein.
- Zielland muss im
DhlProductResolverfreigegeben sein. - PLZ-Format fuer
DE,AT,ES. - Packstation/Paketbox nur fuer Deutschland.
- DHL Postnummer muss bei Packstation/Paketbox vorhanden und 6-10-stellig sein.
- Packstation-/Paketbox-Nummer muss vorhanden und 3-stellig im Bereich 100-999 sein.
- Warnungen:
- Telefonnummer fehlt.
- E-Mail-Adresse fehlt.
- Hausnummer enthaelt keine Ziffer.
- Postnummer ist gesetzt, aber Strasse/Nr. sieht nicht nach Packstation/Paketbox aus.
app/Services/DhlModalService.php- Bestehende Modal-Adresspruefung nutzt nun den neuen
DhlAddressValidator. validateShipmentData()fuehrt die Adressvalidierung auch serverseitig vor der Labelerstellung aus.
- Bestehende Modal-Adresspruefung nutzt nun den neuen
app/Http/Controllers/DhlShipmentController.php- Neuer Endpoint
validateAddress(). - Antwortet mit Status, Fehlern, Warnungen und
can_create_label. - Gibt HTTP 422 zurueck, wenn die Adresse nicht label-faehig ist.
- Neuer Endpoint
routes/domains/crm.php- Neue Route
POST /admin/dhl/validate-addressmit Nameadmin.dhl.validate-address.
- Neue Route
resources/views/admin/dhl/modal_create_shipment.blade.php- Modal ruft vor der eigentlichen Labelerstellung den neuen Validierungsendpunkt auf.
- Bei Fehlern wird die Labelerstellung blockiert.
- Bei Warnungen muss der Admin bewusst bestaetigen, bevor das Label erstellt wird.
tests/Unit/Dhl/DhlAddressValidatorTest.php- Neue Tests fuer:
- formal gueltige Adresse
- nicht freigegebenes Zielland
- falsches PLZ-Format fuer aktiviertes Land
- Warnstatus ohne Blockade
- gueltige Packstation
- ungueltige Packstation-Postnummer
- fehlende Packstation-Pflichtdaten
- Neue Tests fuer:
Fachliche Entscheidung:
- Diese Phase implementiert noch keine echte postalische Existenzpruefung von Strasse/PLZ/Ort.
- Der Validator verhindert aber bereits die teuersten formalen Fehler vor Labelerstellung.
- Warnungen blockieren nicht automatisch, weil Admins im Cockpit bewusst korrigierte oder fachlich bekannte Sonderfaelle versenden koennen sollen.
- Die spaetere Provider-Integration kann hinter dem gleichen
DhlAddressValidatorergaenzt werden.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 22 Tests bestanden, 50 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
Offene Folgepunkte:
- Phase 4 Erweiterung: DHL DATAFACTORY AUTOCOMPLETE 2.0 fuer
DE/AT/CHfachlich und technisch evaluieren. - Phase 4 Erweiterung: Falls DHL DATAFACTORY nicht fuer alle benoetigten Laender reicht, externen Provider wie Loqate, Google Address Validation oder HERE bewerten.
- Phase 4 Erweiterung: Validierungsergebnis optional dauerhaft an Shipment/Order protokollieren.
- Phase 5: Referenzfeld und Admin-UX umsetzen. Erledigt am 27.05.2026.
27.05.2026 - Phase 5: Referenzfeld und Admin-UX
Status: abgeschlossen.
Ziel:
- Admins koennen im DHL-Cockpit eine eigene Versandreferenz setzen.
- Die Referenz wird als DHL
refNoan die Shipping API uebergeben. - Die Referenz wird an der Sendung gespeichert und in der Detailansicht angezeigt.
- Das DHL-Laengenlimit von 35 Zeichen wird eingehalten.
- Ohne Admin-Eingabe bleibt der bisherige Fallback
Order-{id}erhalten.
Umsetzung:
database/migrations/2026_05_27_120253_add_reference_to_dhl_package_shipments_table.php- Neue nullable Spalte
referencemit Laenge 35 fuerdhl_package_shipments. - Migration prueft
Schema::hasColumn, damit sie robust gegen bereits vorhandene Spalten bleibt.
- Neue nullable Spalte
packages/acme-laravel-dhl/src/Models/DhlShipment.phpreferencein$fillableaufgenommen.
resources/views/admin/dhl/modal_in_order_shipment.blade.php- Neues Feld
referencein der Sendungskonfiguration. - Default-Wert:
Order-{id}. maxlength="35"und Hilfetext zum DHLrefNo.
- Neues Feld
resources/views/admin/dhl/modal_create_shipment.blade.php- Clientseitige Validierung fuer maximal 35 Zeichen ergaenzt.
app/Http/Controllers/DhlShipmentController.php- Servervalidierung fuer
referencemitmax:35. - Uebergibt
referencein die Optionen fuerDhlShipmentService.
- Servervalidierung fuer
app/Services/DhlDataHelper.php- Uebernimmt
referenceoder alternativshipment_referenceaus den Optionen. - Normalisiert Leerraum.
- Kuerzt programmgesteuert auf 35 Zeichen.
- Nutzt
Order-{id}als Fallback, wenn keine Referenz gesetzt ist.
- Uebernimmt
packages/acme-laravel-dhl/src/Services/ShippingService.php- Bestehendes Mapping nach DHL
refNobleibt aktiv. - Gesendete Referenz wird beim Erstellen des
DhlShipment-Datensatzes gespeichert.
- Bestehendes Mapping nach DHL
resources/views/admin/dhl/show.blade.php- Referenz wird in den Sendungsinformationen angezeigt.
tests/Unit/Dhl/DhlDataHelperReferenceTest.php- Neue Tests fuer Admin-Referenz, Fallback
Order-{id}und 35-Zeichen-Normalisierung.
- Neue Tests fuer Admin-Referenz, Fallback
Fachliche Entscheidung:
- Die Referenz bleibt bewusst ein kurzes Freitextfeld und wird nicht an Bestellnotizen oder interne Kommentare gekoppelt.
- Das Feld wird fuer DHL
refNound spaetere Nachvollziehbarkeit genutzt, nicht als internes Memo. - Der Fallback
Order-{id}bleibt erhalten, damit bestehende Prozesse ohne manuelle Referenz unveraendert funktionieren.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 25 Tests bestanden, 54 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
Offene Folgepunkte:
- Datenbankmigration vor Nutzung in der Zielumgebung ausfuehren.
- Phase 6: DHL-Gewicht korrekt berechnen.
27.05.2026 - Abgleich DHL Geschaeftskundenportal: Aktivierte Dienste
Status: dokumentiert als fachlicher Abgleich vor Phase 6.
Quelle:
- Screenshot aus dem DHL Geschaeftskundenportal vom 27.05.2026 mit aktivierten Produkten und Abrechnungsnummern.
Aktivierte Dienste laut Portal:
63144073550101- DHL Paket GKP63144073550701- DHL Retoure Online63144073555301- DHL Paket International GKP63144073555302- DHL Retoure Int. A63144073556201- Warenpost National / DHL Kleinpaket63144073556601- Warenpost International63144073550801- DHL Retoure MAUL
Abgleich mit aktueller Implementierung:
DHL Paket GKP- Aktueller Produktcode im Modul:
V01PAK - Konfiguriert in
config/dhl.phpalsDHL_ACCOUNT_NUMBER_V01PAK. - Wird fuer nationale Paketsendungen genutzt.
- Status: abgedeckt.
- Aktueller Produktcode im Modul:
DHL Paket International GKP- Aktueller Produktcode im Modul:
V53PAK - Konfiguriert in
config/dhl.phpalsDHL_ACCOUNT_NUMBER_V53PAK. - Wird aktuell nur fuer fachlich freigegebene Ziellaender
ATundESgenutzt. - Status: technisch abgedeckt, Laenderfreigabe bleibt bewusst begrenzt.
- Aktueller Produktcode im Modul:
Warenpost National / DHL Kleinpaket- Aktueller Produktcode im Modul:
V62KP. - Konfiguriert in
config/dhl.phpalsDHL_ACCOUNT_NUMBER_V62KP. - Ersetzt das alte
V62WP. - Status: abgedeckt.
- Aktueller Produktcode im Modul:
DHL Retoure Online- Konfiguriert in
config/dhl.phpalsDHL_ACCOUNT_NUMBER_V07PAK. - Status: Konto ist konfiguriert. Der bestehende
ReturnsServicenutzt in Teilen noch Fallback-Logik und muss vor produktiver Retourennutzung separat gegen das aktive Retoure-Konto geprueft werden.
- Konfiguriert in
DHL Retoure Int. A- Konto im Portal aktiv.
- Im Modul aktuell nicht als eigenstaendiger internationaler Retourenprozess modelliert.
- Status: offen, eigener Folgepunkt.
Warenpost International- Konto im Portal aktiv.
- Im Modul aktuell nicht freigeschaltet. Laut DHL API ist dafuer
V66WPIrelevant; dafuer sind Zoll-/CN22-Daten und eigene Gewichts-/Laenderregeln erforderlich. - Status: bewusst nicht Teil der bisherigen Phasen.
DHL Retoure MAUL- Konto im Portal aktiv.
- Im Modul aktuell nicht modelliert.
- Status: offen, nur nach fachlichem Bedarf umsetzen.
Technische Entscheidung:
- Fuer Phase 6 wird nur das Gewicht fuer die bereits freigegebenen Ausgangsprodukte betrachtet:
V01PAK,V53PAK,V62KP. - Internationale Warenpost (
V66WPI) wird nicht stillschweigend aktiviert, obwohl ein Konto im Portal sichtbar ist. Die Produktart benoetigt separate Regeln und ggf. Zollangaben. - Internationale Retouren und Retoure MAUL werden nicht mit bestehenden Paket-/Retoure-Fallbacks vermischt.
Neue Folgepunkte aus dem Portal-Abgleich:
- Retourenlogik separat gegen aktives
DHL Retoure OnlineKonto pruefen und ggf.V07PAK/Returns-API sauber modellieren. - Internationales Retourenprodukt
DHL Retoure Int. Afachlich klaeren. Warenpost International/V66WPInur als eigene Phase ergaenzen, wenn Zoll-, Gewichts- und Laenderregeln geklaert sind.DHL Retoure MAULnur bei konkretem Prozessbedarf aufnehmen.
27.05.2026 - Nachtrag vor Phase 6: Internationale Paketlaender per DHL-Settings steuerbar
Status: abgeschlossen.
Ziel:
- Kunden/Admins koennen selbst entscheiden, welche Ziellaender fuer
DHL Paket Internationalaktiv sind. - Die Freigabe erfolgt im bestehenden Settings-Bereich ueber Checkboxen.
- Der
DhlProductResolvernutzt die gespeicherten Laender dynamisch statt einer fest kodiertenAT/ES-Liste. - Deutschland bleibt separat geregelt und wird nicht als internationales Paketland gespeichert.
Umsetzung:
config/dhl.php- Neuer Fallback
international_countriesausDHL_INTERNATIONAL_COUNTRIES. - Default bleibt
AT,ES.
- Neuer Fallback
app/Http/Controllers/SettingController.phpgetDhlConfig()liefert nuninternational_countries.- Bei
DHL_CONFIG_SOURCE=envwird keine Datenbankabfrage fuer diese Liste ausgefuehrt. - Bei Datenbankprioritaet wird
dhl_international_countriesaus den Settings gelesen.
resources/views/admin/settings/index.blade.php- Neuer Checkbox-Bereich
DHL Paket International Ziellaender. - Es werden aktive App-Laender angezeigt, deren ISO-Code im DHL-Resolver bekannt ist.
- Speicherung als Setting
dhl_international_countriesvom Typobject.
- Neuer Checkbox-Bereich
app/Services/DhlProductResolver.php- Feste internationale Liste durch
getSupportedInternationalCountries()ersetzt. - Resolver liest je nach
DHL_CONFIG_SOURCEentweder Config/ENV oder Datenbank-Setting. normalizeCountryCodeList()normalisiert, dedupliziert und filtert unbekannte Codes sowieDE.- Produktvorschlaege fuer das Modal werden dynamisch aus der aktivierten Laenderliste erzeugt.
- Feste internationale Liste durch
app/Http/Controllers/ModalController.php- Fallback-Daten fuer das DHL-Modal nutzen nun ebenfalls dynamische Produktvorschlaege.
tests/Unit/Dhl/DhlProductResolverTest.php- Tests fuer konfigurierbare internationale Laender ergaenzt.
- Tests fuer Normalisierung und Filterung der Laenderliste ergaenzt.
Fachliche Entscheidung:
- Die Checkboxen aktivieren nur
V53PAKfuer DHL Paket International. V66WPIWarenpost International bleibt davon unberuehrt und wird nicht versehentlich aktiviert.DEwird nicht als internationales Zielland zugelassen, weil nationale Sendungen ueberV01PAK/V62KPlaufen.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 27 Tests bestanden, 60 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
27.05.2026 - Phase 6: DHL-Gewicht korrekt berechnen
Status: abgeschlossen.
Ziel:
- Das DHL-Labelgewicht beruecksichtigt Kompensationsprodukte.
- Die bestehende Warenkorb-, Versandkosten- und Kompensationslogik bleibt unveraendert.
- Admins koennen das Gewicht weiterhin im Modal erhoehen, aber nicht unter das berechnete DHL-Mindestgewicht druecken.
- Produktbezogene DHL-Gewichtsgrenzen werden geprueft.
Umsetzung:
app/Services/DhlShipmentWeightCalculator.php- Neuer zentraler Gewichtsdienst fuer DHL-Labelerstellung.
- Basisgewicht ist
ShoppingOrder->weightin Gramm. - Fuer
shopping_order_itemsmitcomp > 0wird das verknuepfteProduct->weightjeqtyaddiert. - Falls kein Gewicht vorhanden ist, wird ein sicherer Fallback von
1.0 kggenutzt. - Rundung erfolgt auf drei Nachkommastellen.
- Produktlimits:
V01PAK: 31.5 kgV53PAK: 31.5 kgV62KP: 1.0 kg
app/Services/DhlModalService.php- Laedt Bestellpositionen jetzt mit Produktrelation.
- Modal-Gewicht nutzt den neuen Kalkulator.
- Validierung prueft das Gewicht gegen das gewaehlte DHL-Produkt.
app/Http/Controllers/DhlShipmentController.php- Vor Labelerstellung wird das tatsaechliche Versandgewicht auf mindestens das berechnete DHL-Gewicht gesetzt.
- Ein manuell hoeheres Gewicht aus dem Formular bleibt erhalten.
app/Services/DhlShipmentService.php- Ermittelt serverseitig ebenfalls das Mindestgewicht, damit Queue- und Direktaufrufe abgesichert sind.
packages/acme-laravel-dhl/src/Services/ShippingService.php- Prueft produktbezogene DHL-Gewichtsgrenzen vor Payload-Erstellung.
resources/views/admin/dhl/modal_in_order_shipment.blade.php- Hinweistext am Gewichtsfeld stellt klar, dass Kompensationsprodukte eingerechnet sind.
tests/Unit/Dhl/DhlShipmentWeightCalculatorTest.php- Neue Tests fuer:
- Basisgewicht aus Bestellung
- Addition von Kompensationsprodukt-Gewichten
- Fallbackgewicht
V62KP-Gewichtslimit- erlaubtes Paketgewicht fuer
V01PAK
- Neue Tests fuer:
Fachliche Entscheidung:
- Die Berechnung wirkt nur auf das DHL-Labelgewicht.
ShoppingOrder->weightund die bestehende Checkout-/Versandkostenlogik werden nicht veraendert.- Kompensationsartikel werden nur dann addiert, wenn
comp > 0und ein Produktgewicht vorhanden ist. V62KPwird mit 1.0 kg begrenzt, damit Kleinpaket nicht versehentlich fuer schwerere Sendungen genutzt wird.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 32 Tests bestanden, 66 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
27.05.2026 - Phase 7: Tracking-Codes und Tracking-Mails finalisiert
Status: abgeschlossen fuer Admin/User-Anzeige und automatische Mail-Ausloesung.
Ziel:
- Tracking-Codes sind in Admin- und User-Order-Details sichtbar.
- Automatische Tracking-Mails werden nur einmal pro Sendung versendet.
- Mails werden nur bei relevanter Statusaenderung ausgeloest.
- Statusspruenge wie
createddirekt nachout_for_deliverywerden abgedeckt. - Mehrere passende Sendungen einer Bestellung werden weiterhin in einer Mail zusammengefasst.
Umsetzung:
packages/acme-laravel-dhl/src/Models/DhlShipment.php- Neue Konstante
TRACKING_EMAIL_TRIGGER_STATUSES. - Relevante automatische Mail-Statuswerte:
in_transitout_for_delivery
- Neue Methode
shouldTriggerTrackingEmail(). - Bedingung:
- aktueller Status ist relevant
- Status hat sich gegenueber dem vorherigen Status geaendert
- Tracking-Mail wurde noch nicht markiert
- Sendung hat DHL-Sendungsnummer und Empfaengeradresse
- Scope
needsTrackingEmail()nutzt die zentrale Statusliste.
- Neue Konstante
app/Console/Commands/DhlUpdateTracking.php- Automatische Mailentscheidung nutzt nun
DhlShipment::shouldTriggerTrackingEmail(). - Beim Zusammenfassen mehrerer Sendungen werden alle unbenachrichtigten Sendungen der Bestellung mit relevantem Status aufgenommen.
- Dadurch werden direkte Spruenge nach
out_for_deliverynicht mehr uebersehen.
- Automatische Mailentscheidung nutzt nun
app/Services/DhlTrackingService.php- DHL-Statusmapping erweitert:
transit,in-transit,in_transit->in_transitout-for-delivery,out_for_delivery->out_for_delivery- weitere Varianten fuer
pre_transitundfailed
- Mapping ist nun statisch nutzbar und separat testbar.
- DHL-Statusmapping erweitert:
resources/views/admin/dhl/show.blade.php- Oeffentlicher Tracking-Link nutzt nun den korrekten Query-Parameter
tracking_number.
- Oeffentlicher Tracking-Link nutzt nun den korrekten Query-Parameter
resources/views/admin/sales/_detail_dhl_shipments.blade.php- Bereits vorhandener DHL-Block wird auch in den User-Order-Modalen mit eingebunden, Aktionen bleiben ueber
isAdminabgesichert.
- Bereits vorhandener DHL-Block wird auch in den User-Order-Modalen mit eingebunden, Aktionen bleiben ueber
tests/Unit/Dhl/DhlShipmentStatusTest.php- Tests fuer Tracking-Mail-Ausloesung bei
out_for_delivery. - Tests fuer einmalige Mail-Ausloesung.
- Tests, dass
deliveredkeine neue automatische Tracking-Mail mehr ausloest. - Tests fuer DHL-Statusmapping-Varianten.
- Tests fuer Tracking-Mail-Ausloesung bei
Fachliche Entscheidung:
- Automatische Tracking-Mails werden bei
in_transitoderout_for_deliveryversendet. deliveredloest keine neue automatische Tracking-Mail aus, weil die Benachrichtigung dann fachlich zu spaet waere und Mehrfachmails vermieden werden sollen.- Manuelles erneutes Senden im Admin bleibt weiterhin moeglich.
- Mehrere Sendungen einer Bestellung werden zusammengefasst, sofern sie noch keine Tracking-Mail erhalten haben und einen relevanten Status besitzen.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 38 Tests bestanden, 74 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
27.05.2026 - Nachtrag Phase 7: Tracking-E-Mail-Historie in der Detailansicht
Status: abgeschlossen.
Ziel:
- In der DHL-Detailansicht soll nicht nur der letzte Tracking-Mail-Status sichtbar sein.
- Es soll nachvollziehbar sein, welche Tracking-E-Mails mit welchem Sendungsstatus versendet wurden.
- Automatische und manuelle Versendungen sollen unterscheidbar bleiben.
- Zusammengefasste Tracking-Mails sollen zeigen, welche Sendungen enthalten waren.
Umsetzung:
packages/acme-laravel-dhl/src/Models/DhlShipment.phpmarkTrackingEmailSent()erweitert.- Bei jedem Versand wird ein Eintrag in
api_response_data.tracking_email_historygeschrieben. - Gespeicherte Felder je Eintrag:
sent_attype(autoodermanual)recipient_emailstatustracking_statusdhl_shipment_noincluded_shipment_ids
- Neue Methode
getTrackingEmailHistory()liefert die Historie mit neuestem Eintrag zuerst. - Neue statische Methode
getStatusBadgeClassFor()fuer Status-Badges in historischen Eintraegen.
app/Http/Controllers/DhlShipmentController.php- Manueller Tracking-Mail-Versand uebergibt Empfaenger und enthaltene Sendungen an
markTrackingEmailSent().
- Manueller Tracking-Mail-Versand uebergibt Empfaenger und enthaltene Sendungen an
app/Console/Commands/DhlUpdateTracking.php- Automatischer Tracking-Mail-Versand uebergibt Empfaenger und enthaltene Sendungen an
markTrackingEmailSent().
- Automatischer Tracking-Mail-Versand uebergibt Empfaenger und enthaltene Sendungen an
resources/views/admin/dhl/show.blade.php- Bereich
Tracking-E-Mail Statuszeigt weiterhin den letzten Versand prominent an. - Darunter wird eine Historientabelle angezeigt mit:
- Zeitpunkt
- Typ
- Status zum Versandzeitpunkt
- Empfaenger
- enthaltene Sendungs-IDs
- Bereich
tests/Unit/Dhl/DhlShipmentStatusTest.php- Tests fuer Tracking-Mail-Historie mit neuestem Eintrag zuerst.
- Test fuer Legacy-Sendungen ohne Historie.
Fachliche Entscheidung:
- Die Historie wird im bestehenden
api_response_dataJSON der Sendung gespeichert, damit keine neue Tabelle notwendig ist. - Die bestehenden Felder
tracking_email_sent_atundtracking_email_typebleiben fuer schnelle Anzeige und bestehende Logik erhalten. - Historische Sendungen, die nur die alten Felder besitzen, bleiben kompatibel und zeigen weiterhin den letzten Versandstatus.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 40 Tests bestanden, 79 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
27.05.2026 - Nachtrag: Modale Vorabpruefung vor Labelerstellung
Status: abgeschlossen.
Ziel:
- Vor der finalen DHL-Labelerstellung soll im bestehenden Erstellungsmodal eine sichtbare Vorabpruefung erscheinen.
- Der Admin soll Produktcode, nationale/internationale Sendungsart, Zielland und Lieferadressstatus sehen.
- Fehler blockieren die Labelerstellung; Warnungen bleiben sichtbar und muessen bewusst bestaetigt werden.
Umsetzung:
app/Http/Controllers/DhlShipmentController.php- Der bestehende Endpoint
validateAddress()liefert nun zusaetzlich strukturiertepreflight-Daten. - Die Produktpruefung nutzt
DhlProductResolver. - Fehler aus Produkt-/Zielland-Kombinationen werden gemeinsam mit Adressfehlern zurueckgegeben.
- Der bestehende Endpoint
app/Services/DhlProductResolver.php- Neue Methoden
getProductScope()undgetProductScopeLabel(). - Dadurch kann die UI Produktcodes fachlich als national oder international anzeigen.
- Neue Methoden
resources/views/admin/dhl/modal_in_order_shipment.blade.php- Neuer Statusbereich
Vorabpruefung vor Labelerstellung. - Der Statusbereich sitzt am Ende des Formulars direkt vor den Aktionsbuttons.
- Initialer Buttontext:
Vorabpruefung durchfuehren.
- Neuer Statusbereich
app/Services/DhlAddressValidator.php- Die Lieferadresse wird zusaetzlich auf plausible Feldinhalte geprueft.
- Offensichtlich ungueltige Werte bei Straße, PLZ oder Ort fuehren jetzt zu Fehlern statt nur zu einer positiven Formalpruefung.
- Fuer DE, AT und CH ist eine formale DACH-Pruefung hinterlegt.
- Diese umfasst Pflichtfelder, PLZ-Format, Plausibilitaet, Platzhalter-/Testdaten und Packstation-Regeln.
- DACH-Hausnummern ohne Ziffer werden als Fehler blockiert.
- Die UI weist nun ausdruecklich darauf hin, dass keine echte DHL-/Adressdatenbank- oder Leitcodepruefung angebunden ist.
- Fuer unterstuetzte Ziellaender ohne landesspezifische Pruefung wird ein Hinweis auf die reine Basis-Adresspruefung ausgegeben.
resources/views/admin/dhl/modal_create_shipment.blade.php- Der erste Klick fuehrt nur die Vorabpruefung aus.
- Die separate Browser-Alert-Fehlermeldung bei Vorpruefungsfehlern wurde entfernt.
- Der Validierungsstatus zeigt nun
Formale DACH-Pruefungstatt irrefuehrendAktiv. - Das Ergebnis wird direkt im Modal angezeigt:
- Produktcode
- Sendungsart
- Zielland
- normalisierte Lieferadresse
- Status der Adressvalidierung
- Fehler und Hinweise
- Erst nach erfolgreicher Vorabpruefung wechselt der Button auf
Sendung jetzt erstellen. - Aenderungen an Formularfeldern setzen die Freigabe automatisch zurueck.
tests/Unit/Dhl/DhlProductResolverTest.php- Neuer Test fuer nationale und internationale Produktklassifizierung.
tests/Unit/Dhl/DhlAddressValidatorTest.php- Neuer Test fuer unplausible Lieferadressfelder.
- Neue Tests fuer CH-Adressvalidierung und Basispruefungs-Hinweise.
- Neue Tests fuer Platzhalteradressen und DACH-Hausnummern ohne Ziffer.
Fachliche Entscheidung:
- Die bestehende Servervalidierung bleibt die Quelle der Wahrheit.
- Die Vorabpruefung ersetzt keine Validierung bei der finalen Erstellung; vor dem Erstellen wird nochmals gegen denselben Endpoint geprueft.
- Dadurch werden nachtraegliche Formularaenderungen oder veraltete Modalzustande nicht ungeprueft an DHL uebergeben.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 46 Tests bestanden, 109 Assertions.
- IDE/Linter-Pruefung der geaenderten Dateien:
- Ergebnis: keine Fehler.
27.05.2026 - Phase 8: DHL-seitige Adressvalidierung ueber mustEncode
Status: umgesetzt fuer deutsche Empfaengeradressen.
Ziel:
- DHL soll selbst die finale Adress-/Leitcodefaehigkeit pruefen.
- Grundlage ist der DHL-Query-Parameter
mustEncode=true. printOnlyIfCodableist laut DHL-Spezifikation der Legacy-Name.- Wenn diese Option gesetzt ist, soll DHL das Etikett nur dann erstellen, wenn die Adresse codeable/leitcodierbar ist.
- Wird die Adresse von DHL abgelehnt, soll der Fehler im bestehenden Modal erscheinen und dort korrigierbar sein.
- Laut DHL-Dokumentation ist die Funktion nur fuer deutsche Empfaengeradressen relevant.
Umsetzung:
- Die aktuelle formale Vorabpruefung bleibt erhalten.
config/dhl.php- Neue Option
print_only_if_codeable, steuerbar ueberDHL_PRINT_ONLY_IF_CODEABLE. - Standard: aktiv.
- Neue Option
app/Http/Controllers/SettingController.php- DHL-Konfiguration liefert
print_only_if_codeable.
- DHL-Konfiguration liefert
resources/views/admin/settings/index.blade.php- Neue Checkbox
DHL-Leitcodierung erzwingen (mustEncode).
- Neue Checkbox
app/Services/DhlDataHelper.php- Option wird in die Orderdaten fuer den DHL-Request uebernommen.
packages/acme-laravel-dhl/src/Services/ShippingService.php- Fuer deutsche Empfaengeradressen wird bei aktiver Option der Query-Parameter
mustEncode=truean die DHL Create-Shipment-Operation uebergeben. - DHL-Responses ohne Label/Shipment oder mit Item-Fehlerstatus werden vor dem Speichern der Sendung abgefangen.
- Nicht leitcodierbare Adressen werden als
DhlAddressValidationExceptionnormalisiert.
- Fuer deutsche Empfaengeradressen wird bei aktiver Option der Query-Parameter
packages/acme-laravel-dhl/src/Exceptions/DhlAddressValidationException.php- Neue fachliche Exception fuer DHL-Adressablehnungen.
app/Services/DhlShipmentService.php- DHL-Adressablehnungen werden als Validierungsfehler zurueckgegeben.
- Wenn Queue aktiv ist, aber
mustEncodefuer eine deutsche Empfaengeradresse greift, wird synchron erstellt, damit der DHL-Fehler direkt im Modal sichtbar bleibt.
app/Http/Controllers/DhlShipmentController.php- Gibt DHL-Adressvalidierungsfehler mit HTTP 422 zurueck.
resources/views/admin/dhl/modal_create_shipment.blade.php- Fehler aus der finalen DHL-Erstellung werden in der bestehenden Vorabpruefungsbox angezeigt.
- Keine separate Browser-Alert-Meldung.
Offene Punkte:
- DHL-Sandbox-Verhalten testen.
- Fehlercodes fuer nicht codeable Adressen sammeln.
- Produktabdeckung fuer
V01PAK,V62KPundV53PAKklaeren. - Klaeren, wie internationale Sendungen behandelt werden, da DHL
mustEncodeals nur fuer deutsche Empfaengeradressen relevant beschreibt.
Verifikation:
./vendor/bin/pint --dirty --format agentphp artisan test --compact tests/Unit/Dhl- Ergebnis: 49 Tests bestanden, 115 Assertions.
Legacy-Dokumentation
Die bisherigen Markdown-Dateien wurden nach dev/dhl-modul/legacy verschoben. Sie bleiben als Historie erhalten, sind aber nicht mehr die aktuelle Arbeitsgrundlage.