# 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: 1. **Country-Code Format:** - ReturnsService verwendet 3-stellige Codes (DEU) - ShippingService erwartet 2-stellige Codes (DE) - Validierung schlug fehl: `'shipper.country' => 'required|string|size:2'` 2. **Fehlende Felder:** - Keine `dimensions` für V07PAK - Kein `print_format` gesetzt - Logging unzureichend ## Lösung ### 1. Country-Code Konvertierung **Neue Hilfsfunktion hinzugefügt:** ```php 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:** ```php $shipper = $this->convertAddressFor2LetterCountry($returnData['shipper']); $consignee = $this->convertAddressFor2LetterCountry($returnData['consignee']); ``` ### 2. Dimensions hinzugefügt ```php '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 ```php 'print_format' => $dhlConfig['retoure_print_format'] ?? $dhlConfig['print_format'] ?? 'A4', ``` **Priorität:** 1. `retoure_print_format` (falls konfiguriert) 2. `print_format` (allgemeines Format) 3. 'A4' (Fallback) ### 4. Erweitertes Logging ```php 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 ```php 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 ```php 'shipper.country' => 'nullable|string|min:2|max:3', // 2 oder 3 Buchstaben ``` ### ShippingService Validierung ```php '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 1. ✅ `packages/acme-laravel-dhl/src/Services/ReturnsService.php` - `createReturnViaRegularShipment()` komplett überarbeitet - `convertAddressFor2LetterCountry()` hinzugefügt - Logging verbessert 2. ✅ `app/Jobs/CreateReturnLabelJob.php` - Zusätzliches Logging hinzugefügt ## Testen ### Test-Szenario ```bash # 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 1. ✅ "Using regular Shipping API as fallback" 2. ✅ "Prepared shipment data for fallback" mit korrekten Daten 3. ✅ "Return label created via Shipping API fallback" 4. ✅ Neue Sendung in DB mit `type='return'` 5. ✅ Label-PDF herunterladbar ### Verifikation in DB ```sql 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-Sendung - `dhl_shipment_no` = Neue Tracking-Nummer - `status` = '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 `shipper` und `consignee` vorhanden? - `weight_kg` gesetzt? - `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 ```php '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 1. [ ] Return-Label mit V01PAK testen 2. [ ] Label-PDF herunterladen und prüfen 3. [ ] Tracking-Nummer testen 4. [ ] Bei Kunden testen (End-to-End) 5. [ ] Optional: V07PAK-Berechtigung bei DHL beantragen