20-02-2026
This commit is contained in:
parent
a8b395e20d
commit
a00c42e770
252 changed files with 28785 additions and 8907 deletions
|
|
@ -17,18 +17,20 @@ class DhlUpdateTracking extends Command
|
|||
* @var string
|
||||
*/
|
||||
protected $signature = 'dhl:update-tracking
|
||||
{--days=14 : Sendungen der letzten X Tage aktualisieren}
|
||||
{--days=30 : 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)}';
|
||||
{--order= : Nur für bestimmte Bestellung (Order-ID)}
|
||||
{--force : Intervall-Filter überspringen, alle aktiven Sendungen aktualisieren}
|
||||
{--stale-days=30 : Sendungen ohne Statusänderung nach X Tagen als abgeschlossen markieren}';
|
||||
|
||||
/**
|
||||
* 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';
|
||||
protected $description = 'Aktualisiert Tracking-Status für DHL Sendungen (status-basierte Intervalle, Batch-API)';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
|
|
@ -40,9 +42,14 @@ class DhlUpdateTracking extends Command
|
|||
$dryRun = $this->option('dry-run');
|
||||
$testEmail = $this->option('test-email');
|
||||
$orderId = $this->option('order');
|
||||
$force = $this->option('force');
|
||||
$staleDays = (int) $this->option('stale-days');
|
||||
|
||||
$this->info('DHL Tracking Update gestartet');
|
||||
$this->info("Optionen: --days={$days}, --send-emails=" . ($sendEmails ? 'ja' : 'nein') . ', --dry-run=' . ($dryRun ? 'ja' : 'nein'));
|
||||
$this->info("Optionen: --days={$days}, --send-emails=".($sendEmails ? 'ja' : 'nein')
|
||||
.', --dry-run='.($dryRun ? 'ja' : 'nein')
|
||||
.', --force='.($force ? 'ja' : 'nein')
|
||||
.", --stale-days={$staleDays}");
|
||||
if ($testEmail) {
|
||||
$this->info("Test-Modus: E-Mails werden an {$testEmail} gesendet");
|
||||
}
|
||||
|
|
@ -51,95 +58,185 @@ class DhlUpdateTracking extends Command
|
|||
}
|
||||
$this->newLine();
|
||||
|
||||
// Hole alle aktiven Sendungen der letzten X Tage
|
||||
$query = DhlShipment::active()
|
||||
// Step 1: Mark stale shipments as completed (before main query)
|
||||
$staleCompleted = $this->markStaleShipmentsCompleted($staleDays, $dryRun);
|
||||
|
||||
// Step 2: Build query for shipments that need tracking update
|
||||
$query = $this->buildShipmentQuery($days, $orderId, $force);
|
||||
|
||||
$shipments = $query->orderBy('created_at', 'desc')->get();
|
||||
|
||||
// Count total active shipments for statistics (before interval filter)
|
||||
$totalActive = DhlShipment::active()
|
||||
->whereNull('tracking_completed_at')
|
||||
->where('created_at', '>=', now()->subDays($days))
|
||||
->whereNotNull('dhl_shipment_no');
|
||||
->whereNotNull('dhl_shipment_no')
|
||||
->count();
|
||||
|
||||
$total = $shipments->count();
|
||||
$skippedByInterval = $totalActive - $total;
|
||||
|
||||
$this->info("Aktive Sendungen gesamt: {$totalActive}");
|
||||
$this->info('Übersprungen (Intervall): '.max(0, $skippedByInterval));
|
||||
$this->info("Zu aktualisieren: {$total}");
|
||||
|
||||
if ($total === 0) {
|
||||
$this->info('Keine Sendungen zum Aktualisieren gefunden.');
|
||||
$this->printSummary(0, ['updated' => 0, 'failed' => 0, 'completed' => 0, 'emails_sent' => 0, 'skipped' => 0], $staleCompleted, max(0, $skippedByInterval));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$trackingService = new DhlTrackingService;
|
||||
$stats = [
|
||||
'updated' => 0,
|
||||
'failed' => 0,
|
||||
'completed' => 0,
|
||||
'emails_sent' => 0,
|
||||
'skipped' => 0,
|
||||
];
|
||||
|
||||
if ($dryRun) {
|
||||
$stats['skipped'] = $total;
|
||||
$this->info("Dry-Run: {$total} Sendungen würden aktualisiert.");
|
||||
} else {
|
||||
// Collect old statuses for email decision
|
||||
$oldStatuses = $shipments->pluck('status', 'id')->toArray();
|
||||
|
||||
// Use batch API for efficient processing
|
||||
$this->info('Starte Batch-Tracking-Update...');
|
||||
$bar = $this->output->createProgressBar($total);
|
||||
$bar->start();
|
||||
|
||||
$batchResult = $trackingService->updateTrackingBatch($shipments);
|
||||
|
||||
$stats['updated'] = $batchResult['updated'];
|
||||
$stats['failed'] = $batchResult['failed'];
|
||||
$stats['completed'] = $batchResult['completed'];
|
||||
|
||||
$bar->advance($total);
|
||||
$bar->finish();
|
||||
$this->newLine(2);
|
||||
|
||||
// Send tracking emails if enabled
|
||||
if ($sendEmails) {
|
||||
$this->info('Prüfe E-Mail-Versand...');
|
||||
|
||||
foreach ($shipments as $shipment) {
|
||||
$shipment->refresh();
|
||||
$oldStatus = $oldStatuses[$shipment->id] ?? '';
|
||||
|
||||
if ($this->shouldSendEmail($shipment, $oldStatus)) {
|
||||
try {
|
||||
$this->sendTrackingEmail($shipment, $testEmail);
|
||||
$stats['emails_sent']++;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('[DHL Cron] Failed to send tracking email', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->printSummary($total, $stats, $staleCompleted, max(0, $skippedByInterval));
|
||||
|
||||
Log::info('[DHL Cron] Tracking update completed', array_merge($stats, [
|
||||
'total' => $total,
|
||||
'stale_completed' => $staleCompleted,
|
||||
'skipped_interval' => max(0, $skippedByInterval),
|
||||
]));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the shipment query with or without interval filtering.
|
||||
*/
|
||||
private function buildShipmentQuery(int $days, ?string $orderId, bool $force)
|
||||
{
|
||||
if ($force) {
|
||||
// --force: Alle aktiven Sendungen ohne Intervall-Filter
|
||||
$query = DhlShipment::active()
|
||||
->whereNull('tracking_completed_at')
|
||||
->where('created_at', '>=', now()->subDays($days))
|
||||
->whereNotNull('dhl_shipment_no');
|
||||
} else {
|
||||
// Normal: Status-basierte Intervalle beachten
|
||||
$query = DhlShipment::needsTrackingUpdate()
|
||||
->where('created_at', '>=', now()->subDays($days));
|
||||
}
|
||||
|
||||
// Filter nach Order-ID wenn angegeben
|
||||
if ($orderId) {
|
||||
$query->where('order_id', $orderId);
|
||||
}
|
||||
|
||||
$shipments = $query->orderBy('created_at', 'desc')->get();
|
||||
return $query;
|
||||
}
|
||||
|
||||
$total = $shipments->count();
|
||||
$this->info("Gefundene aktive Sendungen: {$total}");
|
||||
/**
|
||||
* Mark shipments as tracking-completed if they haven't changed status
|
||||
* for a given number of days (stale shipments).
|
||||
*/
|
||||
private function markStaleShipmentsCompleted(int $staleDays, bool $dryRun): int
|
||||
{
|
||||
$staleShipments = DhlShipment::active()
|
||||
->whereNull('tracking_completed_at')
|
||||
->whereNotNull('last_tracked_at')
|
||||
->where('last_tracked_at', '<', now()->subDays($staleDays))
|
||||
->where('created_at', '<', now()->subDays($staleDays))
|
||||
->get();
|
||||
|
||||
if ($total === 0) {
|
||||
$this->info('Keine Sendungen zum Aktualisieren gefunden.');
|
||||
$count = $staleShipments->count();
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
if ($count > 0) {
|
||||
$this->warn("Veraltete Sendungen gefunden: {$count} (>{$staleDays} Tage ohne Änderung)");
|
||||
|
||||
$bar = $this->output->createProgressBar($total);
|
||||
$bar->start();
|
||||
if (! $dryRun) {
|
||||
foreach ($staleShipments as $shipment) {
|
||||
$shipment->markTrackingCompleted();
|
||||
|
||||
$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']++;
|
||||
Log::info('[DHL Cron] Stale shipment tracking completed', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'dhl_shipment_no' => $shipment->dhl_shipment_no,
|
||||
'status' => $shipment->status,
|
||||
'last_tracked_at' => $shipment->last_tracked_at?->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$stats['failed']++;
|
||||
Log::error('[DHL Cron] Exception during tracking update', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
$this->info(" → {$count} Sendungen als Tracking-abgeschlossen markiert.");
|
||||
} else {
|
||||
$this->info(" → Dry-Run: {$count} Sendungen würden als abgeschlossen markiert.");
|
||||
}
|
||||
}
|
||||
|
||||
$bar->finish();
|
||||
$this->newLine(2);
|
||||
$this->newLine();
|
||||
|
||||
// Zusammenfassung
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the final summary table.
|
||||
*/
|
||||
private function printSummary(int $total, array $stats, int $staleCompleted, int $skippedByInterval): void
|
||||
{
|
||||
$this->info('Zusammenfassung:');
|
||||
$this->table(
|
||||
['Metrik', 'Anzahl'],
|
||||
[
|
||||
['Gesamt', $total],
|
||||
['Zu aktualisieren', $total],
|
||||
['Aktualisiert', $stats['updated']],
|
||||
['Fehlgeschlagen', $stats['failed']],
|
||||
['Tracking abgeschlossen', $stats['completed']],
|
||||
['E-Mails gesendet', $stats['emails_sent']],
|
||||
['Übersprungen (Dry-Run)', $stats['skipped']],
|
||||
['Übersprungen (Intervall)', $skippedByInterval],
|
||||
['Veraltet → abgeschlossen', $staleCompleted],
|
||||
]
|
||||
);
|
||||
|
||||
Log::info('[DHL Cron] Tracking update completed', $stats);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -212,9 +309,9 @@ class DhlUpdateTracking extends Command
|
|||
]);
|
||||
|
||||
if ($allShipments->count() > 1) {
|
||||
$this->line(" -> E-Mail mit {$allShipments->count()} Sendungen gesendet an: {$recipientEmail}");
|
||||
$this->line(" → E-Mail mit {$allShipments->count()} Sendungen gesendet an: {$recipientEmail}");
|
||||
} else {
|
||||
$this->line(" -> E-Mail gesendet an: {$recipientEmail}");
|
||||
$this->line(" → E-Mail gesendet an: {$recipientEmail}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('[DHL Cron] Failed to send tracking email', [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue