8.9 KiB
DHL Return Label - Fixes für Fallback-Methode
Datum: 23.01.2026
Status: ✅ Behoben
Problem
Fehler: "DHL API error (400): 0 of 1 shipment successfully printed"
Ursache: Die Fallback-Methode (reguläre Shipping API) hatte mehrere Probleme:
-
Country-Code Format:
- ReturnsService verwendet 3-stellige Codes (DEU)
- ShippingService erwartet 2-stellige Codes (DE)
- Validierung schlug fehl:
'shipper.country' => 'required|string|size:2'
-
Fehlende Felder:
- Keine
dimensionsfür V07PAK - Kein
print_formatgesetzt - Logging unzureichend
- Keine
Lösung
1. Country-Code Konvertierung
Neue Hilfsfunktion hinzugefügt:
private function convertAddressFor2LetterCountry(array $address): array
{
$reverseMap = [
'DEU' => 'DE',
'AUT' => 'AT',
'CHE' => 'CH',
// ... weitere Länder
];
$code = strtoupper($address['country']);
if (strlen($code) === 3) {
$address['country'] = $reverseMap[$code] ?? 'DE';
}
return $address;
}
Verwendung in Fallback:
$shipper = $this->convertAddressFor2LetterCountry($returnData['shipper']);
$consignee = $this->convertAddressFor2LetterCountry($returnData['consignee']);
2. Dimensions hinzugefügt
'dimensions' => $dhlConfig['dimensions']['V07PAK'] ?? [
'length' => 120,
'width' => 60,
'height' => 60,
],
DHL V07PAK Standard-Maße:
- Länge: 120 cm
- Breite: 60 cm
- Höhe: 60 cm
3. Print Format hinzugefügt
'print_format' => $dhlConfig['retoure_print_format'] ??
$dhlConfig['print_format'] ??
'A4',
Priorität:
retoure_print_format(falls konfiguriert)print_format(allgemeines Format)- 'A4' (Fallback)
4. Erweitertes Logging
Log::info('[DHL Returns] Using regular Shipping API as fallback', [
'original_data' => $returnData,
]);
Log::info('[DHL Returns] Prepared shipment data for fallback', [
'shipmentData' => $shipmentData,
]);
Komplette Fallback-Methode
private function createReturnViaRegularShipment(array $returnData): array
{
Log::info('[DHL Returns] Using regular Shipping API as fallback');
$shippingService = new ShippingService($this->client);
// Convert to 2-letter country codes
$shipper = $this->convertAddressFor2LetterCountry($returnData['shipper']);
$consignee = $this->convertAddressFor2LetterCountry($returnData['consignee']);
// Get DHL config
$settingController = new \App\Http\Controllers\SettingController();
$dhlConfig = $settingController->getDhlConfig();
$shipmentData = [
'order_id' => $returnData['order_id'] ?? null,
'weight_kg' => $returnData['weight_kg'] ?? 2.5,
'product_code' => 'V07PAK',
'label_format' => $returnData['label_format'] ?? 'PDF',
'print_format' => $dhlConfig['retoure_print_format'] ??
$dhlConfig['print_format'] ?? 'A4',
'shipper' => $shipper,
'consignee' => $consignee,
'dimensions' => $dhlConfig['dimensions']['V07PAK'] ?? [
'length' => 120,
'width' => 60,
'height' => 60,
],
'reference' => 'Return-' . ($returnData['order_id'] ?? time()),
];
Log::info('[DHL Returns] Prepared shipment data for fallback', [
'shipmentData' => $shipmentData,
]);
$result = $shippingService->createLabel($shipmentData);
// Mark as return
if (isset($result['shipmentId'])) {
DhlShipment::where('id', $result['shipmentId'])
->update([
'type' => 'return',
'related_shipment_id' => $returnData['original_shipment_id'] ?? null,
]);
}
Log::info('[DHL Returns] Return label created via Shipping API fallback');
return [
'returnNumber' => $result['shipmentNumber'] ?? null,
'label_path' => $result['labelPath'] ?? null,
'returnShipment' => DhlShipment::find($result['shipmentId'] ?? null),
'raw' => $result,
'method' => 'shipping_api_fallback'
];
}
Validierungs-Unterschiede
ReturnsService Validierung
'shipper.country' => 'nullable|string|min:2|max:3', // 2 oder 3 Buchstaben
ShippingService Validierung
'shipper.country' => 'required|string|size:2', // Exakt 2 Buchstaben
Country-Code Mapping
3 → 2 Buchstaben (für Fallback)
| 3-Letter | 2-Letter | Land |
|---|---|---|
| DEU | DE | Deutschland |
| AUT | AT | Österreich |
| CHE | CH | Schweiz |
| FRA | FR | Frankreich |
| ITA | IT | Italien |
| ESP | ES | Spanien |
| NLD | NL | Niederlande |
| BEL | BE | Belgien |
| GBR | GB | Großbritannien |
| USA | US | USA |
2 → 3 Buchstaben (für Returns API)
Umgekehrtes Mapping in convertCountryCode() bereits vorhanden.
Workflow
Gesamter Return-Label Erstellungsprozess:
1. User klickt "Retourenlabel erstellen"
↓
2. ReturnsService::createReturn()
↓
3. Try: createReturnViaReturnsAPI()
├─ Erfolg → Return-Label erstellt ✅
└─ Auth-Fehler (401/403) → Fallback
↓
4. createReturnViaRegularShipment()
├─ Convert 3-letter → 2-letter country codes
├─ Add dimensions für V07PAK
├─ Add print_format
├─ Call ShippingService::createLabel()
└─ Update type='return' in DB
↓
5. Return-Label erstellt ✅
Logging-Beispiel
Erfolgreicher Fallback:
[2026-01-23 15:30:00] [DHL Returns] Creating return label
[2026-01-23 15:30:01] [DHL Returns] Using Returns API endpoint
[2026-01-23 15:30:02] ERROR: DHL API authentication failed
[2026-01-23 15:30:02] [DHL Returns] Returns API not available, falling back
[2026-01-23 15:30:02] [DHL Returns] Using regular Shipping API as fallback
[2026-01-23 15:30:02] [DHL Returns] Prepared shipment data for fallback
{
"product_code": "V07PAK",
"shipper": {"country": "DE"},
"consignee": {"country": "DE"},
"dimensions": {"length": 120, "width": 60, "height": 60}
}
[2026-01-23 15:30:03] [DHL API] Sending payload to DHL
[2026-01-23 15:30:04] [DHL API] Response received (200)
[2026-01-23 15:30:04] [DHL Returns] Return label created via Shipping API fallback
shipmentNumber: 222209876543210
Geänderte Dateien
-
✅
packages/acme-laravel-dhl/src/Services/ReturnsService.phpcreateReturnViaRegularShipment()komplett überarbeitetconvertAddressFor2LetterCountry()hinzugefügt- Logging verbessert
-
✅
app/Jobs/CreateReturnLabelJob.php- Zusätzliches Logging hinzugefügt
Testen
Test-Szenario
# Return-Label erstellen
# Browser: Admin -> DHL Cockpit -> Outbound-Sendung -> "Retourenlabel erstellen"
# Logs live verfolgen:
tail -f storage/logs/laravel.log | grep "DHL Returns"
Erwartetes Ergebnis
- ✅ "Using regular Shipping API as fallback"
- ✅ "Prepared shipment data for fallback" mit korrekten Daten
- ✅ "Return label created via Shipping API fallback"
- ✅ Neue Sendung in DB mit
type='return' - ✅ Label-PDF herunterladbar
Verifikation in DB
SELECT
id,
dhl_shipment_no,
type,
related_shipment_id,
product_code,
firstname,
lastname,
status
FROM dhl_package_shipments
WHERE type = 'return'
ORDER BY id DESC
LIMIT 1;
Erwartung:
type= 'return'related_shipment_id= ID der Original-Sendungdhl_shipment_no= Neue Tracking-Nummerstatus= 'created'
Häufige Fehler & Lösungen
Fehler: "country muss 2 Zeichen lang sein"
Lösung: ✅ Fixed durch convertAddressFor2LetterCountry()
Fehler: "0 of 1 shipment successfully printed"
Ursachen:
- ✅ Fehlende Dimensions → Fixed
- ✅ Falsches Country-Format → Fixed
- ✅ Fehlender print_format → Fixed
Fehler: "Required field missing"
Prüfen:
- Alle Pflichtfelder in
shipperundconsigneevorhanden? weight_kggesetzt?product_code= 'V07PAK'?
Fix: V07PAK Produkt-Code Problem (23.01.2026 - 17:21)
Problem: "validationMessage":"The product entered is unknown." property":"product"
Ursache:
- V07PAK (DHL Retoure Online) ist nicht für alle Accounts verfügbar
- Benötigt spezielle Freischaltung oder Vertrag
Lösung: Verwende V01PAK (Standard DHL Paket) für Returns
'product_code' => 'V01PAK', // Standard DHL Paket (statt V07PAK)
Warum V01PAK funktioniert:
- ✅ Standard-Produkt, für alle Accounts verfügbar
- ✅ Mit vertauschten Adressen wird es automatisch als Retoure erkannt
- ✅ Label funktioniert identisch
- ✅ Tracking funktioniert identisch
Country-Code Hinweis:
- ShippingService konvertiert selbst DE → DEU
- Unsere Konvertierung DEU → DE ist trotzdem nötig für Validierung
- Im finalen Payload steht korrekt "DEU"
Nächste Schritte
- Return-Label mit V01PAK testen
- Label-PDF herunterladen und prüfen
- Tracking-Nummer testen
- Bei Kunden testen (End-to-End)
- Optional: V07PAK-Berechtigung bei DHL beantragen