20-02-2026
This commit is contained in:
parent
a8b395e20d
commit
a00c42e770
252 changed files with 28785 additions and 8907 deletions
93
dev/2026-01-22/dhl-cancellation-info.md
Normal file
93
dev/2026-01-22/dhl-cancellation-info.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# DHL Sendungs-Stornierung - Troubleshooting
|
||||
|
||||
## Problem: "RF-UndefinedResource" Fehler
|
||||
|
||||
### Aktuelle Situation:
|
||||
- **Config:** Sandbox-Modus aktiv (`DHL_SANDBOX=true`)
|
||||
- **Base URL:** `https://api-sandbox.dhl.com`
|
||||
- **Sendung:** ID 11, Nr. `0034043333301020021021115`
|
||||
- **Status:** `created` (stornierbar)
|
||||
- **Fehler:** "RF-UndefinedResource"
|
||||
|
||||
### Ursachen:
|
||||
|
||||
#### 1. **Sandbox-Einschränkungen**
|
||||
Im DHL Sandbox-Modus:
|
||||
- Sendungen sind nur für begrenzte Zeit verfügbar
|
||||
- Test-Sendungen werden nach kurzer Zeit automatisch gelöscht
|
||||
- Stornierung ist nur innerhalb weniger Stunden möglich
|
||||
|
||||
#### 2. **Zeitfenster überschritten**
|
||||
- Sendung erstellt: `2026-01-23 13:08:07`
|
||||
- Wenn mehr als 2-3 Stunden vergangen: Nicht mehr stornierbar
|
||||
|
||||
#### 3. **Sandbox vs. Production Mismatch**
|
||||
- Sendung im Sandbox erstellt
|
||||
- Versuch im Production-Modus zu stornieren (oder umgekehrt)
|
||||
|
||||
### Lösungen:
|
||||
|
||||
#### Option 1: Neue Test-Sendung erstellen
|
||||
```bash
|
||||
# Neue Sendung erstellen und SOFORT stornieren (innerhalb von Minuten)
|
||||
# Im DHL Cockpit: Neue Sendung erstellen → Sofort Storno-Button klicken
|
||||
```
|
||||
|
||||
#### Option 2: Production-Modus testen (nur mit echten Credentials!)
|
||||
```env
|
||||
# .env
|
||||
DHL_SANDBOX=false
|
||||
DHL_BASE_URL=https://api-eu.dhl.com
|
||||
DHL_API_KEY=<production_key>
|
||||
DHL_USERNAME=<production_user>
|
||||
DHL_PASSWORD=<production_password>
|
||||
```
|
||||
|
||||
#### Option 3: Status manuell setzen (nur für Entwicklung)
|
||||
```bash
|
||||
php artisan tinker
|
||||
```
|
||||
```php
|
||||
$shipment = Acme\Dhl\Models\DhlShipment::find(11);
|
||||
$shipment->update(['status' => 'canceled']);
|
||||
```
|
||||
|
||||
### Empfehlung:
|
||||
|
||||
**Für Sandbox-Tests:**
|
||||
1. Sendung erstellen
|
||||
2. **SOFORT** (innerhalb von 1-2 Minuten) stornieren
|
||||
3. Nicht länger warten
|
||||
|
||||
**Für Production:**
|
||||
- Stornierung funktioniert zuverlässig innerhalb von 24 Stunden
|
||||
- Sendungen bleiben länger in der API verfügbar
|
||||
|
||||
### Debug-Commands:
|
||||
|
||||
```bash
|
||||
# Prüfe Sendung
|
||||
php artisan tinker --execute="
|
||||
\$s = Acme\Dhl\Models\DhlShipment::find(11);
|
||||
echo 'Status: ' . \$s->status . PHP_EOL;
|
||||
echo 'Created: ' . \$s->created_at . PHP_EOL;
|
||||
echo 'Age: ' . \$s->created_at->diffForHumans() . PHP_EOL;
|
||||
"
|
||||
|
||||
# Prüfe Config
|
||||
php artisan tinker --execute="
|
||||
\$c = (new \App\Http\Controllers\SettingController())->getDhlConfig();
|
||||
echo 'Mode: ' . (\$c['base_url'] == 'https://api-sandbox.dhl.com' ? 'SANDBOX' : 'PRODUCTION') . PHP_EOL;
|
||||
"
|
||||
```
|
||||
|
||||
### Workaround für alte Sandbox-Sendungen:
|
||||
|
||||
Da alte Sandbox-Sendungen nicht mehr storniert werden können, setzen wir den Status manuell:
|
||||
|
||||
```php
|
||||
// Alle alten "created" Sendungen als "failed" markieren
|
||||
Acme\Dhl\Models\DhlShipment::where('status', 'created')
|
||||
->where('created_at', '<', now()->subHours(6))
|
||||
->update(['status' => 'failed']);
|
||||
```
|
||||
362
dev/2026-01-22/dhl-return-label-info.md
Normal file
362
dev/2026-01-22/dhl-return-label-info.md
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
# DHL Return Label (Retourenlabel) - Dokumentation
|
||||
|
||||
## 📦 Übersicht
|
||||
|
||||
Die Return Label Funktionalität ermöglicht es, automatisch Retourenlabels für ausgehende DHL-Sendungen zu erstellen.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
| Feature | Status | Beschreibung |
|
||||
|---------|--------|--------------|
|
||||
| **Button in allen Views** | ✅ | Überall wo DHL Sendungen angezeigt werden |
|
||||
| **Sync/Async Modus** | ✅ | Basierend auf `DHL_USE_QUEUE` Config |
|
||||
| **Adress-Tausch** | ✅ | Kunde wird Absender, Lager wird Empfänger |
|
||||
| **Duplikat-Prüfung** | ✅ | Nur ein Retourenlabel pro Sendung |
|
||||
| **Nur für Outbound** | ✅ | Nur für ausgehende Sendungen verfügbar |
|
||||
| **Package Integration** | ✅ | Nutzt neues `acme-laravel-dhl` Package |
|
||||
|
||||
---
|
||||
|
||||
## 📍 Button Standorte
|
||||
|
||||
### **1. Bestelldetails**
|
||||
```
|
||||
Admin → Bestellungen → Bestellung öffnen
|
||||
→ DHL Sendungen Block → Aktionen
|
||||
|
||||
[👁️] [📥] [🔄] [✉️] [🔙] [❌]
|
||||
↑
|
||||
Return Label Button
|
||||
```
|
||||
|
||||
### **2. DHL Cockpit**
|
||||
```
|
||||
Admin → DHL → Cockpit
|
||||
→ DataTable → Aktionen-Spalte
|
||||
|
||||
Gleiche Buttons wie in Bestelldetails
|
||||
```
|
||||
|
||||
### **3. DHL Detail-Seite**
|
||||
```
|
||||
Admin → DHL → Sendung öffnen
|
||||
→ Aktionsbereich oben
|
||||
|
||||
[🔙 Retourenlabel erstellen]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Button-Bedingungen
|
||||
|
||||
Der Button wird **nur** angezeigt wenn:
|
||||
|
||||
✅ `type` = 'outbound' (ausgehende Sendung)
|
||||
✅ Keine Retoure existiert (`returns->count()` = 0)
|
||||
✅ Admin-Bereich (nicht in User-Views)
|
||||
|
||||
```php
|
||||
@if($shipment->type === 'outbound' && !$shipment->returns->count())
|
||||
<button class="btn btn-outline-info dhl-create-return-btn">
|
||||
<i class="fas fa-undo"></i>
|
||||
</button>
|
||||
@endif
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Workflow
|
||||
|
||||
### **Synchroner Modus** (`DHL_USE_QUEUE=false`)
|
||||
|
||||
```
|
||||
1. Admin klickt "Retourenlabel erstellen"
|
||||
2. Bestätigung: "Möchten Sie ein Retourenlabel erstellen?"
|
||||
3. → JA
|
||||
4. Button: "⏳ Wird erstellt..."
|
||||
5. API-Request direkt an DHL
|
||||
6. ✅ Erfolg: "Retourenlabel wurde erfolgreich erstellt!"
|
||||
7. Seite lädt neu
|
||||
8. Neue Retoure ist sichtbar
|
||||
```
|
||||
|
||||
### **Asynchroner Modus** (`DHL_USE_QUEUE=true`)
|
||||
|
||||
```
|
||||
1. Admin klickt "Retourenlabel erstellen"
|
||||
2. Bestätigung: "Möchten Sie ein Retourenlabel erstellen?"
|
||||
3. → JA
|
||||
4. Button: "⏳ Wird erstellt..."
|
||||
5. Job wird in Queue gestellt
|
||||
6. ✅ Erfolg: "Retourenlabel wird im Hintergrund erstellt"
|
||||
7. Seite lädt neu
|
||||
8. Worker verarbeitet Job
|
||||
9. Retoure wird erstellt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technische Details
|
||||
|
||||
### **Controller-Methode**
|
||||
```php
|
||||
// app/Http/Controllers/DhlShipmentController.php
|
||||
public function createReturnLabel(Request $request, DhlShipment $shipment): JsonResponse
|
||||
{
|
||||
// Validierung
|
||||
if ($shipment->type !== 'outbound') { ... }
|
||||
if (existingReturn) { ... }
|
||||
|
||||
// Sync oder Async basierend auf Config
|
||||
if ($useQueue) {
|
||||
CreateReturnLabelJob::dispatch($shipment, $options);
|
||||
} else {
|
||||
$result = $this->createReturnLabelSync($shipment);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Job-Klasse**
|
||||
```php
|
||||
// app/Jobs/CreateReturnLabelJob.php
|
||||
class CreateReturnLabelJob implements ShouldQueue
|
||||
{
|
||||
public function handle(): void
|
||||
{
|
||||
// DHL Client initialisieren
|
||||
$dhlClient = new DhlClient(...);
|
||||
$shippingService = new ShippingService($dhlClient);
|
||||
|
||||
// Return Label Daten vorbereiten (Adressen getauscht)
|
||||
$returnData = $this->prepareReturnLabelData($dhlConfig);
|
||||
|
||||
// Label erstellen
|
||||
$result = $shippingService->createLabel($returnData);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **Adress-Tausch**
|
||||
|
||||
Bei Return Labels werden die Adressen **automatisch getauscht**:
|
||||
|
||||
| Feld | Ausgehende Sendung | Retoure |
|
||||
|------|-------------------|---------|
|
||||
| **Shipper (Absender)** | Unser Lager | **Kunde** |
|
||||
| **Consignee (Empfänger)** | **Kunde** | Unser Lager |
|
||||
|
||||
```php
|
||||
// Shipper: Kunde sendet zurück (aus original recipient)
|
||||
'shipper' => [
|
||||
'name' => 'Max Mustermann',
|
||||
'street' => 'Hauptstraße',
|
||||
'postalCode' => '12345',
|
||||
'city' => 'Berlin',
|
||||
...
|
||||
],
|
||||
|
||||
// Consignee: Unser Lager empfängt (aus DHL settings)
|
||||
'consignee' => [
|
||||
'name' => 'mivita care gmbh',
|
||||
'street' => 'Leinfeld',
|
||||
'postalCode' => '87755',
|
||||
'city' => 'Kirchhaslach',
|
||||
...
|
||||
],
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Validierung & Fehlerbehandlung
|
||||
|
||||
### **Validierungs-Checks**
|
||||
|
||||
```php
|
||||
// 1. Nur für ausgehende Sendungen
|
||||
if ($shipment->type !== 'outbound') {
|
||||
return 'Retourenlabels können nur für ausgehende Sendungen erstellt werden.';
|
||||
}
|
||||
|
||||
// 2. Keine doppelte Retoure
|
||||
$existingReturn = DhlShipment::where('related_shipment_id', $shipment->id)
|
||||
->where('type', 'return')
|
||||
->first();
|
||||
|
||||
if ($existingReturn) {
|
||||
return 'Für diese Sendung existiert bereits ein Retourenlabel.';
|
||||
}
|
||||
```
|
||||
|
||||
### **Fehlerbehandlung**
|
||||
|
||||
| Szenario | Verhalten |
|
||||
|----------|-----------|
|
||||
| API Timeout | Job wird wiederholt (3x) |
|
||||
| Ungültige Adresse | Fehler + Log-Eintrag |
|
||||
| Netzwerkfehler | Job wird wiederholt |
|
||||
| 3 Fehlversuche | `failed()` Methode aufgerufen |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Database Structure
|
||||
|
||||
### **Retoure-Beziehung**
|
||||
|
||||
```sql
|
||||
-- Ausgehende Sendung
|
||||
id: 123
|
||||
type: 'outbound'
|
||||
related_shipment_id: NULL
|
||||
|
||||
-- Zugehörige Retoure
|
||||
id: 456
|
||||
type: 'return'
|
||||
related_shipment_id: 123 -- Verknüpfung zur Original-Sendung
|
||||
```
|
||||
|
||||
### **Model-Beziehungen**
|
||||
|
||||
```php
|
||||
// In DhlShipment Model
|
||||
public function returns(): HasMany
|
||||
{
|
||||
return $this->hasMany(self::class, 'related_shipment_id');
|
||||
}
|
||||
|
||||
public function relatedShipment(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(self::class, 'related_shipment_id');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testen
|
||||
|
||||
### **Test 1: Retourenlabel erstellen (Sync)**
|
||||
```bash
|
||||
# 1. .env setzen
|
||||
DHL_USE_QUEUE=false
|
||||
|
||||
# 2. Label erstellen für Bestellung
|
||||
Admin → Bestellung #45078 → DHL Label erstellen
|
||||
|
||||
# 3. Return Label erstellen
|
||||
→ Bestellung öffnen
|
||||
→ DHL Sendungen Block
|
||||
→ Button "🔙" klicken
|
||||
→ Bestätigen
|
||||
→ ✅ Retoure sollte sofort erscheinen
|
||||
```
|
||||
|
||||
### **Test 2: Retourenlabel erstellen (Async)**
|
||||
```bash
|
||||
# 1. .env setzen
|
||||
DHL_USE_QUEUE=true
|
||||
|
||||
# 2. Queue Worker starten
|
||||
php artisan queue:work
|
||||
|
||||
# 3. Label erstellen
|
||||
Admin → Bestellung #45078 → Button "🔙" klicken
|
||||
|
||||
# 4. Queue prüfen
|
||||
→ Worker-Log anschauen
|
||||
→ Retoure sollte nach wenigen Sekunden erscheinen
|
||||
```
|
||||
|
||||
### **Test 3: Duplikat-Prüfung**
|
||||
```bash
|
||||
# 1. Retoure erstellen (wie Test 1)
|
||||
# 2. Erneut Button "🔙" klicken
|
||||
# → Fehler: "Für diese Sendung existiert bereits ein Retourenlabel."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Logs
|
||||
|
||||
### **Erfolgreiche Erstellung**
|
||||
```
|
||||
[DHL Controller] Return label creation job dispatched
|
||||
- original_shipment_id: 123
|
||||
- shipment_number: 00340433333...
|
||||
|
||||
[DHL Queue] Return label created successfully
|
||||
- original_shipment_id: 123
|
||||
- return_shipment_number: 00340433444...
|
||||
```
|
||||
|
||||
### **Fehler**
|
||||
```
|
||||
[DHL Queue] Return label creation failed
|
||||
- original_shipment_id: 123
|
||||
- error: "DHL API error: Invalid address"
|
||||
- attempt: 1/3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Konfiguration
|
||||
|
||||
### **Queue-Modus**
|
||||
```env
|
||||
# .env
|
||||
DHL_USE_QUEUE=true # Async (empfohlen für Produktion)
|
||||
DHL_USE_QUEUE=false # Sync (für Testing)
|
||||
```
|
||||
|
||||
### **Queue-Name**
|
||||
```php
|
||||
// Normal Priority
|
||||
$job->onQueue('dhl-returns');
|
||||
|
||||
// High Priority
|
||||
$options['priority'] = 'high';
|
||||
$job->onQueue('high-priority');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Routes
|
||||
|
||||
```php
|
||||
// routes/domains/crm.php
|
||||
Route::post('/shipment/{shipment}/return-label',
|
||||
'DhlShipmentController@createReturnLabel')
|
||||
->name('admin.dhl.create-return');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Betroffene Dateien
|
||||
|
||||
| Datei | Änderung |
|
||||
|-------|----------|
|
||||
| `app/Http/Controllers/DhlShipmentController.php` | `createReturnLabel()` + `createReturnLabelSync()` |
|
||||
| `app/Jobs/CreateReturnLabelJob.php` | Aktualisiert für neues Package |
|
||||
| `resources/views/admin/sales/_detail_dhl_shipments.blade.php` | Button + JavaScript Handler |
|
||||
| `resources/views/admin/dhl/show.blade.php` | Button aktiviert |
|
||||
| `resources/views/admin/dhl/cockpit.blade.php` | Button funktioniert bereits |
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checkliste
|
||||
|
||||
- [x] Button in allen DHL Views
|
||||
- [x] JavaScript Handler implementiert
|
||||
- [x] Controller-Methode mit Sync/Async
|
||||
- [x] Job für Queue-Verarbeitung
|
||||
- [x] Adress-Tausch korrekt
|
||||
- [x] Validierung & Fehlerbehandlung
|
||||
- [x] Duplikat-Prüfung
|
||||
- [x] Logging implementiert
|
||||
- [x] Dokumentation erstellt
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Fertig!
|
||||
|
||||
Die Return Label Funktionalität ist vollständig implementiert und einsatzbereit!
|
||||
295
dev/2026-01-22/dhl-tracking-emails.md
Normal file
295
dev/2026-01-22/dhl-tracking-emails.md
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
# DHL Tracking E-Mails - Erweiterte Funktionen
|
||||
|
||||
## 📧 Mehrere Sendungen in einer E-Mail
|
||||
|
||||
### Problem gelöst:
|
||||
Wenn eine Bestellung in **mehrere Pakete** aufgeteilt wird, erhalten Kunden jetzt **eine gesammelte E-Mail** mit allen Tracking-Nummern, statt mehrere einzelne E-Mails.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Neue Features
|
||||
|
||||
### 1. **Automatische Zusammenfassung**
|
||||
Alle Sendungen einer Bestellung werden automatisch in einer E-Mail zusammengefasst:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Deine 3 Sendungen sind unterwegs! │
|
||||
├─────────────────────────────────────┤
|
||||
│ │
|
||||
│ Paket 1 │
|
||||
│ Sendungsnummer: 00340433333... │
|
||||
│ [Sendung bei DHL verfolgen] │
|
||||
│ │
|
||||
│ Paket 2 │
|
||||
│ Sendungsnummer: 00340433334... │
|
||||
│ [Sendung bei DHL verfolgen] │
|
||||
│ │
|
||||
│ Paket 3 │
|
||||
│ Sendungsnummer: 00340433335... │
|
||||
│ [Sendung bei DHL verfolgen] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2. **Intelligente Versand-Logik**
|
||||
- ✅ Sammelt alle Sendungen einer Bestellung
|
||||
- ✅ Versendet eine E-Mail pro Bestellung (nicht pro Paket)
|
||||
- ✅ Markiert alle Sendungen als versendet
|
||||
- ✅ Verhindert doppelte E-Mails
|
||||
|
||||
### 3. **Manuelle Versand-Option**
|
||||
Im Admin unter **DHL Cockpit** oder **Bestelldetails**:
|
||||
- Button "Tracking-E-Mail senden" klicken
|
||||
- Sendet automatisch **alle** Sendungen der Bestellung
|
||||
- Zeigt Anzahl der Sendungen in der Bestätigung
|
||||
|
||||
### 4. **Test-Modus für Cronjob**
|
||||
Testen Sie E-Mails, bevor sie an Kunden gehen!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Verwendung
|
||||
|
||||
### Manuelle E-Mail versenden (Admin)
|
||||
|
||||
#### Option 1: Aus Bestelldetails
|
||||
1. Bestellung öffnen
|
||||
2. DHL Sendungen-Block scrollen
|
||||
3. Button "📧" klicken
|
||||
4. Alle Sendungen dieser Bestellung werden versendet
|
||||
|
||||
#### Option 2: Aus DHL Cockpit
|
||||
1. DHL Cockpit öffnen
|
||||
2. Sendung finden
|
||||
3. Button "📧" klicken
|
||||
4. Alle Sendungen dieser Bestellung werden versendet
|
||||
|
||||
### Automatischer Cronjob
|
||||
|
||||
#### Standard (täglich 06:00 Uhr)
|
||||
```bash
|
||||
# Läuft automatisch via Cron
|
||||
# Definiert in: app/Console/Kernel.php
|
||||
```
|
||||
|
||||
#### Manuell ausführen
|
||||
```bash
|
||||
# Normale Ausführung
|
||||
php artisan dhl:update-tracking --send-emails
|
||||
|
||||
# Mit Test-E-Mail
|
||||
php artisan dhl:update-tracking --send-emails --test-email=admin@example.com
|
||||
|
||||
# Für bestimmte Bestellung
|
||||
php artisan dhl:update-tracking --send-emails --order=45078
|
||||
|
||||
# Dry-Run (keine Änderungen)
|
||||
php artisan dhl:update-tracking --send-emails --dry-run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Test-Optionen
|
||||
|
||||
### Option 1: Test-E-Mail an eigene Adresse
|
||||
```bash
|
||||
php artisan dhl:update-tracking --send-emails --test-email=meine@email.de
|
||||
```
|
||||
✅ Sendet E-Mails an angegebene Adresse statt an Kunden
|
||||
✅ Perfekt zum Testen des Layouts und Inhalts
|
||||
✅ Markiert Sendungen TROTZDEM als versendet
|
||||
|
||||
### Option 2: Dry-Run (Simulation)
|
||||
```bash
|
||||
php artisan dhl:update-tracking --send-emails --dry-run
|
||||
```
|
||||
✅ Simuliert alle Aktionen
|
||||
✅ Sendet KEINE E-Mails
|
||||
✅ Markiert Sendungen NICHT als versendet
|
||||
✅ Zeigt was passieren würde
|
||||
|
||||
### Option 3: Bestimmte Bestellung testen
|
||||
```bash
|
||||
php artisan dhl:update-tracking --send-emails --order=45078 --test-email=test@example.com
|
||||
```
|
||||
✅ Nur für eine Order-ID
|
||||
✅ An Test-Adresse
|
||||
✅ Perfekt für gezielte Tests
|
||||
|
||||
---
|
||||
|
||||
## 📊 Versand-Status in Bestelldetails
|
||||
|
||||
### Anzeige
|
||||
Für jede Sendung wird angezeigt:
|
||||
|
||||
| Sendung | Status | Tracking | **E-Mail** | Aktionen |
|
||||
|---------|--------|----------|------------|----------|
|
||||
| #11 | created | - | ✅ 23.01.2026<br>🤖 Automatisch | 👁️ 📥 📧 |
|
||||
| #12 | in_transit | ... | ✅ 23.01.2026<br>👤 Manuell | 👁️ 📥 🔄 📧 |
|
||||
| #13 | created | - | ⏳ Nicht gesendet | 👁️ 📥 📧 |
|
||||
|
||||
### Informationen
|
||||
- **✅ Datum**: Wann wurde E-Mail versendet
|
||||
- **🤖 Automatisch**: Via Cronjob versendet
|
||||
- **👤 Manuell**: Über Admin-Button versendet
|
||||
- **⏳ Nicht gesendet**: Noch keine E-Mail
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Technische Details
|
||||
|
||||
### Datenbank-Felder
|
||||
```sql
|
||||
-- dhl_package_shipments Tabelle
|
||||
tracking_email_sent_at TIMESTAMP NULL -- Wann versendet
|
||||
tracking_email_type VARCHAR(20) -- 'auto' oder 'manual'
|
||||
```
|
||||
|
||||
### Mail-Klasse
|
||||
```php
|
||||
// Unterstützt jetzt Collection von Shipments
|
||||
new MailDhlTracking($shipments, $order)
|
||||
|
||||
// Oder einzelne Sendung (backward compatible)
|
||||
new MailDhlTracking($shipment, $order)
|
||||
```
|
||||
|
||||
### Logik
|
||||
```php
|
||||
// Sammelt alle Sendungen einer Bestellung
|
||||
$allShipments = DhlShipment::where('order_id', $order->id)
|
||||
->whereNotNull('dhl_shipment_no')
|
||||
->whereIn('status', ['created', 'in_transit', 'out_for_delivery'])
|
||||
->get();
|
||||
|
||||
// Sendet eine E-Mail mit allen Sendungen
|
||||
Mail::to($email)->send(new MailDhlTracking($allShipments, $order));
|
||||
|
||||
// Markiert alle als versendet
|
||||
foreach ($allShipments as $shipment) {
|
||||
$shipment->markTrackingEmailSent('manual');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Anwendungsfälle
|
||||
|
||||
### Fall 1: Mehrere Pakete bei Erstellung
|
||||
```
|
||||
1. Admin erstellt 3 Labels für Order #45078
|
||||
2. Alle 3 Labels werden erstellt (Status: created)
|
||||
3. Cronjob läuft (06:00 Uhr)
|
||||
4. Status wird aktualisiert (created → in_transit)
|
||||
5. EINE E-Mail mit allen 3 Sendungen wird versendet
|
||||
```
|
||||
|
||||
### Fall 2: Nachträgliches Label
|
||||
```
|
||||
1. Order #45078 hat bereits 2 Labels (E-Mail bereits versendet)
|
||||
2. Admin erstellt 3. Label
|
||||
3. Admin klickt "📧" Button
|
||||
4. NEUE E-Mail mit allen 3 Sendungen wird versendet
|
||||
```
|
||||
|
||||
### Fall 3: Test vor Produktiv-Einsatz
|
||||
```bash
|
||||
# 1. Test mit eigener E-Mail
|
||||
php artisan dhl:update-tracking --send-emails --test-email=admin@firma.de
|
||||
|
||||
# 2. Prüfen der E-Mail
|
||||
# 3. Bei OK: Cronjob aktivieren (läuft automatisch)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Konfiguration
|
||||
|
||||
### Cronjob-Einstellung
|
||||
```php
|
||||
// app/Console/Kernel.php
|
||||
$schedule->command('dhl:update-tracking --days=14 --send-emails')
|
||||
->dailyAt('06:00')
|
||||
->withoutOverlapping()
|
||||
->runInBackground();
|
||||
```
|
||||
|
||||
### Anpassungen
|
||||
```php
|
||||
// Andere Uhrzeit
|
||||
->dailyAt('08:00')
|
||||
|
||||
// Nur Werktage
|
||||
->weekdays()->at('06:00')
|
||||
|
||||
// Nur wenn Sendungen vorhanden
|
||||
->when(function() {
|
||||
return DhlShipment::active()->count() > 0;
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Übersetzungen
|
||||
|
||||
Neue Übersetzungs-Keys in `resources/lang/{de,en,es}/email.php`:
|
||||
|
||||
```php
|
||||
'dhl_tracking_subject_multiple' => 'Deine :count Sendungen sind unterwegs'
|
||||
'dhl_tracking_message_multiple' => 'Deine Bestellung wurde in :count Paketen versendet'
|
||||
'dhl_tracking_package_label' => 'Paket :number'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Vorteile
|
||||
|
||||
| Vorher | Nachher |
|
||||
|--------|---------|
|
||||
| 3 Pakete = 3 E-Mails | 3 Pakete = 1 E-Mail |
|
||||
| Kunde verwirrt | Kunde hat Überblick |
|
||||
| Einzelne Tracking-Nummern | Alle Nummern auf einen Blick |
|
||||
| Manuell testen schwierig | Test-Modus integriert |
|
||||
| Kein Überblick über Versand | Klare Anzeige in Admin |
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Problem: E-Mail wird nicht versendet
|
||||
```bash
|
||||
# Prüfen ob Sendungen vorhanden
|
||||
php artisan tinker
|
||||
>>> Acme\Dhl\Models\DhlShipment::active()->count()
|
||||
|
||||
# Prüfen ob E-Mail-Adresse vorhanden
|
||||
>>> $order = App\Models\ShoppingOrder::find(45078);
|
||||
>>> $order->shopping_user->email
|
||||
```
|
||||
|
||||
### Problem: Mehrfache E-Mails
|
||||
```bash
|
||||
# Prüfen welche Sendungen noch keine E-Mail haben
|
||||
php artisan tinker
|
||||
>>> Acme\Dhl\Models\DhlShipment::whereNull('tracking_email_sent_at')->count()
|
||||
```
|
||||
|
||||
### Problem: Test-E-Mail kommt nicht an
|
||||
```bash
|
||||
# Queue prüfen
|
||||
php artisan queue:work --once
|
||||
|
||||
# Logs prüfen
|
||||
tail -f storage/logs/laravel.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
Bei Fragen zur Implementierung siehe:
|
||||
- `/dev/22-01-2026/next-steps.md` - Vollständige Dokumentation
|
||||
- `app/Console/Commands/DhlUpdateTracking.php` - Command-Code
|
||||
- `app/Mail/MailDhlTracking.php` - Mail-Klasse
|
||||
- `resources/views/emails/dhl_tracking.blade.php` - E-Mail Template
|
||||
2302
dev/2026-01-22/next-steps.md
Normal file
2302
dev/2026-01-22/next-steps.md
Normal file
File diff suppressed because it is too large
Load diff
161
dev/2026-01-22/packstation-anleitung.md
Normal file
161
dev/2026-01-22/packstation-anleitung.md
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
# DHL Packstation / Paketbox - Korrekte Eingabe
|
||||
|
||||
## ❌ HÄUFIGER FEHLER
|
||||
|
||||
**Fehler:** `Packstation-Nummer muss eine 3-stellige Zahl zwischen 100 und 999 sein`
|
||||
|
||||
**Ursache:** Die Packstation-NUMMER (am Gerät) wird mit der DHL Postnummer (Kundennummer) verwechselt!
|
||||
|
||||
---
|
||||
|
||||
## ✅ KORREKTE EINGABE
|
||||
|
||||
### Was ist was?
|
||||
|
||||
| Feld | Was eintragen | Beispiel | Wo zu finden |
|
||||
|------|---------------|----------|--------------|
|
||||
| **DHL Postnummer** | 6-10-stellige Kundennummer | `1234567890` | DHL App / Registrierung |
|
||||
| **Straße / Nr.** | Packstation + 3-stellige Nummer | `Packstation 145` | Gelbes Schild am Gerät |
|
||||
| **PLZ / Ort** | Standort der Packstation | `12345 Berlin` | Gelbes Schild am Gerät |
|
||||
|
||||
---
|
||||
|
||||
## 📋 SCHRITT-FÜR-SCHRITT ANLEITUNG
|
||||
|
||||
### 1. DHL Postnummer (oben im Formular)
|
||||
```
|
||||
✅ Richtig: 1234567890
|
||||
✅ Richtig: 123456
|
||||
❌ Falsch: 145 (das ist die Packstation-Nummer!)
|
||||
```
|
||||
|
||||
### 2. Lieferadresse → Straße / Nr.
|
||||
```
|
||||
✅ Richtig: Packstation 145
|
||||
✅ Richtig: Paketbox 278
|
||||
❌ Falsch: Packstation 12345 (zu lang!)
|
||||
❌ Falsch: Packstation (Nummer fehlt!)
|
||||
```
|
||||
|
||||
### 3. Lieferadresse → PLZ / Ort
|
||||
```
|
||||
✅ Richtig: 33739 Bielefeld (Standort der Packstation)
|
||||
❌ Falsch: 10115 Berlin (Ihre Wohnadresse)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 WO FINDE ICH DIE NUMMERN?
|
||||
|
||||
### Packstation-Nummer (3-stellig: 100-999)
|
||||
📍 **Am gelben DHL-Schild** auf dem Packstation-Gerät
|
||||
```
|
||||
┌─────────────────────────┐
|
||||
│ DHL Packstation │
|
||||
│ Nr. 145 │ ← DIESE NUMMER!
|
||||
│ Hauptstraße 1 │
|
||||
│ 12345 Beispielstadt │
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
### DHL Postnummer (6-10-stellig)
|
||||
📱 **In der DHL App** unter "Mein Konto" → "Postnummer"
|
||||
🌐 **Auf dhl.de** nach der Registrierung
|
||||
📧 **Per E-Mail** nach Aktivierung
|
||||
|
||||
---
|
||||
|
||||
## 💡 BEISPIELE
|
||||
|
||||
### Beispiel 1: Standard Packstation
|
||||
```
|
||||
[Formular]
|
||||
DHL Postnummer: 1234567890
|
||||
──────────────────────────────
|
||||
Straße / Nr.: Packstation 145
|
||||
PLZ: 33739
|
||||
Ort: Bielefeld
|
||||
```
|
||||
|
||||
### Beispiel 2: Paketbox
|
||||
```
|
||||
[Formular]
|
||||
DHL Postnummer: 9876543210
|
||||
──────────────────────────────
|
||||
Straße / Nr.: Paketbox 278
|
||||
PLZ: 10115
|
||||
Ort: Berlin
|
||||
```
|
||||
|
||||
### Beispiel 3: Kurze Postnummer (auch gültig)
|
||||
```
|
||||
[Formular]
|
||||
DHL Postnummer: 123456
|
||||
──────────────────────────────
|
||||
Straße / Nr.: Packstation 500
|
||||
PLZ: 80331
|
||||
Ort: München
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ HÄUFIGE FEHLER & LÖSUNGEN
|
||||
|
||||
| Fehler | Problem | Lösung |
|
||||
|--------|---------|--------|
|
||||
| "lockerID must be 100-999" | Packstation-Nummer zu lang/kurz | Nur 3 Ziffern eingeben (z.B. "145") |
|
||||
| "postNumber must be 6-10 digits" | Postnummer zu kurz/lang | 6-10 Ziffern, keine Leerzeichen |
|
||||
| "RF-UndefinedResource" | Packstation existiert nicht | PLZ & Ort der Packstation prüfen |
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ TECHNISCHE DETAILS (für Entwickler)
|
||||
|
||||
### DHL API v2 Locker Schema
|
||||
```json
|
||||
{
|
||||
"consignee": {
|
||||
"name": "Max Mustermann",
|
||||
"lockerID": 145, // Integer 100-999
|
||||
"postNumber": "1234567890", // String 6-10 digits
|
||||
"postalCode": "12345",
|
||||
"city": "Beispielstadt",
|
||||
"country": "DEU"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Validierung
|
||||
```php
|
||||
// Packstation-Nummer: 3-stellig
|
||||
if ($lockerID < 100 || $lockerID > 999) {
|
||||
throw new InvalidArgumentException('Packstation-Nummer muss 3-stellig sein');
|
||||
}
|
||||
|
||||
// DHL Postnummer: 6-10 Ziffern
|
||||
if (!preg_match('/^[0-9]{6,10}$/', $postNumber)) {
|
||||
throw new InvalidArgumentException('DHL Postnummer muss 6-10 Ziffern haben');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 CHECKLISTE VOR DEM ABSENDEN
|
||||
|
||||
- [ ] DHL Postnummer ist 6-10-stellig (z.B. `1234567890`)
|
||||
- [ ] Straße enthält "Packstation" + 3-stellige Nummer (z.B. `Packstation 145`)
|
||||
- [ ] PLZ + Ort ist der **Standort der Packstation**, nicht Ihre Wohnadresse
|
||||
- [ ] Alle Felder sind ausgefüllt
|
||||
|
||||
---
|
||||
|
||||
## 📞 SUPPORT
|
||||
|
||||
Bei Fragen zur DHL Postnummer:
|
||||
- 📞 DHL Hotline: 0228 4333112
|
||||
- 🌐 dhl.de/packstation
|
||||
- 📱 DHL App → Mein Konto
|
||||
|
||||
Bei technischen Problemen:
|
||||
- Prüfen Sie zuerst die Eingabe anhand dieser Anleitung
|
||||
- Screenshots des Fehlers und der Eingabe helfen bei der Fehlersuche
|
||||
Loading…
Add table
Add a link
Reference in a new issue