diff --git a/app/controllers/administrador.php b/app/controllers/administrador.php index a7c4d97..8c1b98c 100644 --- a/app/controllers/administrador.php +++ b/app/controllers/administrador.php @@ -418,6 +418,7 @@ function guardar_usuario() exit; } + $conn = getConnection(); // 1. Capturar y validar datos diff --git a/app/controllers/importadores.php b/app/controllers/importadores.php index 44dbb40..2080886 100644 --- a/app/controllers/importadores.php +++ b/app/controllers/importadores.php @@ -2,6 +2,12 @@ require_once __DIR__ . '/../helpers/session.php'; require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/crypto.php'; +require_once __DIR__ . '/../../vendor/autoload.php'; + +use PHPMailer\PHPMailer\PHPMailer; +use PHPMailer\PHPMailer\Exception; + +loadEnv(); // Función para obtener catálogos visibles del usuario function obtenerCatalogosVisibles($idUsuario) @@ -228,6 +234,21 @@ function vincular() } } + // Obtener información del importador y la agencia para el correo + $infoSql = "SELECT + u.nombre AS nombre_importador, u.email AS email_importador, + a.nombre_agencia, a.email AS email_agencia, + admin.email AS admin_email, admin.nombre AS admin_nombre + FROM usuarios_sistema u + CROSS JOIN agencias_aduanales a + LEFT JOIN usuarios_sistema admin + ON a.id_administrador = admin.id_usuario + WHERE u.id_usuario = ? + AND a.id_agencia = ? + "; + $infoStmt = sqlsrv_query($conn, $infoSql, [$id_importador, $id_agencia]); + $info = sqlsrv_fetch_array($infoStmt, SQLSRV_FETCH_ASSOC); + // Insertar la nueva solicitud $sql = "INSERT INTO solicitudes_vinculacion (id_importador, id_agencia, mensaje, estado, fecha_solicitud) @@ -237,6 +258,48 @@ function vincular() $stmt = sqlsrv_prepare($conn, $sql, $params); if ($stmt && sqlsrv_execute($stmt)) { + // Enviar notificación al administrador de la agencia + if (!empty($info['admin_email'])) { + $mail = new PHPMailer(true); + try { + $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; + + $mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos'); + $mail->addAddress($info['admin_email']); + $mail->CharSet = 'UTF-8'; + $mail->isHTML(true); + $mail->Subject = 'Nueva solicitud de vinculación en SIIH'; + + $mail->Body = " +
+
+
+

¡Nueva solicitud de vinculación!

+
+
+

El importador {$info['nombre_importador']} ha solicitado vincularse con su agencia {$info['nombre_agencia']}.

+

Correo del importador: {$info['email_importador']}

+

Por favor, revise la solicitud en su panel de administración para aprobarla o rechazarla.

