Ir al contenido principal

Desarrollo de sistema gerencial (parte 5)

 Ahora vamos a probar paso a paso.


馃И Prueba del Reporte Autom谩tico

Paso 1: Verificar la configuraci贸n de correo

Antes de enviar emails reales, verific谩 que el mailer est茅 configurado. En .env:

env
MAIL_MAILER=log

Recomendaci贸n: Us谩 log para pruebas. Los emails se escribir谩n en storage/logs/laravel.log en lugar de enviarse realmente. Cuando confirmes que todo funciona, cambi谩s a smtp o mailpit.


Paso 2: Ejecutar el comando manualmente

bash
php artisan dashboard:enviar-reporte

Salida esperada:

text
馃摟 Enviando reportes del dashboard...
Encontrados X usuarios.
  • Encolado para: Juan P茅rez (juan@example.com)
  • Encolado para: Mar铆a Garc铆a (maria@example.com)
✅ Reportes encolados correctamente.

Paso 3: Verificar que los jobs est茅n en cola

bash
php artisan queue:monitor

O consult谩 la tabla jobs:

bash
php artisan tinker
>>> DB::table('jobs')->count();

Paso 4: Procesar la cola

bash
php artisan queue:work --once

Salida esperada:

text
[2026-09-18 10:30:00] Processing: App\Jobs\EnviarReporteDashboardJob
[2026-09-18 10:30:05] Processed:  App\Jobs\EnviarReporteDashboardJob

Paso 5: Verificar el email

Si usaste MAIL_MAILER=log:

bash
tail -f storage/logs/laravel.log

Busc谩 algo como:

text
[2026-09-18 10:30:00] local.DEBUG: Message-ID: <...>
Subject: Dashboard Gerencial - September 2026
From: noreply@midominio.com
To: juan@example.com
...

Paso 6: Verificar los adjuntos

Los PDFs y Excels se generan en storage/app/reportes/. Verific谩:

bash
ls -la storage/app/reportes/

Deber铆as ver archivos como:

text
reporte-1-2026-09-18-103000.pdf
reporte-1-2026-09-18-103000.xlsx
reporte-2-2026-09-18-103000.pdf
reporte-2-2026-09-18-103000.xlsx

⚠️ Posibles errores y soluciones

ErrorCausaSoluci贸n
Call to undefined method User::consultorios()Falta la relaci贸n en el modelo UserAgregar consultorios() al modelo
Call to undefined relationship [roles]Falta el trait HasRoles en UserAgregar use HasRoles;
No query results for model [Consultorio]No hay consultorios asociadosAsignar consultorios a los usuarios
Storage path not foundFalta el directorio reportesCrear el directorio o verificar permisos
Class DashboardGerencialExport not foundFalta el archivo de exportaci贸nVerificar que est茅 en app/Exports/
Connection refused (SMTP)Mailer mal configuradoCambiar a MAIL_MAILER=log para pruebas

馃搵 Checklist de prueba

  • php artisan dashboard:enviar-reporte encola jobs correctamente

  • Los jobs se procesan sin errores

  • Los PDFs se generan en storage/app/reportes/

  • Los Excels se generan en storage/app/reportes/

  • El email se registra en laravel.log (con MAIL_MAILER=log)

  • El email contiene los KPIs de cada consultorio

  • Los adjuntos aparecen en el email


Ejecut谩 el comando y contame qu茅 resultados obten茅s. Si hay errores, pasame el mensaje completo.

✅ php artisan dashboard:enviar-reporte encola jobs correctamente. ✅ Los jobs se procesan sin errores. ❌ Los PDFs no se generan en storage/app/reportes. ❌ Los Excels no se generan en storage/app/reportes. ❌ El email no se registra en laravel.log (incluso con MAIL_MAILER=log). ❌ El email no contiene los KPIs de cada consultorio. ❌ Los adjuntos no aparecen en el email. ¿Me permit铆s esbozar una teor铆a de lo que est谩 pasando y proponer una soluci贸n?

Por supuesto, adelante. Te escucho.

