From 8e7873f2dcf2fdd214b7715d4f757aff02f7738b Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Fri, 14 Nov 2025 16:31:15 -0600 Subject: [PATCH] ADD: Command para ver vencimiento de paquetes --- .../Commands/CheckExpiringPackages.php | 154 ++++++++++++++++++ app/Models/SimCard.php | 18 ++ routes/console.php | 6 + 3 files changed, 178 insertions(+) create mode 100644 app/Console/Commands/CheckExpiringPackages.php diff --git a/app/Console/Commands/CheckExpiringPackages.php b/app/Console/Commands/CheckExpiringPackages.php new file mode 100644 index 0000000..64afa8d --- /dev/null +++ b/app/Console/Commands/CheckExpiringPackages.php @@ -0,0 +1,154 @@ +info('Verificando paquetes por vencer...'); + $this->newLine(); + + // Obtener configuración + $notificationDays = array_map('intval', explode(',', $this->option('days'))); + $testMode = $this->option('test'); + + if ($testMode) { + $this->warn('TEST'); + $this->newLine(); + } + + // Obtener paquetes activos con sus relaciones + $activePackages = PackSim::with(['package', 'simCard.clientSims.client']) + ->where('is_active', true) + ->whereNotNull('activated_at') + ->get(); + + $this->info("paquetes activos: {$activePackages->count()}"); + $this->newLine(); + + $notificationsSent = 0; + $packagesChecked = 0; + + if ($this->option('show-all')) { + $this->showAllPackages($activePackages); + return Command::SUCCESS; + } + + foreach ($activePackages as $packSim) { + $packagesChecked++; + + // Calcular fecha de vencimiento + $activatedAt = Carbon::parse($packSim->activated_at); + $expirationDate = $activatedAt->copy()->addDays($packSim->package->period); + + // Días restante + $daysRemaining = (int) now()->diffInDays($expirationDate, false); + + // Verificar si debe notificar + if (in_array($daysRemaining, $notificationDays)) { + // Obtener cliente activo + $clientRelation = $packSim->simCard->activeClient()->first(); + $client = $clientRelation; + + if (!$client) { + $this->warn("SIM {$packSim->simCard->iccid} sin cliente activo"); + continue; + } + + // Mostrar información + if ($testMode) { + $this->displayNotificationDetails($client, $packSim, $daysRemaining); + } else { + // notificacion real + $this->sendWhatsAppNotification($client, $packSim, $daysRemaining); + } + + $notificationsSent++; + } + } + + $this->newLine(); + $this->info('Resumen'); + $this->table( + ['Métrica', 'Valor'], + [ + ['Paquetes revisados', $packagesChecked], + ['Notificaciones enviadas', $notificationsSent], + ['Modo', $testMode ? 'TEST' : 'PRODUCCIÓN'], + ] + ); + + return Command::SUCCESS; + } + + private function displayNotificationDetails($client, $packSim, $daysRemaining) + { + $this->line('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + $this->info(" NOTIFICACIÓN A ENVIAR:"); + $this->line(" Cliente: {$client->full_name}"); + $this->line(" Teléfono: {$client->phone}"); + $this->line(" Email: {$client->email}"); + $this->line(" Paquete: {$packSim->package->name}"); + $this->line(" SIM (ICCID): {$packSim->simCard->iccid}"); + $this->line(" Activado: " . Carbon::parse($packSim->activated_at)->format('d/m/Y')); + $this->line(" Vence en: {$daysRemaining} día(s)"); + $this->line('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + $this->newLine(); + } + + + private function showAllPackages($packages) + { + $this->info('Mostrando todos los paquetes activos con sus fechas de vencimiento:'); + $this->newLine(); + + $data = []; + + foreach ($packages as $packSim) { + $activatedAt = Carbon::parse($packSim->activated_at); + $expirationDate = $activatedAt->copy()->addDays($packSim->package->period); + $daysRemaining = (int) now()->diffInDays($expirationDate, false); + + $clientRelation = $packSim->simCard->activeClient()->first(); + $clientName = $clientRelation ? $clientRelation->full_name : 'Sin cliente activo'; + + $data[] = [ + 'Cliente' => $clientName, + 'Paquete' => $packSim->package->name, + 'SIM (ICCID)' => $packSim->simCard->iccid, + 'Activado' => $activatedAt->format('d/m/Y'), + 'Vence el' => $expirationDate->format('d/m/Y'), + 'Días restantes' => $daysRemaining, + ]; + } + + $this->table( + ['Cliente', 'Paquete', 'SIM (ICCID)', 'Activado', 'Vence el', 'Días restantes'], + $data + ); + } +} diff --git a/app/Models/SimCard.php b/app/Models/SimCard.php index 1eacd84..c2db10e 100644 --- a/app/Models/SimCard.php +++ b/app/Models/SimCard.php @@ -57,4 +57,22 @@ public function activePackage() ->withTimestamps() ->limit(1); } + + public function clientSims() + { + return $this->hasMany(ClientSim::class, 'sim_card_id'); + } + + public function activeClient() + { + return $this->belongsToMany( + Client::class, + 'client_sims', + 'sim_card_id', + 'client_id' + )->wherePivot('is_active', true) + ->withPivot('assigned_at', 'released_at', 'is_active') + ->withTimestamps() + ->limit(1); + } } diff --git a/routes/console.php b/routes/console.php index 0b326d0..51419df 100644 --- a/routes/console.php +++ b/routes/console.php @@ -8,3 +8,9 @@ } Schedule::call(new DeleteResetPasswords)->hourly(); + +Schedule::command('packages:check-expiring') + ->dailyAt('09:00') + ->timezone('America/Mexico_City') + ->withoutOverlapping() + ->appendOutputTo(storage_path('logs/packages-expiring.log'));