+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos +
+
+
+ "; + + $mail->send(); + } catch (Exception $e) { + error_log("Error al enviar correo: " . $mail->ErrorInfo); + } + } + header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=sended_request'); exit; } else { @@ -257,6 +320,18 @@ function cancelarVinculacion() $id_importador = $_SESSION['usuario_id']; $id_agencia = (int) $_GET['id']; + // Obtener información para el correo + $infoSql = "SELECT + u.nombre AS nombre_importador, u.email AS email_importador, + a.nombre_agencia + FROM solicitudes_vinculacion sv + JOIN usuarios_sistema u ON sv.id_importador = u.id_usuario + JOIN agencias_aduanales a ON sv.id_agencia = a.id_agencia + WHERE sv.id_importador = ? AND sv.id_agencia = ? AND sv.estado = 'PENDIENTE'"; + + $infoStmt = sqlsrv_query($conn, $infoSql, [$id_importador, $id_agencia]); + $info = sqlsrv_fetch_array($infoStmt, SQLSRV_FETCH_ASSOC); + $sql = "UPDATE solicitudes_vinculacion SET estado = 'CANCELADA', fecha_respuesta = GETDATE() WHERE id_importador = ? @@ -267,6 +342,48 @@ function cancelarVinculacion() $stmt = sqlsrv_prepare($conn, $sql, $params); if ($stmt && sqlsrv_execute($stmt)) { + // Enviar notificación al importador + if (!empty($info['email_importador'])) { + $mail = new PHPMailer(true); + try { + $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; + + $mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos'); + $mail->addAddress($info['email_importador']); + $mail->CharSet = 'UTF-8'; + $mail->isHTML(true); + $mail->Subject = 'Cancelación de solicitud de vinculación en SIIH'; + + $mail->Body = " +
+
+
+

Solicitud cancelada

+
+
+

Estimado/a {$info['nombre_importador']},

+

Has cancelado tu solicitud de vinculación con la agencia {$info['nombre_agencia']}.

+

Si esto fue un error, puedes volver a solicitar la vinculación desde tu panel de importador.

+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos +
+
+
+ "; + + $mail->send(); + } catch (Exception $e) { + error_log("Error al enviar correo: " . $mail->ErrorInfo); + } + } + header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=cancelled'); exit; } @@ -296,12 +413,16 @@ function desvincularUsuario() // 1. Verificar que la relación existe y pertenece a la agencia del admin $sqlVerificar = "SELECT - ia.*, u.id_usuario, u.nombre as importador_nombre, aa.nombre_agencia + ia.*, u.id_usuario, u.nombre as importador_nombre, u.email as importador_email, + aa.nombre_agencia, aa.email as agencia_email, + admin.email as admin_email, admin.nombre as admin_nombre FROM importador_agencia ia INNER JOIN usuarios_sistema u ON ia.id_importador = u.id_usuario INNER JOIN agencias_aduanales aa ON ia.id_agencia = aa.id_agencia + LEFT JOIN usuarios_sistema admin + ON aa.id_administrador = admin.id_usuario WHERE ia.id_relacion = ? AND ia.id_importador = ? "; @@ -358,6 +479,93 @@ function desvincularUsuario() } } + // Enviar notificaciones por correo + if (!empty($relacion['importador_email'])) { + // Notificación al importador + $mailImportador = new PHPMailer(true); + try { + $mailImportador->isSMTP(); + $mailImportador->Host = 'secure.emailsrvr.com'; + $mailImportador->SMTPAuth = true; + $mailImportador->Username = 'noreply@aduanasoft.com.mx'; + $mailImportador->Password = $_ENV['SMTP_PASS']; + $mailImportador->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; + $mailImportador->Port = 587; + + $mailImportador->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos'); + $mailImportador->addAddress($relacion['importador_email']); + $mailImportador->CharSet = 'UTF-8'; + $mailImportador->isHTML(true); + $mailImportador->Subject = 'Confirmación de desvinculación en SIIH'; + + $mailImportador->Body = " +
+
+
+

Desvinculación completada

+
+
+

Estimado/a {$relacion['importador_nombre']},

+

Has sido desvinculado de la agencia {$relacion['nombre_agencia']}.

+

Fecha de desvinculación: " . date('d/m/Y H:i:s') . "

+

Si esto es un error, por favor contacta al administrador de la agencia.

+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos +
+
+
+ "; + + $mailImportador->send(); + } catch (Exception $e) { + error_log("Error al enviar correo a importador: " . $mailImportador->ErrorInfo); + } + } + + if (!empty($relacion['admin_email'])) { + // Notificación al administrador de la agencia + $mailAdmin = new PHPMailer(true); + try { + $mailAdmin->isSMTP(); + $mailAdmin->Host = 'secure.emailsrvr.com'; + $mailAdmin->SMTPAuth = true; + $mailAdmin->Username = 'noreply@aduanasoft.com.mx'; + $mailAdmin->Password = $_ENV['SMTP_PASS']; + $mailAdmin->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; + $mailAdmin->Port = 587; + + $mailAdmin->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos'); + $mailAdmin->addAddress($relacion['admin_email']); + $mailAdmin->CharSet = 'UTF-8'; + $mailAdmin->isHTML(true); + $mailAdmin->Subject = 'Notificación de desvinculación en SIIH'; + + $mailAdmin->Body = " +
+
+
+

Notificación de desvinculación

+
+
+

Estimado/a {$relacion['admin_nombre']},

+

El importador {$relacion['importador_nombre']} se ha desvinculado de su agencia {$relacion['nombre_agencia']}.

+

Correo del importador: {$relacion['importador_email']}

+

Fecha de desvinculación: " . date('d/m/Y H:i:s') . "

+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos +
+
+
+ "; + + $mailAdmin->send(); + } catch (Exception $e) { + error_log("Error al enviar correo a administrador: " . $mailAdmin->ErrorInfo); + } + } + // Limpiar statements if (isset($stmtVerificar) && is_resource($stmtVerificar)) { sqlsrv_free_stmt($stmtVerificar); @@ -369,7 +577,6 @@ function desvincularUsuario() sqlsrv_free_stmt($stmtActualizarAgencia); } - // Confirmar transacción sqlsrv_commit($conn); sqlsrv_close($conn); diff --git a/app/controllers/registro.php b/app/controllers/registro.php index c56f2a2..69a1b2c 100644 --- a/app/controllers/registro.php +++ b/app/controllers/registro.php @@ -131,6 +131,10 @@ function obtenerConfiguracion($conn) // Función auxiliar para enviar email function enviarEmailConfirmacion($destinatario, $datosEmpresa, $esAgencia = false) { + if ($datosEmpresa['status'] !== 'pending') { + return false; + } + $mail = new PHPMailer(true); try { diff --git a/app/controllers/solicitud_importacion.php b/app/controllers/solicitud_importacion.php index b93afda..44b88d1 100644 --- a/app/controllers/solicitud_importacion.php +++ b/app/controllers/solicitud_importacion.php @@ -422,9 +422,7 @@ function guardar() $patente_id = $_POST['patente'] ?? null; if ($patente_id) { - $stmtValidatePatente = sqlsrv_query($conn, - "SELECT id_agente FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ? AND activo = 1", - [$patente_id, $id_agencia]); + $stmtValidatePatente = sqlsrv_query($conn, "SELECT id_agente FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ? AND activo = 1", [$patente_id, $id_agencia]); if (!$stmtValidatePatente || !sqlsrv_fetch_array($stmtValidatePatente, SQLSRV_FETCH_ASSOC)) { die("❌ La patente seleccionada no es válida para su agencia."); @@ -562,9 +560,9 @@ function guardar() if(!empty($_POST['partidas'])&&is_array($_POST['partidas'])){ $sqlP = "INSERT INTO dbo.solicitud_importacion_partidas - (id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; - + (id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + "; $partidas_insertadas = 0; // ← contador foreach ($_POST['partidas'] as $i => $p) { @@ -637,46 +635,47 @@ function enviarNotificacionNuevaSolicitud($email, $nombreUsuario, $datosSolicitu ' : ''; $mail->Body = " -
-
-
-

📥 Nueva Solicitud Registrada

-
-
- $tipoNotificacion -

Hola " . htmlspecialchars($nombreUsuario) . ",

-

Tu solicitud de importación ha sido registrada correctamente con los siguientes datos:

- -
- - - - - - - - - - - - - - - - - -
ID Solicitud:$idSolicitud
Número de Factura:$numeroFactura
Fecha:$fechaFactura
Valor:$valorFactura $tipoMoneda
+
+
+
+ h2 style='color: white; margin: 0;'>📥 Nueva Solicitud Registrada +
+
+ $tipoNotificacion +

Hola " . htmlspecialchars($nombreUsuario) . ",

+

Tu solicitud de importación ha sido registrada correctamente con los siguientes datos:

+ +
+ + + + + + + + + + + + + + + + + +
ID Solicitud:$idSolicitud
Número de Factura:$numeroFactura
Fecha:$fechaFactura
Valor:$valorFactura $tipoMoneda
+
+ +

Puedes consultar el estado de tu solicitud accediendo a tu panel de control.

+
+

Si no realizaste esta acción, contacta al administrador del sistema.

+
+
+ © " . date('Y') . " SIIH · Desarrollado por AduanaSoft +
- -

Puedes consultar el estado de tu solicitud accediendo a tu panel de control.

-
-

Si no realizaste esta acción, contacta al administrador del sistema.

-
- © " . date('Y') . " SIIH · Desarrollado por AduanaSoft -
-
-
"; + "; $envioExitoso = $mail->send(); @@ -929,8 +928,13 @@ function actualizar() if (!empty($p['id_partida']) && intval($p['id_partida']) > 0) { // ACTUALIZAR partida existente $sql = "UPDATE dbo.solicitud_importacion_partidas SET - descripcion = ?, cantidad_comercial = ?, cantidad_tarifa = ?, - valor_factura = ?, peso_bruto = ?, unidad_comercial_id = ?, tasa_preferencial = ? + descripcion = ?, + cantidad_comercial = ?, + cantidad_tarifa = ?, + valor_factura = ?, + peso_bruto = ?, + unidad_comercial_id = ?, + tasa_preferencial = ? WHERE id_partida = ? AND id_solicitud = ? "; @@ -1287,7 +1291,7 @@ function update_status() ON s.id_importador = u.id_usuario WHERE u.id_usuario = ? AND s.id_solicitud = ? - "; + "; $stmtNotif = sqlsrv_prepare($conn, $sqlNotif, [$_SESSION['usuario_id'], $id]); if ($stmtNotif && sqlsrv_execute($stmtNotif)) { @@ -1858,7 +1862,8 @@ function pdf() { } // NUEVA FUNCIÓN: Obtener información del proveedor por clave -function obtenerProveedorPorClave($clave) { +function obtenerProveedorPorClave($clave) +{ // Obtener token de la API $token = getApiToken(); if (!$token) { @@ -1906,7 +1911,8 @@ function obtenerProveedorPorClave($clave) { return null; } -function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = null) { +function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = null) +{ // Formatear fecha $fecha_expedicion = $solicitud['fecha_factura']->format('d/m/Y'); $fecha_vencimiento = $solicitud['fecha_factura']->modify('+30 days')->format('d/m/Y'); @@ -2047,162 +2053,163 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = } $html = ' - - - - - Solicitud de Importación - - - - - - - - - - -
-
-
-
' . htmlspecialchars($solicitud['importador_nombre']) . '
-
' . htmlspecialchars($direccion_completa ?: 'Dirección no disponible') . '
-
RFC: ' . htmlspecialchars($solicitud['importador_rfc'] ?? 'No disponible') . '
-
Tel: ' . htmlspecialchars($solicitud['telefono'] ?? 'No disponible') . '
-
Email: ' . htmlspecialchars($solicitud['correo'] ?? 'No disponible') . '
-
-
' . htmlspecialchars($configuracion['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos') . '

-
Solicitud de Importación
-
No. ' . htmlspecialchars($solicitud['id_solicitud']) . '
-
+ + + + + Solicitud de Importación + + + + + + + + + + +
+
+
+
' . htmlspecialchars($solicitud['importador_nombre']) . '
+
' . htmlspecialchars($direccion_completa ?: 'Dirección no disponible') . '
+
RFC: ' . htmlspecialchars($solicitud['importador_rfc'] ?? 'No disponible') . '
+
Tel: ' . htmlspecialchars($solicitud['telefono'] ?? 'No disponible') . '
+
Email: ' . htmlspecialchars($solicitud['correo'] ?? 'No disponible') . '
+
+
' . htmlspecialchars($configuracion['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos') . '

+
Solicitud de Importación
+
No. ' . htmlspecialchars($solicitud['id_solicitud']) . '
+
- - - - - - - - -
- + +
+ + + + + + +
+ + + + + +
RAZÓN SOCIAL:' . htmlspecialchars($proveedor_nombre) . '
+ + + + + +
DIRECCIÓN:' . htmlspecialchars($proveedor_direccion) . '
+ + + + + +
RFC:' . htmlspecialchars($proveedor_rfc) . '
+
+ + + + + +
FECHA DE EXPEDICIÓN
' . $fecha_expedicion . '
FECHA DE VENCIMIENTO
' . $fecha_vencimiento . '
+
+ + + + + + + +
CLAVE:' . htmlspecialchars($solicitud['proveedor_clave'] ?? 'No disponible') . 'TELÉFONO:' . htmlspecialchars($proveedor_telefono) . '
+ + + + - - + + + + + -
RAZÓN SOCIAL:' . htmlspecialchars($proveedor_nombre) . 'ProductoUnidad de MedidaPrecio UnitarioCantidadTotal
- - - - - -
DIRECCIÓN:' . htmlspecialchars($proveedor_direccion) . '
- - - - - -
RFC:' . htmlspecialchars($proveedor_rfc) . '
-
- - - - - -
FECHA DE EXPEDICIÓN
' . $fecha_expedicion . '
FECHA DE VENCIMIENTO
' . $fecha_vencimiento . '
-
- - - - - - - -
CLAVE:' . htmlspecialchars($solicitud['proveedor_clave'] ?? 'No disponible') . 'TELÉFONO:' . htmlspecialchars($proveedor_telefono) . '
+ + '; - - - - - - - - - - - - '; + // Agregar partidas + foreach ($partidas as $partida) { + $precio_unitario = (float)($partida['precio_unitario'] ?? 0); + $cantidad = (float)($partida['cantidad_comercial'] ?? 0); + $valor_partida = (float)($partida['valor_factura'] ?? 0); + + $html .= ' + + + + + + + '; + } - // Agregar partidas - foreach ($partidas as $partida) { - $precio_unitario = (float)($partida['precio_unitario'] ?? 0); - $cantidad = (float)($partida['cantidad_comercial'] ?? 0); - $valor_partida = (float)($partida['valor_factura'] ?? 0); - - $html .= ' - - - - - - - '; - } + $html .= ' + +
ProductoUnidad de MedidaPrecio UnitarioCantidadTotal
' . htmlspecialchars($partida['descripcion']) . '' . htmlspecialchars($partida['unidad_descripcion'] ?? 'Unidad de servicio (E48)') . '' . $moneda_codigo . ' ' . number_format($precio_unitario > 0 ? $precio_unitario : $valor_partida, 2) . '' . number_format($cantidad > 0 ? $cantidad : 1, 0) . '' . $moneda_codigo . ' ' . number_format($valor_partida, 2) . '
' . htmlspecialchars($partida['descripcion']) . '' . htmlspecialchars($partida['unidad_descripcion'] ?? 'Unidad de servicio (E48)') . '' . $moneda_codigo . ' ' . number_format($precio_unitario > 0 ? $precio_unitario : $valor_partida, 2) . '' . number_format($cantidad > 0 ? $cantidad : 1, 0) . '' . $moneda_codigo . ' ' . number_format($valor_partida, 2) . '
- $html .= ' - - + + - - + +
+
+ Total: + ' . $moneda_codigo . ' ' . number_format($total, 2) . ' +
+
- -
-
- Total: - ' . $moneda_codigo . ' ' . number_format($total, 2) . ' -
-
- - -'; + + + '; return $html; } \ No newline at end of file diff --git a/views/admin/alta_usuarios.php b/views/admin/alta_usuarios.php index 08b57b4..701261d 100644 --- a/views/admin/alta_usuarios.php +++ b/views/admin/alta_usuarios.php @@ -302,12 +302,24 @@ e.preventDefault(); let isValid = true; + const inputs = document.querySelectorAll('input.form-control, select.form-select'); + + // Validar todos los campos inputs.forEach(input => { if (!input.checkValidity()) { input.classList.add('shake'); isValid = false; + setTimeout(() => input.classList.remove('shake'), 500); } }); + + // Si todo es válido, enviar el formulario + if (isValid) { + this.submit(); // Esta línea faltaba en tu código original + } else { + // Mostrar mensaje de error si lo deseas + Swal.fire({ title: 'Campos incompletos', text: 'Por favor complete todos los campos requeridos', icon: 'error' }); + } }); }); diff --git a/views/admin/dashboard_admin.php b/views/admin/dashboard_admin.php index 28f506a..0682c7e 100644 --- a/views/admin/dashboard_admin.php +++ b/views/admin/dashboard_admin.php @@ -149,7 +149,7 @@
-
Aprobar de usuarios
+
Aprobar usuarios

Aprueba los usuarios que solicitaron un registro.

Cancelar
@@ -186,7 +186,7 @@ if ($tipoUsuario === 'agente_aduanal') {
Cancelar
diff --git a/views/login/verificar_codigo.php b/views/login/verificar_codigo.php index cf1614f..2f68e66 100644 --- a/views/login/verificar_codigo.php +++ b/views/login/verificar_codigo.php @@ -173,16 +173,16 @@ if (!isset($_SESSION['email_recuperacion'])) { diff --git a/views/vinculaciones/vinculaciones_importador.php b/views/vinculaciones/vinculaciones_importador.php index f7bc062..da7c715 100644 --- a/views/vinculaciones/vinculaciones_importador.php +++ b/views/vinculaciones/vinculaciones_importador.php @@ -71,7 +71,7 @@ ➕ Nueva Vinculación
-
🏪 Agencia Vinculadas
+
🏪 Agencias Vinculadas
@@ -101,7 +101,7 @@ En uso - Usar Agencia + @@ -138,6 +138,21 @@ } }); } + + function confirmChangeAgency(id) { + Swal.fire({ + title: '¿Quieres cambiar de agencia?', + text: 'Dejaras de usar la agencia actual y cambiarás a la nueva.', + icon: 'warning', + showCancelButton: true, + confirmButtonText: 'Sí, cambiar agencia', + cancelButtonText: 'Cancelar' + }).then((result) => { + if (result.isConfirmed) { + window.location.href = `/IMPORTADORES/importadores/cambiarAgenciaActiva?id=${id}`; + } + }); + }