Por un lado hoy no es el primer lunes del mes. Por otro lado no hay datos que populen los reportes que queremos generar, resultando las queries de KPIs y otras m茅tricas en conjuntos vac铆os que provocan que se anule los emails que est谩n construy茅ndose en el proceso. La soluci贸n, supongo, ser铆a por una parte permitir mediante alg煤n modo de ejecuci贸n de prueba, que el job omita la condici贸n de que sea el primer lunes de cada mes. La otra parte de la soluci贸n ser铆a, supongo, crear seeders para datos que simulen que durante un per铆odo de poco m谩s de un a帽o hubo una variedad de odont贸logos y pacientes participando en diversas operaciones, con varios consultorios involucrados. Ponete en rol anal铆tico y debat铆 conmigo tu parecer.

Me parece una teor铆a excelente y muy bien orientada. Ten茅s raz贸n en ambos puntos. Vamos por partes.


馃攳 An谩lisis de tu teor铆a

Punto 1: "Hoy no es el primer lunes del mes"

S铆, es correcto, pero con matices.

El comando dashboard:enviar-reporte no verifica si es el primer lunes. Esa verificaci贸n la hace el scheduler en routes/console.php. Cuando ejecut谩s manualmente php artisan dashboard:enviar-reporte, el comando se ejecuta sin importar la fecha, porque est谩s invoc谩ndolo directamente.

Entonces, si el comando encol贸 jobs correctamente (✅), significa que:

  • El comando pas贸 los filtros internos

  • Los jobs se encolaron

El problema no es la fecha. Es otra cosa.


Punto 2: "No hay datos que populen los reportes"

Aqu铆 s铆 ten茅s raz贸n, pero con matices.

Vamos a verificar qu茅 pasa realmente:

EscenarioComportamiento esperado
No hay usuarios con rol gerenteEl comando no encola jobs para gerentes
Hay gerentes pero sin consultoriosEl job se ejecuta, pero no genera reportes
Hay gerentes con consultoriosEl job genera PDFs y Excels (aunque est茅n vac铆os)
KPIs vac铆osEl PDF y Excel se generan igual (con ceros)

El problema: Incluso sin datos, el PDF y el Excel deber铆an generarse. Los KPIs estar铆an en cero, pero el archivo existir铆a.

Entonces, ¿por qu茅 no se generan?

Mi sospecha es que hay un error silencioso en el job. Como el job se ejecuta en cola, si falla, Laravel lo reintenta (por los 9 intentos que configuramos). Pero como no vemos errores en laravel.log, puede ser que:

  1. El job est茅 fallando antes de llegar a generar los reportes

  2. El job est茅 fallando en la generaci贸n de PDF/Excel pero sin lanzar excepci贸n visible

  3. El job est茅 generando los archivos pero en una ruta distinta a la que busc谩s


馃И Diagn贸stico: ¿Qu茅 verificar?

Antes de escribir seeders, verifiquemos qu茅 est谩 pasando realmente:

1. Verificar la cantidad de jobs en cola

bash
php artisan tinker
>>> DB::table('jobs')->count();
>>> DB::table('failed_jobs')->count();

2. Verificar si hay jobs fallidos

bash
php artisan queue:failed

3. Verificar los logs

bash
tail -n 100 storage/logs/laravel.log | grep -i "reporte\|dashboard\|error"

4. Verificar la ruta de storage

bash
ls -la storage/app/
ls -la storage/app/reportes/ 2>/dev/null || echo "Directorio no existe"

5. Probar el Service directamente

bash
php artisan tinker
php
$service = app(App\Services\ReporteDashboardService::class);
$reporte = $service->generarReporteConsultorio(1);
dump($reporte);

Si esto falla, el problema est谩 en el Service o en las dependencias (PDF, Excel).


馃幆 Mi parecer sobre tu propuesta de soluci贸n

Sobre el punto 1: Modo de ejecuci贸n de prueba

Totalmente de acuerdo. Pero no es un problema del comando, sino del scheduler. El scheduler es el que filtra por d铆a. El comando en s铆 no filtra.

Soluci贸n propuesta:

Agregar una opci贸n --force o --ahora al comando para que ignore cualquier verificaci贸n de fecha y ejecute siempre:

php
protected $signature = 'dashboard:enviar-reporte {--force : Ignorar verificaciones de fecha}';

