Resumen diario

This commit is contained in:
2025-05-30 10:59:54 -06:00
parent f6c9495b3e
commit 59b9b402fb
4 changed files with 642 additions and 49 deletions

2
.env
View File

@@ -1,4 +1,4 @@
DB_HOST=localhost
DB_HOST=DESKTOP-22T88B6
DB_DATABASE=Importaciones_HC
DB_USERNAME=sa
DB_PASSWORD=Soluciones01

View File

@@ -749,8 +749,6 @@ function enviarNotificacionSeguridadIntentos($emailDestino, $nombreUsuario, $dat
$asunto = "🚨 Alerta de Seguridad - Intentos de Verificación Excedidos";
$mail->Subject = $asunto;
$tipoCorreo = $esCorreoAdicional ? "(Correo Adicional)" : "";
$mail->Body = "
<html>
<head>
@@ -761,7 +759,6 @@ function enviarNotificacionSeguridadIntentos($emailDestino, $nombreUsuario, $dat
<div style='max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #ddd; border-radius: 10px;'>
<div style='text-align: center; margin-bottom: 30px;'>
<h1 style='color: #dc3545; margin: 0;'>🚨 Alerta de Seguridad</h1>
<p style='color: #666; margin: 5px 0;'>$tipoCorreo</p>
</div>
<div style='background-color: #f8f9fa; padding: 20px; border-radius: 8px; margin-bottom: 20px;'>
@@ -820,30 +817,93 @@ function enviarNotificacionSeguridadIntentos($emailDestino, $nombreUsuario, $dat
}
}
/** Función para enviar el email de notificación de cuenta bloqueado **/
function enviarNotificacionCuentaBloqueada($email, $esCorreoAdicional = false)
/** Función para enviar el email de notificación de cuenta bloqueada **/
function enviarNotificacionCuentaBloqueada($email)
{
$conn = getConnection();
if (!$conn) throw new Exception("No se pudo conectar a la base de datos");
if (!$conn) {
throw new Exception("No se pudo conectar a la base de datos");
}
// Buscar información del usuario por email (incluyendo correo extra)
$emailEncrypted = encrypt($email);
$sqlNotif = "SELECT nombre, email FROM usuarios_sistema WHERE email = ?";
$stmt = sqlsrv_query($conn, $sqlNotif, [$emailEncrypted]);
$sqlNotif = "
SELECT
u.nombre,
u.email,
u.notificaciones,
u.notificaciones_extra,
ce.correo as correo_extra
FROM usuarios_sistema u
LEFT JOIN correo_extra ce ON u.id_usuario = ce.id_usuario
WHERE u.email = ?";
if (!$stmt) throw new Exception("Error al consultar información del usuario");
$stmtUsuario = sqlsrv_query($conn, $sqlNotif, [$emailEncrypted]);
$usuario = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
sqlsrv_free_stmt($stmt);
if ($stmtUsuario === false) {
throw new Exception("Error al consultar información del usuario");
}
$usuario = sqlsrv_fetch_array($stmtUsuario, SQLSRV_FETCH_ASSOC);
sqlsrv_free_stmt($stmtUsuario);
if (!$usuario) {
error_log("⚠️ Usuario no encontrado para enviar notificación de cuenta bloqueada");
return false;
}
// 🔐 Desencriptar datos sensibles
$usuario['email'] = decrypt($usuario['email']);
$usuario['nombre'] = decrypt($usuario['nombre']);
// Preparar datos para la notificación
$datosNotificacion = [
'email' => $usuario['email'],
'nombre' => $usuario['nombre'],
'fecha_hora' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Desconocido'
];
$resultadoEnvio = false;
// Enviar al correo principal
$resultadoPrincipal = enviarEmailCuentaBloqueada(
$usuario['email'],
$usuario['nombre'],
$datosNotificacion
);
if ($resultadoPrincipal) {
$resultadoEnvio = true;
error_log("✅ Notificación de cuenta bloqueada enviada a: {$usuario['email']}");
}
// Enviar al correo adicional si está configurado
if ($usuario['notificaciones_extra'] == 1 && !empty($usuario['correo_extra'])) {
$resultadoExtra = enviarEmailCuentaBloqueada(
$usuario['correo_extra'],
$usuario['nombre'],
$datosNotificacion,
true // Indicar que es correo adicional
);
if ($resultadoExtra) {
$resultadoEnvio = true;
error_log("✅ Notificación de cuenta bloqueada enviada a correo adicional: {$usuario['correo_extra']}");
}
}
return $resultadoEnvio;
}
/** Función auxiliar para enviar el email físico de cuenta bloqueada **/
function enviarEmailCuentaBloqueada($emailDestino, $nombreUsuario, $datos, $esCorreoAdicional = false)
{
try {
$mail = new PHPMailer(true);
// Configuración de servidor SMTP
$mail->isSMTP();
$mail->Host = 'secure.emailsrvr.com';
$mail->SMTPAuth = true;
@@ -852,53 +912,94 @@ function enviarNotificacionCuentaBloqueada($email, $esCorreoAdicional = false)
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// Configuración de correo
// Configuración del correo
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
$mail->addAddress($usuario['email']);
$mail->addAddress($emailDestino);
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
$asunto = "🚫 Cuenta Bloqueada por Seguridad";
$mail->Subject = $asunto;
$tipoCorreo = $esCorreoAdicional ? "(Correo Adicional)" : "";
$mail->Body = "
<html>
<head>
<meta charset='UTF-8'>
<title>Alerta de Seguridad</title>
<title>Cuenta Bloqueada</title>
</head>
<body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>
<div style='max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #ddd; border-radius: 10px;'>
<div style='text-align: center; margin-bottom: 30px;'>
<h1 style='color: #dc3545; margin: 0;'>🚫 Cuenta Bloqueada</h1>
<p style='color: #666; margin: 5px 0;'>$tipoCorreo</p>
</div>
<hr>
<div style='background-color: #f8f9fa; padding: 20px; border-radius: 8px; margin-bottom: 20px;'>
<p>Hola <b>{$usuario['nombre']}</b>,</p>
<p>Tu cuenta ha sido bloqueada automáticamente tras 5 intentos fallidos al verificar tu código de recuperación.</p>
<p>Por seguridad, deberás contactar a tu agente aduanal para reactivar tu cuenta.</p>
<p>Fecha: <b>" . date('Y-m-d H:i:s') . "</b><br>
IP: <b>" . ($_SERVER['REMOTE_ADDR'] ?? 'Desconocida') . "</b></p>
<h2 style='color: #dc3545; margin-top: 0;'>Cuenta Bloqueada por Seguridad</h2>
<p>Hola <strong>" . htmlspecialchars($nombreUsuario) . "</strong>,</p>
<p>Tu cuenta ha sido <strong>bloqueada automáticamente</strong> tras detectarse múltiples intentos fallidos de verificación del código de recuperación de contraseña.</p>
</div>
<div style='background-color: #fff3cd; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #ffc107;'>
<h3 style='color: #856404; margin-top: 0;'>📋 Detalles del Bloqueo:</h3>
<ul style='margin: 10px 0; padding-left: 20px;'>
<li><strong>Fecha y Hora:</strong> " . htmlspecialchars($datos['fecha_hora']) . "</li>
<li><strong>Dirección IP:</strong> " . htmlspecialchars($datos['ip']) . "</li>
<li><strong>Navegador:</strong> " . htmlspecialchars(substr($datos['user_agent'], 0, 100)) . "...</li>
<li><strong>Motivo:</strong> 5 intentos fallidos de verificación de código</li>
</ul>
</div>
<div style='background-color: #d1ecf1; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #bee5eb;'>
<h3 style='color: #0c5460; margin-top: 0;'>🔒 ¿Qué significa esto?</h3>
<ul style='margin: 10px 0; padding-left: 20px;'>
<li>Tu cuenta ha sido <strong>suspendida temporalmente</strong> por seguridad</li>
<li>No podrás acceder al sistema hasta que sea reactivada</li>
<li>Todos los códigos de recuperación han sido invalidados</li>
<li>Este evento ha sido registrado en nuestros logs de seguridad</li>
</ul>
</div>
<div style='background-color: #d4edda; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #c3e6cb;'>
<h3 style='color: #155724; margin-top: 0;'>🔧 ¿Cómo reactivar tu cuenta?</h3>
<p><strong>Deberás contactar a tu agente aduanal</strong> para solicitar la reactivación de tu cuenta.</p>
<p>El agente aduanal podrá:</p>
<ul style='margin: 10px 0; padding-left: 20px;'>
<li>Verificar tu identidad</li>
<li>Reactivar tu cuenta de manera segura</li>
<li>Ayudarte a establecer una nueva contraseña</li>
</ul>
</div>
<div style='background-color: #f8d7da; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #f5c6cb;'>
<h3 style='color: #721c24; margin-top: 0;'>⚠️ ¿No fuiste tú?</h3>
<p>Si <strong>no intentaste recuperar tu contraseña</strong>, esto podría indicar que alguien está tratando de acceder a tu cuenta de manera no autorizada.</p>
<p><strong>Te recomendamos:</strong></p>
<ul style='margin: 10px 0; padding-left: 20px;'>
<li>Contactar inmediatamente a tu agente aduanal</li>
<li>Reportar esta actividad sospechosa</li>
<li>Revisar tus dispositivos en busca de malware</li>
<li>Cambiar las contraseñas de tus otras cuentas importantes</li>
</ul>
</div>
<hr>
<div style='text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid #eee;'>
<p style='color: #666; font-size: 12px; margin: 0;'>
Esta es una notificación automática de seguridad.<br>
Si tienes preguntas, contacta a nuestro equipo de soporte.
Si tienes preguntas, contacta a tu agente aduanal o a nuestro equipo de soporte.
</p>
</div>
</div>
</body>
</html>";
// Enviar el correo
$mail->send();
error_log("✅ Notificación de cuenta bloqueada enviada a: {$usuario['email']}");
return true;
} catch (Exception $e) {
error_log("❌ Error al enviar notificación de cuenta bloqueada: " . $e->getMessage());
return false;
}
}
function cambiarPasswordVista()

494
resumen_diario.php Normal file
View File

@@ -0,0 +1,494 @@
<?php
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/crypto.php';
require_once __DIR__ . '/../helpers/env.php';
require_once __DIR__ . '/../../vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
loadEnv();
/** Función principal para enviar resúmenes diarios a todos los usuarios que lo tengan activado **/
function procesarResumenesDiarios()
{
$conn = getConnection();
if (!$conn) {
error_log("❌ No se pudo conectar a la base de datos para procesar resúmenes diarios");
return false;
}
try {
// Obtener usuarios que tienen activado el resumen diario
$fechaAyer = date('Y-m-d', strtotime('-1 day'));
$horaActual = date('H:i');
$diaActual = obtenerDiaSemana();
$sqlUsuarios = "
SELECT DISTINCT
u.id_usuario,
u.nombre,
u.email,
u.notificaciones,
u.notificaciones_extra,
ce.correo as correo_extra,
pnu.resumen_diario,
pnu.resumen_diario_hora,
pnu.resumen_diario_dias
FROM usuarios_sistema u
INNER JOIN preferencias_notificaciones_usuario pnu ON u.id_usuario = pnu.id_usuario
LEFT JOIN correo_extra ce ON u.id_usuario = ce.id_usuario
LEFT JOIN informacion_general ig ON u.id_usuario = ig.id_usuario
WHERE u.notificaciones = 1
AND pnu.resumen_diario = 1
AND u.activo = 1
";
$stmtUsuarios = sqlsrv_query($conn, $sqlUsuarios);
if ($stmtUsuarios === false) {
throw new Exception("Error al consultar usuarios para resumen diario");
}
$usuariosProcesados = 0;
$resumenesEnviados = 0;
while ($usuario = sqlsrv_fetch_array($stmtUsuarios, SQLSRV_FETCH_ASSOC)) {
// Verificar si es hora de enviar el resumen para este usuario
if (!esHoraDeEnvio($usuario, $horaActual, $diaActual)) {
continue;
}
$usuariosProcesados++;
// Desencriptar datos del usuario
$usuario['email'] = decrypt($usuario['email']);
$usuario['nombre'] = decrypt($usuario['nombre']);
// Generar y enviar el resumen
if (enviarResumenDiarioUsuario($usuario, $fechaAyer)) {
$resumenesEnviados++;
}
}
sqlsrv_free_stmt($stmtUsuarios);
sqlsrv_close($conn);
error_log("✅ Proceso de resúmenes diarios completado. Usuarios procesados: $usuariosProcesados, Resúmenes enviados: $resumenesEnviados");
return true;
} catch (Exception $e) {
error_log("❌ Error en proceso de resúmenes diarios: " . $e->getMessage());
if (isset($conn)) {
sqlsrv_close($conn);
}
return false;
}
}
/** Función para verificar si es hora de enviar el resumen para un usuario específico **/
function esHoraDeEnvio($usuario, $horaActual, $diaActual)
{
$horaConfigurada = $usuario['resumen_diario_hora'] ?: '08:00';
$diasConfigurados = $usuario['resumen_diario_dias'] ?: 'L-V';
// Verificar hora (con margen de 5 minutos)
$horaActualMinutos = horaAMinutos($horaActual);
$horaConfiguradaMinutos = horaAMinutos($horaConfigurada);
if (abs($horaActualMinutos - $horaConfiguradaMinutos) > 5) {
return false;
}
// Verificar día
if ($diasConfigurados === 'TODOS') {
return true;
} elseif ($diasConfigurados === 'L-V') {
return in_array($diaActual, ['L', 'M', 'X', 'J', 'V']);
} else {
// Días personalizados
$diasArray = array_map('trim', explode(',', $diasConfigurados));
return in_array($diaActual, $diasArray);
}
}
/** Función auxiliar para convertir hora a minutos **/
function horaAMinutos($hora)
{
list($h, $m) = explode(':', $hora);
return ($h * 60) + $m;
}
/** Función auxiliar para obtener el día de la semana **/
function obtenerDiaSemana()
{
$dias = ['D', 'L', 'M', 'X', 'J', 'V', 'S'];
return $dias[date('w')];
}
/** Función para enviar el resumen diario a un usuario específico **/
function enviarResumenDiarioUsuario($usuario, $fechaFiltro)
{
try {
// Obtener datos del importador
$datosImportador = obtenerDatosImportador($usuario['id_usuario']);
if (!$datosImportador) {
error_log("⚠️ No se encontraron datos del importador para usuario ID: {$usuario['id_usuario']}");
return false;
}
// Obtener operaciones del día anterior
$operaciones = obtenerOperacionesDiarias($usuario['id_usuario'], $fechaFiltro);
// Si no hay operaciones, no enviar resumen (opcional: enviar notificación de "sin actividad")
if (empty($operaciones)) {
error_log(" Sin operaciones para enviar resumen a: {$usuario['email']} en fecha: $fechaFiltro");
return false;
}
// Generar PDF
$rutaPdf = generarPdfResumenDiario($datosImportador, $operaciones, $fechaFiltro);
if (!$rutaPdf) {
error_log("❌ Error al generar PDF para usuario: {$usuario['email']}");
return false;
}
$resultadoEnvio = false;
// Enviar al correo principal
$resultadoPrincipal = enviarEmailResumenDiario(
$usuario['email'],
$usuario['nombre'],
$datosImportador,
$fechaFiltro,
count($operaciones),
$rutaPdf
);
if ($resultadoPrincipal) {
$resultadoEnvio = true;
error_log("✅ Resumen diario enviado a: {$usuario['email']}");
}
// Enviar al correo adicional si está configurado
if ($usuario['notificaciones_extra'] == 1 && !empty($usuario['correo_extra'])) {
$resultadoExtra = enviarEmailResumenDiario(
$usuario['correo_extra'],
$usuario['nombre'],
$datosImportador,
$fechaFiltro,
count($operaciones),
$rutaPdf,
true
);
if ($resultadoExtra) {
$resultadoEnvio = true;
error_log("✅ Resumen diario enviado a correo adicional: {$usuario['correo_extra']}");
}
}
// Limpiar archivo temporal
if (file_exists($rutaPdf)) {
unlink($rutaPdf);
}
return $resultadoEnvio;
} catch (Exception $e) {
error_log("❌ Error al procesar resumen diario para usuario {$usuario['email']}: " . $e->getMessage());
return false;
}
}
/** Función para obtener datos del importador **/
function obtenerDatosImportador($idUsuario)
{
$conn = getConnection();
if (!$conn) {
return null;
}
$sql = "
SELECT
ig.nombre,
ig.rfc,
CONCAT(ig.calle, ' ',
CASE WHEN ig.num_exterior IS NOT NULL THEN CONCAT('#', ig.num_exterior) ELSE '' END,
CASE WHEN ig.num_interior IS NOT NULL AND ig.num_interior != '' THEN CONCAT(' Int. ', ig.num_interior) ELSE '' END,
CASE WHEN ig.colonia IS NOT NULL AND ig.colonia != '' THEN CONCAT(', ', ig.colonia) ELSE '' END,
CASE WHEN ig.ciudad IS NOT NULL AND ig.ciudad != '' THEN CONCAT(', ', ig.ciudad) ELSE '' END,
CASE WHEN ig.estado IS NOT NULL AND ig.estado != '' THEN CONCAT(', ', ig.estado) ELSE '' END,
CASE WHEN ig.codigo_postal IS NOT NULL THEN CONCAT(' C.P. ', ig.codigo_postal) ELSE '' END
) as direccion,
ig.correo as correo_contacto,
ig.telefono,
u.email as email_usuario
FROM informacion_general ig
INNER JOIN usuarios_sistema u ON ig.id_usuario = u.id_usuario
WHERE u.id_usuario = ?
";
$stmt = sqlsrv_prepare($conn, $sql, [$idUsuario]);
if (!$stmt || !sqlsrv_execute($stmt)) {
sqlsrv_close($conn);
return null;
}
$datos = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
if ($datos) {
// Desencriptar datos sensibles
$datos['nombre_importador'] = decrypt($datos['nombre']); // Mapear nombre a nombre_importador para compatibilidad
$datos['direccion'] = $datos['direccion']; // Ya concatenada en la consulta
$datos['correo_contacto'] = decrypt($datos['correo_contacto']);
$datos['email_usuario'] = decrypt($datos['email_usuario']);
$datos['rfc'] = $datos['rfc']; // RFC generalmente no se encripta
}
return $datos;
}
/** Función para obtener operaciones diarias **/
function obtenerOperacionesDiarias($idUsuario, $fecha)
{
$conn = getConnection();
if (!$conn) {
return [];
}
$sql = "
SELECT
sif.numero_factura,
sif.valor_factura,
sif.tipo_moneda,
sif.fecha_factura,
sif.numero_pedimento,
sif.pais_proveedor,
sif.aduana,
CASE
WHEN sif.status = 0 THEN 'Pendiente'
WHEN sif.status = 1 THEN 'En Proceso'
WHEN sif.status = 2 THEN 'Completado'
WHEN sif.status = 3 THEN 'Cancelado'
ELSE 'Sin Estado'
END as status
FROM solicitud_importacion_factura sif
INNER JOIN usuarios_sistema u ON sif.id_importador = u.id_importador
WHERE u.id_usuario = ?
AND CAST(sif.fecha_factura AS DATE) = ?
ORDER BY sif.fecha_factura DESC
";
$stmt = sqlsrv_prepare($conn, $sql, [$idUsuario, $fecha]);
if (!$stmt || !sqlsrv_execute($stmt)) {
sqlsrv_close($conn);
return [];
}
$operaciones = [];
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Desencriptar datos si es necesario
$row['numero_factura'] = decrypt($row['numero_factura']);
$row['numero_pedimento'] = $row['numero_pedimento'] ? decrypt($row['numero_pedimento']) : 'N/A';
$operaciones[] = $row;
}
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
return $operaciones;
}
/** Función para generar el PDF del resumen **/
function generarPdfResumenDiario($datosImportador, $operaciones, $fecha)
{
require_once 'vendor/autoload.php'; // Asumiendo que usas TCPDF o similar
try {
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// Configuración del documento
$pdf->SetCreator('SIIH | AduanaSoft');
$pdf->SetAuthor('Sistema de Importaciones');
$pdf->SetTitle('Resumen Diario de Importaciones - ' . $fecha);
$pdf->SetSubject('Resumen de Operaciones');
// Configurar margenes
$pdf->SetMargins(15, 20, 15);
$pdf->SetHeaderMargin(10);
$pdf->SetFooterMargin(10);
// Agregar página
$pdf->AddPage();
// Encabezado
$html = '<h1 style="text-align: center; color: #2c3e50;">📊 Resumen Diario de Importaciones</h1>';
$html .= '<h2 style="text-align: center; color: #7f8c8d;">Fecha: ' . date('d/m/Y', strtotime($fecha)) . '</h2>';
// Datos del importador
$html .= '<div style="margin: 20px 0; padding: 15px; background-color: #f8f9fa; border: 1px solid #dee2e6;">';
$html .= '<h3 style="color: #495057; margin-top: 0;">🏢 Datos del Importador</h3>';
$html .= '<p><strong>Nombre:</strong> ' . htmlspecialchars($datosImportador['nombre_importador']) . '</p>';
$html .= '<p><strong>RFC:</strong> ' . htmlspecialchars($datosImportador['rfc'] ?? 'N/A') . '</p>';
$html .= '<p><strong>Dirección:</strong> ' . htmlspecialchars($datosImportador['direccion']) . '</p>';
$html .= '<p><strong>Correo:</strong> ' . htmlspecialchars($datosImportador['correo_contacto']) . '</p>';
$html .= '</div>';
// Resumen estadístico
$totalOperaciones = count($operaciones);
$valorTotal = array_sum(array_column($operaciones, 'valor_factura'));
$html .= '<div style="margin: 20px 0; padding: 15px; background-color: #e8f4fd; border: 1px solid #b8daff;">';
$html .= '<h3 style="color: #004085; margin-top: 0;">📈 Resumen Estadístico</h3>';
$html .= '<p><strong>Total de Operaciones:</strong> ' . $totalOperaciones . '</p>';
$html .= '<p><strong>Valor Total:</strong> $' . number_format($valorTotal, 2) . '</p>';
$html .= '</div>';
// Tabla de operaciones
$html .= '<h3 style="color: #495057;">📋 Detalle de Operaciones</h3>';
$html .= '<table border="1" cellpadding="8" cellspacing="0" style="width: 100%; border-collapse: collapse;">';
$html .= '<thead style="background-color: #6c757d; color: white;">';
$html .= '<tr>';
$html .= '<th style="width: 20%;">No. Factura</th>';
$html .= '<th style="width: 20%;">Valor</th>';
$html .= '<th style="width: 15%;">Moneda</th>';
$html .= '<th style="width: 25%;">Estado</th>';
$html .= '<th style="width: 20%;">Fecha</th>';
$html .= '</tr>';
$html .= '</thead>';
$html .= '<tbody>';
foreach ($operaciones as $op) {
$html .= '<tr>';
$html .= '<td>' . htmlspecialchars($op['numero_factura']) . '</td>';
$html .= '<td>$' . number_format($op['valor_factura'], 2) . '</td>';
$html .= '<td>' . htmlspecialchars($op['tipo_moneda']) . '</td>';
$html .= '<td>' . htmlspecialchars($op['status']) . '</td>';
$html .= '<td>' . date('d/m/Y H:i', strtotime($op['fecha_factura'])) . '</td>';
$html .= '</tr>';
}
$html .= '</tbody>';
$html .= '</table>';
// Pie del documento
$html .= '<div style="margin-top: 30px; text-align: center; color: #6c757d; font-size: 10px;">';
$html .= '<p>Este documento fue generado automáticamente el ' . date('d/m/Y H:i:s') . '</p>';
$html .= '<p>SIIH | AduanaSoft - Sistema Integral de Importaciones</p>';
$html .= '</div>';
$pdf->writeHTML($html, true, false, true, false, '');
// Generar nombre único para el archivo
$nombreArchivo = 'resumen_diario_' . $fecha . '_' . uniqid() . '.pdf';
$rutaCompleta = sys_get_temp_dir() . '/' . $nombreArchivo;
$pdf->Output($rutaCompleta, 'F');
return $rutaCompleta;
} catch (Exception $e) {
error_log("❌ Error al generar PDF: " . $e->getMessage());
return false;
}
}
/** Función para enviar el email con el resumen **/
function enviarEmailResumenDiario($emailDestino, $nombreUsuario, $datosImportador, $fecha, $totalOperaciones, $rutaPdf, $esCorreoAdicional = false)
{
try {
$mail = new PHPMailer(true);
// Configuración de servidor SMTP
$mail->isSMTP();
$mail->Host = 'secure.emailsrvr.com';
$mail->SMTPAuth = true;
$mail->Username = 'noreply@aduanasoft.com.mx';
$mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// Configuración del correo
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
$mail->addAddress($emailDestino);
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
// Adjuntar PDF
$mail->addAttachment($rutaPdf, 'resumen_diario_' . $fecha . '.pdf');
$fechaFormateada = date('d/m/Y', strtotime($fecha));
$asunto = "📊 Resumen Diario de Importaciones - $fechaFormateada$tipoCorreo";
$mail->Subject = $asunto;
$mail->Body = "
<html>
<head>
<meta charset='UTF-8'>
<title>Resumen Diario de Importaciones</title>
</head>
<body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>
<div style='max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #ddd; border-radius: 10px;'>
<div style='text-align: center; margin-bottom: 30px;'>
<h1 style='color: #2c3e50; margin: 0;'>📊 Resumen Diario de Importaciones</h1>
<h2 style='color: #7f8c8d; margin: 10px 0 0 0;'>$fechaFormateada</h2>
</div>
<div style='background-color: #f8f9fa; padding: 20px; border-radius: 8px; margin-bottom: 20px;'>
<h2 style='color: #2c3e50; margin-top: 0;'>Hola " . htmlspecialchars($nombreUsuario) . ",</h2>
<p>Te enviamos el resumen de tus operaciones de importación correspondientes al día <strong>$fechaFormateada</strong>.</p>
</div>
<div style='background-color: #e8f4fd; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #0066cc;'>
<h3 style='color: #004085; margin-top: 0;'>🏢 Importador: " . htmlspecialchars($datosImportador['nombre_importador']) . "</h3>
<p style='margin: 5px 0;'><strong>📧 Correo:</strong> " . htmlspecialchars($datosImportador['correo_contacto']) . "</p>
<p style='margin: 5px 0;'><strong>📍 Dirección:</strong> " . htmlspecialchars($datosImportador['direccion']) . "</p>
</div>
<div style='background-color: #d4edda; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #28a745;'>
<h3 style='color: #155724; margin-top: 0;'>📈 Resumen del Día</h3>
<p style='margin: 5px 0; font-size: 16px;'><strong>Total de Operaciones:</strong> <span style='color: #28a745; font-size: 18px;'>$totalOperaciones</span></p>
<p style='margin: 10px 0 0 0;'>📎 <strong>Adjunto:</strong> Reporte detallado en formato PDF con todas tus operaciones</p>
</div>
<div style='background-color: #fff3cd; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #ffc107;'>
<h3 style='color: #856404; margin-top: 0;'>📋 ¿Qué incluye el reporte?</h3>
<ul style='margin: 10px 0; padding-left: 20px;'>
<li>Número de factura de cada operación</li>
<li>Valor y moneda de las facturas</li>
<li>Estado actual de cada solicitud</li>
<li>Fecha y hora de registro</li>
<li>Resumen estadístico del día</li>
</ul>
</div>
<div style='background-color: #d1ecf1; padding: 15px; border-radius: 8px; margin-bottom: 20px; border-left: 4px solid #17a2b8;'>
<h3 style='color: #0c5460; margin-top: 0;'>⚙️ Configurar Notificaciones</h3>
<p>Puedes modificar la frecuencia y horario de estos resúmenes desde tu panel de <strong>Preferencias de Notificaciones</strong> en el sistema.</p>
</div>
<div style='text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid #eee;'>
<p style='color: #666; font-size: 12px; margin: 0;'>
Este resumen se genera automáticamente según tus preferencias de notificación.<br>
SIIH | AduanaSoft - Sistema Integral de Importaciones<br>
<em>Generado el " . date('d/m/Y H:i:s') . "</em>
</p>
</div>
</div>
</body>
</html>";
// Enviar el correo
$mail->send();
return true;
} catch (Exception $e) {
error_log("❌ Error al enviar resumen diario a $emailDestino: " . $e->getMessage());
return false;
}
}
?>

View File

@@ -416,6 +416,7 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
</div>
</div>
<br>
<!-- Configuración de correo adicional -->
<div class="section-divider">
<div class="form-check form-switch">
@@ -434,9 +435,6 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
<?php if (!empty($correoExtra)): ?>
<div class="alert alert-info d-flex align-items-center">
<div class="me-3">
<i class="fas fa-envelope" style="font-size: 1.2em;"></i>
</div>
<div>
<strong>📧 Correo adicional configurado:</strong><br>
<code><?= htmlspecialchars($correoExtra) ?></code>