mivita/app/Console/Commands/DhlUpdateTracking.php
2026-01-23 17:35:23 +01:00

226 lines
7.9 KiB
PHP

<?php
namespace App\Console\Commands;
use Acme\Dhl\Models\DhlShipment;
use App\Mail\MailDhlTracking;
use App\Services\DhlTrackingService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
class DhlUpdateTracking extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'dhl:update-tracking
{--days=14 : Sendungen der letzten X Tage aktualisieren}
{--send-emails : Automatisch E-Mails bei Transit-Status senden}
{--dry-run : Nur simulieren, keine Änderungen}
{--test-email= : Test-E-Mail an angegebene Adresse senden}
{--order= : Nur für bestimmte Bestellung (Order-ID)}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Aktualisiert Tracking-Status für alle aktiven DHL Sendungen und sendet automatisch E-Mails bei Transit-Status';
/**
* Execute the console command.
*/
public function handle(): int
{
$days = (int) $this->option('days');
$sendEmails = $this->option('send-emails');
$dryRun = $this->option('dry-run');
$testEmail = $this->option('test-email');
$orderId = $this->option('order');
$this->info('DHL Tracking Update gestartet');
$this->info("Optionen: --days={$days}, --send-emails=" . ($sendEmails ? 'ja' : 'nein') . ', --dry-run=' . ($dryRun ? 'ja' : 'nein'));
if ($testEmail) {
$this->info("Test-Modus: E-Mails werden an {$testEmail} gesendet");
}
if ($orderId) {
$this->info("Filter: Nur Order-ID {$orderId}");
}
$this->newLine();
// Hole alle aktiven Sendungen der letzten X Tage
$query = DhlShipment::active()
->where('created_at', '>=', now()->subDays($days))
->whereNotNull('dhl_shipment_no');
// Filter nach Order-ID wenn angegeben
if ($orderId) {
$query->where('order_id', $orderId);
}
$shipments = $query->orderBy('created_at', 'desc')->get();
$total = $shipments->count();
$this->info("Gefundene aktive Sendungen: {$total}");
if ($total === 0) {
$this->info('Keine Sendungen zum Aktualisieren gefunden.');
return self::SUCCESS;
}
$bar = $this->output->createProgressBar($total);
$bar->start();
$trackingService = new DhlTrackingService;
$stats = [
'updated' => 0,
'failed' => 0,
'emails_sent' => 0,
'skipped' => 0,
];
foreach ($shipments as $shipment) {
try {
$oldStatus = $shipment->status;
if (! $dryRun) {
// Tracking aktualisieren
$result = $trackingService->updateTracking($shipment, ['auto_retrack' => false]);
if ($result['success']) {
$shipment->refresh();
$stats['updated']++;
// Prüfen ob E-Mail gesendet werden soll
if ($sendEmails && $this->shouldSendEmail($shipment, $oldStatus)) {
$this->sendTrackingEmail($shipment, $testEmail);
$stats['emails_sent']++;
}
} else {
$stats['failed']++;
Log::warning('[DHL Cron] Tracking update failed', [
'shipment_id' => $shipment->id,
'message' => $result['message'] ?? 'Unknown error',
]);
}
} else {
$stats['skipped']++;
}
} catch (\Exception $e) {
$stats['failed']++;
Log::error('[DHL Cron] Exception during tracking update', [
'shipment_id' => $shipment->id,
'error' => $e->getMessage(),
]);
}
$bar->advance();
}
$bar->finish();
$this->newLine(2);
// Zusammenfassung
$this->info('Zusammenfassung:');
$this->table(
['Metrik', 'Anzahl'],
[
['Gesamt', $total],
['Aktualisiert', $stats['updated']],
['Fehlgeschlagen', $stats['failed']],
['E-Mails gesendet', $stats['emails_sent']],
['Übersprungen (Dry-Run)', $stats['skipped']],
]
);
Log::info('[DHL Cron] Tracking update completed', $stats);
return self::SUCCESS;
}
/**
* Prüft ob eine E-Mail gesendet werden soll
*/
private function shouldSendEmail(DhlShipment $shipment, string $oldStatus): bool
{
// E-Mail nur senden wenn:
// 1. Status ist jetzt "in_transit"
// 2. Vorheriger Status war NICHT "in_transit" (also Status hat sich geändert)
// 3. Noch keine E-Mail gesendet wurde
return $shipment->status === 'in_transit'
&& $oldStatus !== 'in_transit'
&& ! $shipment->wasTrackingEmailSent()
&& $shipment->canSendTrackingEmail();
}
/**
* Sendet die Tracking-E-Mail (mit Unterstützung für mehrere Sendungen pro Bestellung)
*/
private function sendTrackingEmail(DhlShipment $shipment, ?string $testEmail = null): void
{
try {
$order = $shipment->shoppingOrder;
// Determine recipient email: test email > shipment email > shopping user email
$recipientEmail = null;
if ($testEmail) {
$recipientEmail = $testEmail;
} elseif (! empty($shipment->email)) {
$recipientEmail = $shipment->email;
} elseif ($order->shopping_user && ! empty($order->shopping_user->email)) {
$recipientEmail = $order->shopping_user->email;
}
if (! $recipientEmail) {
Log::warning('[DHL Cron] Cannot send email - no recipient', [
'shipment_id' => $shipment->id,
]);
return;
}
// Sammle alle Sendungen für diese Bestellung, die noch keine E-Mail erhalten haben
$allShipments = DhlShipment::where('order_id', $order->id)
->where('status', 'in_transit')
->whereNotNull('dhl_shipment_no')
->whereNull('tracking_email_sent_at')
->get();
// Wenn keine Sendungen gefunden, nutze nur die aktuelle
if ($allShipments->isEmpty()) {
$allShipments = collect([$shipment]);
}
// Sende E-Mail mit allen Sendungen
Mail::to($recipientEmail)->send(new MailDhlTracking($allShipments, $order));
// Markiere alle Sendungen als versendet
foreach ($allShipments as $s) {
$s->markTrackingEmailSent('auto');
}
Log::info('[DHL Cron] Tracking email sent automatically', [
'shipment_ids' => $allShipments->pluck('id')->toArray(),
'shipments_count' => $allShipments->count(),
'dhl_shipment_nos' => $allShipments->pluck('dhl_shipment_no')->toArray(),
'email' => $recipientEmail,
'is_test' => ! is_null($testEmail),
]);
if ($allShipments->count() > 1) {
$this->line(" -> E-Mail mit {$allShipments->count()} Sendungen gesendet an: {$recipientEmail}");
} else {
$this->line(" -> E-Mail gesendet an: {$recipientEmail}");
}
} catch (\Exception $e) {
Log::error('[DHL Cron] Failed to send tracking email', [
'shipment_id' => $shipment->id,
'error' => $e->getMessage(),
]);
}
}
}