Pero insisto: el comando ya no filtra por fecha. El filtro est谩 en el scheduler. Si ejecut谩s el comando manualmente, no hay filtro.

Lo que s铆 puede estar pasando: el job, al no tener datos, quiz谩s est茅 fallando silenciosamente. Pero eso no depende de la fecha.


Sobre el punto 2: Seeders con datos de prueba

Totalmente de acuerdo. Es la mejor manera de:

  1. Verificar que el dashboard funciona con datos reales

  2. Probar el env铆o de reportes con contenido

  3. Detectar problemas de rendimiento (queries lentas)

  4. Validar los c谩lculos de KPIs

Mi propuesta de seeders:

SeederContenido
DemoConsultorioSeeder3 consultorios
DemoUserSeeder1 admin, 2 gerentes, 3 odont贸logos, 1 recepcionista
DemoPacienteSeeder50 pacientes distribuidos en consultorios
DemoPropuestaSeeder200 propuestas (aceptadas, rechazadas, emitidas)
DemoPagoSeeder150 pagos distribuidos en el tiempo
DemoTratamientoRealizadoSeeder300 tratamientos realizados con fechas del 煤ltimo a帽o
DemoOdontogramaSeederOdontogramas asociados a pacientes

馃 Antes de escribir los seeders, necesito saber:

1. Sobre el diagn贸stico previo

¿Ya ejecutaste los comandos de diagn贸stico que te pas茅? Especialmente:

  • php artisan queue:failed → ¿hay jobs fallidos?

  • php artisan tinker + $service->generarReporteConsultorio(1) → ¿qu茅 error da?

Sin este diagn贸stico, no sabemos si el problema es de datos o de c贸digo.


2. Sobre los seeders

  • ¿Prefer铆s seeders que generen datos con Faker (aleatorios) o datos realistas y controlados?

    • Faker: m谩s r谩pido, pero los datos no tienen sentido narrativo

    • Controlados: m谩s lento, pero los datos cuentan una historia coherente

  • ¿Cu谩ntos datos quer茅s?

    • 3 consultorios, 10 usuarios, 50 pacientes, 200 propuestas...

    • ¿O m谩s?

  • ¿Quer茅s que los datos se generen con fechas distribuidas en el 煤ltimo a帽o?

    • S铆, para que las variaciones mes a mes tengan sentido

    • Esto implica manipular created_at y emitida_at

  • ¿Quer茅s que los seeders sean idempotentes?

    • Es decir, que se puedan ejecutar varias veces sin duplicar datos

    • O que limpien la BD antes de ejecutarse


3. Sobre el modo de prueba del comando

  • ¿Quer茅s un flag --force en el comando para ignorar el scheduler, o

  • ¿Prefer铆s ejecutar el comando directamente (que ya ignora el scheduler)?

Si es lo segundo, no hace falta hacer nada: el comando ya se ejecuta sin filtros cuando lo llam谩s manualmente.


馃搵 Mi propuesta de plan

  1. Diagn贸stico primero: ejecutar los comandos de verificaci贸n

  2. Si el problema es de c贸digo: corregir el Service o el Job

  3. Si el problema es de datos: crear seeders

  4. Probar de nuevo con datos


¿Empezamos por el diagn贸stico? ¿O prefer铆s que avancemos directamente con los seeders?

php artisan tinker Psy Shell v0.12.24 (PHP 8.3.6 — cli) by Justin Hileman New PHP manual is available (latest: 3.1.1). Update with `doc --update-manual` > $service = app(App\Services\ReporteDashboardService::class) = App\Services\ReporteDashboardService {#7855} > $reporte = $service->generarReporteConsultorio(1) Illuminate\Database\QueryException SQLSTATE[42S22]: Column not found: 1054 Unknown column 'consultorio_id' in 'where clause' (Connection: mysql, Host: 127.0.0.1, Port: 3306, Database: laravel, SQL: select sum(`saldo`) as aggregate from `cuentas` where exists (select * from `pacientes` where `cuentas`.`paciente_id` = `pacientes`.`id` and `consultorio_id` = 1 and `pacientes`.`deleted_at` is null)).

Ah铆 est谩 el problema. No es un problema de datos ni de fecha. Es un problema de dise帽o de la base de datos.

Comentarios