From 287ad27274e8422214fefb5768d452d883954ce3 Mon Sep 17 00:00:00 2001 From: Alexeer Date: Wed, 9 Jul 2025 16:14:22 -0600 Subject: [PATCH] Sintaxis --- app/controllers/administrador.php | 9 +- app/controllers/agencias.php | 55 +- app/controllers/agentes.php | 98 +-- app/controllers/bitacoras.php | 122 +-- app/controllers/choferes.php | 317 +++---- app/controllers/configuracion.php | 53 +- app/controllers/expediente.php | 100 ++- app/controllers/importadores.php | 103 ++- app/controllers/locaciones.php | 145 ++-- app/controllers/login.php | 86 +- app/controllers/patente.php | 181 ++-- app/controllers/preferencias.php | 155 ++-- app/controllers/productos_frecuentes.php | 153 ++-- app/controllers/proveedores.php | 57 +- app/controllers/registro.php | 17 +- app/controllers/reset.php | 146 ++-- app/controllers/seguridad.php | 60 +- app/controllers/solicitud_importacion.php | 813 +++++++++--------- app/controllers/transportes.php | 213 ++--- app/controllers/transportistas.php | 303 ++++--- app/controllers/vinculaciones.php | 348 ++++---- views/admin/alta_agencias.php | 14 +- views/admin/alta_usuarios.php | 4 +- views/admin/dashboard_admin.php | 26 +- views/agencias/dashboard_agencias.php | 48 +- views/agentes/dashboard_agentes.php | 22 +- views/bitacoras/dashboard_bitacoras.php | 4 +- views/choferes/crear.php | 392 ++++++++- .../configuracion/dashboard_configuracion.php | 4 +- views/importadores/dashboard_importador.php | 10 +- views/locaciones/alta_locaciones.php | 8 +- views/partials/sidebar_agencia.php | 6 +- views/partials/sidebar_agente.php | 4 +- views/preferencias/dashboard_preferencias.php | 4 +- views/reset/change_password.php | 109 ++- views/seguridad/agregar.php | 298 +++++-- views/transportes/crear.php | 16 +- views/transportistas/alta.php | 10 +- views/transportistas/lista.php | 4 +- 39 files changed, 2517 insertions(+), 2000 deletions(-) diff --git a/app/controllers/administrador.php b/app/controllers/administrador.php index 7514e22..c3cc461 100644 --- a/app/controllers/administrador.php +++ b/app/controllers/administrador.php @@ -525,7 +525,7 @@ function aprobar_agencia() $sqlGetAgenciaId = "SELECT SCOPE_IDENTITY() AS id_agencia"; $stmtGetAgenciaId = sqlsrv_query($conn, $sqlGetAgenciaId); $agenciaIdRow = sqlsrv_fetch_array($stmtGetAgenciaId, SQLSRV_FETCH_ASSOC); - $id_agencia = $idUsuarioRow['id_agencia'] ?? null; + $id_agencia = $agenciaIdRow['id_agencia'] ?? null; if (!$id_agencia) { die("❌ No se pudo obtener el ID de la agencia recién creada."); @@ -535,9 +535,7 @@ function aprobar_agencia() $sqlInsert2 = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por) VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?) "; - $stmtInsert2 = sqlsrv_query($conn, $sqlInsert, [ - $admin_name_encrypt, $admin_email_encrypt, $password_hash, $tipo, $usuario_id - ]); + $stmtInsert2 = sqlsrv_query($conn, $sqlInsert, [$admin_name_encrypt, $admin_email_encrypt, $password_hash, $tipo, $usuario_id]); if (!$stmtInsert2) { die("❌ Error al crear usuario administrador: " . print_r(sqlsrv_errors(), true)); @@ -576,7 +574,8 @@ function aprobar_agencia() SET request_status = 'approved', approval_date = GETDATE(), approved_by = ? - WHERE request_id = ?"; + WHERE request_id = ? + "; $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$usuario_id, $id]); if (!$stmtUpdate) { diff --git a/app/controllers/agencias.php b/app/controllers/agencias.php index 6c3729a..e22b456 100644 --- a/app/controllers/agencias.php +++ b/app/controllers/agencias.php @@ -1,6 +1,5 @@ false, 'message' => 'No autorizado']); exit; } - $gafete = trim($_GET['numero_gafete'] ?? ''); + $gafete = trim($_GET['numero_gafete'] ?? ''); $id_chofer = $_GET['id_chofer'] ?? null; if ($gafete === '') { @@ -235,11 +257,11 @@ function validarNumeroGafete() { if ($id_chofer) { // Edición: excluir el chofer actual - $sql = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND id_chofer <> ? AND status = 1"; + $sql = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND id_chofer <> ? AND status = 1"; $stmt = sqlsrv_query($conn, $sql, [$gafete, $id_chofer]); } else { // Alta nueva - $sql = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND status = 1"; + $sql = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND status = 1"; $stmt = sqlsrv_query($conn, $sql, [$gafete]); } @@ -252,21 +274,22 @@ function validarNumeroGafete() { } /** Procesa la actualización de un chofer **/ -function actualizar() { +function actualizar() +{ if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } - $id = $_POST['id_chofer'] ?? null; - $transportista_id = $_POST['transportista_id'] ?? null; - $nombre = trim($_POST['nombre'] ?? ''); - $apellido = trim($_POST['apellido'] ?? ''); - $licencia = trim($_POST['numero_licencia']?? ''); - $gafete = trim($_POST['numero_gafete']?? ''); - $telefono = trim($_POST['telefono'] ?? ''); - $email = trim($_POST['email'] ?? ''); - $fecha_ingreso = $_POST['fecha_ingreso'] ?: null; - $status = isset($_POST['status']) ? 1 : 0; + $id = $_POST['id_chofer'] ?? null; + $transportista_id = $_POST['transportista_id'] ?? null; + $nombre = trim($_POST['nombre'] ?? ''); + $apellido = trim($_POST['apellido'] ?? ''); + $licencia = trim($_POST['numero_licencia'] ?? ''); + $gafete = trim($_POST['numero_gafete'] ?? ''); + $telefono = trim($_POST['telefono'] ?? ''); + $email = trim($_POST['email'] ?? ''); + $fecha_ingreso = $_POST['fecha_ingreso'] ?: null; + $status = isset($_POST['status']) ? 1 : 0; // Validación básica if ( @@ -281,7 +304,8 @@ function actualizar() { // ✅ CRÍTICO: Verificar que el número de gafete no existe (excluyendo el chofer actual) $sqlCheckGafete = "SELECT id_chofer FROM dbo.choferes WHERE numero_gafete = ? AND id_chofer <> ? AND status = 1"; - $stmtCheck = sqlsrv_query($conn, $sqlCheckGafete, [$gafete, $id_chofer]); + $stmtCheck = sqlsrv_query($conn, $sqlCheckGafete, [$gafete, $id_chofer]); + if ($stmtCheck && sqlsrv_fetch($stmtCheck)) { die("❌ El número de gafete '{$gafete}' ya está en uso. Por favor, use otro número."); } @@ -290,7 +314,7 @@ function actualizar() { $fotoUrl = null; if (!empty($_FILES['foto']['tmp_name']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) { $allowedTypes = ['jpg', 'jpeg', 'png', 'gif']; - $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); + $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); if (!in_array($ext, $allowedTypes)) { die("❌ Tipo de archivo no permitido. Solo JPG, PNG, GIF."); @@ -314,64 +338,62 @@ function actualizar() { } if ($fotoUrl) { - $sql = " - UPDATE dbo.choferes SET - transportista_id = ?, - nombre = ?, - apellido = ?, - numero_licencia = ?, - numero_gafete = ?, - telefono = ?, - email = ?, - fecha_ingreso = ?, - foto_url = ?, - status = ?, - updated_at = GETDATE() - WHERE id_chofer = ? - "; + $sql = "UPDATE dbo.choferes SET + transportista_id = ?, + nombre = ?, + apellido = ?, + numero_licencia = ?, + numero_gafete = ?, + telefono = ?, + email = ?, + fecha_ingreso = ?, + foto_url = ?, + status = ?, + updated_at = GETDATE() + WHERE id_chofer = ? + "; $params = [ - (int)$transportista_id, - $nombre, - $apellido, - $licencia, - $gafete, - $telefono, - $email, - $fecha_ingreso, - $fotoUrl, - $status, - (int)$id - ]; + (int)$transportista_id, + $nombre, + $apellido, + $licencia, + $gafete, + $telefono, + $email, + $fecha_ingreso, + $fotoUrl, + $status, + (int)$id + ]; } else { - $sql = " - UPDATE dbo.choferes SET - transportista_id = ?, - nombre = ?, - apellido = ?, - numero_licencia = ?, - numero_gafete = ?, - telefono = ?, - email = ?, - fecha_ingreso = ?, - status = ?, - updated_at = GETDATE() - WHERE id_chofer = ? - "; + $sql = "UPDATE dbo.choferes SET + transportista_id = ?, + nombre = ?, + apellido = ?, + numero_licencia = ?, + numero_gafete = ?, + telefono = ?, + email = ?, + fecha_ingreso = ?, + status = ?, + updated_at = GETDATE() + WHERE id_chofer = ? + "; $params = [ - (int)$transportista_id, - $nombre, - $apellido, - $licencia, - $gafete, - $telefono, - $email, - $fecha_ingreso, - $status, - (int)$id - ]; + (int)$transportista_id, + $nombre, + $apellido, + $licencia, + $gafete, + $telefono, + $email, + $fecha_ingreso, + $status, + (int)$id + ]; } - $stmt = sqlsrv_query($conn, $sql, $params); + if ($stmt === false) { $errors = sqlsrv_errors(); // ✅ Manejo específico de error de duplicado @@ -388,25 +410,28 @@ function actualizar() { } /** “Soft-delete” (status = 0) de un chofer **/ -function eliminar() { +function eliminar() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } $id = $_GET['id'] ?? null; + if (!$id || !is_numeric($id)) { die("❌ ID inválido."); } $conn = getConnection(); - $sql = " - UPDATE dbo.choferes - SET status = 0, - updated_at = GETDATE() - WHERE id_chofer = ? - "; + + $sql = "UPDATE dbo.choferes + SET status = 0, + updated_at = GETDATE() + WHERE id_chofer = ? + "; $stmt = sqlsrv_query($conn, $sql, [(int)$id]); + if ($stmt === false) { die("❌ Error en eliminar(): " . print_r(sqlsrv_errors(), true)); } diff --git a/app/controllers/configuracion.php b/app/controllers/configuracion.php index e79022c..ae7c96f 100644 --- a/app/controllers/configuracion.php +++ b/app/controllers/configuracion.php @@ -6,6 +6,7 @@ require_once __DIR__ . '/../helpers/crypto.php'; function index() { $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id'] ?? null; if (!$id_usuario) { @@ -35,7 +36,7 @@ function index() // Dependiendo del tipo de usuario, obtenemos información adicional switch (trim($usuario['tipo_usuario'])) { // Agregué trim() por si hay espacios case 'importador': - $sql_importador = "SELECT * FROM informacion_general WHERE id_usuario = ?"; + $sql_importador = "SELECT * FROM informacion_general WHERE id_usuario = ?"; $stmt_importador = sqlsrv_query($conn, $sql_importador, [$id_usuario]); if ($stmt_importador !== false) { @@ -48,15 +49,17 @@ function index() case 'admin_agencia': case 'agente_aduanal': - $sql_agencia = " - SELECT aa.id_agencia, aa.nombre_agencia, aa.rfc_agencia, - aa.direccion AS direccion_agencia, aa.telefono AS telefono_agencia, - aa.email AS email_agencia, aga.fecha_asignacion - FROM agente_agencia aga - INNER JOIN agencias_aduanales aa ON aga.id_agencia = aa.id_agencia - WHERE aga.id_agente = ? AND aga.activo = 1 AND aa.activo = 1 - "; - + $sql_agencia = "SELECT + aa.id_agencia, aa.nombre_agencia, aa.rfc_agencia, + aa.direccion AS direccion_agencia, aa.telefono AS telefono_agencia, + aa.email AS email_agencia, aga.fecha_asignacion + FROM agente_agencia aga + INNER JOIN agencias_aduanales aa + ON aga.id_agencia = aa.id_agencia + WHERE aga.id_agente = ? + AND aga.activo = 1 + AND aa.activo = 1 + "; $stmt_agencia = sqlsrv_query($conn, $sql_agencia, [$id_usuario]); if ($stmt_agencia !== false) { @@ -88,7 +91,8 @@ function index() function editar() { - $conn = getConnection(); + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id'] ?? null; if (!$id_usuario) { @@ -96,9 +100,9 @@ function editar() } // Traer los datos existentes del usuario - $sql = "SELECT * FROM informacion_general WHERE id_usuario = ?"; + $sql = "SELECT * FROM informacion_general WHERE id_usuario = ?"; $params = [$id_usuario]; - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { die(print_r(sqlsrv_errors(), true)); @@ -112,6 +116,7 @@ function editar() function guardar() { $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id'] ?? null; if (!$id_usuario) { @@ -125,7 +130,7 @@ function guardar() ]; $sql_parts = []; - $params = []; + $params = []; foreach ($campos as $campo) { if (isset($_POST[$campo]) && $_POST[$campo] !== '') { @@ -144,10 +149,10 @@ function guardar() try { // 1. Actualiza la tabla informacion_general - $sql = "UPDATE informacion_general SET " . implode(", ", $sql_parts) . " WHERE id_usuario = ?"; + $sql = "UPDATE informacion_general SET " . implode(", ", $sql_parts) . " WHERE id_usuario = ?"; $params[] = $id_usuario; + $stmt = sqlsrv_query($conn, $sql, $params); - $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { throw new Exception(print_r(sqlsrv_errors(), true)); } @@ -157,9 +162,9 @@ function guardar() $telefono = $_POST['telefono']; // Primero obtenemos el nombre de la empresa de informacion_general - $sql_get_name = "SELECT nombre FROM informacion_general WHERE id_usuario = ?"; + $sql_get_name = "SELECT nombre FROM informacion_general WHERE id_usuario = ?"; $params_get_name = [$id_usuario]; - $stmt_get_name = sqlsrv_query($conn, $sql_get_name, $params_get_name); + $stmt_get_name = sqlsrv_query($conn, $sql_get_name, $params_get_name); if ($stmt_get_name === false) { throw new Exception("Error al obtener nombre de empresa: " . print_r(sqlsrv_errors(), true)); @@ -174,10 +179,9 @@ function guardar() $nombre_encriptado = encrypt($nombre_empresa); // Actualizar solicitudes_importadores usando el company_name encriptado - $sql_solicitud = "UPDATE solicitudes_importadores SET phone = ? WHERE company_name = ?"; + $sql_solicitud = "UPDATE solicitudes_importadores SET phone = ? WHERE company_name = ?"; $params_solicitud = [$telefono, $nombre_encriptado]; - - $stmt_solicitud = sqlsrv_query($conn, $sql_solicitud, $params_solicitud); + $stmt_solicitud = sqlsrv_query($conn, $sql_solicitud, $params_solicitud); if ($stmt_solicitud === false) { throw new Exception("Error al actualizar teléfono en solicitudes: " . print_r(sqlsrv_errors(), true)); @@ -190,16 +194,15 @@ function guardar() error_log("No se encontró registro en solicitudes_importadores para actualizar teléfono. Empresa: " . $nombre_empresa); // Opcional: Buscar por RFC como fallback - $sql_rfc = "SELECT rfc FROM informacion_general WHERE id_usuario = ?"; + $sql_rfc = "SELECT rfc FROM informacion_general WHERE id_usuario = ?"; $stmt_rfc = sqlsrv_query($conn, $sql_rfc, [$id_usuario]); if ($stmt_rfc) { $rfc_data = sqlsrv_fetch_array($stmt_rfc, SQLSRV_FETCH_ASSOC); if ($rfc_data && !empty($rfc_data['rfc'])) { - $sql_solicitud_rfc = "UPDATE solicitudes_importadores SET phone = ? WHERE rfc = ?"; + $sql_solicitud_rfc = "UPDATE solicitudes_importadores SET phone = ? WHERE rfc = ?"; $params_solicitud_rfc = [$telefono, $rfc_data['rfc']]; - - $stmt_solicitud_rfc = sqlsrv_query($conn, $sql_solicitud_rfc, $params_solicitud_rfc); + $stmt_solicitud_rfc = sqlsrv_query($conn, $sql_solicitud_rfc, $params_solicitud_rfc); if ($stmt_solicitud_rfc === false) { error_log("Error al actualizar por RFC: " . print_r(sqlsrv_errors(), true)); diff --git a/app/controllers/expediente.php b/app/controllers/expediente.php index 4ec0398..ae1ab0d 100644 --- a/app/controllers/expediente.php +++ b/app/controllers/expediente.php @@ -4,33 +4,33 @@ require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/env.php'; // Mostrar tabla de expedientes -function index() { +function index() +{ if (!isset($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } + $conn = getConnection(); + $id_importador = $_SESSION['usuario_id']; - $sql = " - SELECT - sif.id_solicitud, - sif.numero_pedimento, - sif.fecha_factura, - sif.aduana, - sif.proveedor_clave, - COUNT(ea.id) AS total_archivos, - ISNULL(SUM(ea.tamano_archivo), 0) AS total_tamano - FROM solicitud_importacion_factura sif - LEFT JOIN expediente_archivos ea ON ea.id_solicitud = sif.id_solicitud - WHERE sif.numero_pedimento IS NOT NULL AND sif.id_importador = ? and sif.status > 0 - GROUP BY sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave - ORDER BY sif.fecha_factura DESC - "; - + $sql = "SELECT + sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave, + COUNT(ea.id) AS total_archivos, + ISNULL(SUM(ea.tamano_archivo), 0) AS total_tamano + FROM solicitud_importacion_factura sif + LEFT JOIN expediente_archivos ea + ON ea.id_solicitud = sif.id_solicitud + WHERE sif.numero_pedimento IS NOT NULL + AND sif.id_importador = ? + AND sif.status > 0 + GROUP BY sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave + ORDER BY sif.fecha_factura DESC + "; $stmt = sqlsrv_query($conn, $sql, [$id_importador]); - $expedientes = []; + $expedientes = []; if ($stmt) { while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $expedientes[] = $row; @@ -40,17 +40,20 @@ function index() { include __DIR__ . '/../../views/expediente/index.php'; } -function subir($id_solicitud) { +function subir($id_solicitud) +{ include __DIR__ . '/../../views/expediente/subir.php'; } -function subir_handler() { +function subir_handler() +{ if (!isset($_POST['id_solicitud']) || !isset($_FILES['archivos']) || !isset($_SESSION['usuario_id'])) { die("❌ Solicitud inválida."); } $conn = getConnection(); - $id_solicitud = (int) $_POST['id_solicitud']; + + $id_solicitud = (int) $_POST['id_solicitud']; $id_importador = $_SESSION['usuario_id']; // Validar propiedad de la solicitud @@ -60,7 +63,7 @@ function subir_handler() { } $archivos = $_FILES['archivos']; - $usuario = $_SESSION['usuario_nombre'] ?? 'sistema'; + $usuario = $_SESSION['usuario_nombre'] ?? 'sistema'; $uploadDir = __DIR__ . '/../../uploads/expedientes/' . $id_solicitud; if (!is_dir($uploadDir)) { @@ -71,18 +74,19 @@ function subir_handler() { if ($archivos['error'][$i] !== 0) continue; $nombreOriginal = basename($archivos['name'][$i]); - $nombreSeguro = uniqid() . '_' . preg_replace('/[^A-Za-z0-9._-]/', '_', $nombreOriginal); - $rutaFinal = $uploadDir . '/' . $nombreSeguro; + $nombreSeguro = uniqid() . '_' . preg_replace('/[^A-Za-z0-9._-]/', '_', $nombreOriginal); + $rutaFinal = $uploadDir . '/' . $nombreSeguro; move_uploaded_file($archivos['tmp_name'][$i], $rutaFinal); - $rutaDb = "uploads/expedientes/$id_solicitud/$nombreSeguro"; - $tamanoKb = round(filesize($rutaFinal) / 1024, 2); + $rutaDb = "uploads/expedientes/$id_solicitud/$nombreSeguro"; + $tamanoKb = round(filesize($rutaFinal) / 1024, 2); $tipoArchivo = mime_content_type($rutaFinal); - $sql = "INSERT INTO expediente_archivos (id_solicitud, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por) - VALUES (?, ?, ?, ?, ?, ?)"; - + $sql = "INSERT INTO expediente_archivos + (id_solicitud, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por) + VALUES (?, ?, ?, ?, ?, ?) + "; $params = [$id_solicitud, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario]; sqlsrv_query($conn, $sql, $params); } @@ -99,12 +103,13 @@ function ver($id_solicitud) } $conn = getConnection(); - $id_importador = $_SESSION['usuario_id']; - $archivos = []; - $sql = "SELECT * FROM expediente_archivos WHERE id_solicitud = ? AND id_solicitud IN (SELECT id_solicitud FROM solicitud_importacion_factura WHERE id_importador = ?) ORDER BY creado_en DESC"; + $id_importador = $_SESSION['usuario_id']; + + $sql = "SELECT * FROM expediente_archivos WHERE id_solicitud = ? AND id_solicitud IN (SELECT id_solicitud FROM solicitud_importacion_factura WHERE id_importador = ?) ORDER BY creado_en DESC"; $stmt = sqlsrv_query($conn, $sql, [$id_solicitud, $id_importador]); + $archivos = []; if ($stmt) { while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { if (is_string($row['creado_en'])) { @@ -117,15 +122,17 @@ function ver($id_solicitud) include __DIR__ . '/../../views/expediente/ver.php'; } -function ver_archivo($id_archivo) { +function ver_archivo($id_archivo) +{ if (!isset($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } $conn = getConnection(); - $sql = "SELECT ea.*, sif.id_importador FROM expediente_archivos ea JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud WHERE ea.id = ?"; - $stmt = sqlsrv_query($conn, $sql, [$id_archivo]); + + $sql = "SELECT ea.*, sif.id_importador FROM expediente_archivos ea JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud WHERE ea.id = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id_archivo]); $archivo = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if (!$archivo || $archivo['id_importador'] != $_SESSION['usuario_id']) { @@ -141,7 +148,7 @@ function ver_archivo($id_archivo) { exit; } - $tipo = $archivo['tipo_archivo'] ?? mime_content_type($ruta); + $tipo = $archivo['tipo_archivo'] ?? mime_content_type($ruta); $nombre = $archivo['nombre_archivo']; header('Content-Type: ' . $tipo); @@ -160,16 +167,19 @@ function descargar_zip($id_solicitud) } $conn = getConnection(); + $id_importador = $_SESSION['usuario_id']; - $sql = " - SELECT ea.nombre_archivo, ea.ruta_archivo - FROM expediente_archivos ea - JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud - WHERE ea.id_solicitud = ? AND sif.id_importador = ? - "; - + $sql = "SELECT + ea.nombre_archivo, ea.ruta_archivo + FROM expediente_archivos ea + JOIN solicitud_importacion_factura sif + ON sif.id_solicitud = ea.id_solicitud + WHERE ea.id_solicitud = ? + AND sif.id_importador = ? + "; $stmt = sqlsrv_query($conn, $sql, [$id_solicitud, $id_importador]); + if (!$stmt) { http_response_code(500); echo "Error al consultar archivos."; @@ -181,7 +191,7 @@ function descargar_zip($id_solicitud) $ruta_absoluta = __DIR__ . '/../../' . $row['ruta_archivo']; if (file_exists($ruta_absoluta)) { $archivos[] = [ - 'ruta' => $ruta_absoluta, + 'ruta' => $ruta_absoluta, 'nombre' => $row['nombre_archivo'] ]; } @@ -194,7 +204,7 @@ function descargar_zip($id_solicitud) } $zip_file = tempnam(sys_get_temp_dir(), 'expediente_') . '.zip'; - $zip = new ZipArchive(); + $zip = new ZipArchive(); if ($zip->open($zip_file, ZipArchive::CREATE) !== true) { http_response_code(500); diff --git a/app/controllers/importadores.php b/app/controllers/importadores.php index f920f32..eaf0aa3 100644 --- a/app/controllers/importadores.php +++ b/app/controllers/importadores.php @@ -4,7 +4,8 @@ require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/crypto.php'; // Función para obtener catálogos visibles del usuario -function obtenerCatalogosVisibles($idUsuario) { +function obtenerCatalogosVisibles($idUsuario) +{ $conn = getConnection(); // Obtener configuración general y tipo de usuario @@ -132,7 +133,8 @@ function obtenerCatalogosVisibles($idUsuario) { } // Función para obtener icono según el nombre del catálogo -function obtenerIconoCatalogo($nombre) { +function obtenerIconoCatalogo($nombre) +{ $iconos = [ 'Locaciones' => '📍', 'Vinculación' => '🔗', @@ -169,28 +171,30 @@ function dashboard() function lista() { $conn = getConnection(); - $locaciones = []; // Consulta conjunta para evitar múltiples queries anidadas - $sql = " - SELECT - p.id_pais, p.nombre AS nombre_pais, p.iso2, p.iso3, - e.id_estado, e.nombre AS nombre_estado, e.abreviatura, - c.id_ciudad, c.nombre AS nombre_ciudad - FROM paises p - LEFT JOIN estados e ON p.id_pais = e.pais_id - LEFT JOIN ciudades c ON e.id_estado = c.estado_id - ORDER BY p.id_pais, e.id_estado, c.id_ciudad - "; - + $sql = "SELECT + p.id_pais, p.nombre AS nombre_pais, p.iso2, p.iso3, + e.id_estado, e.nombre AS nombre_estado, e.abreviatura, + c.id_ciudad, c.nombre AS nombre_ciudad + FROM paises p + LEFT JOIN estados e + ON p.id_pais = e.pais_id + LEFT JOIN ciudades c + ON e.id_estado = c.estado_id + ORDER BY p.id_pais, e.id_estado, c.id_ciudad + "; $stmt = sqlsrv_query($conn, $sql); + + $locaciones = []; while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $locaciones[] = $row; } // Obtener países para los selects del modal - $sql_paises_select = "SELECT id_pais, nombre FROM paises ORDER BY nombre"; + $sql_paises_select = "SELECT id_pais, nombre FROM paises ORDER BY nombre"; $stmt_paises_select = sqlsrv_query($conn, $sql_paises_select); + $paises = []; while ($row = sqlsrv_fetch_array($stmt_paises_select, SQLSRV_FETCH_ASSOC)) { $paises[] = $row; @@ -225,7 +229,10 @@ function vincular() } // Insertar la nueva solicitud - $sql = "INSERT INTO solicitudes_vinculacion (id_importador, id_agencia, mensaje, estado, fecha_solicitud) VALUES (?, ?, 'Solicitud de vinculación', 'PENDIENTE', GETDATE())"; + $sql = "INSERT INTO solicitudes_vinculacion + (id_importador, id_agencia, mensaje, estado, fecha_solicitud) + VALUES (?, ?, 'Solicitud de vinculación', 'PENDIENTE', GETDATE()) + "; $params = [$id_importador, $id_agencia]; $stmt = sqlsrv_prepare($conn, $sql, $params); @@ -250,12 +257,14 @@ function cancelarVinculacion() $id_importador = $_SESSION['usuario_id']; $id_agencia = (int) $_GET['id']; - $sql = "UPDATE solicitudes_vinculacion - SET estado = 'CANCELADA', fecha_respuesta = GETDATE() - WHERE id_importador = ? AND id_agencia = ? AND estado = 'PENDIENTE'"; - + $sql = "UPDATE solicitudes_vinculacion + SET estado = 'CANCELADA', fecha_respuesta = GETDATE() + WHERE id_importador = ? + AND id_agencia = ? + AND estado = 'PENDIENTE' + "; $params = [$id_importador, $id_agencia]; - $stmt = sqlsrv_prepare($conn, $sql, $params); + $stmt = sqlsrv_prepare($conn, $sql, $params); if ($stmt && sqlsrv_execute($stmt)) { header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=cancelled'); @@ -284,15 +293,16 @@ function desvincularUsuario() sqlsrv_begin_transaction($conn); // 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 - 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 - WHERE ia.id_relacion = ? AND ia.id_importador = ? - "; + $sqlVerificar = "SELECT + ia.*, u.id_usuario, u.nombre as importador_nombre, aa.nombre_agencia + 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 + WHERE ia.id_relacion = ? + AND ia.id_importador = ? + "; $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$id_relacion, $_SESSION['usuario_id']]); // Verificar si la consulta fue exitosa @@ -313,14 +323,13 @@ function desvincularUsuario() } // 2. Desactivar la relación (no eliminar, mantener historial) - $sqlDesactivar = " - UPDATE importador_agencia - SET activo = 0, - fecha_desvinculacion = GETDATE(), - estado = 'DESVINCULADO' - WHERE id_relacion = ? AND id_importador = ? - "; - + $sqlDesactivar = "UPDATE importador_agencia + SET activo = 0, + fecha_desvinculacion = GETDATE(), + estado = 'DESVINCULADO' + WHERE id_relacion = ? + AND id_importador = ? + "; $stmtDesactivar = sqlsrv_query($conn, $sqlDesactivar, [$id_relacion, $_SESSION['usuario_id']]); if ($stmtDesactivar === false) { @@ -337,11 +346,7 @@ function desvincularUsuario() // 3. Actualizar el campo id_agencia_en_uso del usuario si es necesario if ($_SESSION['id_agencia_en_uso'] == $relacion['id_agencia']) { - $sqlActualizarAgencia = " - UPDATE usuarios_sistema - SET id_agencia_en_uso = NULL - WHERE id_usuario = ? - "; + $sqlActualizarAgencia = "UPDATE usuarios_sistema SET id_agencia_en_uso = NULL WHERE id_usuario = ?"; $stmtActualizarAgencia = sqlsrv_query($conn, $sqlActualizarAgencia, [$_SESSION['usuario_id']]); if ($stmtActualizarAgencia === false) { @@ -392,11 +397,7 @@ function cambiarAgenciaActiva() $conn = getConnection(); // Validar que el importador está vinculado a esta agencia - $sqlVerificacion = " - SELECT 1 - FROM importador_agencia - WHERE id_importador = ? AND id_agencia = ? AND activo = 1 - "; + $sqlVerificacion = "SELECT 1 FROM importador_agencia WHERE id_importador = ? AND id_agencia = ? AND activo = 1"; $stmtVerificacion = sqlsrv_query($conn, $sqlVerificacion, [$id_usuario, $id_agencia]); if ($stmtVerificacion === false || !sqlsrv_fetch($stmtVerificacion)) { @@ -405,11 +406,7 @@ function cambiarAgenciaActiva() } // Actualizar campo id_agencia_en_uso - $sqlUpdate = " - UPDATE usuarios_sistema - SET id_agencia_en_uso = ? - WHERE id_usuario = ? - "; + $sqlUpdate = "UPDATE usuarios_sistema SET id_agencia_en_uso = ? WHERE id_usuario = ?"; $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$id_agencia, $id_usuario]); if ($stmtUpdate === false) { diff --git a/app/controllers/locaciones.php b/app/controllers/locaciones.php index bb228b5..1de0189 100644 --- a/app/controllers/locaciones.php +++ b/app/controllers/locaciones.php @@ -1,6 +1,5 @@ false, 'message' => 'Debe seleccionar un país']); @@ -106,8 +106,8 @@ function guardarEstado() $conn = getConnection(); // Verificar que el país existe - $sql_pais = "SELECT COUNT(*) as count FROM paises WHERE id_pais = ?"; - $stmt_pais = sqlsrv_query($conn, $sql_pais, [$pais_id]); + $sql_pais = "SELECT COUNT(*) as count FROM paises WHERE id_pais = ?"; + $stmt_pais = sqlsrv_query($conn, $sql_pais, [$pais_id]); $pais_exists = sqlsrv_fetch_array($stmt_pais, SQLSRV_FETCH_ASSOC); if ($pais_exists['count'] == 0) { @@ -116,9 +116,9 @@ function guardarEstado() } // Verificar si ya existe el estado en ese país - $sql_check = "SELECT COUNT(*) as count FROM estados WHERE pais_id = ? AND nombre = ?"; + $sql_check = "SELECT COUNT(*) as count FROM estados WHERE pais_id = ? AND nombre = ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$pais_id, $entidad]); - $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); if ($exists['count'] > 0) { echo json_encode(['success' => false, 'message' => 'Este estado ya existe en el país seleccionado']); @@ -127,12 +127,12 @@ function guardarEstado() // Insertar nuevo estado // Primero obtenemos el siguiente ID disponible - $sql_max = "SELECT ISNULL(MAX(id_estado), 0) + 1 as next_id FROM estados"; - $stmt_max = sqlsrv_query($conn, $sql_max); + $sql_max = "SELECT ISNULL(MAX(id_estado), 0) + 1 as next_id FROM estados"; + $stmt_max = sqlsrv_query($conn, $sql_max); $next_id_row = sqlsrv_fetch_array($stmt_max, SQLSRV_FETCH_ASSOC); - $next_id = $next_id_row['next_id']; + $next_id = $next_id_row['next_id']; - $sql = "INSERT INTO estados (id_estado, pais_id, nombre) VALUES (?, ?, ?)"; + $sql = "INSERT INTO estados (id_estado, pais_id, nombre) VALUES (?, ?, ?)"; $stmt = sqlsrv_query($conn, $sql, [$next_id, $pais_id, $entidad]); if ($stmt) { @@ -160,8 +160,8 @@ function guardarCiudad() header('Content-Type: application/json; charset=utf-8'); try { - $estado_id = $_POST['entidad'] ?? ''; - $ciudad = trim($_POST['ciudad'] ?? ''); + $estado_id = $_POST['entidad'] ?? ''; + $ciudad = trim($_POST['ciudad'] ?? ''); // Validaciones if (empty($estado_id) || empty($ciudad)) { @@ -172,9 +172,9 @@ function guardarCiudad() $conn = getConnection(); // Verificar si ya existe la ciudad en ese estado - $sql_check = "SELECT COUNT(*) as count FROM ciudades WHERE estado_id = ? AND nombre = ?"; + $sql_check = "SELECT COUNT(*) as count FROM ciudades WHERE estado_id = ? AND nombre = ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$estado_id, $ciudad]); - $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); if ($exists['count'] > 0) { echo json_encode(['success' => false, 'message' => 'Esta ciudad ya existe en el estado seleccionado']); @@ -182,11 +182,11 @@ function guardarCiudad() } // Insertar nueva ciudad - $sql = "INSERT INTO ciudades (estado_id, nombre) VALUES (?, ?)"; + $sql = "INSERT INTO ciudades (estado_id, nombre) VALUES (?, ?)"; $stmt = sqlsrv_query($conn, $sql, [$estado_id, $ciudad]); if ($stmt) { - echo json_encode(['success' => true, 'message' => 'Ciudad registrada exitosamente']); + echo json_encode(['success' => true, 'message' => 'Ciudad registrada exitosamente']); } else { echo json_encode(['success' => false, 'message' => 'Error al registrar la ciudad']); } @@ -211,11 +211,12 @@ function obtenerPaisPorEstado() } $conn = getConnection(); - $sql = "SELECT pais_id FROM estados WHERE id_estado = ?"; + + $sql = "SELECT pais_id FROM estados WHERE id_estado = ?"; $stmt = sqlsrv_query($conn, $sql, [$estado_id]); if ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { - echo json_encode(['success' => true, 'pais_id' => $row['pais_id']]); + echo json_encode(['success' => true, 'pais_id' => $row['pais_id']]); } else { echo json_encode(['success' => false, 'message' => 'Estado no encontrado']); } @@ -258,10 +259,10 @@ function actualizarPais() header('Content-Type: application/json; charset=utf-8'); try { - $id = $_POST['id'] ?? ''; + $id = $_POST['id'] ?? ''; $nombre = trim($_POST['nombre'] ?? ''); - $iso2 = trim($_POST['iso2'] ?? ''); - $iso3 = trim($_POST['iso3'] ?? ''); + $iso2 = trim($_POST['iso2'] ?? ''); + $iso3 = trim($_POST['iso3'] ?? ''); // Validaciones if (empty($id) || empty($nombre)) { @@ -270,13 +271,14 @@ function actualizarPais() } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => 'Error de conexión a la base de datos']); exit; } // Verificar duplicados - $sql_check = "SELECT COUNT(*) as count FROM paises WHERE nombre = ? AND id_pais != ?"; + $sql_check = "SELECT COUNT(*) as count FROM paises WHERE nombre = ? AND id_pais != ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$nombre, $id]); if (!$stmt_check) { @@ -294,10 +296,9 @@ function actualizarPais() $iso2_val = empty($iso2) ? null : $iso2; $iso3_val = empty($iso3) ? null : $iso3; - $sql = "UPDATE paises SET nombre = ?, iso2 = ?, iso3 = ? WHERE id_pais = ?"; + $sql = "UPDATE paises SET nombre = ?, iso2 = ?, iso3 = ? WHERE id_pais = ?"; $params = [$nombre, $iso2_val, $iso3_val, $id]; - - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt && sqlsrv_rows_affected($stmt) > 0) { echo json_encode(['success' => true, 'message' => 'País actualizado exitosamente']); @@ -317,10 +318,10 @@ function actualizarEstado() header('Content-Type: application/json; charset=utf-8'); try { - $id = $_POST['id'] ?? ''; - $nombre = trim($_POST['nombre'] ?? ''); + $id = $_POST['id'] ?? ''; + $nombre = trim($_POST['nombre'] ?? ''); $abreviatura = trim($_POST['abreviatura'] ?? ''); - $pais_id = $_POST['pais_id'] ?? ''; + $pais_id = $_POST['pais_id'] ?? ''; // Validaciones if (empty($id) || empty($nombre) || empty($pais_id)) { @@ -329,13 +330,14 @@ function actualizarEstado() } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => 'Error de conexión a la base de datos']); exit; } // Verificar duplicados - $sql_check = "SELECT COUNT(*) as count FROM estados WHERE nombre = ? AND pais_id = ? AND id_estado != ?"; + $sql_check = "SELECT COUNT(*) as count FROM estados WHERE nombre = ? AND pais_id = ? AND id_estado != ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$nombre, $pais_id, $id]); if (!$stmt_check) { @@ -352,10 +354,9 @@ function actualizarEstado() // Actualizar $abreviatura_val = empty($abreviatura) ? null : $abreviatura; - $sql = "UPDATE estados SET nombre = ?, abreviatura = ?, pais_id = ? WHERE id_estado = ?"; + $sql = "UPDATE estados SET nombre = ?, abreviatura = ?, pais_id = ? WHERE id_estado = ?"; $params = [$nombre, $abreviatura_val, $pais_id, $id]; - - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt && sqlsrv_rows_affected($stmt) > 0) { echo json_encode(['success' => true, 'message' => 'Estado actualizado exitosamente']); @@ -375,9 +376,9 @@ function actualizarCiudad() header('Content-Type: application/json; charset=utf-8'); try { - $id = $_POST['id'] ?? ''; - $nombre = trim($_POST['nombre'] ?? ''); - $estado_id = $_POST['estado_id'] ?? ''; + $id = $_POST['id'] ?? ''; + $nombre = trim($_POST['nombre'] ?? ''); + $estado_id = $_POST['estado_id'] ?? ''; // Validaciones if (empty($id) || empty($nombre) || empty($estado_id)) { @@ -386,13 +387,14 @@ function actualizarCiudad() } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => 'Error de conexión a la base de datos']); exit; } // Verificar duplicados - $sql_check = "SELECT COUNT(*) as count FROM ciudades WHERE nombre = ? AND estado_id = ? AND id_ciudad != ?"; + $sql_check = "SELECT COUNT(*) as count FROM ciudades WHERE nombre = ? AND estado_id = ? AND id_ciudad != ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$nombre, $estado_id, $id]); if (!$stmt_check) { @@ -407,10 +409,9 @@ function actualizarCiudad() } // Actualizar - $sql = "UPDATE ciudades SET nombre = ?, estado_id = ? WHERE id_ciudad = ?"; + $sql = "UPDATE ciudades SET nombre = ?, estado_id = ? WHERE id_ciudad = ?"; $params = [$nombre, $estado_id, $id]; - - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt && sqlsrv_rows_affected($stmt) > 0) { echo json_encode(['success' => true, 'message' => 'Ciudad actualizada exitosamente']); @@ -432,8 +433,8 @@ function eliminar() try { // Obtener datos del JSON enviado $input = json_decode(file_get_contents('php://input'), true); - $tipo = $input['tipo'] ?? ''; - $id = $input['id'] ?? ''; + $tipo = $input['tipo'] ?? ''; + $id = $input['id'] ?? ''; if (empty($tipo) || empty($id)) { echo json_encode(['success' => false, 'message' => 'Datos incompletos']); @@ -445,8 +446,8 @@ function eliminar() switch ($tipo) { case 'pais': // Verificar si el país tiene estados asociados - $sql_check = "SELECT COUNT(*) as count FROM estados WHERE pais_id = ?"; - $stmt_check = sqlsrv_query($conn, $sql_check, [$id]); + $sql_check = "SELECT COUNT(*) as count FROM estados WHERE pais_id = ?"; + $stmt_check = sqlsrv_query($conn, $sql_check, [$id]); $has_estados = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); if ($has_estados['count'] > 0) { @@ -455,7 +456,7 @@ function eliminar() } // Eliminar país - $sql = "DELETE FROM paises WHERE id_pais = ?"; + $sql = "DELETE FROM paises WHERE id_pais = ?"; $stmt = sqlsrv_query($conn, $sql, [$id]); if ($stmt) { @@ -472,8 +473,8 @@ function eliminar() case 'estado': // Verificar si el estado tiene ciudades asociadas - $sql_check = "SELECT COUNT(*) as count FROM ciudades WHERE estado_id = ?"; - $stmt_check = sqlsrv_query($conn, $sql_check, [$id]); + $sql_check = "SELECT COUNT(*) as count FROM ciudades WHERE estado_id = ?"; + $stmt_check = sqlsrv_query($conn, $sql_check, [$id]); $has_ciudades = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); if ($has_ciudades['count'] > 0) { @@ -482,7 +483,7 @@ function eliminar() } // Eliminar estado - $sql = "DELETE FROM estados WHERE id_estado = ?"; + $sql = "DELETE FROM estados WHERE id_estado = ?"; $stmt = sqlsrv_query($conn, $sql, [$id]); if ($stmt) { @@ -502,7 +503,7 @@ function eliminar() // (aquí puedes agregar más verificaciones según tu modelo de datos) // Eliminar ciudad - $sql = "DELETE FROM ciudades WHERE id_ciudad = ?"; + $sql = "DELETE FROM ciudades WHERE id_ciudad = ?"; $stmt = sqlsrv_query($conn, $sql, [$id]); if ($stmt) { diff --git a/app/controllers/login.php b/app/controllers/login.php index 26960ba..f1423a1 100644 --- a/app/controllers/login.php +++ b/app/controllers/login.php @@ -4,8 +4,8 @@ require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/crypto.php'; require_once __DIR__ . '/../helpers/bitacoras.php'; require_once __DIR__ . '/../helpers/env.php'; - require_once __DIR__ . '/../../vendor/autoload.php'; + use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; @@ -33,9 +33,7 @@ function validar() $emailEncrypted = encrypt($email); // Obtenemos el usuario incluyendo el campo dos_factores - $sql = "SELECT id_usuario, nombre, email, password_hash, tipo_usuario, activo, dos_factores - FROM usuarios_sistema WHERE email = ?"; - + $sql = "SELECT id_usuario, nombre, email, password_hash, tipo_usuario, activo, dos_factores FROM usuarios_sistema WHERE email = ?"; $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]); if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { @@ -225,9 +223,7 @@ function confirmarAcceso() exit; } - $sql = "SELECT codigo, expiracion FROM verificaciones - WHERE id_usuario = ? AND codigo = ? - ORDER BY id DESC"; + $sql = "SELECT codigo, expiracion FROM verificaciones WHERE id_usuario = ? AND codigo = ? ORDER BY id DESC"; $stmt = sqlsrv_query($conn, $sql, [$usuarioId, $codigoIngresado]); if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) { @@ -282,7 +278,9 @@ function recuperar() function enviarCodigo() { header('Content-Type: application/json'); + $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']); exit; @@ -314,8 +312,7 @@ function enviarCodigo() } $now = (new DateTime())->format('Y-m-d H:i:s'); - $sqlCheck = "SELECT COUNT(*) AS total FROM recuperacion_password - WHERE email = ? AND estatus = 0 AND expiracion > ?"; + $sqlCheck = "SELECT COUNT(*) AS total FROM recuperacion_password WHERE email = ? AND estatus = 0 AND expiracion > ?"; $checkStmt = sqlsrv_query($conn, $sqlCheck, [$emailEncrypted, $now]); $checkRow = sqlsrv_fetch_array($checkStmt, SQLSRV_FETCH_ASSOC); @@ -339,7 +336,7 @@ function enviarCodigo() // ✅ AGREGAR ESTAS LÍNEAS PARA ESTABLECER LA SESIÓN $_SESSION['email_recuperacion'] = $email; - $_SESSION['id_usuario'] = $id_usuario; + $_SESSION['id_usuario'] = $id_usuario; try { $mail = new PHPMailer(true); @@ -458,6 +455,7 @@ function reenviarCodigo() } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']); exit; @@ -467,10 +465,8 @@ function reenviarCodigo() $emailEncrypted = encrypt($_SESSION['email_recuperacion']); // Obtener el último código activo de recuperación - $now = (new DateTime())->format('Y-m-d H:i:s'); - $sql = "SELECT TOP 1 codigo FROM recuperacion_password - WHERE email = ? AND estatus = 0 AND expiracion > ? - ORDER BY expiracion DESC"; + $now = (new DateTime())->format('Y-m-d H:i:s'); + $sql = "SELECT TOP 1 codigo FROM recuperacion_password WHERE email = ? AND estatus = 0 AND expiracion > ? ORDER BY expiracion DESC"; $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted, $now]); if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) { @@ -530,8 +526,7 @@ function verificarCodigo() $emailEncrypted = encrypt($email); // Consulta el último código válido para ese email - $sql = "SELECT TOP 1 id, codigo, expiracion FROM recuperacion_password - WHERE email = ? AND estatus = 0 ORDER BY id DESC"; + $sql = "SELECT TOP 1 id, codigo, expiracion FROM recuperacion_password WHERE email = ? AND estatus = 0 ORDER BY id DESC"; $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]); if ($stmt === false) { @@ -567,13 +562,13 @@ function verificarCodigo() // Verificar si se han excedido los intentos if ($_SESSION['intentos_codigo'] >= 5) { // Bloquear el código - $sqlUpdate = "UPDATE recuperacion_password SET estatus = 1 WHERE id = ?"; + $sqlUpdate = "UPDATE recuperacion_password SET estatus = 1 WHERE id = ?"; $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$row['id']]); if ($stmtUpdate) sqlsrv_free_stmt($stmtUpdate); // Bloquear la cuenta del usuario $sqlBloquearUsuario = "UPDATE usuarios_sistema SET activo = 0 WHERE email = ?"; - $stmtBloqueo = sqlsrv_query($conn, $sqlBloquearUsuario, [$emailEncrypted]); + $stmtBloqueo = sqlsrv_query($conn, $sqlBloquearUsuario, [$emailEncrypted]); if ($stmtBloqueo) sqlsrv_free_stmt($stmtBloqueo); // Enviar notificación @@ -639,25 +634,25 @@ function verificarCodigo() function enviarNotificacionIntentosExcedidos($email) { $conn = getConnection(); + if (!$conn) { throw new Exception("No se pudo conectar a la base de datos"); } // Buscar información del usuario por email $emailEncrypted = encrypt($email); - $sqlNotif = " - SELECT - u.nombre, - u.email, - u.notificaciones, - u.notificaciones_extra, - COALESCE(p.intentos_fallidos, 0) as intentos_fallidos, - ce.correo as correo_extra - FROM usuarios_sistema u - LEFT JOIN preferencias_notificaciones_usuario p ON u.id_usuario = p.id_usuario - LEFT JOIN correo_extra ce ON u.id_usuario = ce.id_usuario - WHERE u.email = ?"; + $sqlNotif = "SELECT + u.nombre, u.email, u.notificaciones, u.notificaciones_extra, + COALESCE(p.intentos_fallidos, 0) as intentos_fallidos, + ce.correo as correo_extra + FROM usuarios_sistema u + LEFT JOIN preferencias_notificaciones_usuario p + ON u.id_usuario = p.id_usuario + LEFT JOIN correo_extra ce + ON u.id_usuario = ce.id_usuario + WHERE u.email = ? + "; $stmtUsuario = sqlsrv_query($conn, $sqlNotif, [$emailEncrypted]); if ($stmtUsuario === false) { @@ -687,7 +682,7 @@ function enviarNotificacionIntentosExcedidos($email) 'email' => $usuario['email'], 'nombre' => $usuario['nombre'], 'fecha_hora' => date('Y-m-d H:i:s'), - 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida', + 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida', 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Desconocido' ]; @@ -822,23 +817,21 @@ function enviarNotificacionSeguridadIntentos($emailDestino, $nombreUsuario, $dat function enviarNotificacionCuentaBloqueada($email) { $conn = getConnection(); + 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 - 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 = ?"; - + $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 = ? + "; $stmtUsuario = sqlsrv_query($conn, $sqlNotif, [$emailEncrypted]); if ($stmtUsuario === false) { @@ -854,7 +847,7 @@ function enviarNotificacionCuentaBloqueada($email) } // 🔐 Desencriptar datos sensibles - $usuario['email'] = decrypt($usuario['email']); + $usuario['email'] = decrypt($usuario['email']); $usuario['nombre'] = decrypt($usuario['nombre']); // Preparar datos para la notificación @@ -862,7 +855,7 @@ function enviarNotificacionCuentaBloqueada($email) 'email' => $usuario['email'], 'nombre' => $usuario['nombre'], 'fecha_hora' => date('Y-m-d H:i:s'), - 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida', + 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida', 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Desconocido' ]; @@ -1019,8 +1012,9 @@ function cambiarPassword() return; } - $conn = getConnection(); - $password = $_POST['password'] ?? ''; + $conn = getConnection(); + + $password = $_POST['password'] ?? ''; $confirmar = $_POST['confirmar'] ?? ''; // Validaciones diff --git a/app/controllers/patente.php b/app/controllers/patente.php index ff728f7..0d677bb 100644 --- a/app/controllers/patente.php +++ b/app/controllers/patente.php @@ -1,6 +1,5 @@ 10) die("❌ El campo {$campo} no puede exceder 10 caracteres."); // Opcional: Si quieres mantener solo números, descomenta la siguiente línea - // if (!is_numeric($valor)) die("❌ El campo {$campo} debe ser numérico."); + if (!is_numeric($valor)) die("❌ El campo {$campo} debe ser numérico."); } } // Validar todos los campos de folios - validarFolio($vp_inicio, 'VP Inicio'); - validarFolio($vp_final, 'VP Final'); - validarFolio($vp_siguiente, 'VP Siguiente'); - validarFolio($vpe_inicio, 'VPE Inicio'); - validarFolio($vpe_final, 'VPE Final'); - validarFolio($vpe_siguiente, 'VPE Siguiente'); - validarFolio($vat_pb_inicio, 'VAT PB Inicio'); - validarFolio($vat_pb_final, 'VAT PB Final'); + validarFolio($vp_inicio, 'VP Inicio'); + validarFolio($vp_final, 'VP Final'); + validarFolio($vp_siguiente, 'VP Siguiente'); + validarFolio($vpe_inicio, 'VPE Inicio'); + validarFolio($vpe_final, 'VPE Final'); + validarFolio($vpe_siguiente, 'VPE Siguiente'); + validarFolio($vat_pb_inicio, 'VAT PB Inicio'); + validarFolio($vat_pb_final, 'VAT PB Final'); validarFolio($vat_pb_siguiente, 'VAT PB Siguiente'); - validarFolio($vcc_inicio, 'VCC Inicio'); - validarFolio($vcc_final, 'VCC Final'); - validarFolio($vcc_siguiente, 'VCC Siguiente'); - validarFolio($vae_inicio, 'VAE Inicio'); - validarFolio($vae_final, 'VAE Final'); - validarFolio($vae_siguiente, 'VAE Siguiente'); + validarFolio($vcc_inicio, 'VCC Inicio'); + validarFolio($vcc_final, 'VCC Final'); + validarFolio($vcc_siguiente, 'VCC Siguiente'); + validarFolio($vae_inicio, 'VAE Inicio'); + validarFolio($vae_final, 'VAE Final'); + validarFolio($vae_siguiente, 'VAE Siguiente'); // Validar duplicado para este usuario - $sqlCheck = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales WHERE aduana = ? AND patente = ? AND id_usuario = ?"; + $sqlCheck = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales WHERE aduana = ? AND patente = ? AND id_usuario = ?"; $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$aduana, $patente, $id_usuario]); if ($stmtCheck === false) die("❌ Error al verificar duplicados: " . print_r(sqlsrv_errors(), true)); @@ -209,27 +215,27 @@ function guardar() $vae_siguiente = empty($vae_siguiente) ? null : $vae_siguiente; // Insertar registro - $sql = "INSERT INTO dbo.agentes_aduanales - (id_agencia, aduana, patente, agente_aduanal, rfc, curp, razon_social, id_usuario, activo, - mf_nombre, mf_paterno, mf_materno, - vp_inicio, vp_final, vp_siguiente, - vpe_inicio, vpe_final, vpe_siguiente, - vat_pb_inicio, vat_pb_final, vat_pb_siguiente, - vcc_inicio, vcc_final, vcc_siguiente, - vae_inicio, vae_final, vae_siguiente) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - + $sql = "INSERT INTO dbo.agentes_aduanales + (id_agencia, aduana, patente, agente_aduanal, rfc, curp, razon_social, id_usuario, activo, + mf_nombre, mf_paterno, mf_materno, + vp_inicio, vp_final, vp_siguiente, + vpe_inicio, vpe_final, vpe_siguiente, + vat_pb_inicio, vat_pb_final, vat_pb_siguiente, + vcc_inicio, vcc_final, vcc_siguiente, + vae_inicio, vae_final, vae_siguiente) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "; $params = [ - $id_agencia, $aduana, $patente, $agente_aduanal, $rfc, $curp, $razon_social, $id_usuario, - $mf_nombre, $mf_paterno, $mf_materno, - $vp_inicio, $vp_final, $vp_siguiente, - $vpe_inicio, $vpe_final, $vpe_siguiente, - $vat_pb_inicio, $vat_pb_final, $vat_pb_siguiente, - $vcc_inicio, $vcc_final, $vcc_siguiente, - $vae_inicio, $vae_final, $vae_siguiente - ]; + $id_agencia, $aduana, $patente, $agente_aduanal, $rfc, $curp, $razon_social, $id_usuario, + $mf_nombre, $mf_paterno, $mf_materno, + $vp_inicio, $vp_final, $vp_siguiente, + $vpe_inicio, $vpe_final, $vpe_siguiente, + $vat_pb_inicio, $vat_pb_final, $vat_pb_siguiente, + $vcc_inicio, $vcc_final, $vcc_siguiente, + $vae_inicio, $vae_final, $vae_siguiente + ]; + $stmt = sqlsrv_query($conn, $sql, $params); - $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) die("❌ Error al guardar agente aduanal."); sqlsrv_free_stmt($stmt); @@ -246,9 +252,9 @@ function editar() exit; } - $id_usuario = $_SESSION['usuario_id']; + $id_usuario = $_SESSION['usuario_id']; $tipo_usuario = $_SESSION['tipo_usuario']; - $id = $_GET['id'] ?? null; + $id = $_GET['id'] ?? null; if (!$id || !is_numeric($id)) { die("❌ ID inválido."); @@ -262,13 +268,13 @@ function editar() if ($tipo_usuario === 'agente_aduanal') { // Obtener la agencia vinculada al agente $stmtAgencia = sqlsrv_query($conn, "SELECT id_agencia FROM dbo.agente_agencia WHERE id_agente = ?", [$id_usuario]); - $rowAgencia = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC); - $id_agencia = $rowAgencia['id_agencia'] ?? null; + $rowAgencia = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC); + $id_agencia = $rowAgencia['id_agencia'] ?? null; } elseif ($tipo_usuario === 'admin_agencia') { // Obtener la agencia del admin $stmtAgencia = sqlsrv_query($conn, "SELECT id_agencia FROM dbo.agente_agencia WHERE id_agente = ?", [$id_usuario]); - $rowAgencia = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC); - $id_agencia = $rowAgencia['id_agencia'] ?? null; + $rowAgencia = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC); + $id_agencia = $rowAgencia['id_agencia'] ?? null; } else { die("❌ Tipo de usuario no autorizado."); } @@ -278,7 +284,7 @@ function editar() } // Consultar la patente que tenga ese id_agente y que pertenezca a la agencia del usuario - $sql = "SELECT * FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ?"; + $sql = "SELECT * FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ?"; $stmt = sqlsrv_query($conn, $sql, [$id, $id_agencia]); if ($stmt === false) { @@ -314,6 +320,7 @@ function actualizar() // ✅ NUEVO: Obtener la agencia actual del usuario $stmt = sqlsrv_query($conn, "SELECT id_agencia FROM dbo.agente_agencia WHERE id_agente = ?", [$id_usuario]); + $id_agencia = null; if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $id_agencia = $row['id_agencia']; @@ -354,13 +361,13 @@ function actualizar() if (strlen($curp) > 18) die("❌ El CURP no puede exceder 18 caracteres."); // Validar duplicado (excepto el propio id) - $sqlCheck = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales - WHERE aduana = ? AND patente = ? AND id_usuario = ? AND id_agente != ?"; + $sqlCheck = "SELECT COUNT(*) as count FROM dbo.agentes_aduanales WHERE aduana = ? AND patente = ? AND id_usuario = ? AND id_agente != ?"; $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$aduana, $patente, $id_usuario, $id_agente]); if ($stmtCheck === false) die("❌ Error al verificar duplicados."); $row = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + if ($row['count'] > 0) die("❌ Ya existe un agente aduanal con esta combinación de aduana y patente."); sqlsrv_free_stmt($stmtCheck); @@ -383,28 +390,29 @@ function actualizar() $vae_siguiente = empty($vae_siguiente) ? null : $vae_siguiente; // UPDATE - $sql = "UPDATE dbo.agentes_aduanales SET - aduana = ?, patente = ?, agente_aduanal = ?, rfc = ?, curp = ?, razon_social = ?, - mf_nombre = ?, mf_paterno = ?, mf_materno = ?, - vp_inicio = ?, vp_final = ?, vp_siguiente = ?, - vpe_inicio = ?, vpe_final = ?, vpe_siguiente = ?, - vat_pb_inicio = ?, vat_pb_final = ?, vat_pb_siguiente = ?, - vcc_inicio = ?, vcc_final = ?, vcc_siguiente = ?, - vae_inicio = ?, vae_final = ?, vae_siguiente = ?, id_agencia = ? - WHERE id_agente = ? AND id_usuario = ?"; - + $sql = "UPDATE dbo.agentes_aduanales SET + aduana = ?, patente = ?, agente_aduanal = ?, rfc = ?, curp = ?, razon_social = ?, + mf_nombre = ?, mf_paterno = ?, mf_materno = ?, + vp_inicio = ?, vp_final = ?, vp_siguiente = ?, + vpe_inicio = ?, vpe_final = ?, vpe_siguiente = ?, + vat_pb_inicio = ?, vat_pb_final = ?, vat_pb_siguiente = ?, + vcc_inicio = ?, vcc_final = ?, vcc_siguiente = ?, + vae_inicio = ?, vae_final = ?, vae_siguiente = ?, id_agencia = ? + WHERE id_agente = ? + AND id_usuario = ? + "; $params = [ - $aduana, $patente, $agente_aduanal, $rfc, $curp, $razon_social, - $mf_nombre, $mf_paterno, $mf_materno, - $vp_inicio, $vp_final, $vp_siguiente, - $vpe_inicio, $vpe_final, $vpe_siguiente, - $vat_pb_inicio, $vat_pb_final, $vat_pb_siguiente, - $vcc_inicio, $vcc_final, $vcc_siguiente, - $vae_inicio, $vae_final, $vae_siguiente, $id_agencia, - $id_agente, $id_usuario - ]; + $aduana, $patente, $agente_aduanal, $rfc, $curp, $razon_social, + $mf_nombre, $mf_paterno, $mf_materno, + $vp_inicio, $vp_final, $vp_siguiente, + $vpe_inicio, $vpe_final, $vpe_siguiente, + $vat_pb_inicio, $vat_pb_final, $vat_pb_siguiente, + $vcc_inicio, $vcc_final, $vcc_siguiente, + $vae_inicio, $vae_final, $vae_siguiente, $id_agencia, + $id_agente, $id_usuario + ]; + $stmt = sqlsrv_query($conn, $sql, $params); - $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) die("❌ Error al actualizar agente aduanal."); sqlsrv_free_stmt($stmt); @@ -424,6 +432,7 @@ function eliminar() $usr = $_SESSION['usuario_id']; $id = $_GET['id'] ?? null; + if (!$id || !is_numeric($id)) { die("❌ ID inválido."); } @@ -431,17 +440,17 @@ function eliminar() $conn = getConnection(); // Verificar que el transportista exista y pertenezca al usuario - $sqlChk = "SELECT COUNT(*) AS cnt - FROM dbo.agentes_aduanales - WHERE id_agente = ? AND id_usuario = ?"; + $sqlChk = "SELECT COUNT(*) AS cnt FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_usuario = ?"; $stmtChk = sqlsrv_query($conn, $sqlChk, [$id, $usr]); $rowChk = sqlsrv_fetch_array($stmtChk, SQLSRV_FETCH_ASSOC); + if ($rowChk['cnt'] == 0) { die("❌ Agente no encontrado o no autorizado."); } $sql = "UPDATE dbo.agentes_aduanales SET activo = 0 WHERE id_agente = ?"; $stmt = sqlsrv_query($conn, $sql, [(int)$id]); + if ($stmt === false) { die("❌ Error en eliminar(): " . print_r(sqlsrv_errors(), true)); } diff --git a/app/controllers/preferencias.php b/app/controllers/preferencias.php index fed85a0..31ae09b 100644 --- a/app/controllers/preferencias.php +++ b/app/controllers/preferencias.php @@ -10,7 +10,8 @@ function index() function notificaciones() { - $conn = getConnection(); + $conn = getConnection(); + $idUsuario = $_SESSION['usuario_id'] ?? null; if (!$idUsuario) { @@ -353,7 +354,7 @@ function guardarPreferenciasAjax() try { // Obtener tipo de usuario $query = "SELECT tipo_usuario FROM usuarios_sistema WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); if (!$stmt || !sqlsrv_execute($stmt)) { throw new Exception("Error al obtener tipo de usuario"); } @@ -385,7 +386,7 @@ function guardarPreferenciasAjax() $notificaciones_extra = $notificaciones ? ($input['notificaciones_extra'] ?? 0) : 0; $query = "UPDATE usuarios_sistema SET notificaciones = ?, notificaciones_extra = ? WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$notificaciones, $notificaciones_extra, $id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$notificaciones, $notificaciones_extra, $id_usuario]); if (!$stmt || !sqlsrv_execute($stmt)) { throw new Exception("Error al actualizar configuración general"); @@ -397,7 +398,7 @@ function guardarPreferenciasAjax() $tabla_preferencias = getTablaPreferencias($tipo_usuario); if ($tabla_preferencias) { $query_delete = "DELETE FROM $tabla_preferencias WHERE id_usuario = ?"; - $stmt_delete = sqlsrv_prepare($conn, $query_delete, [$id_usuario]); + $stmt_delete = sqlsrv_prepare($conn, $query_delete, [$id_usuario]); if ($stmt_delete) { sqlsrv_execute($stmt_delete); sqlsrv_free_stmt($stmt_delete); @@ -406,7 +407,7 @@ function guardarPreferenciasAjax() } $response_data = [ - 'notificaciones' => $notificaciones, + 'notificaciones' => $notificaciones, 'notificaciones_extra' => $notificaciones_extra ]; break; @@ -417,7 +418,7 @@ function guardarPreferenciasAjax() // Validar que existe correo extra si se quiere activar if ($notificaciones_extra) { $query_check = "SELECT correo FROM correo_extra WHERE id_usuario = ?"; - $stmt_check = sqlsrv_prepare($conn, $query_check, [$id_usuario]); + $stmt_check = sqlsrv_prepare($conn, $query_check, [$id_usuario]); if ($stmt_check && sqlsrv_execute($stmt_check)) { $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); sqlsrv_free_stmt($stmt_check); @@ -431,7 +432,7 @@ function guardarPreferenciasAjax() } $query = "UPDATE usuarios_sistema SET notificaciones_extra = ? WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$notificaciones_extra, $id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$notificaciones_extra, $id_usuario]); if (!$stmt || !sqlsrv_execute($stmt)) { throw new Exception("Error al actualizar configuración de correo extra"); @@ -445,16 +446,16 @@ function guardarPreferenciasAjax() case 'tipo_notificacion': $tipo_nombre = $input['nombre'] ?? ''; - $valor = $input['valor'] ? 1 : 0; + $valor = $input['valor'] ? 1 : 0; if (empty($tipo_nombre)) { throw new Exception("Tipo de notificación no especificado"); } // Obtener configuración específica según tipo de usuario - $config = getConfiguracionTipoUsuario($tipo_usuario); + $config = getConfiguracionTipoUsuario($tipo_usuario); $tabla_preferencias = $config['tabla']; - $tipos_validos = $config['tipos_validos']; + $tipos_validos = $config['tipos_validos']; // Validar que el tipo de notificación es válido para este tipo de usuario if (!in_array($tipo_nombre, $tipos_validos)) { @@ -463,7 +464,7 @@ function guardarPreferenciasAjax() // Verificar que las notificaciones generales estén activadas $query_check = "SELECT notificaciones FROM usuarios_sistema WHERE id_usuario = ?"; - $stmt_check = sqlsrv_prepare($conn, $query_check, [$id_usuario]); + $stmt_check = sqlsrv_prepare($conn, $query_check, [$id_usuario]); if ($stmt_check && sqlsrv_execute($stmt_check)) { $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); sqlsrv_free_stmt($stmt_check); @@ -477,10 +478,11 @@ function guardarPreferenciasAjax() // Verificar si existe el registro $query_exists = "SELECT COUNT(*) as count FROM $tabla_preferencias WHERE id_usuario = ?"; - $stmt_exists = sqlsrv_prepare($conn, $query_exists, [$id_usuario]); + $stmt_exists = sqlsrv_prepare($conn, $query_exists, [$id_usuario]); + $exists = false; if ($stmt_exists && sqlsrv_execute($stmt_exists)) { - $row = sqlsrv_fetch_array($stmt_exists, SQLSRV_FETCH_ASSOC); + $row = sqlsrv_fetch_array($stmt_exists, SQLSRV_FETCH_ASSOC); $exists = $row['count'] > 0; sqlsrv_free_stmt($stmt_exists); } @@ -488,7 +490,7 @@ function guardarPreferenciasAjax() if ($exists) { // Actualizar el campo específico $query = "UPDATE $tabla_preferencias SET [$tipo_nombre] = ? WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$valor, $id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$valor, $id_usuario]); } else { // Crear registro con valores por defecto específicos del tipo de usuario $tipos_default = $config['valores_default']; @@ -496,12 +498,12 @@ function guardarPreferenciasAjax() // Establecer el valor específico $tipos_default[$tipo_nombre] = $valor; - $campos = '[' . implode('], [', array_keys($tipos_default)) . ']'; + $campos = '[' . implode('], [', array_keys($tipos_default)) . ']'; $placeholders = rtrim(str_repeat('?, ', count($tipos_default)), ', '); - $query = "INSERT INTO $tabla_preferencias (id_usuario, $campos) VALUES (?, $placeholders)"; + $query = "INSERT INTO $tabla_preferencias (id_usuario, $campos) VALUES (?, $placeholders)"; $params = array_merge([$id_usuario], array_values($tipos_default)); - $stmt = sqlsrv_prepare($conn, $query, $params); + $stmt = sqlsrv_prepare($conn, $query, $params); } if (!$stmt || !sqlsrv_execute($stmt)) { @@ -577,7 +579,7 @@ function guardarPreferenciasAjax() $stmt = sqlsrv_prepare($conn, $query, [$hora, $dias, $id_usuario]); } else { // Crear registro con valores por defecto específicos del tipo de usuario - $config = getConfiguracionTipoUsuario($tipo_usuario); + $config = getConfiguracionTipoUsuario($tipo_usuario); $tipos_default = $config['valores_default']; // Activar resumen diario y configurar hora/días @@ -755,20 +757,24 @@ function getConfiguracionTipoUsuario($tipo_usuario) { // Función auxiliar para obtener el correo extra de un usuario (útil para el sistema de notificaciones) function obtenerCorreoExtra($id_usuario) { - $conn = getConnection(); - $query = " - SELECT ce.correo - FROM correo_extra ce - INNER JOIN usuarios_sistema us ON ce.id_usuario = us.id_usuario - WHERE ce.id_usuario = ? AND us.notificaciones_extra = 1 - "; + $conn = getConnection(); + + $query = "SELECT ce.correo + FROM correo_extra ce + INNER JOIN usuarios_sistema us + ON ce.id_usuario = us.id_usuario + WHERE ce.id_usuario = ? + AND us.notificaciones_extra = 1 + "; $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + $correo = null; if ($stmt && sqlsrv_execute($stmt)) { $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); $correo = $row ? $row['correo'] : null; sqlsrv_free_stmt($stmt); } + sqlsrv_close($conn); return $correo; } @@ -781,10 +787,12 @@ function obtenerPreferenciasNotificacion($id_usuario) // Obtener configuración general $query = "SELECT notificaciones, notificaciones_extra FROM usuarios_sistema WHERE id_usuario = ?"; $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + if (!$stmt || !sqlsrv_execute($stmt)) { sqlsrv_close($conn); return null; } + $config = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); sqlsrv_free_stmt($stmt); @@ -796,6 +804,7 @@ function obtenerPreferenciasNotificacion($id_usuario) // Obtener preferencias específicas $query = "SELECT * FROM preferencias_notificaciones_usuario WHERE id_usuario = ?"; $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + $preferencias = null; if ($stmt && sqlsrv_execute($stmt)) { $preferencias = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); @@ -843,18 +852,20 @@ function debeRecibirNotificacion($id_usuario, $tipo_notificacion) // Función auxiliar para obtener la configuración del resumen diario de un usuario function obtenerConfigResumenDiario($id_usuario) { - $conn = getConnection(); - - $query = " - SELECT pnu.resumen_diario, pnu.resumen_diario_hora, pnu.resumen_diario_dias - FROM preferencias_notificaciones_usuario pnu - INNER JOIN usuarios_sistema us ON pnu.id_usuario = us.id_usuario - WHERE pnu.id_usuario = ? AND us.notificaciones = 1 AND pnu.resumen_diario = 1 - "; + $conn = getConnection(); + $query = "SELECT + pnu.resumen_diario, pnu.resumen_diario_hora, pnu.resumen_diario_dias + FROM preferencias_notificaciones_usuario pnu + INNER JOIN usuarios_sistema us + ON pnu.id_usuario = us.id_usuario + WHERE pnu.id_usuario = ? + AND us.notificaciones = 1 + AND pnu.resumen_diario = 1 + "; $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + $config = null; - if ($stmt && sqlsrv_execute($stmt)) { $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if ($row) { @@ -890,7 +901,8 @@ function esDiaResumen($config_dias) function catalogos() { - $conn = getConnection(); + $conn = getConnection(); + $idUsuario = $_SESSION['usuario_id'] ?? null; if (!$idUsuario) { @@ -901,16 +913,18 @@ function catalogos() // Obtener configuración general de catalogos y tipo de usuario $query = "SELECT preferencias_catalogos, tipo_usuario FROM usuarios_sistema WHERE id_usuario = ?"; $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]); + if (!$stmt || !sqlsrv_execute($stmt)) { die("Error al obtener configuración: " . print_r(sqlsrv_errors(), true)); } + $usuario = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if (!$usuario) { die("Usuario no encontrado"); } $catalogos = $usuario['preferencias_catalogos'] ?? 0; - $tipoUsuario = $usuario['tipo_usuario'] ?? 'importador'; + $tipoUsuario = $usuario['tipo_usuario'] ?? 'importador'; sqlsrv_free_stmt($stmt); // Obtener preferencias específicas según el tipo de usuario @@ -949,22 +963,22 @@ function catalogos() // $query = "SELECT * FROM preferencias_catalogos_agente WHERE id_usuario = ?"; // $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]); // if ($stmt && sqlsrv_execute($stmt)) { - // $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); - // sqlsrv_free_stmt($stmt); + // $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + // sqlsrv_free_stmt($stmt); // } else { - // $preferenciasRow = false; + // $preferenciasRow = false; // } // Si no existe registro, crear valores por defecto para agente aduanal // if (!$preferenciasRow) { - // $preferencias = [ - // Aquí se definirán los campos específicos para agente aduanal - // cuando se creen las tablas correspondientes - // 'configuracion' => 0, - // 'cerrar_sesion' => 0 - // ]; + // $preferencias = [ + // // Aquí se definirán los campos específicos para agente aduanal + // // cuando se creen las tablas correspondientes + // 'configuracion' => 0, + // 'cerrar_sesion' => 0 + // ]; // } else { - // $preferencias = $preferenciasRow; + // $preferencias = $preferenciasRow; // } // break; @@ -972,22 +986,22 @@ function catalogos() // $query = "SELECT * FROM preferencias_catalogos_agencia WHERE id_usuario = ?"; // $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]); // if ($stmt && sqlsrv_execute($stmt)) { - // $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); - // sqlsrv_free_stmt($stmt); + // $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + // sqlsrv_free_stmt($stmt); // } else { - // $preferenciasRow = false; + // $preferenciasRow = false; // } // Si no existe registro, crear valores por defecto para admin agencia // if (!$preferenciasRow) { - // $preferencias = [ - // Aquí se definirán los campos específicos para admin agencia - // cuando se creen las tablas correspondientes - // 'configuracion' => 0, - // 'cerrar_sesion' => 0 - // ]; + // $preferencias = [ + // // Aquí se definirán los campos específicos para admin agencia + // // cuando se creen las tablas correspondientes + // 'configuracion' => 0, + // 'cerrar_sesion' => 0 + // ]; // } else { - // $preferencias = $preferenciasRow; + // $preferencias = $preferenciasRow; // } // break; @@ -995,22 +1009,22 @@ function catalogos() // $query = "SELECT * FROM preferencias_catalogos_admin WHERE id_usuario = ?"; // $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]); // if ($stmt && sqlsrv_execute($stmt)) { - // $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); - // sqlsrv_free_stmt($stmt); + // $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + // sqlsrv_free_stmt($stmt); // } else { - // $preferenciasRow = false; + // $preferenciasRow = false; // } // Si no existe registro, crear valores por defecto para super admin // if (!$preferenciasRow) { - // $preferencias = [ - // Aquí se definirán los campos específicos para super admin - // cuando se creen las tablas correspondientes - // 'configuracion' => 0, - // 'cerrar_sesion' => 0 - // ]; + // $preferencias = [ + // // Aquí se definirán los campos específicos para super admin + // // cuando se creen las tablas correspondientes + // 'configuracion' => 0, + // 'cerrar_sesion' => 0 + // ]; // } else { - // $preferencias = $preferenciasRow; + // $preferencias = $preferenciasRow; // } // break; @@ -1026,6 +1040,7 @@ function catalogos() // Obtener tipos de catalogos disponibles según el tipo de usuario $query = "SELECT nombre, descripcion, color FROM tipos_catalogos WHERE tipo_usuario = ? ORDER BY id"; $stmt = sqlsrv_prepare($conn, $query, [$tipoUsuario]); + if (!$stmt || !sqlsrv_execute($stmt)) { die("Error al obtener tipos: " . print_r(sqlsrv_errors(), true)); } @@ -1063,7 +1078,8 @@ function guardarCatalogosAjax() exit; } - $conn = getConnection(); + $conn = getConnection(); + $idUsuario = $_SESSION['usuario_id'] ?? null; if (!$idUsuario) { @@ -1075,11 +1091,13 @@ function guardarCatalogosAjax() // Obtener tipo de usuario $query = "SELECT tipo_usuario FROM usuarios_sistema WHERE id_usuario = ?"; $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]); + if (!$stmt || !sqlsrv_execute($stmt)) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Error al obtener información del usuario']); exit; } + $usuario = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); $tipoUsuario = $usuario['tipo_usuario'] ?? 'importador'; sqlsrv_free_stmt($stmt); @@ -1091,13 +1109,13 @@ function guardarCatalogosAjax() case 'catalogos_general': // Actualizar preferencias generales de catálogos $valor = isset($input['valor']) && $input['valor'] ? 1 : 0; - $query = "UPDATE usuarios_sistema SET preferencias_catalogos = ? WHERE id_usuario = ?"; $stmt = sqlsrv_prepare($conn, $query, [$valor, $idUsuario]); if (!$stmt || !sqlsrv_execute($stmt)) { throw new Exception('Error al actualizar preferencias generales'); } + sqlsrv_free_stmt($stmt); break; @@ -1132,6 +1150,7 @@ function guardarCatalogosAjax() // Verificar si existe un registro para este usuario $query = "SELECT id_preferencia FROM $tabla WHERE id_usuario = ?"; $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]); + if (!$stmt || !sqlsrv_execute($stmt)) { throw new Exception('Error al verificar preferencias existentes'); } diff --git a/app/controllers/productos_frecuentes.php b/app/controllers/productos_frecuentes.php index 85de855..9bf9a34 100644 --- a/app/controllers/productos_frecuentes.php +++ b/app/controllers/productos_frecuentes.php @@ -1,6 +1,4 @@ []]; @@ -93,6 +90,7 @@ function lista() header('Location: /IMPORTADORES/login'); exit; } + include __DIR__ . '/../../views/productos_frecuentes/lista.php'; } @@ -100,11 +98,11 @@ function lista() * Muestra el formulario de creación **/ function alta() { - if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } + include __DIR__ . '/../../views/productos_frecuentes/alta.php'; } @@ -112,7 +110,6 @@ function alta() * Procesa alta de producto frecuente **/ function guardar() { - if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; @@ -121,29 +118,29 @@ function guardar() $conn = getConnection(); // Recoger y sanear - $sinonimo = trim($_POST['sinonimo'] ?? ''); - $fraccion = trim($_POST['fraccion'] ?? ''); - $nico = trim($_POST['nico'] ?? ''); - $numero_parte = trim($_POST['numero_parte'] ?? null); - $descripcion = trim($_POST['descripcion'] ?? null); - $umc_id = intval($_POST['umc_id'] ?? 0); - $pais_origen_destino = trim($_POST['pais_origen_destino'] ?? null); + $sinonimo = trim($_POST['sinonimo'] ?? ''); + $fraccion = trim($_POST['fraccion'] ?? ''); + $nico = trim($_POST['nico'] ?? ''); + $numero_parte = trim($_POST['numero_parte'] ?? null); + $descripcion = trim($_POST['descripcion'] ?? null); + $umc_id = intval($_POST['umc_id'] ?? 0); + $pais_origen_destino = trim($_POST['pais_origen_destino'] ?? null); $pais_comprador_vendedor = trim($_POST['pais_comprador_vendedor'] ?? null); - $uso_mercancia = trim($_POST['uso_mercancia'] ?? null); - $estado_mercancia = trim($_POST['estado_mercancia'] ?? null); - $vinculacion = trim($_POST['vinculacion'] ?? null); - $observaciones = trim($_POST['observaciones'] ?? null); - $preferencia = trim($_POST['preferencia'] ?? null); - $criterio_preferencia = trim($_POST['criterio_preferencia'] ?? null); - $uso_producto = trim($_POST['uso_producto'] ?? null); - $descripcion_producto = trim($_POST['descripcion_producto'] ?? null); - $certificado_origen = isset($_POST['certificado_origen']) ? 1 : 0; - $tipo_mercancia = trim($_POST['tipo_mercancia'] ?? null); + $uso_mercancia = trim($_POST['uso_mercancia'] ?? null); + $estado_mercancia = trim($_POST['estado_mercancia'] ?? null); + $vinculacion = trim($_POST['vinculacion'] ?? null); + $observaciones = trim($_POST['observaciones'] ?? null); + $preferencia = trim($_POST['preferencia'] ?? null); + $criterio_preferencia = trim($_POST['criterio_preferencia'] ?? null); + $uso_producto = trim($_POST['uso_producto'] ?? null); + $descripcion_producto = trim($_POST['descripcion_producto'] ?? null); + $certificado_origen = isset($_POST['certificado_origen']) ? 1 : 0; + $tipo_mercancia = trim($_POST['tipo_mercancia'] ?? null); $documento_en_original = isset($_POST['documento_en_original']) ? 1 : 0; - $proveedor = trim($_POST['proveedor'] ?? null); + $proveedor = trim($_POST['proveedor'] ?? null); $id_importador = intval($_SESSION['usuario_id']); $status = 1; - $frecuencia_uso = intval($_POST['frecuencia_uso'] ?? 1); + $frecuencia_uso = intval($_POST['frecuencia_uso'] ?? 1); // Validación mínima if ($sinonimo === '' || $fraccion === '' || $nico === '' || $umc_id <= 0) { @@ -153,41 +150,22 @@ function guardar() } // INSERT - $sql = " - INSERT INTO dbo.productos_frecuentes ( - sinonimo, fraccion, nico, numero_parte, - descripcion, umc_id, - pais_origen_destino, pais_comprador_vendedor, - uso_mercancia, estado_mercancia, vinculacion, - observaciones, preferencia, criterio_preferencia, - uso_producto, descripcion_producto, - certificado_origen, tipo_mercancia, - documento_en_original, proveedor, - id_importador, fecha_alta, status, frecuencia_uso - ) VALUES ( - ?,?,?,?, - ?,?, - ?,?, - ?,?,?, - ?,?,?, - ?,?, - ?,?, - ?,?, - ?,GETDATE(),?,? - ) - "; + $sql = "INSERT INTO dbo.productos_frecuentes + (sinonimo, fraccion, nico, numero_parte, descripcion, umc_id, + pais_origen_destino, pais_comprador_vendedor, uso_mercancia, estado_mercancia, vinculacion, + observaciones, preferencia, criterio_preferencia, uso_producto, descripcion_producto, + certificado_origen, tipo_mercancia, documento_en_original, proveedor, + id_importador, fecha_alta, status, frecuencia_uso) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, GETDATE(), ?, ?) + "; $params = [ - $sinonimo, $fraccion, $nico, $numero_parte, - $descripcion, $umc_id, - $pais_origen_destino, $pais_comprador_vendedor, - $uso_mercancia, $estado_mercancia, $vinculacion, - $observaciones, $preferencia, $criterio_preferencia, - $uso_producto, $descripcion_producto, - $certificado_origen, $tipo_mercancia, - $documento_en_original, $proveedor, - $id_importador, $status, $frecuencia_uso - ]; - $stmt = sqlsrv_query($conn, $sql, $params); + $sinonimo, $fraccion, $nico, $numero_parte, $descripcion, $umc_id, + $pais_origen_destino, $pais_comprador_vendedor, $uso_mercancia, $estado_mercancia, $vinculacion, + $observaciones, $preferencia, $criterio_preferencia, $uso_producto, $descripcion_producto, + $certificado_origen, $tipo_mercancia, $documento_en_original, $proveedor, + $id_importador, $status, $frecuencia_uso + ]; + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { $_SESSION['flash_error'] = 'Error al guardar el producto frecuente.'; @@ -204,21 +182,23 @@ function guardar() * Muestra el formulario de edición **/ function editar() { - if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } $id = intval($_GET['id'] ?? 0); + if ($id <= 0) { header('Location: /IMPORTADORES/productos_frecuentes'); exit; } $conn = getConnection(); - $sql = "SELECT * FROM dbo.productos_frecuentes WHERE id_producto_frecuente = ?"; + + $sql = "SELECT * FROM dbo.productos_frecuentes WHERE id_producto_frecuente = ?"; $stmt = sqlsrv_query($conn, $sql, [$id]); + if ($stmt === false || ($producto = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) === null) { $_SESSION['flash_error'] = 'Producto frecuente no encontrado.'; header('Location: /IMPORTADORES/productos_frecuentes'); @@ -232,42 +212,30 @@ function editar() * Procesa la actualización **/ function actualizar() { - session_start(); if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } - $id = intval($_POST['id_producto_frecuente'] ?? 0); - $sinonimo = trim($_POST['sinonimo'] ?? ''); - // ... (resto de campos idénticos a guardar) - // Validaciones similares... - // UPDATE ... $conn = getConnection(); - $sql = " - UPDATE dbo.productos_frecuentes SET - sinonimo = ?, fraccion = ?, nico = ?, numero_parte = ?, - descripcion = ?, umc_id = ?, - pais_origen_destino = ?, pais_comprador_vendedor = ?, - uso_mercancia = ?, estado_mercancia = ?, vinculacion = ?, - observaciones = ?, preferencia = ?, criterio_preferencia = ?, - uso_producto = ?, descripcion_producto = ?, - certificado_origen = ?, tipo_mercancia = ?, - documento_en_original = ?, proveedor = ? - WHERE id_producto_frecuente = ? - "; + + $id = intval($_POST['id_producto_frecuente'] ?? 0); + $sinonimo = trim($_POST['sinonimo'] ?? ''); + + $sql = "UPDATE dbo.productos_frecuentes SET + sinonimo = ?, fraccion = ?, nico = ?, numero_parte = ?, descripcion = ?, umc_id = ?, + pais_origen_destino = ?, pais_comprador_vendedor = ?, uso_mercancia = ?, estado_mercancia = ?, vinculacion = ?, + observaciones = ?, preferencia = ?, criterio_preferencia = ?, uso_producto = ?, descripcion_producto = ?, + certificado_origen = ?, tipo_mercancia = ?, documento_en_original = ?, proveedor = ? + WHERE id_producto_frecuente = ? + "; $params = [ - $sinonimo, $fraccion, $nico, $numero_parte, - $descripcion, $umc_id, - $pais_origen_destino, $pais_comprador_vendedor, - $uso_mercancia, $estado_mercancia, $vinculacion, - $observaciones, $preferencia, $criterio_preferencia, - $uso_producto, $descripcion_producto, - $certificado_origen, $tipo_mercancia, - $documento_en_original, $proveedor, - $id - ]; - $stmt = sqlsrv_query($conn, $sql, $params); + $sinonimo, $fraccion, $nico, $numero_parte, $descripcion, $umc_id, + $pais_origen_destino, $pais_comprador_vendedor, $uso_mercancia, $estado_mercancia, $vinculacion, + $observaciones, $preferencia, $criterio_preferencia, $uso_producto, $descripcion_producto, + $certificado_origen, $tipo_mercancia, $documento_en_original, $proveedor, $id + ]; + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { $_SESSION['flash_error'] = 'Error al actualizar el producto frecuente.'; @@ -300,6 +268,7 @@ function ajax_unidades() } $conn = getConnection(); + $sql = "SELECT id, descripcion FROM dbo.unidades_medida_apendice7 ORDER BY descripcion"; $stmt = sqlsrv_query($conn, $sql); @@ -332,7 +301,9 @@ function procesar_csv() } $file = fopen($_FILES['csv_file']['tmp_name'], 'r'); + $conn = getConnection(); + $row = 0; while (($data = fgetcsv($file, 0, ',')) !== false) { $row++; diff --git a/app/controllers/proveedores.php b/app/controllers/proveedores.php index 69f4cf6..b8292f4 100644 --- a/app/controllers/proveedores.php +++ b/app/controllers/proveedores.php @@ -1,13 +1,11 @@ $user, 'password' => $pass]); error_log("[getApiToken] POST $url → $body"); @@ -120,24 +118,24 @@ function ajax_lista() // Construir dirección $direccion = trim(implode(', ', array_filter([ - $p['Calles'] ?? '', - 'Num. Ext: ' . ($p['NumExt'] ?? ''), - 'Num. Int: ' . ($p['NumInt'] ?? ''), - $p['Colonia'] ?? '', - $p['Municipio'] ?? '', - $p['Ciudad'] ?? '', + $p['Calles'] ?? '', + 'Num. Ext: ' . ($p['NumExt'] ?? ''), + 'Num. Int: ' . ($p['NumInt'] ?? ''), + $p['Colonia'] ?? '', + $p['Municipio'] ?? '', + $p['Ciudad'] ?? '', 'C.P. ' . ($p['CodigoPostal'] ?? ''), - $p['EntidadFederativa'] ?? '', - $p['Pais'] ?? '' + $p['EntidadFederativa'] ?? '', + $p['Pais'] ?? '' ]))); $dataList[] = [ $clave, - htmlspecialchars($p['Nombre'] ?? '', ENT_QUOTES), - htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES), - htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES), - htmlspecialchars($p['Telefono']?? '', ENT_QUOTES), - htmlspecialchars($direccion ?? '', ENT_QUOTES), + htmlspecialchars($p['Nombre'] ?? '', ENT_QUOTES), + htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES), + htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES), + htmlspecialchars($p['Telefono'] ?? '', ENT_QUOTES), + htmlspecialchars($direccion ?? '', ENT_QUOTES), // Acciones "✏️ " @@ -157,6 +155,7 @@ function eliminar() { $token = getApiToken(); $clave = $_GET['clave'] ?? ''; + if (!$token || !$clave) { header('Location: /IMPORTADORES/proveedores'); exit; @@ -204,16 +203,16 @@ function guardar() // 2) Recoger datos del formulario $payload = [ - 'Clave' => trim($_POST['Clave'] ?? ''), - 'Nombre' => trim($_POST['Nombre'] ?? ''), - 'RFC' => trim($_POST['RFC'] ?? ''), - 'Ciudad' => trim($_POST['Ciudad'] ?? ''), - 'Telefono' => trim($_POST['Telefono'] ?? ''), - 'Pais' => trim($_POST['Pais'] ?? ''), - 'Colonia' => trim($_POST['Colonia'] ?? ''), - 'Municipio' => trim($_POST['Municipio'] ?? ''), - 'CodigoPostal' => trim($_POST['CodigoPostal'] ?? ''), - 'EntidadFederativa' => trim($_POST['EntidadFederativa'] ?? ''), + 'Clave' => trim($_POST['Clave'] ?? ''), + 'Nombre' => trim($_POST['Nombre'] ?? ''), + 'RFC' => trim($_POST['RFC'] ?? ''), + 'Ciudad' => trim($_POST['Ciudad'] ?? ''), + 'Telefono' => trim($_POST['Telefono'] ?? ''), + 'Pais' => trim($_POST['Pais'] ?? ''), + 'Colonia' => trim($_POST['Colonia'] ?? ''), + 'Municipio' => trim($_POST['Municipio'] ?? ''), + 'CodigoPostal' => trim($_POST['CodigoPostal'] ?? ''), + 'EntidadFederativa' => trim($_POST['EntidadFederativa'] ?? ''), ]; // 3) Validar campos obligatorios @@ -233,7 +232,7 @@ function guardar() // 5) Llamada a la API para crear el proveedor $url = rtrim($_ENV['API_URL'] ?? '', '/') . '/api/proveedores'; - $ch = curl_init($url); + $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ diff --git a/app/controllers/registro.php b/app/controllers/registro.php index cf07584..c56f2a2 100644 --- a/app/controllers/registro.php +++ b/app/controllers/registro.php @@ -149,6 +149,7 @@ function enviarEmailConfirmacion($destinatario, $datosEmpresa, $esAgencia = fals // Obtener configuración $conn = getConnection(); + $conf = obtenerConfiguracion($conn); $nombrePlataforma = $conf['nombre_plataforma']; @@ -228,10 +229,10 @@ function enviarSoliImportador() $rfcEncriptado = encrypt(strtoupper($rfc)); // Insertar en base de datos - $sql = "INSERT INTO solicitudes_importadores - (company_name, rfc, email, phone, opinion_file, request_status, request_date) - VALUES (?, ?, ?, ?, ?, 'pending', GETDATE())"; - + $sql = "INSERT INTO solicitudes_importadores + (company_name, rfc, email, phone, opinion_file, request_status, request_date) + VALUES (?, ?, ?, ?, ?, 'pending', GETDATE()) + "; $params = [$empresaEncriptada, $rfcEncriptado, $email, $telefono, $nombreArchivo]; $stmt = sqlsrv_query($conn, $sql, $params); @@ -289,10 +290,10 @@ function enviarSoliAgencia() $adminEncriptado = encrypt($admin); // Insertar en base de datos - $sql = "INSERT INTO solicitudes_agencias - (agencia_name, rfc, email, phone, direccion, opinion_file, admin_name, admin_email, request_status, request_date) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', GETDATE())"; - + $sql = "INSERT INTO solicitudes_agencias + (agencia_name, rfc, email, phone, direccion, opinion_file, admin_name, admin_email, request_status, request_date) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', GETDATE()) + "; $params = [$agenciaEncriptada, $rfcEncriptado, $correo, $telefono, $direccion, $nombreArchivo, $adminEncriptado, $admin_correo]; $stmt = sqlsrv_query($conn, $sql, $params); diff --git a/app/controllers/reset.php b/app/controllers/reset.php index f905525..bee438c 100644 --- a/app/controllers/reset.php +++ b/app/controllers/reset.php @@ -4,8 +4,8 @@ require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/crypto.php'; require_once __DIR__ . '/../helpers/bitacoras.php'; require_once __DIR__ . '/../helpers/env.php'; - require_once __DIR__ . '/../../vendor/autoload.php'; + use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; @@ -22,17 +22,18 @@ function enviarCodigoInterno() } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']); exit; } - $id_usuario = $_SESSION['usuario_id']; - $email = $_SESSION['usuario_email']; + $id_usuario = $_SESSION['usuario_id']; + $email = $_SESSION['usuario_email']; $emailEncrypted = encrypt($email); // Verificar que la cuenta esté activa - $sql = "SELECT activo FROM usuarios_sistema WHERE id_usuario = ?"; + $sql = "SELECT activo FROM usuarios_sistema WHERE id_usuario = ?"; $stmt = sqlsrv_query($conn, $sql, [$id_usuario]); if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) { @@ -46,11 +47,10 @@ function enviarCodigoInterno() } // Verificar si ya existe un código activo - $now = (new DateTime())->format('Y-m-d H:i:s'); - $sqlCheck = "SELECT COUNT(*) AS total FROM recuperacion_password - WHERE email = ? AND estatus = 0 AND expiracion > ?"; + $now = (new DateTime())->format('Y-m-d H:i:s'); + $sqlCheck = "SELECT COUNT(*) AS total FROM recuperacion_password WHERE email = ? AND estatus = 0 AND expiracion > ?"; $checkStmt = sqlsrv_query($conn, $sqlCheck, [$emailEncrypted, $now]); - $checkRow = sqlsrv_fetch_array($checkStmt, SQLSRV_FETCH_ASSOC); + $checkRow = sqlsrv_fetch_array($checkStmt, SQLSRV_FETCH_ASSOC); if ($checkRow['total'] > 0) { echo json_encode(['success' => false, 'message' => '⚠️ Ya tienes un código activo. Revisa tu correo o espera 10 minutos.']); @@ -58,8 +58,8 @@ function enviarCodigoInterno() } // Generar nuevo código - $codigo = strval(random_int(100000, 999999)); - $expira = (new DateTime('+10 minutes'))->format('Y-m-d H:i:s'); + $codigo = strval(random_int(100000, 999999)); + $expira = (new DateTime('+10 minutes'))->format('Y-m-d H:i:s'); $estatus = 0; $insert = "INSERT INTO recuperacion_password (email, codigo, expiracion, estatus) VALUES (?, ?, ?, ?)"; @@ -72,7 +72,7 @@ function enviarCodigoInterno() } // Establecer variables de sesión para el cambio interno - $_SESSION['cambio_interno'] = true; + $_SESSION['cambio_interno'] = true; $_SESSION['codigo_timestamp'] = time(); // Agregar estos logs: @@ -143,6 +143,7 @@ function reenviarCodigoInterno() } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']); exit; @@ -153,9 +154,7 @@ function reenviarCodigoInterno() // Obtener el último código activo de recuperación $now = (new DateTime())->format('Y-m-d H:i:s'); - $sql = "SELECT TOP 1 codigo FROM recuperacion_password - WHERE email = ? AND estatus = 0 AND expiracion > ? - ORDER BY expiracion DESC"; + $sql = "SELECT TOP 1 codigo FROM recuperacion_password WHERE email = ? AND estatus = 0 AND expiracion > ? ORDER BY expiracion DESC"; $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted, $now]); if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) { @@ -167,7 +166,7 @@ function reenviarCodigoInterno() // Llamar a la función para reenviar el correo al respaldo if (enviarCorreoRespaldo($conn, $id_usuario, $codigo)) { - echo json_encode(['success' => true, 'message' => '📤 Código reenviado al correo de respaldo.']); + echo json_encode(['success' => true, 'message' => '📤 Código reenviado al correo de respaldo.']); } else { echo json_encode(['success' => false, 'message' => '❌ Error al reenviar el código al correo de respaldo.']); } @@ -261,15 +260,15 @@ function verificarCodigoInterno() $conn = getConnection(); - $email = $_SESSION['usuario_email']; + $email = $_SESSION['usuario_email']; $emailEncrypted = encrypt($email); // aplica aquí también try { // Verificar conexión if (!isset($conn) || $conn === false) { echo json_encode([ - 'success' => false, - 'message' => '❌ Error de conexión a la base de datos.', + 'success' => false, + 'message' => '❌ Error de conexión a la base de datos.', 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0)) ]); exit; @@ -279,8 +278,8 @@ function verificarCodigoInterno() if (empty($codigo)) { echo json_encode([ - 'success' => false, - 'message' => '❌ Código requerido.', + 'success' => false, + 'message' => '❌ Código requerido.', 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0)) ]); exit; @@ -288,8 +287,8 @@ function verificarCodigoInterno() if (!preg_match('/^\d{6}$/', $codigo)) { echo json_encode([ - 'success' => false, - 'message' => '❌ El código debe tener 6 dígitos numéricos.', + 'success' => false, + 'message' => '❌ El código debe tener 6 dígitos numéricos.', 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0)) ]); exit; @@ -299,10 +298,10 @@ function verificarCodigoInterno() if ($intentosActuales >= 3) { echo json_encode([ - 'success' => false, - 'message' => '❌ Demasiados intentos fallidos. Solicita un nuevo código.', - 'blocked' => true, - 'redirect' => '/IMPORTADORES/seguridad/index', + 'success' => false, + 'message' => '❌ Demasiados intentos fallidos. Solicita un nuevo código.', + 'blocked' => true, + 'redirect' => '/IMPORTADORES/seguridad/index', 'intentos_restantes' => 0 ]); exit; @@ -310,21 +309,23 @@ function verificarCodigoInterno() if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email'])) { echo json_encode([ - 'success' => false, - 'message' => '❌ Sesión inválida. Intenta nuevamente.', - 'blocked' => true, + 'success' => false, + 'message' => '❌ Sesión inválida. Intenta nuevamente.', + 'blocked' => true, 'redirect' => '/IMPORTADORES/seguridad/index' ]); exit; } // Consulta principal para verificar el código - $sql = "SELECT id, codigo, expiracion + $sql = "SELECT + id, codigo, expiracion FROM recuperacion_password - WHERE email = ? AND estatus = 0 AND expiracion > GETDATE() + WHERE email = ? + AND estatus = 0 + AND expiracion > GETDATE() ORDER BY expiracion DESC "; - $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]); if (!$stmt) { @@ -337,8 +338,8 @@ function verificarCodigoInterno() if (!$row) { $_SESSION['intentos_codigo_interno'] = $intentosActuales + 1; echo json_encode([ - 'success' => false, - 'message' => '❌ Código inválido o expirado.', + 'success' => false, + 'message' => '❌ Código inválido o expirado.', 'intentos_restantes' => max(0, 3 - $_SESSION['intentos_codigo_interno']) ]); exit; @@ -351,15 +352,15 @@ function verificarCodigoInterno() if ($codigo !== $row['codigo']) { $_SESSION['intentos_codigo_interno'] = $intentosActuales + 1; echo json_encode([ - 'success' => false, - 'message' => '❌ Código incorrecto.', + 'success' => false, + 'message' => '❌ Código incorrecto.', 'intentos_restantes' => max(0, 3 - $_SESSION['intentos_codigo_interno']) ]); exit; } $expiracion = $row['expiracion']; - $ahora = new DateTime(); + $ahora = new DateTime(); if ($expiracion instanceof DateTime) { $expiracionStr = $expiracion->format('Y-m-d H:i:s'); @@ -367,8 +368,8 @@ function verificarCodigoInterno() if ($expiracion <= $ahora) { $_SESSION['intentos_codigo_interno'] = $intentosActuales + 1; echo json_encode([ - 'success' => false, - 'message' => '❌ El código ha expirado.', + 'success' => false, + 'message' => '❌ El código ha expirado.', 'intentos_restantes' => max(0, 3 - $_SESSION['intentos_codigo_interno']) ]); exit; @@ -390,15 +391,15 @@ function verificarCodigoInterno() unset($_SESSION['intentos_codigo_interno']); echo json_encode([ - 'success' => true, - 'message' => '✅ Código verificado correctamente.', + 'success' => true, + 'message' => '✅ Código verificado correctamente.', 'redirect' => '/IMPORTADORES/reset/cambiarPasswordInternoView' ]); } catch (Exception $e) { echo json_encode([ - 'success' => false, - 'message' => '❌ Error interno del servidor. Intenta nuevamente.', + 'success' => false, + 'message' => '❌ Error interno del servidor. Intenta nuevamente.', 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0)) ]); exit; @@ -413,7 +414,7 @@ function verificarCodigoInterno() function cambiarPasswordInternoView() { // Verificar si el usuario ya está autenticado y el código verificado - if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) || + if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) || !isset($_SESSION['cambio_interno']) || !isset($_SESSION['codigo_verificado_interno'])) { header("Location: /IMPORTADORES/login"); exit; @@ -425,23 +426,34 @@ function cambiarPasswordInternoView() function cambiarPasswordInterno() { + // Limpiar buffer de salida + if (ob_get_level()) { + ob_end_clean(); + } + + // Iniciar buffer limpio + ob_start(); + header('Content-Type: application/json'); // ⬅️ AGREGAR ESTA LÍNEA // Verificar autorización completa - if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) || + if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) || !isset($_SESSION['cambio_interno']) || !isset($_SESSION['codigo_verificado_interno'])) { + + ob_end_clean(); // Limpiar buffer antes de enviar JSON echo json_encode(['success' => false, 'message' => '❌ No tienes autorización para cambiar la contraseña.']); exit; } $conn = getConnection(); + if (!$conn) { echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']); exit; } - $passwordActual = $_POST['password_actual'] ?? ''; - $passwordNueva = $_POST['password_nueva'] ?? ''; + $passwordActual = $_POST['password_actual'] ?? ''; + $passwordNueva = $_POST['password_nueva'] ?? ''; $confirmarPassword = $_POST['confirmar_password'] ?? ''; // Validaciones @@ -465,12 +477,12 @@ function cambiarPasswordInterno() exit; } - $id_usuario = $_SESSION['usuario_id']; - $email = $_SESSION['usuario_email']; + $id_usuario = $_SESSION['usuario_id']; + $email = $_SESSION['usuario_email']; $emailEncrypted = encrypt($email); // Verificar contraseña actual - $sql = "SELECT password_hash FROM usuarios_sistema WHERE id_usuario = ?"; + $sql = "SELECT password_hash FROM usuarios_sistema WHERE id_usuario = ?"; $stmt = sqlsrv_query($conn, $sql, [$id_usuario]); if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) { @@ -484,8 +496,8 @@ function cambiarPasswordInterno() } // Actualizar contraseña - $hashNueva = password_hash($passwordNueva, PASSWORD_BCRYPT); - $sqlUpdate = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?"; + $hashNueva = password_hash($passwordNueva, PASSWORD_BCRYPT); + $sqlUpdate = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?"; $stmtUpdate = sqlsrv_prepare($conn, $sqlUpdate, [$hashNueva, $id_usuario]); if (!$stmtUpdate || !sqlsrv_execute($stmtUpdate)) { @@ -495,18 +507,18 @@ function cambiarPasswordInterno() // Registrar en bitácora $ip = $_SERVER['REMOTE_ADDR'] ?? 'N/A'; - registrarBitacora($conn, $id_usuario, $email, $ip, 1, 'Cambio de contraseña interno'); + registrarBitacora($id_usuario, $email, $ip, 1, 'Cambio de contraseña interno'); // Enviar correo de confirmación try { - $mail = new PHPMailer(true); + $mail = new PHPMailer(true); $mail->isSMTP(); - $mail->Host = 'secure.emailsrvr.com'; - $mail->SMTPAuth = true; - $mail->Username = 'noreply@aduanasoft.com.mx'; - $mail->Password = $_ENV['SMTP_PASS']; + $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->Port = 587; $mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft'); $mail->addAddress($email); @@ -547,9 +559,11 @@ function cambiarPasswordInterno() unset($_SESSION['codigo_verificado_interno']); unset($_SESSION['codigo_timestamp']); + // Al final, antes de cada echo json_encode: + ob_end_clean(); echo json_encode([ - 'success' => true, - 'message' => '✅ Contraseña actualizada exitosamente.', + 'success' => true, + 'message' => '✅ Contraseña actualizada exitosamente.', 'redirect' => '/IMPORTADORES/login' // Redirigir a la página de seguridad ]); exit; @@ -565,8 +579,8 @@ function cancelarCambioInterno() if ($conn && isset($_SESSION['usuario_email'])) { // Invalidar códigos activos $emailEncrypted = encrypt($_SESSION['usuario_email']); - $sql = "UPDATE recuperacion_password SET estatus = 1 WHERE email = ? AND estatus = 0"; - $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]); + $sql = "UPDATE recuperacion_password SET estatus = 1 WHERE email = ? AND estatus = 0"; + $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]); if ($stmt) sqlsrv_free_stmt($stmt); } @@ -587,16 +601,16 @@ function obtenerEstadoDosFactores() // CORRIGIDO: Cambiar id_usuario por usuario_id $id_usuario = $_SESSION['usuario_id'] ?? null; + if (!$id_usuario) { return 0; // valor por defecto si no hay sesión } - $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?"; - $params = [$id_usuario]; + $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?"; + $params = [$id_usuario]; $stmt_dos_factores = sqlsrv_prepare($conn, $sql_dos_factores, $params); $dos_factores_estado = 0; // valor por defecto - if ($stmt_dos_factores && sqlsrv_execute($stmt_dos_factores)) { if ($row = sqlsrv_fetch_array($stmt_dos_factores, SQLSRV_FETCH_ASSOC)) { $dos_factores_estado = (int)$row['dos_factores']; diff --git a/app/controllers/seguridad.php b/app/controllers/seguridad.php index 001d0da..1ab764f 100644 --- a/app/controllers/seguridad.php +++ b/app/controllers/seguridad.php @@ -25,6 +25,7 @@ function index() function opciones() { $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id'] ?? null; // Asegúrate de que el usuario está autenticado @@ -49,12 +50,11 @@ function obtenerEstadoDosFactores() return 0; // valor por defecto si no hay sesión } - $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?"; - $params = [$id_usuario]; + $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?"; + $params = [$id_usuario]; $stmt_dos_factores = sqlsrv_prepare($conn, $sql_dos_factores, $params); $dos_factores_estado = 0; // valor por defecto - if ($stmt_dos_factores && sqlsrv_execute($stmt_dos_factores)) { if ($row = sqlsrv_fetch_array($stmt_dos_factores, SQLSRV_FETCH_ASSOC)) { $dos_factores_estado = (int)$row['dos_factores']; @@ -90,10 +90,9 @@ function autenticacionDosFactores() } $dos_factores = isset($_POST['dos_factores']) ? 1 : 0; - - $sql = "UPDATE usuarios_sistema SET dos_factores = ? WHERE id_usuario = ?"; - $params = [$dos_factores, $id_usuario]; - $stmt = sqlsrv_prepare($conn, $sql, $params); + $sql = "UPDATE usuarios_sistema SET dos_factores = ? WHERE id_usuario = ?"; + $params = [$dos_factores, $id_usuario]; + $stmt = sqlsrv_prepare($conn, $sql, $params); if (!$stmt) { die("Error en la preparación: " . print_r(sqlsrv_errors(), true)); @@ -125,12 +124,13 @@ function correoExtra() exit; } - $id_usuario = $_SESSION['usuario_id']; // CORRIGIDO + $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); - $sql_check = "SELECT COUNT(*) AS total FROM correo_extra WHERE id_usuario = ?"; + $sql_check = "SELECT COUNT(*) AS total FROM correo_extra WHERE id_usuario = ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$id_usuario]); - $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); if ($row['total'] > 0) { echo "Ya tienes un correo adicional registrado."; @@ -145,7 +145,7 @@ function correoExtra() } $query = "INSERT INTO correo_extra (id_usuario, correo) VALUES (?, ?)"; - $stmt = sqlsrv_prepare($conn, $query, [$id_usuario, $correo]); + $stmt = sqlsrv_prepare($conn, $query, [$id_usuario, $correo]); if ($stmt && sqlsrv_execute($stmt)) { $_SESSION['config_success'] = 'Correo adicional registrado correctamente.'; @@ -164,6 +164,7 @@ function modificarCorreoExtra() } $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); $correo = $_POST['email-extra'] ?? ''; @@ -174,7 +175,7 @@ function modificarCorreoExtra() } $query = "UPDATE correo_extra SET correo = ? WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$correo, $id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$correo, $id_usuario]); if ($stmt && sqlsrv_execute($stmt)) { $_SESSION['config_success'] = 'Correo adicional actualizado correctamente.'; @@ -193,10 +194,11 @@ function eliminarCorreoExtra() } $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); $query = "DELETE FROM correo_extra WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); if ($stmt && sqlsrv_execute($stmt)) { $_SESSION['config_success'] = 'Correo adicional eliminado correctamente.'; @@ -215,12 +217,13 @@ function correoRespaldo() exit; } - $id_usuario = $_SESSION['usuario_id']; // CORRIGIDO + $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); - $sql_check = "SELECT COUNT(*) AS total FROM correo_respaldo WHERE id_usuario = ?"; + $sql_check = "SELECT COUNT(*) AS total FROM correo_respaldo WHERE id_usuario = ?"; $stmt_check = sqlsrv_query($conn, $sql_check, [$id_usuario]); - $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); if ($row['total'] > 0) { echo "Ya tienes un correo de respaldo registrado."; @@ -235,7 +238,7 @@ function correoRespaldo() } $query = "INSERT INTO correo_respaldo (id_usuario, correo) VALUES (?, ?)"; - $stmt = sqlsrv_prepare($conn, $query, [$id_usuario, $correo]); + $stmt = sqlsrv_prepare($conn, $query, [$id_usuario, $correo]); if ($stmt && sqlsrv_execute($stmt)) { $_SESSION['config_success'] = 'Correo de respaldo registrado correctamente.'; @@ -246,7 +249,7 @@ function correoRespaldo() } } -function modificarCorreoRspaldo() +function modificarCorreoRespaldo() { if (!isset($_SESSION['usuario_id']) || ($_SESSION['pendiente_confirmacion'] ?? false)) { echo "Error: no se ha iniciado sesión o sesión incompleta."; @@ -254,6 +257,7 @@ function modificarCorreoRspaldo() } $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); $correo = $_POST['email-respaldo'] ?? ''; @@ -264,7 +268,7 @@ function modificarCorreoRspaldo() } $query = "UPDATE correo_respaldo SET correo = ? WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$correo, $id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$correo, $id_usuario]); if ($stmt && sqlsrv_execute($stmt)) { $_SESSION['config_success'] = 'Correo de respaldo actualizado correctamente.'; @@ -283,10 +287,11 @@ function eliminarCorreoRespaldo() } $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); $query = "DELETE FROM correo_respaldo WHERE id_usuario = ?"; - $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); + $stmt = sqlsrv_prepare($conn, $query, [$id_usuario]); if ($stmt && sqlsrv_execute($stmt)) { $_SESSION['config_success'] = 'Correo de respaldo eliminado correctamente.'; @@ -300,15 +305,16 @@ function eliminarCorreoRespaldo() function obtenerCorreos($conn, $id_usuario) { $correos = [ - 'dos_factores' => 0, - 'correo_extra' => '', + 'dos_factores' => 0, + 'correo_extra' => '', 'correo_respaldo' => '' ]; // Obtener estado dos_factores - $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?"; - $params = [$id_usuario]; + $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?"; + $params = [$id_usuario]; $stmt_dos_factores = sqlsrv_prepare($conn, $sql_dos_factores, $params); + if ($stmt_dos_factores && sqlsrv_execute($stmt_dos_factores)) { if ($row = sqlsrv_fetch_array($stmt_dos_factores, SQLSRV_FETCH_ASSOC)) { $correos['dos_factores'] = (int)$row['dos_factores']; // MEJORADO: Cast a int @@ -316,8 +322,9 @@ function obtenerCorreos($conn, $id_usuario) } // Obtener correo_extra - $sql_extra = "SELECT correo FROM correo_extra WHERE id_usuario = ?"; + $sql_extra = "SELECT correo FROM correo_extra WHERE id_usuario = ?"; $stmt_extra = sqlsrv_prepare($conn, $sql_extra, $params); + if ($stmt_extra && sqlsrv_execute($stmt_extra)) { if ($row = sqlsrv_fetch_array($stmt_extra, SQLSRV_FETCH_ASSOC)) { $correos['correo_extra'] = $row['correo']; @@ -325,8 +332,9 @@ function obtenerCorreos($conn, $id_usuario) } // Obtener correo_respaldo - $sql_respaldo = "SELECT correo FROM correo_respaldo WHERE id_usuario = ?"; + $sql_respaldo = "SELECT correo FROM correo_respaldo WHERE id_usuario = ?"; $stmt_respaldo = sqlsrv_prepare($conn, $sql_respaldo, $params); + if ($stmt_respaldo && sqlsrv_execute($stmt_respaldo)) { if ($row = sqlsrv_fetch_array($stmt_respaldo, SQLSRV_FETCH_ASSOC)) { $correos['correo_respaldo'] = $row['correo']; diff --git a/app/controllers/solicitud_importacion.php b/app/controllers/solicitud_importacion.php index 64d8023..12a0381 100644 --- a/app/controllers/solicitud_importacion.php +++ b/app/controllers/solicitud_importacion.php @@ -1,14 +1,19 @@ $user, 'password' => $pass]); error_log("[getApiToken] POST $url → $body"); @@ -70,38 +75,40 @@ function lista() exit; } $id_importador = $_SESSION['usuario_id']; + $conn = getConnection(); // ✅ NUEVO: Obtener la agencia actual del usuario $stmt = sqlsrv_query($conn, "SELECT id_agencia_en_uso FROM dbo.usuarios_sistema WHERE id_usuario = ?", [$id_importador]); + $id_agencia = null; if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $id_agencia = $row['id_agencia_en_uso']; } - $sql = " - SELECT - f.*, - tr.nombre AS transportista, - (c.nombre + ' ' + c.apellido) AS chofer, - p.nombre AS nombre_pais_proveedor, - f.foto_solicitud_url, - a.patente AS patente - FROM dbo.solicitud_importacion_factura f - JOIN dbo.transportistas tr - ON f.transportista_id = tr.id_transportista - LEFT JOIN dbo.choferes c - ON f.chofer_id = c.id_chofer - LEFT JOIN dbo.paises p - ON f.pais_proveedor = p.id_pais - LEFT JOIN dbo.agentes_aduanales a - ON f.patente_id = a.id_agente - WHERE f.id_importador = ? - AND f.id_agencia = ? - AND f.status >= 1 - ORDER BY f.created_at DESC - "; + $sql = "SELECT + f.*, + tr.nombre AS transportista, + (c.nombre + ' ' + c.apellido) AS chofer, + p.nombre AS nombre_pais_proveedor, + f.foto_solicitud_url, + a.patente AS patente + FROM dbo.solicitud_importacion_factura f + JOIN dbo.transportistas tr + ON f.transportista_id = tr.id_transportista + LEFT JOIN dbo.choferes c + ON f.chofer_id = c.id_chofer + LEFT JOIN dbo.paises p + ON f.pais_proveedor = p.id_pais + LEFT JOIN dbo.agentes_aduanales a + ON f.patente_id = a.id_agente + WHERE f.id_importador = ? + AND f.id_agencia = ? + AND f.status >= 1 + ORDER BY f.created_at DESC + "; $stmt = sqlsrv_query($conn, $sql, [$id_importador, $id_agencia]); + if ($stmt === false) { die("Error en lista(): " . print_r(sqlsrv_errors(), true)); } @@ -126,11 +133,13 @@ function crear() } $id_importador = $_SESSION['usuario_id']; - $conn = getConnection(); + + $conn = getConnection(); // ✅ NUEVO: Obtener la agencia actual del usuario $stmt = sqlsrv_query($conn, "SELECT id_agencia_en_uso FROM dbo.usuarios_sistema WHERE id_usuario = ?", [$id_importador]); if ($stmt === false) { die(print_r(sqlsrv_errors(), true)); } + $id_agencia = null; if ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $id_agencia = $row['id_agencia_en_uso']; } @@ -180,7 +189,7 @@ function obtenerChoferesPorTransportista() exit; } - $id_importador = $_SESSION['usuario_id']; + $id_importador = $_SESSION['usuario_id']; $transportista_id = $_GET['transportista_id'] ?? null; if (!$transportista_id || !is_numeric($transportista_id)) { @@ -238,10 +247,12 @@ function guardar() } $id_importador = $_SESSION['usuario_id']; - $conn = getConnection(); + + $conn = getConnection(); // ✅ Obtener id_agencia_en_uso del usuario $stmtAgencia = sqlsrv_query($conn, "SELECT id_agencia_en_uso FROM dbo.usuarios_sistema WHERE id_usuario = ?", [$id_importador]); + $id_agencia = null; if ($stmtAgencia && $row = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC)) { $id_agencia = $row['id_agencia_en_uso']; @@ -282,47 +293,45 @@ function guardar() } // Foto solicitud - $fotoUrl=null; + $fotoUrl = null; if (!empty($_FILES['foto_solicitud']['tmp_name']) && $_FILES['foto_solicitud']['error']===UPLOAD_ERR_OK) { - $ext=pathinfo($_FILES['foto_solicitud']['name'],PATHINFO_EXTENSION); - $dest=__DIR__.'/../../public/uploads/solicitud_'.uniqid().".$ext"; + $ext = pathinfo($_FILES['foto_solicitud']['name'], PATHINFO_EXTENSION); + $dest = __DIR__.'/../../public/uploads/solicitud_'.uniqid().".$ext"; if (!is_dir(dirname($dest))) mkdir(dirname($dest),0755,true); if(move_uploaded_file($_FILES['foto_solicitud']['tmp_name'],$dest)) { - $fotoUrl="/IMPORTADORES/public/uploads/".basename($dest); + $fotoUrl = "/IMPORTADORES/public/uploads/".basename($dest); } } $params = [ - $id_importador, - $id_agencia, - $aduana_seccion, - $aduana_seccion, - $num_factura, - $fecha, - $incoterm, - $pais_proveedor, - $tipo_moneda, - $valor_factura, - $vinculacion, - (int)$transportista_id, - (int)$chofer_id, - $fotoUrl, - $status, - $proveedor_clave, - $patente_id ? (int)$patente_id : null - ]; + $id_importador, + $id_agencia, + $aduana_seccion, + $aduana_seccion, + $num_factura, + $fecha, + $incoterm, + $pais_proveedor, + $tipo_moneda, + $valor_factura, + $vinculacion, + (int)$transportista_id, + (int)$chofer_id, + $fotoUrl, + $status, + $proveedor_clave, + $patente_id ? (int)$patente_id : null + ]; + $sql = "INSERT INTO dbo.solicitud_importacion_factura + (id_importador, id_agencia, aduana, anexo22_apendice, numero_factura, + fecha_factura, numero_pedimento, incoterm, pais_proveedor, tipo_moneda, + valor_factura, vinculacion, transportista_id, chofer_id, + foto_solicitud_url, status, proveedor_clave, patente_id) + OUTPUT INSERTED.id_solicitud + VALUES(?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "; + $stmt = sqlsrv_query($conn, $sql, $params, ['Scrollable' => SQLSRV_CURSOR_KEYSET]); - $sql = " - INSERT INTO dbo.solicitud_importacion_factura - (id_importador, id_agencia, aduana, anexo22_apendice, numero_factura, - fecha_factura, numero_pedimento, incoterm, pais_proveedor, tipo_moneda, - valor_factura, vinculacion, transportista_id, chofer_id, - foto_solicitud_url, status, proveedor_clave, patente_id) - OUTPUT INSERTED.id_solicitud - VALUES(?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - "; - - $stmt = sqlsrv_query($conn, $sql, $params, ['Scrollable' => SQLSRV_CURSOR_KEYSET]); if ($stmt === false) { die("❌ Error ejecutando INSERT con OUTPUT: " . print_r(sqlsrv_errors(), true)); } @@ -336,22 +345,17 @@ function guardar() try { // Verificar configuración de notificaciones del usuario - $sqlNotif = " - SELECT - u.nombre, - u.email, - u.notificaciones, - u.notificaciones_extra, - COALESCE(p.nuevas_solicitudes, 0) as nuevas_solicitudes, - ce.correo as correo_extra - FROM usuarios_sistema u - LEFT JOIN preferencias_notificaciones_usuario p - ON u.id_usuario = p.id_usuario - LEFT JOIN correo_extra ce - ON u.id_usuario = ce.id_usuario - WHERE u.id_usuario = ? - "; - + $sqlNotif = "SELECT + u.nombre, u.email, u.notificaciones, u.notificaciones_extra, + COALESCE(p.nuevas_solicitudes, 0) as nuevas_solicitudes, + ce.correo as correo_extra + FROM usuarios_sistema u + LEFT JOIN preferencias_notificaciones_usuario p + ON u.id_usuario = p.id_usuario + LEFT JOIN correo_extra ce + ON u.id_usuario = ce.id_usuario + WHERE u.id_usuario = ? + "; $stmtNotif = sqlsrv_prepare($conn, $sqlNotif, [$id_importador]); if ($stmtNotif && sqlsrv_execute($stmtNotif)) { @@ -361,7 +365,7 @@ function guardar() // 🔐 Desencriptar datos if ($notifConfig) { // Correo - $notifConfig['email'] = decrypt($notifConfig['email']); + $notifConfig['email'] = decrypt($notifConfig['email']); // Nombre $notifConfig['nombre'] = decrypt($notifConfig['nombre']); } @@ -452,10 +456,8 @@ function guardar() } /** Función para generar la notificación **/ -use PHPMailer\PHPMailer\PHPMailer; -use PHPMailer\PHPMailer\Exception; - -function enviarNotificacionNuevaSolicitud($email, $nombreUsuario, $datosSolicitud, $esCorreoExtra = false) { +function enviarNotificacionNuevaSolicitud($email, $nombreUsuario, $datosSolicitud, $esCorreoExtra = false) +{ $mail = new PHPMailer(true); try { @@ -558,16 +560,19 @@ function editar() } $id_solicitud = $_GET['id']??null; + if(!$id_solicitud || !is_numeric($id_solicitud)) { die("❌ ID inválido."); } $id_importador = $_SESSION['usuario_id']; - $conn = getConnection(); + + $conn = getConnection(); // ✅ NUEVO: Obtener la agencia actual del usuario $stmtAg = sqlsrv_query($conn, "SELECT id_agencia_en_uso FROM dbo.usuarios_sistema WHERE id_usuario = ?", [$id_importador]); if ($stmtAg === false) { die(print_r(sqlsrv_errors(), true)); } + $id_agencia = null; if ($row = sqlsrv_fetch_array($stmtAg, SQLSRV_FETCH_ASSOC)) { $id_agencia = $row['id_agencia_en_uso']; } @@ -575,10 +580,12 @@ function editar() if($stmt === false) { die(print_r(sqlsrv_errors(),true)); } + $factura = sqlsrv_fetch_array($stmt,SQLSRV_FETCH_ASSOC); if(!$factura) { die("❌ No autorizado."); } + if($factura['fecha_factura'] instanceof DateTime) { $factura['fecha_factura'] = $factura['fecha_factura']->format('Y-m-d'); } @@ -595,24 +602,24 @@ function editar() // Transportistas $transportistas = []; $stmtT = sqlsrv_query($conn, "SELECT id_transportista, clave_identificador, nombre FROM dbo.transportistas WHERE id_usuario = ? AND activo = 1 ORDER BY nombre",[$id_importador]); - while($r = sqlsrv_fetch_array($stmtT,SQLSRV_FETCH_ASSOC)) { $transportistas[] = $r; } + while ($r = sqlsrv_fetch_array($stmtT, SQLSRV_FETCH_ASSOC)) { $transportistas[] = $r; } // Choferes $choferes = []; - $stmtC = sqlsrv_query($conn, "SELECT c.id_chofer, c.nombre+' '+c.apellido AS nombre, c.transportista_id FROM dbo.choferes c JOIN dbo.transportistas t ON c.transportista_id=t.id_transportista - WHERE t.id_usuario=? AND c.status=1 ORDER BY c.nombre",[$id_importador]); - while($r=sqlsrv_fetch_array($stmtC,SQLSRV_FETCH_ASSOC)) { $choferes[] = $r; } + $stmtC = sqlsrv_query($conn, "SELECT c.id_chofer, c.nombre+' '+c.apellido AS nombre, c.transportista_id FROM dbo.choferes c JOIN dbo.transportistas t ON c.transportista_id = t.id_transportista + WHERE t.id_usuario=? AND c.status=1 ORDER BY c.nombre",[$id_importador]); + while ($r = sqlsrv_fetch_array($stmtC, SQLSRV_FETCH_ASSOC)) { $choferes[] = $r; } // Paises $paises = []; $stmtP = sqlsrv_query($conn, "SELECT id_pais, nombre FROM dbo.paises ORDER BY nombre"); - while($r=sqlsrv_fetch_array($stmtP,SQLSRV_FETCH_ASSOC)) { $paises[] = $r;} + while ($r = sqlsrv_fetch_array($stmtP, SQLSRV_FETCH_ASSOC)) { $paises[] = $r;} // Aduanas $aduanas = []; $stmtA = sqlsrv_query($conn, "SELECT DISTINCT RIGHT(REPLICATE('0', 3) + CAST(aduana_seccion AS VARCHAR), 3) AS aduana_seccion, nombre FROM dbo.aduanas ORDER BY aduana_seccion"); - while($r = sqlsrv_fetch_array($stmtA,SQLSRV_FETCH_ASSOC)) { $aduanas[] = $r; } + while ($r = sqlsrv_fetch_array($stmtA, SQLSRV_FETCH_ASSOC)) { $aduanas[] = $r; } // Incoterms $incoterms = []; $stmtI = sqlsrv_query($conn, "SELECT INCOTERM, DESCESPANOL FROM dbo.gIncoterms ORDER BY INCOTERM"); - while($r = sqlsrv_fetch_array($stmtI,SQLSRV_FETCH_ASSOC)) { $incoterms[] = $r; } + while ($r = sqlsrv_fetch_array($stmtI, SQLSRV_FETCH_ASSOC)) { $incoterms[] = $r; } // Unidades de Medida $unidades_medida = []; $stmtU = sqlsrv_query($conn, "SELECT id, descripcion FROM dbo.unidades_medida_apendice7 ORDER BY id"); @@ -620,12 +627,9 @@ function editar() // Partidas existentes $partidas = []; - $stmtPar = sqlsrv_query($conn, - "SELECT id_partida, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial - FROM dbo.solicitud_importacion_partidas WHERE id_solicitud=? ORDER BY id_partida", [(int)$id_solicitud]); - while($r=sqlsrv_fetch_array($stmtPar,SQLSRV_FETCH_ASSOC)) { - $partidas[]=$r; - } + $stmtPar = sqlsrv_query($conn, "SELECT id_partida, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial + FROM dbo.solicitud_importacion_partidas WHERE id_solicitud = ? ORDER BY id_partida", [(int)$id_solicitud]); + while ($r = sqlsrv_fetch_array($stmtPar, SQLSRV_FETCH_ASSOC)) { $partidas[]=$r; } include __DIR__ . '/../../views/solicitud_importacion/editar.php'; } @@ -638,8 +642,8 @@ function actualizar() } $id_importador = $_SESSION['usuario_id']; + $id_solicitud = (int)($_POST['id_solicitud'] ?? 0); - $id_solicitud = (int)($_POST['id_solicitud'] ?? 0); if ($id_solicitud <= 0) { die("❌ ID inválido."); } @@ -649,6 +653,7 @@ function actualizar() // ✅ NUEVO: Obtener la agencia actual del usuario $stmt = sqlsrv_query($conn, "SELECT id_agencia_en_uso FROM dbo.usuarios_sistema WHERE id_usuario = ?", [$id_importador]); + $id_agencia = null; if ($stmt && $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $id_agencia = $row['id_agencia_en_uso']; @@ -656,28 +661,20 @@ function actualizar() // 2) Obtener URL de foto actual desde BD para conservar si no suben nueva $fotoUrl = null; - $stmtFoto = sqlsrv_query( - $conn, - "SELECT foto_solicitud_url - FROM dbo.solicitud_importacion_factura - WHERE id_solicitud = ? AND id_importador = ? AND id_agencia = ?", - [ $id_solicitud, $_SESSION['usuario_id'], $id_agencia ] - ); + $stmtFoto = sqlsrv_query($conn, "SELECT foto_solicitud_url FROM dbo.solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ? AND id_agencia = ?", [ $id_solicitud, $_SESSION['usuario_id'], $id_agencia ] ); + if ($stmtFoto !== false && ($row = sqlsrv_fetch_array($stmtFoto, SQLSRV_FETCH_ASSOC))) { $fotoUrl = $row['foto_solicitud_url']; } // 3) Procesar posible nueva foto - if (!empty($_FILES['foto_solicitud']['tmp_name']) - && $_FILES['foto_solicitud']['error'] === UPLOAD_ERR_OK) { + if (!empty($_FILES['foto_solicitud']['tmp_name']) && $_FILES['foto_solicitud']['error'] === UPLOAD_ERR_OK) { $ext = pathinfo($_FILES['foto_solicitud']['name'], PATHINFO_EXTENSION); $dest = __DIR__ . '/../../public/uploads/solicitud_' . uniqid() . ".$ext"; - if (!is_dir(dirname($dest))) { - mkdir(dirname($dest), 0755, true); - } - if (move_uploaded_file($_FILES['foto_solicitud']['tmp_name'], $dest)) { - $fotoUrl = "/IMPORTADORES/public/uploads/" . basename($dest); - } + + if (!is_dir(dirname($dest))) { mkdir(dirname($dest), 0755, true); } + + if (move_uploaded_file($_FILES['foto_solicitud']['tmp_name'], $dest)) { $fotoUrl = "/IMPORTADORES/public/uploads/" . basename($dest); } } // 4) Extraer campos del formulario @@ -697,9 +694,7 @@ function actualizar() // ✅ NUEVO: Validar que la patente pertenezca a la agencia del usuario (si se seleccionó una) 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."); @@ -714,68 +709,66 @@ function actualizar() // 6) UPDATE de la cabecera $paramsU = [ - $aduana_seccion, - $aduana_seccion, - $num_factura, - $fecha, - $incoterm, - $pais_proveedor, - $tipo_moneda, - $valor_factura, - $vinculacion, - (int)$transportista_id, - (int)$chofer_id, - $fotoUrl, - $status, - $proveedor_clave, - $patente_id ? (int)$patente_id : null, - $id_solicitud, - $_SESSION['usuario_id'], - $id_agencia - ]; + $aduana_seccion, + $aduana_seccion, + $num_factura, + $fecha, + $incoterm, + $pais_proveedor, + $tipo_moneda, + $valor_factura, + $vinculacion, + (int)$transportista_id, + (int)$chofer_id, + $fotoUrl, + $status, + $proveedor_clave, + $patente_id ? (int)$patente_id : null, + $id_solicitud, + $_SESSION['usuario_id'], + $id_agencia + ]; + $sqlU = "UPDATE dbo.solicitud_importacion_factura SET + aduana = ?, + anexo22_apendice = ?, + numero_factura = ?, + fecha_factura = ?, + incoterm = ?, + pais_proveedor = ?, + tipo_moneda = ?, + valor_factura = ?, + vinculacion = ?, + transportista_id = ?, + chofer_id = ?, + foto_solicitud_url = ?, + status = ?, + proveedor_clave = ?, + patente_id = ?, + updated_at = GETDATE() + WHERE id_solicitud = ? + AND id_importador = ? + AND id_agencia = ? + "; + $stmtU = sqlsrv_query($conn, $sqlU, $paramsU); - $sqlU = " - UPDATE dbo.solicitud_importacion_factura - SET aduana = ?, - anexo22_apendice = ?, - numero_factura = ?, - fecha_factura = ?, - incoterm = ?, - pais_proveedor = ?, - tipo_moneda = ?, - valor_factura = ?, - vinculacion = ?, - transportista_id = ?, - chofer_id = ?, - foto_solicitud_url = ?, - status = ?, - proveedor_clave = ?, - patente_id = ?, - updated_at = GETDATE() - WHERE id_solicitud = ? - AND id_importador = ? - AND id_agencia = ? - "; - - $stmtU = sqlsrv_query($conn, $sqlU, $paramsU); if ($stmtU === false) { die("❌ Error ejecutando UPDATE: " . print_r(sqlsrv_errors(), true)); } // 7) Borrar partidas anteriores $del = sqlsrv_query($conn, "DELETE FROM dbo.solicitud_importacion_partidas WHERE id_solicitud = ?", [ $id_solicitud ]); + if ($del === false) { die("❌ Error borrando partidas previas: " . print_r(sqlsrv_errors(), true)); } // 8) Reinsertar partidas desde el formulario 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 (?, ?, ?, ?, ?, ?, ?, ?) - "; + $sqlP = "INSERT INTO dbo.solicitud_importacion_partidas + (id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, + valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + "; foreach ($_POST['partidas'] as $i => $p) { $desc = trim($p['descripcion'] ?? ''); $cantCom = floatval($p['cantidad_comercial'] ?? 0); @@ -788,16 +781,17 @@ function actualizar() // Sólo inserta si descripción y cantidad comercial válidos if ($desc !== '' && $cantCom > 0) { $paramsP = [ - $id_solicitud, - $desc, - $cantCom, - $cantTar, - $valPart, - $peso, - $umId, - $tasaPref - ]; - $stmtP = sqlsrv_query($conn, $sqlP, $paramsP); + $id_solicitud, + $desc, + $cantCom, + $cantTar, + $valPart, + $peso, + $umId, + $tasaPref + ]; + $stmtP = sqlsrv_query($conn, $sqlP, $paramsP); + if ($stmtP === false) { die("❌ Error insertando partida #$i: " . print_r(sqlsrv_errors(), true)); } @@ -811,19 +805,24 @@ function actualizar() } /** “Soft-delete” de una factura **/ -function eliminar() { +function eliminar() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $id = (int) ($_GET['id'] ?? 0); + $conn = getConnection(); + sqlsrv_query($conn, "UPDATE dbo.solicitud_importacion_factura SET status = 0, updated_at = GETDATE() WHERE id_solicitud = ? AND id_importador = ?",[$id,$_SESSION['usuario_id']]); header('Location: /IMPORTADORES/solicitud_importacion/lista?deleted=ok'); exit; } -function actualizar_masivo() { +function actualizar_masivo() +{ header('Content-Type: application/json; charset=utf-8'); if (!($_SESSION['usuario_id'] ?? false)) { @@ -838,7 +837,7 @@ function actualizar_masivo() { exit; } - $ids = $_POST['ids'] ?? []; + $ids = $_POST['ids'] ?? []; $status = (int) ($_POST['status'] ?? 0); if (empty($ids) || !is_array($ids)) { @@ -847,18 +846,19 @@ function actualizar_masivo() { } $conn = getConnection(); - $usuarioId = $_SESSION['usuario_id']; - $token = ($status === 2) ? getApiToken() : null; - $actualizadas = 0; - $fallidas = []; + $usuarioId = $_SESSION['usuario_id']; + $token = ($status === 2) ? getApiToken() : null; + + $actualizadas = 0; + $fallidas = []; $pedimentosGenerados = []; foreach ($ids as $id) { $id = (int)$id; // 1. Actualizar el status - $sql = "UPDATE dbo.solicitud_importacion_factura SET status = ? WHERE id_solicitud = ? AND id_importador = ?"; + $sql = "UPDATE dbo.solicitud_importacion_factura SET status = ? WHERE id_solicitud = ? AND id_importador = ?"; $stmt = sqlsrv_query($conn, $sql, [$status, $id, $usuarioId]); if ($stmt === false) { @@ -880,47 +880,49 @@ function actualizar_masivo() { } echo json_encode([ - 'success' => true, + 'success' => true, 'actualizadas' => $actualizadas, - 'fallidas' => $fallidas, - 'pedimentos' => $pedimentosGenerados + 'fallidas' => $fallidas, + 'pedimentos' => $pedimentosGenerados ]); exit; } -function generarPedimentoDesdeSolicitud($conn, $id, $usuarioId, $token) { +function generarPedimentoDesdeSolicitud($conn, $id, $usuarioId, $token) +{ try { // Consulta solicitud - $sqlSel = "SELECT *, '9999' as patente FROM dbo.solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ?"; - $stmtSel = sqlsrv_query($conn, $sqlSel, [$id, $usuarioId]); + $sqlSel = "SELECT *, '9999' as patente FROM dbo.solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ?"; + $stmtSel = sqlsrv_query($conn, $sqlSel, [$id, $usuarioId]); $solicitud = sqlsrv_fetch_array($stmtSel, SQLSRV_FETCH_ASSOC); + if (!$solicitud) return ['success' => false, 'error' => 'Solicitud no encontrada']; // Fechas - $solicitud['fecha_factura'] = $solicitud['fecha_factura'] instanceof DateTime ? $solicitud['fecha_factura']->format('Y-m-d') : $solicitud['fecha_factura']; - $solicitud['created_at'] = $solicitud['created_at'] instanceof DateTime ? $solicitud['created_at']->format('Y-m-d\TH:i:s') : $solicitud['created_at']; - $solicitud['updated_at'] = $solicitud['updated_at'] instanceof DateTime ? $solicitud['updated_at']->format('Y-m-d\TH:i:s') : $solicitud['updated_at']; + $solicitud['fecha_factura'] = $solicitud['fecha_factura'] instanceof DateTime ? $solicitud['fecha_factura'] ->format('Y-m-d') : $solicitud['fecha_factura']; + $solicitud['created_at'] = $solicitud['created_at'] instanceof DateTime ? $solicitud['created_at'] ->format('Y-m-d\TH:i:s') : $solicitud['created_at']; + $solicitud['updated_at'] = $solicitud['updated_at'] instanceof DateTime ? $solicitud['updated_at'] ->format('Y-m-d\TH:i:s') : $solicitud['updated_at']; // Partidas $partidas = []; $stmtPart = sqlsrv_query($conn, "SELECT * FROM dbo.solicitud_importacion_partidas WHERE id_solicitud = ?", [$id]); while ($p = sqlsrv_fetch_array($stmtPart, SQLSRV_FETCH_ASSOC)) { if ($p['creado_en'] instanceof DateTime) $p['creado_en'] = $p['creado_en']->format('Y-m-d\TH:i:s'); - $p['cantidad_comercial'] = (float)$p['cantidad_comercial']; - $p['cantidad_tarifa'] = (float)$p['cantidad_tarifa']; - $p['valor_factura'] = (float)$p['valor_factura']; - $p['peso_bruto'] = (float)$p['peso_bruto']; + $p['cantidad_comercial'] = (float)$p['cantidad_comercial']; + $p['cantidad_tarifa'] = (float)$p['cantidad_tarifa']; + $p['valor_factura'] = (float)$p['valor_factura']; + $p['peso_bruto'] = (float)$p['peso_bruto']; $p['unidad_comercial_id'] = (int)$p['unidad_comercial_id']; $partidas[] = $p; } $solicitud['numero_pedimento'] = ""; - $solicitud['transporte_id'] = null; - $solicitud['partidas'] = $partidas; + $solicitud['transporte_id'] = null; + $solicitud['partidas'] = $partidas; $jsonPayload = json_encode($solicitud); - $apiBase = rtrim($_ENV['API_URL'] ?? '', '/'); - $urlPed = $apiBase . '/pedimentos/crearPedimento'; + $apiBase = rtrim($_ENV['API_URL'] ?? '', '/'); + $urlPed = $apiBase . '/pedimentos/crearPedimento'; $ch = curl_init($urlPed); curl_setopt_array($ch, [ @@ -1036,15 +1038,15 @@ function ajax_lista() // Construir dirección $direccion = trim(implode(', ', array_filter([ - $p['Calles'] ?? '', - 'Num. Ext: ' . ($p['NumExt'] ?? ''), - 'Num. Int: ' . ($p['NumInt'] ?? ''), - $p['Colonia'] ?? '', - $p['Municipio'] ?? '', - $p['Ciudad'] ?? '', + $p['Calles'] ?? '', + 'Num. Ext: ' . ($p['NumExt'] ?? ''), + 'Num. Int: ' . ($p['NumInt'] ?? ''), + $p['Colonia'] ?? '', + $p['Municipio'] ?? '', + $p['Ciudad'] ?? '', 'C.P. ' . ($p['CodigoPostal'] ?? ''), - $p['EntidadFederativa'] ?? '', - $p['Pais'] ?? '' + $p['EntidadFederativa'] ?? '', + $p['Pais'] ?? '' ]))); $dataList[] = [ @@ -1067,8 +1069,10 @@ function ajax_lista() echo json_encode(['data' => $dataList]); } -function update_status() { +function update_status() +{ header('Content-Type: application/json; charset=utf-8'); + if (!($_SESSION['usuario_id'] ?? false)) { http_response_code(401); echo json_encode(['error' => 'No autorizado']); @@ -1082,11 +1086,10 @@ function update_status() { $conn = getConnection(); // 2) Actualizar el status en la tabla solicitud_importacion_factura - $sql = "UPDATE dbo.solicitud_importacion_factura - SET status=? - WHERE id_solicitud=? AND id_importador=?"; + $sql = "UPDATE dbo.solicitud_importacion_factura SET status = ? WHERE id_solicitud=? AND id_importador=?"; $params = [$status, $id, $_SESSION['usuario_id']]; - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); + if ($stmt === false) { http_response_code(500); echo json_encode(['error' => 'Error al actualizar status']); @@ -1095,24 +1098,21 @@ function update_status() { // 3) Obtener datos del usuario y solicitud para notificación try { - $sqlNotif = " - SELECT - u.nombre, - u.email, - u.notificaciones, - u.notificaciones_extra, - COALESCE(p.cambio_estado, 0) as cambio_estado, - ce.correo as correo_extra, - s.numero_factura, - s.fecha_factura, - s.valor_factura, - s.tipo_moneda - FROM usuarios_sistema u - LEFT JOIN preferencias_notificaciones_usuario p ON u.id_usuario = p.id_usuario - LEFT JOIN correo_extra ce ON u.id_usuario = ce.id_usuario - INNER JOIN solicitud_importacion_factura s ON s.id_importador = u.id_usuario - WHERE u.id_usuario = ? AND s.id_solicitud = ?"; - + $sqlNotif = "SELECT + u.nombre, u.email, u.notificaciones, u.notificaciones_extra, + COALESCE(p.cambio_estado, 0) as cambio_estado, + ce.correo as correo_extra, + s.numero_factura, s.fecha_factura, s.valor_factura, s.tipo_moneda + FROM usuarios_sistema u + LEFT JOIN preferencias_notificaciones_usuario p + ON u.id_usuario = p.id_usuario + LEFT JOIN correo_extra ce + ON u.id_usuario = ce.id_usuario + INNER JOIN solicitud_importacion_factura s + 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)) { @@ -1121,14 +1121,12 @@ function update_status() { // 🔐 Desencriptar datos if ($notifConfig) { - $notifConfig['email'] = decrypt($notifConfig['email']); + $notifConfig['email'] = decrypt($notifConfig['email']); $notifConfig['nombre'] = decrypt($notifConfig['nombre']); } // Verificar si debe enviar notificaciones de cambio de status - if ($notifConfig && - $notifConfig['notificaciones'] == 1 && - $notifConfig['cambio_estado'] == 1) { + if ($notifConfig && $notifConfig['notificaciones'] == 1 && $notifConfig['cambio_estado'] == 1) { // Formatear fecha si es DateTime $fechaFactura = ($notifConfig['fecha_factura'] instanceof DateTime) @@ -1137,16 +1135,16 @@ function update_status() { // Preparar datos para la notificación $datosSolicitud = [ - 'id_solicitud' => $id, + 'id_solicitud' => $id, 'numero_factura' => $notifConfig['numero_factura'], - 'fecha_factura' => $fechaFactura, - 'valor_factura' => $notifConfig['valor_factura'], - 'tipo_moneda' => $notifConfig['tipo_moneda'], - 'nuevo_status' => $status + 'fecha_factura' => $fechaFactura, + 'valor_factura' => $notifConfig['valor_factura'], + 'tipo_moneda' => $notifConfig['tipo_moneda'], + 'nuevo_status' => $status ]; $notificacionesEnviadas = 0; - $erroresNotificacion = []; + $erroresNotificacion = []; // Enviar al correo principal if (!empty($notifConfig['email']) && filter_var($notifConfig['email'], FILTER_VALIDATE_EMAIL)) { @@ -1199,7 +1197,7 @@ function update_status() { $razon[] = 'configuración no encontrada'; } else { if ($notifConfig['notificaciones'] != 1) $razon[] = 'notificaciones generales deshabilitadas'; - if ($notifConfig['cambio_estado'] != 1) $razon[] = 'notificaciones de cambio de estado deshabilitadas'; + if ($notifConfig['cambio_estado'] != 1) $razon[] = 'notificaciones de cambio de estado deshabilitadas'; } error_log("ℹ️ Usuario ID: {$_SESSION['usuario_id']} no recibirá notificación de cambio de status. Razón: " . implode(', ', $razon)); @@ -1225,36 +1223,24 @@ function update_status() { } // 4.2) Leer de la BD todos los campos de la cabecera de la solicitud - $sqlSel = " - SELECT - s.id_solicitud, - s.id_importador, - s.aduana, - s.numero_pedimento, - s.anexo22_apendice, - s.numero_factura, - s.fecha_factura, - s.incoterm, - s.pais_proveedor, - s.tipo_moneda, - s.valor_factura, - s.vinculacion, - s.transportista_id, - s.chofer_id, - s.foto_solicitud_url, - s.proveedor_clave, - s.created_at, - s.updated_at, - '9999' as patente - FROM dbo.solicitud_importacion_factura s - WHERE s.id_solicitud = ? AND s.id_importador = ? - "; + $sqlSel = "SELECT + s.id_solicitud, s.id_importador, s.aduana, s.numero_pedimento, s.anexo22_apendice, + s.numero_factura, s.fecha_factura, s.incoterm, s.pais_proveedor, + s.tipo_moneda, s.valor_factura, s.vinculacion, s.transportista_id, s.chofer_id, + s.foto_solicitud_url, s.proveedor_clave, s.created_at, s.updated_at, + '9999' as patente + FROM dbo.solicitud_importacion_factura s + WHERE s.id_solicitud = ? + AND s.id_importador = ? + "; $stmtSel = sqlsrv_query($conn, $sqlSel, [$id, $_SESSION['usuario_id']]); + if ($stmtSel === false) { error_log("[update_status] Error al consultar solicitud: " . print_r(sqlsrv_errors(), true)); echo json_encode(['success' => true, 'warning' => 'Status actualizado, fallo al leer datos para pedimento']); exit; } + $solicitud = sqlsrv_fetch_array($stmtSel, SQLSRV_FETCH_ASSOC); sqlsrv_free_stmt($stmtSel); @@ -1269,37 +1255,30 @@ function update_status() { ? $solicitud['fecha_factura']->format('Y-m-d') : $solicitud['fecha_factura']; - $createdAt = ($solicitud['created_at'] instanceof DateTime) - ? $solicitud['created_at']->format('Y-m-d\TH:i:s') - : $solicitud['created_at']; + $createdAt = ($solicitud['created_at'] instanceof DateTime) + ? $solicitud['created_at']->format('Y-m-d\TH:i:s') + : $solicitud['created_at']; - $updatedAt = ($solicitud['updated_at'] instanceof DateTime) - ? $solicitud['updated_at']->format('Y-m-d\TH:i:s') - : $solicitud['updated_at']; + $updatedAt = ($solicitud['updated_at'] instanceof DateTime) + ? $solicitud['updated_at']->format('Y-m-d\TH:i:s') + : $solicitud['updated_at']; // 4.4) Obtener todas las partidas asociadas a esta solicitud - $sqlPart = " - SELECT - p.id_partida, - p.id_solicitud, - p.descripcion, - p.creado_en, - p.cantidad_comercial, - p.cantidad_tarifa, - p.valor_factura, - p.peso_bruto, - p.unidad_comercial_id, - p.tasa_preferencial - FROM dbo.solicitud_importacion_partidas p - WHERE p.id_solicitud = ? - ORDER BY p.id_partida - "; + $sqlPart = "SELECT + p.id_partida, p.id_solicitud, p.descripcion, p.creado_en, p.cantidad_comercial, + p.cantidad_tarifa, p.valor_factura, p.peso_bruto, p.unidad_comercial_id, p.tasa_preferencial + FROM dbo.solicitud_importacion_partidas p + WHERE p.id_solicitud = ? + ORDER BY p.id_partida + "; $stmtPart = sqlsrv_query($conn, $sqlPart, [$id]); + if ($stmtPart === false) { error_log("[update_status] Error al consultar partidas: " . print_r(sqlsrv_errors(), true)); echo json_encode(['success' => true, 'warning' => 'Status actualizado, fallo al leer partidas para pedimento']); exit; } + $partidas = []; while ($row = sqlsrv_fetch_array($stmtPart, SQLSRV_FETCH_ASSOC)) { if ($row['creado_en'] instanceof DateTime) { @@ -1315,30 +1294,29 @@ function update_status() { sqlsrv_free_stmt($stmtPart); // 4.5) Construir el arreglo PHP con la misma estructura JSON que envías - $payload = [ - "id_solicitud" => intval($solicitud['id_solicitud']), - "id_importador" => intval($solicitud['id_importador']), - "aduana" => strval($solicitud['aduana']), - "patente" => strval($solicitud['patente']), - "anexo22_apendice" => strval($solicitud['anexo22_apendice']), - "numero_factura" => strval($solicitud['numero_factura']), - "fecha_factura" => $fechaFactura, - "numero_pedimento" => "", // La API lo rellenará - "incoterm" => strval($solicitud['incoterm']), - "pais_proveedor" => strval($solicitud['pais_proveedor']), - "tipo_moneda" => strval($solicitud['tipo_moneda']), - "valor_factura" => floatval($solicitud['valor_factura']), - "vinculacion" => intval($solicitud['vinculacion']), - "transportista_id" => intval($solicitud['transportista_id']), - - "created_at" => $createdAt, - "updated_at" => $updatedAt, - "transporte_id" => null, - "chofer_id" => intval($solicitud['chofer_id']), - "foto_solicitud_url"=> strval($solicitud['foto_solicitud_url']), - "proveedor_clave" => strval($solicitud['proveedor_clave']), - "partidas" => $partidas - ]; + $payload = [ + "id_solicitud" => intval($solicitud['id_solicitud']), + "id_importador" => intval($solicitud['id_importador']), + "aduana" => strval($solicitud['aduana']), + "patente" => strval($solicitud['patente']), + "anexo22_apendice" => strval($solicitud['anexo22_apendice']), + "numero_factura" => strval($solicitud['numero_factura']), + "fecha_factura" => $fechaFactura, + "numero_pedimento" => "", // La API lo rellenará + "incoterm" => strval($solicitud['incoterm']), + "pais_proveedor" => strval($solicitud['pais_proveedor']), + "tipo_moneda" => strval($solicitud['tipo_moneda']), + "valor_factura" => floatval($solicitud['valor_factura']), + "vinculacion" => intval($solicitud['vinculacion']), + "transportista_id" => intval($solicitud['transportista_id']), + "created_at" => $createdAt, + "updated_at" => $updatedAt, + "transporte_id" => null, + "chofer_id" => intval($solicitud['chofer_id']), + "foto_solicitud_url"=> strval($solicitud['foto_solicitud_url']), + "proveedor_clave" => strval($solicitud['proveedor_clave']), + "partidas" => $partidas + ]; $jsonPayload = json_encode($payload); // 3.6) Preparar cURL para hacer POST a /pedimentos/crearPedimento @@ -1350,7 +1328,7 @@ function update_status() { CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_HTTPHEADER => [ "Authorization: $token", - 'Content-Type: application/json' + 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => $jsonPayload, CURLOPT_RETURNTRANSFER => true, @@ -1369,17 +1347,9 @@ function update_status() { $numeroPedimento = $decoded['pedimento']['PEDIMENTO']; // 3.8) Actualizar localmente el campo numero_pedimento - $sqlUpdPed = " - UPDATE dbo.solicitud_importacion_factura - SET numero_pedimento = ? - WHERE id_solicitud = ? - AND id_importador = ? - "; - $stmtUpdPed = sqlsrv_query( - $conn, - $sqlUpdPed, - [$numeroPedimento, $id, $_SESSION['usuario_id']] - ); + $sqlUpdPed = "UPDATE dbo.solicitud_importacion_factura SET numero_pedimento = ? WHERE id_solicitud = ? AND id_importador = ?"; + $stmtUpdPed = sqlsrv_query($conn, $sqlUpdPed, [$numeroPedimento, $id, $_SESSION['usuario_id']]); + if ($stmtUpdPed === false) { error_log("[update_status] Error al actualizar numero_pedimento en BD: " . print_r(sqlsrv_errors(), true)); } @@ -1387,9 +1357,9 @@ function update_status() { error_log("[update_status] Pedimento creado con éxito para solicitud $id → HTTP $httpPed → $respPed"); echo json_encode([ - 'success' => true, - 'pedimento' => $decoded['pedimento'], - 'numeroPedimentoLocal' => $numeroPedimento + 'success' => true, + 'pedimento' => $decoded['pedimento'], + 'numeroPedimentoLocal' => $numeroPedimento ]); exit; } else { @@ -1408,7 +1378,8 @@ function update_status() { } /** Envía notificación de cambio de estado de solicitud de importación **/ -function enviarNotificacionCambioStatus($email, $nombreCompleto, $datosSolicitud, $esCorreoExtra = false) { +function enviarNotificacionCambioStatus($email, $nombreCompleto, $datosSolicitud, $esCorreoExtra = false) +{ // Validar datos de entrada if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) { error_log("❌ Email inválido para notificación: $email"); @@ -1425,13 +1396,13 @@ function enviarNotificacionCambioStatus($email, $nombreCompleto, $datosSolicitud try { // Configuración SMTP $mail->isSMTP(); - $mail->Host = 'secure.emailsrvr.com'; - $mail->SMTPAuth = true; - $mail->Username = 'noreply@aduanasoft.com.mx'; - $mail->Password = $_ENV['SMTP_PASS'] ?? ''; + $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->CharSet = 'UTF-8'; + $mail->Port = 587; + $mail->CharSet = 'UTF-8'; // Configuración del mensaje $mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft'); @@ -1484,32 +1455,34 @@ function obtenerInfoStatus($status) { ]; return $statusMap[$status] ?? [ - 'emoji' => '📝', + 'emoji' => '📝', 'descripcion' => 'Estado actualizado', - 'color' => '#6c757d' + 'color' => '#6c757d' ]; } /** Prepara los datos para el template del email **/ -function prepararDatosTemplate($datosSolicitud, $nombreCompleto, $statusInfo, $esCorreoExtra) { +function prepararDatosTemplate($datosSolicitud, $nombreCompleto, $statusInfo, $esCorreoExtra) +{ return [ - 'nombreCompleto' => htmlspecialchars($nombreCompleto ?? 'Usuario'), - 'idSolicitud' => intval($datosSolicitud['id_solicitud'] ?? 0), - 'numeroFactura' => htmlspecialchars($datosSolicitud['numero_factura'] ?? 'N/A'), - 'fechaFactura' => htmlspecialchars($datosSolicitud['fecha_factura'] ?? 'N/A'), - 'valorFactura' => number_format(floatval($datosSolicitud['valor_factura'] ?? 0), 2), - 'tipoMoneda' => htmlspecialchars($datosSolicitud['tipo_moneda'] ?? 'USD'), - 'statusEmoji' => $statusInfo['emoji'], + 'nombreCompleto' => htmlspecialchars($nombreCompleto ?? 'Usuario'), + 'idSolicitud' => intval($datosSolicitud['id_solicitud'] ?? 0), + 'numeroFactura' => htmlspecialchars($datosSolicitud['numero_factura'] ?? 'N/A'), + 'fechaFactura' => htmlspecialchars($datosSolicitud['fecha_factura'] ?? 'N/A'), + 'valorFactura' => number_format(floatval($datosSolicitud['valor_factura'] ?? 0), 2), + 'tipoMoneda' => htmlspecialchars($datosSolicitud['tipo_moneda'] ?? 'USD'), + 'statusEmoji' => $statusInfo['emoji'], 'statusDescripcion' => $statusInfo['descripcion'], - 'statusColor' => $statusInfo['color'], - 'esCorreoExtra' => $esCorreoExtra, - 'fechaActual' => date('Y-m-d H:i:s'), - 'anioActual' => date('Y') + 'statusColor' => $statusInfo['color'], + 'esCorreoExtra' => $esCorreoExtra, + 'fechaActual' => date('Y-m-d H:i:s'), + 'anioActual' => date('Y') ]; } /** Genera el HTML para la notificación **/ -function generarHtmlNotificacion($datos) { +function generarHtmlNotificacion($datos) +{ $tipoNotificacion = $datos['esCorreoExtra'] ? '
📧 Copia enviada a correo adicional @@ -1596,9 +1569,6 @@ function generarHtmlNotificacion($datos) { } // Función para generar el PDF -use Dompdf\Dompdf; -use Dompdf\Options; - function pdf() { // Verificar que se recibió el ID if (!isset($_GET['id'])) { @@ -1614,31 +1584,22 @@ function pdf() { $conn = getConnection(); // 2. Obtener datos de la solicitud principal - $sql = " - SELECT - s.*, - i.nombre as importador_nombre, - i.rfc as importador_rfc, - i.calle, - i.num_exterior, - i.num_interior, - i.ciudad, - i.colonia, - i.codigo_postal, - i.estado, - i.telefono, - i.correo, - t.nombre as transportista_nombre, - c.nombre as chofer_nombre - FROM solicitud_importacion_factura s - LEFT JOIN informacion_general i ON s.id_importador = i.id_usuario - LEFT JOIN transportistas t ON s.transportista_id = t.id_transportista - LEFT JOIN choferes c ON s.chofer_id = c.id_chofer - WHERE s.id_solicitud = ? - "; - + $sql = "SELECT + s.*, i.nombre as importador_nombre, i.rfc as importador_rfc, i.calle, i.num_exterior, + i.num_interior, i.ciudad, i.colonia, i.codigo_postal, i.estado, i.telefono, i.correo, + t.nombre as transportista_nombre, + c.nombre as chofer_nombre + FROM solicitud_importacion_factura s + LEFT JOIN informacion_general i + ON s.id_importador = i.id_usuario + LEFT JOIN transportistas t + ON s.transportista_id = t.id_transportista + LEFT JOIN choferes c + ON s.chofer_id = c.id_chofer + WHERE s.id_solicitud = ? + "; $params = array($id_solicitud); - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { throw new Exception("Error en la consulta: " . print_r(sqlsrv_errors(), true)); @@ -1660,18 +1621,16 @@ function pdf() { } // 3. Obtener partidas de la solicitud - $sql = " - SELECT - p.*, - u.descripcion as unidad_descripcion - FROM solicitud_importacion_partidas p - LEFT JOIN unidades_medida_apendice7 u ON p.unidad_comercial_id = u.id - WHERE p.id_solicitud = ? - ORDER BY p.id_partida - "; - + $sql = "SELECT + p.*, u.descripcion as unidad_descripcion + FROM solicitud_importacion_partidas p + LEFT JOIN unidades_medida_apendice7 u + ON p.unidad_comercial_id = u.id + WHERE p.id_solicitud = ? + ORDER BY p.id_partida + "; $params = array($id_solicitud); - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { throw new Exception("Error en la consulta de partidas: " . print_r(sqlsrv_errors(), true)); @@ -1685,7 +1644,7 @@ function pdf() { // 4. Configuración del sistema $config = "SELECT * FROM configuracion_sistema"; - $stmt = sqlsrv_query($conn, $config); + $stmt = sqlsrv_query($conn, $config); if ($stmt === false) { throw new Exception("Error en la consulta: " . print_r(sqlsrv_errors(), true)); @@ -1693,7 +1652,6 @@ function pdf() { $configuracion = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); - // 5. Generar HTML del PDF $html = generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info); @@ -1701,10 +1659,10 @@ function pdf() { require_once __DIR__ . '/../../vendor/autoload.php'; // Ajusta ruta si es necesario $options = new Options(); - $options->set('defaultFont', 'Arial'); - $options->set('isRemoteEnabled', true); // Permite cargar imágenes remotas si es necesario - $options->set('isHtml5ParserEnabled', true); // Habilita el parser HTML5 - $options->set('isPhpEnabled', true); // Habilita PHP dentro del HTML si es necesario + $options->set('defaultFont', 'Arial'); + $options->set('isRemoteEnabled', true); // Permite cargar imágenes remotas si es necesario + $options->set('isHtml5ParserEnabled', true); // Habilita el parser HTML5 + $options->set('isPhpEnabled', true); // Habilita PHP dentro del HTML si es necesario $options->set('chroot', $_SERVER['DOCUMENT_ROOT']); // Asegura que las rutas relativas funcionen correctamente $dompdf = new Dompdf($options); @@ -1735,7 +1693,7 @@ function obtenerProveedorPorClave($clave) { // Construir URL de la API $apiBase = rtrim($_ENV['API_URL'] ?? '', '/'); - $url = $apiBase . '/proveedores'; + $url = $apiBase . '/proveedores'; // Ejecutar cURL para obtener todos los proveedores $ch = curl_init($url); @@ -1745,7 +1703,7 @@ function obtenerProveedorPorClave($clave) { CURLOPT_TIMEOUT => 10, ]); - $resp = curl_exec($ch); + $resp = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); @@ -1780,12 +1738,12 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = // Construir dirección del importador $direccion_completa = trim( - ($solicitud['calle'] ?? '') . ' ' . - ($solicitud['num_exterior'] ?? '') . ' ' . - ($solicitud['num_interior'] ? 'Int. ' . $solicitud['num_interior'] : '') . ', ' . - ($solicitud['colonia'] ?? '') . ', ' . - ($solicitud['ciudad'] ?? '') . ', ' . - ($solicitud['estado'] ?? '') . ' ' . + ($solicitud['calle'] ?? '') . ' ' . + ($solicitud['num_exterior'] ?? '') . ' ' . + ($solicitud['num_interior'] ? 'Int. ' . $solicitud['num_interior'] : '') . ', ' . + ($solicitud['colonia'] ?? '') . ', ' . + ($solicitud['ciudad'] ?? '') . ', ' . + ($solicitud['estado'] ?? '') . ' ' . ($solicitud['codigo_postal'] ?? '') ); @@ -1798,19 +1756,19 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = // Construir información del proveedor if ($proveedor_info) { // Usar nombres de campos en mayúsculas según la estructura de la tabla - $proveedor_nombre = $proveedor_info['Nombre'] ?? 'Nombre no disponible'; - $proveedor_rfc = $proveedor_info['IdentFiscal'] ??$proveedor_info['RFC'] ?? 'RFC no disponible'; + $proveedor_nombre = $proveedor_info['Nombre'] ?? 'Nombre no disponible'; + $proveedor_rfc = $proveedor_info['IdentFiscal'] ??$proveedor_info['RFC'] ?? 'RFC no disponible'; $proveedor_telefono = trim($proveedor_info['Telefono'] ?? 'Teléfono no disponible'); // Construir dirección del proveedor usando los campos correctos $direccion_partes = array_filter([ - $proveedor_info['Calles'] ?? '', - $proveedor_info['Colonia'] ?? '', - $proveedor_info['Municipio'] ?? '', - $proveedor_info['Ciudad'] ?? '', - ($proveedor_info['CodigoPostal'] ?? '') ? 'C.P. ' . $proveedor_info['CodigoPostal'] : '', + $proveedor_info['Calles'] ?? '', + $proveedor_info['Colonia'] ?? '', + $proveedor_info['Municipio'] ?? '', + $proveedor_info['Ciudad'] ?? '', + ($proveedor_info['CodigoPostal'] ?? '') ? 'C.P. ' . $proveedor_info['CodigoPostal'] : '', $proveedor_info['EntidadFederativa'] ?? '', - $proveedor_info['Pais'] ?? '' + $proveedor_info['Pais'] ?? '' ]); if (!empty($direccion_partes)) { @@ -1826,14 +1784,14 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = // Función para convertir número a texto function numeroATexto($numero) { - $unidades = ['', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve']; - $decenas = ['', '', 'veinte', 'treinta', 'cuarenta', 'cincuenta', 'sesenta', 'setenta', 'ochenta', 'noventa']; + $unidades = ['', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve']; + $decenas = ['', '', 'veinte', 'treinta', 'cuarenta', 'cincuenta', 'sesenta', 'setenta', 'ochenta', 'noventa']; $especiales = ['diez', 'once', 'doce', 'trece', 'catorce', 'quince', 'dieciséis', 'diecisiete', 'dieciocho', 'diecinueve']; - $centenas = ['', 'ciento', 'doscientos', 'trescientos', 'cuatrocientos', 'quinientos', 'seiscientos', 'setecientos', 'ochocientos', 'novecientos']; + $centenas = ['', 'ciento', 'doscientos', 'trescientos', 'cuatrocientos', 'quinientos', 'seiscientos', 'setecientos', 'ochocientos', 'novecientos']; - if ($numero == 0) return 'cero'; - if ($numero == 100) return 'cien'; - if ($numero == 1000) return 'mil'; + if ($numero == 0) return 'cero'; + if ($numero == 100) return 'cien'; + if ($numero == 1000) return 'mil'; if ($numero == 1000000) return 'un millón'; $resultado = ''; @@ -1863,7 +1821,7 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = // Centenas if ($numero >= 100) { $resultado .= $centenas[intval($numero / 100)] . ' '; - $numero %= 100; + $numero %= 100; } // Decenas y unidades @@ -1886,19 +1844,18 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = // Configuración de monedas $monedas_config = [ - 'MXN' => ['nombre' => 'PESOS', 'sufijo' => 'M.N.', 'centavos' => 'CENTAVOS'], - 'USD' => ['nombre' => 'DÓLARES', 'sufijo' => 'USD', 'centavos' => 'CENTAVOS'], - 'EUR' => ['nombre' => 'EUROS', 'sufijo' => 'EUR', 'centavos' => 'CÉNTIMOS'], - 'CNY' => ['nombre' => 'YUANES', 'sufijo' => 'CNY', 'centavos' => 'JIAO'], - 'GBP' => ['nombre' => 'LIBRAS', 'sufijo' => 'GBP', 'centavos' => 'PENIQUES'], - 'JPY' => ['nombre' => 'YENES', 'sufijo' => 'JPY', 'centavos' => 'SEN'] - ]; - - $config_moneda = $monedas_config[$moneda_codigo] ?? $monedas_config['MXN']; + 'MXN' => ['nombre' => 'PESOS', 'sufijo' => 'M.N.', 'centavos' => 'CENTAVOS'], + 'USD' => ['nombre' => 'DÓLARES', 'sufijo' => 'USD', 'centavos' => 'CENTAVOS'], + 'EUR' => ['nombre' => 'EUROS', 'sufijo' => 'EUR', 'centavos' => 'CÉNTIMOS'], + 'CNY' => ['nombre' => 'YUANES', 'sufijo' => 'CNY', 'centavos' => 'JIAO'], + 'GBP' => ['nombre' => 'LIBRAS', 'sufijo' => 'GBP', 'centavos' => 'PENIQUES'], + 'JPY' => ['nombre' => 'YENES', 'sufijo' => 'JPY', 'centavos' => 'SEN'] + ]; + $config_moneda = $monedas_config[$moneda_codigo] ?? $monedas_config['MXN']; // Convertir total a texto - $partes = explode('.', number_format($total, 2, '.', '')); - $enteros = (int)$partes[0]; + $partes = explode('.', number_format($total, 2, '.', '')); + $enteros = (int)$partes[0]; $decimales = (int)$partes[1]; $total_texto = strtoupper(numeroATexto($enteros)) . ' ' . $config_moneda['nombre']; diff --git a/app/controllers/transportes.php b/app/controllers/transportes.php index ee5b867..dbdd89d 100644 --- a/app/controllers/transportes.php +++ b/app/controllers/transportes.php @@ -4,55 +4,62 @@ require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/env.php'; /** Listado de transportes (sólo activos) para el importador logueado **/ -function lista() { +function lista() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $usr = $_SESSION['usuario_id']; + $conn = getConnection(); // Sólo mostrar transportes de los transportistas que le pertenecen al usuario - $sql = " - SELECT t.*, (tr.clave_identificador + ' - ' + tr.nombre) AS transportista - FROM dbo.transportes t - JOIN dbo.transportistas tr - ON t.id_transportista = tr.id_transportista - WHERE tr.id_usuario = ? AND t.status = 1 - ORDER BY t.creado_en DESC - "; + $sql = "SELECT + t.*, (tr.clave_identificador + ' - ' + tr.nombre) AS transportista + FROM dbo.transportes t + JOIN dbo.transportistas tr + ON t.id_transportista = tr.id_transportista + WHERE tr.id_usuario = ? + AND t.status = 1 + ORDER BY t.creado_en DESC + "; $stmt = sqlsrv_query($conn, $sql, [$usr]); + $transportes = []; - while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { - $transportes[] = $r; - } + while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $transportes[] = $r; } include __DIR__ . '/../../views/transportes/lista.php'; } /** Formulario de alta de transporte **/ -function crear() { +function crear() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $usr = $_SESSION['usuario_id']; + $conn = getConnection(); // Traer transportistas propios para el select - $sql = " - SELECT t.id_transportista, t.clave_identificador, t.nombre, t.ciudad, t.domicilio, - c.nombre AS ciudad_nombre - FROM dbo.transportistas t - LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad - WHERE id_usuario = ? AND activo = 1 - ORDER BY nombre - "; + $sql = "SELECT + t.id_transportista, t.clave_identificador, t.nombre, t.ciudad, t.domicilio, + c.nombre AS ciudad_nombre + FROM dbo.transportistas t + LEFT JOIN dbo.ciudades c + ON t.ciudad = c.id_ciudad + WHERE id_usuario = ? + AND activo = 1 + ORDER BY nombre + "; $stmt = sqlsrv_query($conn, $sql, [$usr]); + $transportistas = []; - while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { - $transportistas[] = $r; - } + while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $transportistas[] = $r; } include __DIR__ . '/../../views/transportes/crear.php'; } @@ -64,9 +71,9 @@ function guardar() die("⚠️ No autorizado."); } - $vehiculo = trim($_POST['vehiculo'] ?? ''); + $vehiculo = trim($_POST['vehiculo'] ?? ''); $identFiscal = trim($_POST['identificador_fiscal'] ?? ''); - $idTrans = $_POST['id_transportista'] ?? null; + $idTrans = $_POST['id_transportista'] ?? null; if ($vehiculo === '' || $identFiscal === '' || !$idTrans) { die("❌ Todos los campos son obligatorios."); @@ -74,11 +81,10 @@ function guardar() // Validar que el transportista pertenece al usuario actual $conn = getConnection(); - $sqlCheck = " - SELECT 1 FROM dbo.transportistas - WHERE id_transportista = ? AND id_usuario = ? AND activo = 1 - "; + + $sqlCheck = "SELECT 1 FROM dbo.transportistas WHERE id_transportista = ? AND id_usuario = ? AND activo = 1"; $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$idTrans, $_SESSION['usuario_id']]); + if (!sqlsrv_fetch($stmtCheck)) { die("❌ Transportista no válido o no autorizado."); } @@ -87,7 +93,7 @@ function guardar() $fotoUrl = null; if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) { $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']; - $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); + $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); if (!in_array($ext, $allowedExtensions)) { die("❌ Formato de imagen no válido. Solo se permiten: " . implode(', ', $allowedExtensions)); @@ -114,13 +120,9 @@ function guardar() } // Insertar el nuevo transporte - $sql = " - INSERT INTO dbo.transportes - (vehiculo, identificador_fiscal, foto_url, status, id_transportista) - VALUES (?, ?, ?, 1, ?) - "; + $sql = "INSERT INTO dbo.transportes (vehiculo, identificador_fiscal, foto_url, status, id_transportista) VALUES (?, ?, ?, 1, ?)"; $params = [$vehiculo, $identFiscal, $fotoUrl, $idTrans]; - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { $errors = sqlsrv_errors(); @@ -139,56 +141,66 @@ function guardar() } /** Formulario de edición **/ -function editar() { - +function editar() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $id = $_GET['id'] ?? null; + if (!$id || !is_numeric($id)) { die("❌ ID inválido."); } + $conn = getConnection(); + // Validar pertenencia igual que en index() - $sql = " - SELECT t.*, tr.nombre AS transportista - FROM dbo.transportes t - JOIN dbo.transportistas tr - ON t.id_transportista = tr.id_transportista - WHERE t.id_transporte = ? - AND tr.id_usuario = ? - AND t.status = 1 - "; + $sql = "SELECT + t.*, tr.nombre AS transportista + FROM dbo.transportes t + JOIN dbo.transportistas tr + ON t.id_transportista = tr.id_transportista + WHERE t.id_transporte = ? + AND tr.id_usuario = ? + AND t.status = 1 + "; $stmt = sqlsrv_query($conn, $sql, [$id, $_SESSION['usuario_id']]); + $t = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if (!$t) die("❌ Transporte no encontrado o no autorizado."); // Mismo select de transportistas que en crear() - $sql2 = " - SELECT t.id_transportista, t.clave_identificador, t.nombre, t.ciudad, t.domicilio, - c.nombre AS ciudad_nombre - FROM dbo.transportistas t - LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad - WHERE id_usuario = ? AND activo = 1 - ORDER BY nombre - "; + $sql2 = "SELECT + t.id_transportista, t.clave_identificador, t.nombre, t.ciudad, t.domicilio, + c.nombre AS ciudad_nombre + FROM dbo.transportistas t + LEFT JOIN dbo.ciudades c + ON t.ciudad = c.id_ciudad + WHERE id_usuario = ? + AND activo = 1 + ORDER BY nombre + "; $stmt2 = sqlsrv_query($conn, $sql2, [$_SESSION['usuario_id']]); + $transportistas = []; - while ($r=sqlsrv_fetch_array($stmt2,SQLSRV_FETCH_ASSOC)) $transportistas[]=$r; + while ($r = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_ASSOC)) { $transportistas[] = $r; } include __DIR__ . '/../../views/transportes/editar.php'; } /** Procesa la actualización **/ -function actualizar() { +function actualizar() +{ if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } - $id = $_POST['id_transporte'] ?? null; - $vehiculo = trim($_POST['vehiculo'] ?? ''); + + $id = $_POST['id_transporte'] ?? null; + $vehiculo = trim($_POST['vehiculo'] ?? ''); $identFiscal = trim($_POST['identificador_fiscal'] ?? ''); - $idTrans = $_POST['id_transportista'] ?? null; + $idTrans = $_POST['id_transportista'] ?? null; if (!$id || !is_numeric($id) || $vehiculo === '' || $identFiscal === '' || !$idTrans) { die("❌ Faltan datos."); @@ -197,17 +209,15 @@ function actualizar() { $conn = getConnection(); // Antes del UPDATE, validar que el transporte pertenece al usuario - $sqlCheck = " - SELECT 1 FROM dbo.transportes t - JOIN dbo.transportistas tr ON t.id_transportista = tr.id_transportista - wHERE t.id_transporte = ? AND tr.id_usuario = ? - "; + $sqlCheck = "SELECT 1 FROM dbo.transportes t JOIN dbo.transportistas tr ON t.id_transportista = tr.id_transportista wHERE t.id_transporte = ? AND tr.id_usuario = ?"; $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id, $_SESSION['usuario_id']]); + if ($stmtCheck === false) { $errors = sqlsrv_errors(); error_log("Error SQL al validar transporte: " . print_r($errors, true)); die("❌ Error en la validación SQL."); } + if (!sqlsrv_fetch($stmtCheck)) { die("❌ No autorizado para modificar este transporte."); } @@ -216,7 +226,7 @@ function actualizar() { $fotoUrl = null; if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) { $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']; - $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); + $ext = strtolower(pathinfo($_FILES['foto']['name'], PATHINFO_EXTENSION)); if (!in_array($ext, $allowedExtensions)) { die("❌ Formato de imagen no válido."); @@ -237,27 +247,25 @@ function actualizar() { // —– Construye el UPDATE dinámico —– if ($fotoUrl) { - $sql = " - UPDATE dbo.transportes SET - vehiculo = ?, - identificador_fiscal = ?, - id_transportista = ?, - foto_url = ? - WHERE id_transporte = ? - "; + $sql = "UPDATE dbo.transportes SET + vehiculo = ?, + identificador_fiscal = ?, + id_transportista = ?, + foto_url = ? + WHERE id_transporte = ? + "; $params = [$vehiculo, $identFiscal, $idTrans, $fotoUrl, $id]; } else { - $sql = " - UPDATE dbo.transportes SET - vehiculo = ?, - identificador_fiscal = ?, - id_transportista = ? - WHERE id_transporte = ? - "; + $sql = "UPDATE dbo.transportes SET + vehiculo = ?, + identificador_fiscal = ?, + id_transportista = ? + WHERE id_transporte = ? + "; $params = [$vehiculo, $identFiscal, $idTrans, $id]; } - $stmt = sqlsrv_query($conn, $sql, $params); + if ($stmt === false) { $errors = sqlsrv_errors(); error_log("Error SQL en actualizar transporte: " . print_r($errors, true)); @@ -275,28 +283,35 @@ function actualizar() { } /** “Soft-delete” (status = 0) **/ -function eliminar() { - +function eliminar() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $id = $_GET['id'] ?? null; + if (!$id||!is_numeric($id)) { die("❌ ID inválido."); } + $conn = getConnection(); - $sql = "UPDATE dbo.transportes SET status = 0 WHERE id_transporte = ?"; + + $sql = "UPDATE dbo.transportes SET status = 0 WHERE id_transporte = ?"; $stmt = sqlsrv_query($conn, $sql, [$id]); + if ($stmt === false) { die("❌ Error al eliminar: ".print_r(sqlsrv_errors(),true)); } + header('Location: /IMPORTADORES/transportes/lista?deleted=ok'); exit; } /** Formulario de importación masiva **/ -function masivo() { +function masivo() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; @@ -306,7 +321,8 @@ function masivo() { } /** Procesa la importación masiva desde CSV **/ -function importarGuardar() { +function importarGuardar() +{ if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } @@ -320,12 +336,13 @@ function importarGuardar() { header('Location: /IMPORTADORES/transportes/importar'); exit; } + + $conn = getConnection(); - $tmp = $_FILES['csv']['tmp_name']; - $handle = fopen($tmp, 'r'); - $headers = fgetcsv($handle, 1000, ','); - $conn = getConnection(); - $usr = $_SESSION['usuario_id']; + $tmp = $_FILES['csv']['tmp_name']; + $handle = fopen($tmp, 'r'); + $headers = fgetcsv($handle, 1000, ','); + $usr = $_SESSION['usuario_id']; $imported = 0; $errors = []; $row = 1; @@ -345,21 +362,19 @@ function importarGuardar() { } // Verificar que el transportista pertenezca al usuario - $sqlCheck = "SELECT COUNT(*) AS cnt - FROM dbo.transportistas - WHERE id_transportista = ? AND id_usuario = ?"; + $sqlCheck = "SELECT COUNT(*) AS cnt FROM dbo.transportistas WHERE id_transportista = ? AND id_usuario = ?"; $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$idTrans, $usr]); $rCheck = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + if ($rCheck['cnt'] == 0) { $errors[] = "Fila $row: transportista $idTrans no válido."; continue; } // Insertar sin foto - $sql = "INSERT INTO dbo.transportes - (vehiculo, identificador_fiscal, foto_url, status, id_transportista) - VALUES (?, ?, NULL, 1, ?)"; + $sql = "INSERT INTO dbo.transportes (vehiculo, identificador_fiscal, foto_url, status, id_transportista) VALUES (?, ?, NULL, 1, ?)"; $stmt = sqlsrv_query($conn, $sql, [$vehiculo, $identFiscal, $idTrans]); + if ($stmt === false) { $errors[] = "Fila $row: error al insertar."; continue; diff --git a/app/controllers/transportistas.php b/app/controllers/transportistas.php index 9ef011e..19a1429 100644 --- a/app/controllers/transportistas.php +++ b/app/controllers/transportistas.php @@ -2,9 +2,11 @@ require_once __DIR__ . '/../helpers/session.php'; require_once __DIR__ . '/../../config/database.php'; require_once __DIR__ . '/../helpers/env.php'; + ob_clean(); -function guardar() { +function guardar() +{ if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } @@ -12,30 +14,27 @@ function guardar() { $conn = getConnection(); // Capturar campos del formulario - $clave = $_POST['clave']; - $nombre = $_POST['nombre']; - $rfc = $_POST['rfc']; - $curp = $_POST['curp'] ?? null; - $dom = $_POST['domicilio']; - $pais = $_POST['pais']; - $entidad = $_POST['entidad']; - $ciudad = $_POST['ciudad']; - $tel = $_POST['telefono']; - $caat = $_POST['caat']; - $usr_id = $_SESSION['usuario_id']; + $clave = $_POST['clave']; + $nombre = $_POST['nombre']; + $rfc = $_POST['rfc']; + $curp = $_POST['curp'] ?? null; + $dom = $_POST['domicilio']; + $pais = $_POST['pais']; + $entidad = $_POST['entidad']; + $ciudad = $_POST['ciudad']; + $tel = $_POST['telefono']; + $caat = $_POST['caat']; + $usr_id = $_SESSION['usuario_id']; // INSERT incluyendo id_usuario - $sql = "INSERT INTO dbo.transportistas - (clave_identificador, nombre, rfc, curp, domicilio, pais, - entidad_federativa, ciudad, telefono, caat, id_usuario) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - $params = [ - $clave, $nombre, $rfc, $curp, $dom, - $pais, $entidad, $ciudad, $tel, $caat, - $usr_id - ]; + $sql = "INSERT INTO dbo.transportistas + (clave_identificador, nombre, rfc, curp, domicilio, pais, + entidad_federativa, ciudad, telefono, caat, id_usuario) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "; + $params = [$clave, $nombre, $rfc, $curp, $dom, $pais, $entidad, $ciudad, $tel, $caat, $usr_id]; + $stmt = sqlsrv_query($conn, $sql, $params); - $stmt = sqlsrv_query($conn, $sql, $params); if ($stmt === false) { die("❌ Error al guardar transportista: " . print_r(sqlsrv_errors(), true)); } @@ -45,11 +44,14 @@ function guardar() { exit; } -function alta() { +function alta() +{ $conn = getConnection(); + // 1) Cargar países - $sql = "SELECT id_pais, nombre FROM paises ORDER BY nombre"; + $sql = "SELECT id_pais, nombre FROM paises ORDER BY nombre"; $stmt = sqlsrv_query($conn, $sql); + $paises = []; while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $paises[] = $row; @@ -59,48 +61,69 @@ function alta() { } // AJAX: devuelve los estados de un país dado -function estados() { +function estados() +{ header('Content-Type: application/json; charset=utf-8'); + $pais = $_GET['pais'] ?? ''; + $conn = getConnection(); - $sql = "SELECT id_estado, nombre FROM estados WHERE pais_id = ? ORDER BY nombre"; + + $sql = "SELECT id_estado, nombre FROM estados WHERE pais_id = ? ORDER BY nombre"; $stmt = sqlsrv_query($conn, $sql, [$pais]); + $out = []; while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $out[] = $r; } + echo json_encode($out); exit; } // AJAX: devuelve las ciudades de un estado dado -function ciudades() { +function ciudades() +{ header('Content-Type: application/json; charset=utf-8'); + $estado = $_GET['estado'] ?? ''; + $conn = getConnection(); - $sql = "SELECT id_ciudad, nombre FROM ciudades WHERE estado_id = ? ORDER BY nombre"; + + $sql = "SELECT id_ciudad, nombre FROM ciudades WHERE estado_id = ? ORDER BY nombre"; $stmt = sqlsrv_query($conn, $sql, [$estado]); + $out = []; while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $out[] = $r; } + echo json_encode($out); exit; } function lista() { + // 1) Verificar sesión + if (!($_SESSION['usuario_id'] ?? false)) { + header('Location: /IMPORTADORES/login'); + exit; + } + include __DIR__ . '/../../views/transportistas/lista.php'; } /** Descarga la plantilla CSV para carga masiva **/ -function template() { +function template() +{ $file = __DIR__ . '/../../public/downloads/transportistas_template.csv'; + if (!file_exists($file)) { http_response_code(404); echo "❌ Plantilla no encontrada."; exit; } + header('Content-Type: text/csv; charset=UTF-8'); header('Content-Disposition: attachment; filename="transportistas_template.csv"'); readfile($file); @@ -108,18 +131,22 @@ function template() { } /** Procesa la carga masiva desde un CSV **/ -function importar() { +function importar() +{ // 1) Verificar sesión if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } + $usr_id = $_SESSION['usuario_id']; // 2) Validar archivo subido if (!isset($_FILES['archivo_csv']) || $_FILES['archivo_csv']['error'] !== UPLOAD_ERR_OK) { die("❌ Debes subir un archivo CSV válido."); } + $ext = pathinfo($_FILES['archivo_csv']['name'], PATHINFO_EXTENSION); + if (strtolower($ext) !== 'csv') { die("❌ Solo se permiten archivos .csv"); } @@ -132,17 +159,15 @@ function importar() { // 4) Encabezados esperados $header = fgetcsv($fh, 1000, ','); - $expected = [ - 'clave_identificador','nombre','rfc','curp', - 'telefono','caat','pais_id','estado_id', - 'ciudad_id','domicilio' - ]; + $expected = ['clave_identificador', 'nombre', 'rfc', 'curp', 'telefono', 'caat', 'pais_id', 'estado_id', 'ciudad_id', 'domicilio']; + if ($header === false || array_map('trim', $header) !== $expected) { fclose($fh); die("❌ Encabezado de CSV inválido. Debe contener: " . implode(',', $expected)); } $conn = getConnection(); + $errors = []; $rowNum = 1; @@ -154,7 +179,7 @@ function importar() { continue; } // mapear valores y trim - list($clave,$nombre,$rfc,$curp,$tel,$caat,$pais_id,$estado_id,$ciudad_id,$dom) = array_map('trim', $row); + list($clave, $nombre, $rfc, $curp, $tel, $caat, $pais_id, $estado_id, $ciudad_id, $dom) = array_map('trim', $row); // validar obligatorios if ($clave==='' || $nombre==='' || $rfc==='' || $tel==='' || $caat==='' @@ -164,13 +189,14 @@ function importar() { } // Convertir IDs a nombres - $pais_nombre = ''; + $pais_nombre = ''; $estado_nombre = ''; $ciudad_nombre = ''; // Consultar nombre del país - $sql = "SELECT nombre FROM dbo.paises WHERE id_pais = ?"; + $sql = "SELECT nombre FROM dbo.paises WHERE id_pais = ?"; $stmt = sqlsrv_query($conn, $sql, [$pais_id]); + if ($row_pais = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $pais_nombre = $row_pais['nombre']; } else { @@ -179,8 +205,9 @@ function importar() { } // Consultar nombre del estado - $sql = "SELECT nombre FROM dbo.estados WHERE id_estado = ?"; + $sql = "SELECT nombre FROM dbo.estados WHERE id_estado = ?"; $stmt = sqlsrv_query($conn, $sql, [$estado_id]); + if ($row_estado = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $estado_nombre = $row_estado['nombre']; } else { @@ -189,8 +216,9 @@ function importar() { } // Consultar nombre de la ciudad - $sql = "SELECT nombre FROM dbo.ciudades WHERE id_ciudad = ?"; + $sql = "SELECT nombre FROM dbo.ciudades WHERE id_ciudad = ?"; $stmt = sqlsrv_query($conn, $sql, [$ciudad_id]); + if ($row_ciudad = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { $ciudad_nombre = $row_ciudad['nombre']; } else { @@ -199,16 +227,14 @@ function importar() { } // 5) Insertar en BD con nombres - $sql = "INSERT INTO dbo.transportistas - (clave_identificador, nombre, rfc, curp, telefono, caat, - pais, entidad_federativa, ciudad, domicilio, id_usuario) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - $params = [ - $clave, $nombre, $rfc, $curp, $tel, - $caat, $pais_nombre, $estado_nombre, $ciudad_nombre, $dom, - $usr_id - ]; - $stmt = sqlsrv_query($conn, $sql, $params); + $sql = "INSERT INTO dbo.transportistas + (clave_identificador, nombre, rfc, curp, telefono, caat, + pais, entidad_federativa, ciudad, domicilio, id_usuario) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "; + $params = [$clave, $nombre, $rfc, $curp, $tel, $caat, $pais_nombre, $estado_nombre, $ciudad_nombre, $dom, $usr_id]; + $stmt = sqlsrv_query($conn, $sql, $params); + if ($stmt === false) { $errors[] = "Fila $rowNum: error al guardar → " . print_r(sqlsrv_errors(), true); } @@ -226,89 +252,87 @@ function importar() { exit; } -function bulk_upload() { - +function bulk_upload() +{ include __DIR__ . '/../../views/transportistas/bulk_upload.php'; } -function ajax_lista() { +function ajax_lista() +{ // 1) Autorización if (!($_SESSION['usuario_id'] ?? false)) { http_response_code(403); echo json_encode([]); exit; } + $usr = $_SESSION['usuario_id']; $conn = getConnection(); // 2) Parámetros de DataTables - $draw = intval($_GET['draw'] ?? 0); - $start = intval($_GET['start'] ?? 0); - $length = intval($_GET['length'] ?? 10); + $draw = intval($_GET['draw'] ?? 0); + $start = intval($_GET['start'] ?? 0); + $length = intval($_GET['length'] ?? 10); $search = $_GET['search']['value'] ?? ''; // Mapeo columnas - ahora incluimos el nombre de la ciudad - $cols = ['t.id_transportista','t.clave_identificador','t.nombre','t.rfc','c.nombre','t.creado_en']; - $orderColIdx = intval($_GET['order'][0]['column'] ?? 5); + $cols = ['t.id_transportista', 't.clave_identificador', 't.nombre', 't.rfc', 'c.nombre', 't.creado_en']; + $orderColIdx = intval($_GET['order'][0]['column'] ?? 5); $orderDir = strtoupper($_GET['order'][0]['dir'] ?? 'ASC') === 'DESC' ? 'DESC' : 'ASC'; - $orderCol = in_array($orderColIdx, range(0,5)) ? $cols[$orderColIdx] : 't.creado_en'; + $orderCol = in_array($orderColIdx, range(0,5)) ? $cols[$orderColIdx] : 't.creado_en'; // 3) Total registros sin filtro - $sqlTotal = "SELECT COUNT(*) AS total FROM dbo.transportistas WHERE id_usuario = ? AND activo = 1"; - $stmt = sqlsrv_query($conn, $sqlTotal, [$usr]); - $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + $sqlTotal = "SELECT COUNT(*) AS total FROM dbo.transportistas WHERE id_usuario = ? AND activo = 1"; + $stmt = sqlsrv_query($conn, $sqlTotal, [$usr]); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); $recordsTotal = (int)$row['total']; // 4) Construir condiciones de filtro - $where = "t.id_usuario = ? AND t.activo = 1 "; + $where = "t.id_usuario = ? AND t.activo = 1 "; $params = [$usr]; if ($search !== '') { - $where .= " AND ( - t.nombre LIKE ? OR - t.rfc LIKE ? OR - c.nombre LIKE ? - )"; - $like = "%{$search}%"; + $where .= " AND (t.nombre LIKE ? OR t.rfc LIKE ? OR c.nombre LIKE ?)"; + $like = "%{$search}%"; $params = array_merge($params, array_fill(0, 3, $like)); } // 5) Total registros filtrados (CON JOIN) - $sqlFiltered = " - SELECT COUNT(*) AS total - FROM dbo.transportistas t - LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad - LEFT JOIN dbo.estados e ON c.estado_id = e.id_estado - LEFT JOIN dbo.paises p ON e.pais_id = p.id_pais - WHERE $where - "; - $stmtF = sqlsrv_query($conn, $sqlFiltered, $params); - $rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC); + $sqlFiltered = "SELECT COUNT(*) AS total + FROM dbo.transportistas t + LEFT JOIN dbo.ciudades c + ON t.ciudad = c.id_ciudad + LEFT JOIN dbo.estados e + ON c.estado_id = e.id_estado + LEFT JOIN dbo.paises p + ON e.pais_id = p.id_pais + WHERE $where + "; + $stmtF = sqlsrv_query($conn, $sqlFiltered, $params); + $rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC); $recordsFiltered = (int)$rowF['total']; // 6) Datos de la página con JOIN completo - $sqlData = " - SELECT t.id_transportista, - t.clave_identificador, - t.nombre, - t.rfc, - COALESCE(c.nombre, 'Ciudad no encontrada') as ciudad_nombre, - COALESCE(e.nombre, '') as estado_nombre, - COALESCE(p.nombre, '') as pais_nombre, - t.creado_en - FROM dbo.transportistas t - LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad - LEFT JOIN dbo.estados e ON c.estado_id = e.id_estado - LEFT JOIN dbo.paises p ON e.pais_id = p.id_pais - WHERE $where - ORDER BY $orderCol $orderDir - OFFSET ? ROWS FETCH NEXT ? ROWS ONLY - "; - // agregar offset/limit al final + $sqlData = "SELECT + t.id_transportista, t.clave_identificador, t.nombre, t.rfc, t.creado_en, + COALESCE(c.nombre, 'Ciudad no encontrada') as ciudad_nombre, + COALESCE(e.nombre, '') as estado_nombre, + COALESCE(p.nombre, '') as pais_nombre + FROM dbo.transportistas t + LEFT JOIN dbo.ciudades c + ON t.ciudad = c.id_ciudad + LEFT JOIN dbo.estados e + ON c.estado_id = e.id_estado + LEFT JOIN dbo.paises p + ON e.pais_id = p.id_pais + WHERE $where + ORDER BY $orderCol $orderDir + OFFSET ? ROWS FETCH NEXT ? ROWS ONLY + "; // Agregar offset/limit al final $params[] = $start; $params[] = $length; - $stmtD = sqlsrv_query($conn, $sqlData, $params); + $stmtD = sqlsrv_query($conn, $sqlData, $params); $data = []; while ($r = sqlsrv_fetch_array($stmtD, SQLSRV_FETCH_ASSOC)) { @@ -345,16 +369,19 @@ function ajax_lista() { exit; } -function editar() { +function editar() +{ // 1) Verificar sesión if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $usr = $_SESSION['usuario_id']; // 2) Obtener el ID y validarlo $id = $_GET['id'] ?? null; + if (!$id || !is_numeric($id)) { die("❌ ID de transportista inválido."); } @@ -362,9 +389,9 @@ function editar() { $conn = getConnection(); // 3) Consultar el transportista (pertenece al usuario) - $sql = "SELECT * FROM dbo.transportistas - WHERE id_transportista = ? AND id_usuario = ?"; + $sql = "SELECT * FROM dbo.transportistas WHERE id_transportista = ? AND id_usuario = ?"; $stmt = sqlsrv_query($conn, $sql, [$id, $usr]); + $t = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if (!$t) { die("❌ Transportista no encontrado o no autorizado."); @@ -402,20 +429,21 @@ function actualizar() if (!($_SESSION['usuario_id'] ?? false)) { die("⚠️ No autorizado."); } + $usr = $_SESSION['usuario_id']; // 1) Capturar y validar datos - $id = $_POST['id_transportista'] ?? null; - $clave = trim($_POST['clave'] ?? ''); - $nombre= trim($_POST['nombre'] ?? ''); - $rfc = trim($_POST['rfc'] ?? ''); - $curp = trim($_POST['curp'] ?? ''); - $tel = trim($_POST['telefono'] ?? ''); - $caat = trim($_POST['caat'] ?? ''); - $pais = $_POST['pais'] ?? ''; - $estado= $_POST['entidad'] ?? ''; - $ciudad= $_POST['ciudad'] ?? ''; - $dom = trim($_POST['domicilio'] ?? ''); + $id = $_POST['id_transportista'] ?? null; + $clave = trim($_POST['clave'] ?? ''); + $nombre = trim($_POST['nombre'] ?? ''); + $rfc = trim($_POST['rfc'] ?? ''); + $curp = trim($_POST['curp'] ?? ''); + $tel = trim($_POST['telefono'] ?? ''); + $caat = trim($_POST['caat'] ?? ''); + $pais = $_POST['pais'] ?? ''; + $estado = $_POST['entidad'] ?? ''; + $ciudad = $_POST['ciudad'] ?? ''; + $dom = trim($_POST['domicilio'] ?? ''); if (!$id || !is_numeric($id) || $clave===''||$nombre===''||$rfc===''||$tel===''||$caat==='' @@ -427,33 +455,29 @@ function actualizar() $conn = getConnection(); // 2) Verificar que exista y pertenezca al usuario - $sqlChk = "SELECT COUNT(*) AS cnt - FROM dbo.transportistas - WHERE id_transportista = ? AND id_usuario = ?"; + $sqlChk = "SELECT COUNT(*) AS cnt FROM dbo.transportistas WHERE id_transportista = ? AND id_usuario = ?"; $stmtChk = sqlsrv_query($conn, $sqlChk, [$id, $usr]); - $rowChk = sqlsrv_fetch_array($stmtChk, SQLSRV_FETCH_ASSOC); + $rowChk = sqlsrv_fetch_array($stmtChk, SQLSRV_FETCH_ASSOC); + if ($rowChk['cnt'] == 0) { die("❌ Transportista no encontrado o no autorizado."); } // 3) Ejecutar UPDATE - $sqlUpd = "UPDATE dbo.transportistas SET - clave_identificador = ?, - nombre = ?, - rfc = ?, - curp = ?, - telefono = ?, - caat = ?, - pais = ?, - entidad_federativa = ?, - ciudad = ?, - domicilio = ? - WHERE id_transportista = ?"; - $params = [ - $clave, $nombre, $rfc, $curp, $tel, - $caat, $pais, $estado, $ciudad, $dom, - $id - ]; + $sqlUpd = "UPDATE dbo.transportistas SET + clave_identificador = ?, + nombre = ?, + rfc = ?, + curp = ?, + telefono = ?, + caat = ?, + pais = ?, + entidad_federativa = ?, + ciudad = ?, + domicilio = ? + WHERE id_transportista = ? + "; + $params = [$clave, $nombre, $rfc, $curp, $tel, $caat, $pais, $estado, $ciudad, $dom, $id]; $stmtUpd = sqlsrv_query($conn, $sqlUpd, $params); if ($stmtUpd === false) { die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true)); @@ -464,13 +488,16 @@ function actualizar() exit; } -function eliminar() { +function eliminar() +{ if (!($_SESSION['usuario_id'] ?? false)) { header('Location: /IMPORTADORES/login'); exit; } + $usr = $_SESSION['usuario_id']; $id = $_GET['id'] ?? null; + if (!$id || !is_numeric($id)) { die("❌ ID inválido."); } @@ -478,18 +505,18 @@ function eliminar() { $conn = getConnection(); // Verificar que el transportista exista y pertenezca al usuario - $sqlChk = "SELECT COUNT(*) AS cnt - FROM dbo.transportistas - WHERE id_transportista = ? AND id_usuario = ?"; + $sqlChk = "SELECT COUNT(*) AS cnt FROM dbo.transportistas WHERE id_transportista = ? AND id_usuario = ?"; $stmtChk = sqlsrv_query($conn, $sqlChk, [$id, $usr]); $rowChk = sqlsrv_fetch_array($stmtChk, SQLSRV_FETCH_ASSOC); + if ($rowChk['cnt'] == 0) { die("❌ Transportista no encontrado o no autorizado."); } // ELIMINACIÓN REAL - DELETE en lugar de UPDATE - $sqlDel = "UPDATE dbo.transportistas SET activo = 0 WHERE id_transportista = ?"; + $sqlDel = "UPDATE dbo.transportistas SET activo = 0 WHERE id_transportista = ?"; $stmtDel = sqlsrv_query($conn, $sqlDel, [$id]); + if ($stmtDel === false) { die("❌ Error al eliminar: " . print_r(sqlsrv_errors(), true)); } diff --git a/app/controllers/vinculaciones.php b/app/controllers/vinculaciones.php index de1c608..1c49d13 100644 --- a/app/controllers/vinculaciones.php +++ b/app/controllers/vinculaciones.php @@ -18,15 +18,13 @@ function vinculacionesUsuario() } // Consulta de todas las relaciones del importador - $sql = " - SELECT * - FROM importador_agencia ia - INNER JOIN agencias_aduanales aa - ON ia.id_agencia = aa.id_agencia - WHERE ia.id_importador = ? - AND ia.activo = 1 - ORDER BY ia.fecha_vinculacion DESC - "; + $sql = "SELECT * FROM importador_agencia ia + INNER JOIN agencias_aduanales aa + ON ia.id_agencia = aa.id_agencia + WHERE ia.id_importador = ? + AND ia.activo = 1 + ORDER BY ia.fecha_vinculacion DESC + "; $stmt = sqlsrv_query($conn, $sql, [$_SESSION['usuario_id']]); $vinculaciones = []; @@ -48,23 +46,22 @@ function nuevaVinculacion() $conn = getConnection(); - $sql = " - SELECT - a.*, - s.estado AS estado_solicitud - FROM agencias_aduanales a - LEFT JOIN solicitudes_vinculacion s - ON s.id_agencia = a.id_agencia AND s.id_importador = ? - AND s.estado = 'PENDIENTE' - WHERE NOT EXISTS ( - SELECT 1 - FROM importador_agencia ia - WHERE ia.id_agencia = a.id_agencia - AND ia.id_importador = ? - AND ia.activo = 1 - ) - ORDER BY a.creado_en DESC - "; + $sql = "SELECT + a.*, s.estado AS estado_solicitud + FROM agencias_aduanales a + LEFT JOIN solicitudes_vinculacion s + ON s.id_agencia = a.id_agencia + AND s.id_importador = ? + AND s.estado = 'PENDIENTE' + WHERE NOT EXISTS ( + SELECT 1 + FROM importador_agencia ia + WHERE ia.id_agencia = a.id_agencia + AND ia.id_importador = ? + AND ia.activo = 1 + ) + ORDER BY a.creado_en DESC + "; $params = [$_SESSION['usuario_id'], $_SESSION['usuario_id']]; $stmt = sqlsrv_query($conn, $sql, $params); @@ -120,20 +117,19 @@ function vinculacionesAgencia() $rowCountActive = sqlsrv_fetch_array($stmtCountActive, SQLSRV_FETCH_ASSOC); // Consulta de importadores vinculados ACTIVOS a MI agencia - $sql = " - SELECT - ia.*, - u.nombre as importador_nombre, - u.tipo_usuario as tipo_usuario_sistema, - ig.rfc, - ig.telefono, - 'importador' as tipo_vinculacion - FROM importador_agencia ia - INNER JOIN usuarios_sistema u ON ia.id_importador = u.id_usuario - LEFT JOIN informacion_general ig ON u.id_usuario = ig.id_usuario - WHERE ia.id_agencia = ? AND ia.activo = 1 AND ia.estado = 'APROBADO' - ORDER BY ia.fecha_vinculacion DESC - "; + $sql = "SELECT + ia.*, u.nombre as importador_nombre, u.tipo_usuario as tipo_usuario_sistema, + ig.rfc, ig.telefono, 'importador' as tipo_vinculacion + FROM importador_agencia ia + INNER JOIN usuarios_sistema u + ON ia.id_importador = u.id_usuario + LEFT JOIN informacion_general ig + ON u.id_usuario = ig.id_usuario + WHERE ia.id_agencia = ? + AND ia.activo = 1 + AND ia.estado = 'APROBADO' + ORDER BY ia.fecha_vinculacion DESC + "; $stmt = sqlsrv_query($conn, $sql, [$id_agencia]); // DEBUG: Verificar query principal @@ -160,21 +156,19 @@ function vinculacionesAgencia() $rowCountActive2 = sqlsrv_fetch_array($stmtCountActive2, SQLSRV_FETCH_ASSOC); // Consulta de agentes vinculados ACTIVOS a MI agencia - $sql2 = " - SELECT - aa.*, - aa.fecha_asignacion as fecha_vinculacion, - u.nombre as importador_nombre, - u.tipo_usuario as tipo_usuario_sistema, - ig.rfc, - ig.telefono, - 'agente' as tipo_vinculacion - FROM agente_agencia aa - INNER JOIN usuarios_sistema u ON aa.id_agente = u.id_usuario - LEFT JOIN informacion_general ig ON u.id_usuario = ig.id_usuario - WHERE aa.id_agencia = ? AND aa.activo = 1 - ORDER BY aa.fecha_asignacion DESC - "; + $sql2 = "SELECT + aa.*, aa.fecha_asignacion as fecha_vinculacion, + u.nombre as importador_nombre, u.tipo_usuario as tipo_usuario_sistema, + ig.rfc, ig.telefono, 'agente' as tipo_vinculacion + FROM agente_agencia aa + INNER JOIN usuarios_sistema u + ON aa.id_agente = u.id_usuario + LEFT JOIN informacion_general ig + ON u.id_usuario = ig.id_usuario + WHERE aa.id_agencia = ? + AND aa.activo = 1 + ORDER BY aa.fecha_asignacion DESC + "; $stmt2 = sqlsrv_query($conn, $sql2, [$id_agencia]); // DEBUG: Verificar query de agentes @@ -206,8 +200,8 @@ function desvincularAgencia() } // Verificar que se recibió el ID de la relación - $id_relacion = $_GET['id'] ?? null; - $tipo = $_GET['tipo'] ?? null; + $id_relacion = $_GET['id'] ?? null; + $tipo = $_GET['tipo'] ?? null; if (!$id_relacion || !is_numeric($id_relacion)) { header('Location: /IMPORTADORES/vinculaciones/vinculacionesAgencia?error=invalid_id'); @@ -229,17 +223,17 @@ function desvincularAgencia() if ($tipo === 'importador') { // Verificar relación de importador - $sqlVerificar = " - SELECT - ia.*, - aa.id_administrador, - u.nombre as usuario_nombre, - u.tipo_usuario - FROM importador_agencia ia - INNER JOIN agencias_aduanales aa ON ia.id_agencia = aa.id_agencia - INNER JOIN usuarios_sistema u ON ia.id_importador = u.id_usuario - WHERE ia.id_relacion = ? AND aa.id_administrador = ? AND u.tipo_usuario = 'importador' - "; + $sqlVerificar = "SELECT + ia.*, aa.id_administrador, u.nombre as usuario_nombre, u.tipo_usuario + FROM importador_agencia ia + INNER JOIN agencias_aduanales aa + ON ia.id_agencia = aa.id_agencia + INNER JOIN usuarios_sistema u + ON ia.id_importador = u.id_usuario + WHERE ia.id_relacion = ? + AND aa.id_administrador = ? + AND u.tipo_usuario = 'importador' + "; $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$id_relacion, $_SESSION['usuario_id']]); $relacion = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC); @@ -252,27 +246,21 @@ function desvincularAgencia() } // Desactivar la relación de importador - $sqlDesactivar = " - UPDATE importador_agencia - SET activo = 0, - fecha_desvinculacion = GETDATE(), - estado = 'DESVINCULADO' - WHERE id_relacion = ? - "; - + $sqlDesactivar = "UPDATE importador_agencia SET activo = 0, fecha_desvinculacion = GETDATE(), estado = 'DESVINCULADO' WHERE id_relacion = ?"; + } else if ($tipo === 'agente') { // Verificar relación de agente aduanal - $sqlVerificar = " - SELECT - aa.*, - ag.id_administrador, - u.nombre as usuario_nombre, - u.tipo_usuario - FROM agente_agencia aa - INNER JOIN agencias_aduanales ag ON aa.id_agencia = ag.id_agencia - INNER JOIN usuarios_sistema u ON aa.id_agente = u.id_usuario - WHERE aa.id_relacion = ? AND ag.id_administrador = ? AND u.tipo_usuario = 'agente_aduanal' - "; + $sqlVerificar = "SELECT + aa.*, ag.id_administrador, u.nombre as usuario_nombre, u.tipo_usuario + FROM agente_agencia aa + INNER JOIN agencias_aduanales ag + ON aa.id_agencia = ag.id_agencia + INNER JOIN usuarios_sistema u + ON aa.id_agente = u.id_usuario + WHERE aa.id_relacion = ? + AND ag.id_administrador = ? + AND u.tipo_usuario = 'agente_aduanal' + "; $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$id_relacion, $_SESSION['usuario_id']]); $relacion = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC); @@ -285,11 +273,7 @@ function desvincularAgencia() } // Desactivar la relación de agente - $sqlDesactivar = " - UPDATE agente_agencia - SET activo = 0 - WHERE id_relacion = ? - "; + $sqlDesactivar = "UPDATE agente_agencia SET activo = 0 WHERE id_relacion = ?"; } $stmtDesactivar = sqlsrv_query($conn, $sqlDesactivar, [$id_relacion]); @@ -301,22 +285,13 @@ function desvincularAgencia() // NUEVO: Verificar si el usuario desvinculado tenía esta agencia como activa if ($tipo === 'importador') { // Verificar si el importador tenía esta agencia como activa - $sqlVerificarAgenciaActiva = " - SELECT id_agencia_en_uso - FROM usuarios_sistema - WHERE id_usuario = ? AND id_agencia_en_uso = ? - "; - $stmtVerificarActiva = sqlsrv_query($conn, $sqlVerificarAgenciaActiva, - [$relacion['id_importador'], $relacion['id_agencia']]); + $sqlVerificarAgenciaActiva = "SELECT id_agencia_en_uso FROM usuarios_sistema WHERE id_usuario = ? AND id_agencia_en_uso = ?"; + $stmtVerificarActiva = sqlsrv_query($conn, $sqlVerificarAgenciaActiva, [$relacion['id_importador'], $relacion['id_agencia']]); if ($stmtVerificarActiva && sqlsrv_fetch_array($stmtVerificarActiva, SQLSRV_FETCH_ASSOC)) { // Si tenía esta agencia como activa, quitársela - $sqlQuitarAgenciaActiva = " - UPDATE usuarios_sistema - SET id_agencia_en_uso = NULL - WHERE id_usuario = ? - "; - $stmtQuitarActiva = sqlsrv_query($conn, $sqlQuitarAgenciaActiva, [$relacion['id_importador']]); + $sqlQuitarAgenciaActiva = "UPDATE usuarios_sistema SET id_agencia_en_uso = NULL WHERE id_usuario = ?"; + $stmtQuitarActiva = sqlsrv_query($conn, $sqlQuitarAgenciaActiva, [$relacion['id_importador']]); if (!$stmtQuitarActiva) { throw new Exception('Error al actualizar la agencia activa del importador'); @@ -362,33 +337,32 @@ function solicitudesVinculacion() $id_agencia = $rowAgencia['id_agencia']; // Verificar solicitudes básicas - $debugSql = "SELECT COUNT(*) as total FROM solicitudes_vinculacion WHERE id_agencia = ?"; + $debugSql = "SELECT COUNT(*) as total FROM solicitudes_vinculacion WHERE id_agencia = ?"; $debugStmt = sqlsrv_query($conn, $debugSql, [$id_agencia]); - $debugRow = sqlsrv_fetch_array($debugStmt, SQLSRV_FETCH_ASSOC); + $debugRow = sqlsrv_fetch_array($debugStmt, SQLSRV_FETCH_ASSOC); // Verificar pendientes - $debugSql2 = "SELECT COUNT(*) as total FROM solicitudes_vinculacion WHERE estado = 'PENDIENTE' AND id_agencia = ?"; + $debugSql2 = "SELECT COUNT(*) as total FROM solicitudes_vinculacion WHERE estado = 'PENDIENTE' AND id_agencia = ?"; $debugStmt2 = sqlsrv_query($conn, $debugSql2, [$id_agencia]); - $debugRow2 = sqlsrv_fetch_array($debugStmt2, SQLSRV_FETCH_ASSOC); + $debugRow2 = sqlsrv_fetch_array($debugStmt2, SQLSRV_FETCH_ASSOC); // Consulta principal - $sql = " - SELECT - sv.id_solicitud, - u.nombre AS importador_nombre, - ig.rfc, - sv.mensaje, - sv.fecha_solicitud, - si.opinion_file - FROM solicitudes_vinculacion sv - INNER JOIN usuarios_sistema u ON sv.id_importador = u.id_usuario - LEFT JOIN informacion_general ig ON u.id_usuario = ig.id_usuario - LEFT JOIN solicitudes_importadores si ON LTRIM(RTRIM(LOWER(si.company_name))) = LTRIM(RTRIM(LOWER(u.nombre))) - WHERE sv.estado = 'PENDIENTE' AND sv.id_agencia = ? - ORDER BY sv.fecha_solicitud DESC - "; + $sql = "SELECT + sv.id_solicitud, u.nombre AS importador_nombre, ig.rfc, + sv.mensaje, sv.fecha_solicitud, si.opinion_file + FROM solicitudes_vinculacion sv + INNER JOIN usuarios_sistema u + ON sv.id_importador = u.id_usuario + LEFT JOIN informacion_general ig + ON u.id_usuario = ig.id_usuario + LEFT JOIN solicitudes_importadores si + ON LTRIM(RTRIM(LOWER(si.company_name))) = LTRIM(RTRIM(LOWER(u.nombre))) + WHERE sv.estado = 'PENDIENTE' + AND sv.id_agencia = ? + ORDER BY sv.fecha_solicitud DESC + "; $params = [$id_agencia]; - $stmt = sqlsrv_query($conn, $sql, $params); + $stmt = sqlsrv_query($conn, $sql, $params); // ✅ INICIALIZAR EL ARRAY DE SOLICITUDES $solicitudes = []; @@ -396,18 +370,16 @@ function solicitudesVinculacion() // ✅ VERIFICAR SI LA CONSULTA FUNCIONÓ if ($stmt === false) { // Usar consulta simplificada como backup - $sqlSimple = " - SELECT - sv.id_solicitud, - u.nombre AS importador_nombre, - sv.mensaje, - sv.fecha_solicitud - FROM solicitudes_vinculacion sv - INNER JOIN usuarios_sistema u ON sv.id_importador = u.id_usuario - WHERE sv.estado = 'PENDIENTE' AND sv.id_agencia = ? - ORDER BY sv.fecha_solicitud DESC - "; - $stmt = sqlsrv_query($conn, $sqlSimple, $params); + $sqlSimple = "SELECT + sv.id_solicitud, u.nombre AS importador_nombre, sv.mensaje, sv.fecha_solicitud + FROM solicitudes_vinculacion sv + INNER JOIN usuarios_sistema u + ON sv.id_importador = u.id_usuario + WHERE sv.estado = 'PENDIENTE' + AND sv.id_agencia = ? + ORDER BY sv.fecha_solicitud DESC + "; + $stmt = sqlsrv_query($conn, $sqlSimple, $params); } // ✅ PROCESAR LOS RESULTADOS Y LLENAR EL ARRAY @@ -430,6 +402,7 @@ function aprobarVinculacion() // Verificar que se recibió el ID de la solicitud $id_solicitud = $_GET['id'] ?? null; + if (!$id_solicitud || !is_numeric($id_solicitud)) { header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?error=request_id_invalid'); exit; @@ -442,19 +415,16 @@ function aprobarVinculacion() sqlsrv_begin_transaction($conn); // 1. Obtener datos de la solicitud y verificar que pertenece a la agencia del admin - $sqlSolicitud = " - SELECT - sv.id_solicitud, - sv.id_importador, - sv.id_agencia, - sv.estado, - aa.id_administrador - FROM solicitudes_vinculacion sv - INNER JOIN agencias_aduanales aa ON sv.id_agencia = aa.id_agencia - WHERE sv.id_solicitud = ? AND aa.id_administrador = ? - "; + $sqlSolicitud = "SELECT + sv.id_solicitud, sv.id_importador, sv.id_agencia, sv.estado, aa.id_administrador + FROM solicitudes_vinculacion sv + INNER JOIN agencias_aduanales aa + ON sv.id_agencia = aa.id_agencia + WHERE sv.id_solicitud = ? + AND aa.id_administrador = ? + "; $stmtSolicitud = sqlsrv_query($conn, $sqlSolicitud, [$id_solicitud, $_SESSION['usuario_id']]); - $solicitud = sqlsrv_fetch_array($stmtSolicitud, SQLSRV_FETCH_ASSOC); + $solicitud = sqlsrv_fetch_array($stmtSolicitud, SQLSRV_FETCH_ASSOC); if (!$solicitud) { throw new Exception('Solicitud no encontrada o no tienes permisos para aprobarla'); @@ -465,12 +435,8 @@ function aprobarVinculacion() } // 2. Verificar si ya existe una relación activa entre importador y agencia - $sqlVerificar = " - SELECT id_relacion - FROM importador_agencia - WHERE id_importador = ? AND id_agencia = ? AND activo = 1 - "; - $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$solicitud['id_importador'], $solicitud['id_agencia']]); + $sqlVerificar = " SELECT id_relacion FROM importador_agencia WHERE id_importador = ? AND id_agencia = ? AND activo = 1"; + $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$solicitud['id_importador'], $solicitud['id_agencia']]); $relacionExistente = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC); if ($relacionExistente) { @@ -478,14 +444,13 @@ function aprobarVinculacion() } // 3. Actualizar el estado de la solicitud a APROBADO - $sqlActualizar = " - UPDATE solicitudes_vinculacion - SET estado = 'APROBADO', - fecha_respuesta = GETDATE(), - respondido_por = ?, - comentarios_respuesta = 'Vinculación aprobada' - WHERE id_solicitud = ? - "; + $sqlActualizar = "UPDATE solicitudes_vinculacion + SET estado = 'APROBADO', + fecha_respuesta = GETDATE(), + respondido_por = ?, + comentarios_respuesta = 'Vinculación aprobada' + WHERE id_solicitud = ? + "; $stmtActualizar = sqlsrv_query($conn, $sqlActualizar, [$_SESSION['usuario_id'], $id_solicitud]); if (!$stmtActualizar) { @@ -493,23 +458,11 @@ function aprobarVinculacion() } // 4. Crear la relación en importador_agencia - $sqlRelacion = " - INSERT INTO importador_agencia ( - id_importador, - id_agencia, - activo, - fecha_vinculacion, - creado_por, - aprobado_por, - estado - ) VALUES (?, ?, 1, GETDATE(), ?, ?, 'APROBADO') - "; - $stmtRelacion = sqlsrv_query($conn, $sqlRelacion, [ - $solicitud['id_importador'], - $solicitud['id_agencia'], - $solicitud['id_importador'], // creado_por (el importador que solicitó) - $_SESSION['usuario_id'] // aprobado_por (el admin de agencia) - ]); + $sqlRelacion = "INSERT INTO importador_agencia + (id_importador, id_agencia, activo, fecha_vinculacion, creado_por, aprobado_por, estado) + VALUES (?, ?, 1, GETDATE(), ?, ?, 'APROBADO') + "; + $stmtRelacion = sqlsrv_query($conn, $sqlRelacion, [$solicitud['id_importador'], $solicitud['id_agencia'], $solicitud['id_importador'], $_SESSION['usuario_id']]); if (!$stmtRelacion) { throw new Exception('Error al crear la relación importador-agencia'); @@ -539,6 +492,7 @@ function denegarVinculacion() // Verificar que se recibió el ID de la solicitud $id_solicitud = $_GET['id'] ?? null; + if (!$id_solicitud || !is_numeric($id_solicitud)) { header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?error=request_id_invalid'); exit; @@ -551,19 +505,16 @@ function denegarVinculacion() sqlsrv_begin_transaction($conn); // 1. Obtener datos de la solicitud y verificar que pertenece a la agencia del admin - $sqlSolicitud = " - SELECT - sv.id_solicitud, - sv.id_importador, - sv.id_agencia, - sv.estado, - aa.id_administrador - FROM solicitudes_vinculacion sv - INNER JOIN agencias_aduanales aa ON sv.id_agencia = aa.id_agencia - WHERE sv.id_solicitud = ? AND aa.id_administrador = ? - "; + $sqlSolicitud = "SELECT + sv.id_solicitud, sv.id_importador, sv.id_agencia, sv.estado, aa.id_administrador + FROM solicitudes_vinculacion sv + INNER JOIN agencias_aduanales aa + ON sv.id_agencia = aa.id_agencia + WHERE sv.id_solicitud = ? + AND aa.id_administrador = ? + "; $stmtSolicitud = sqlsrv_query($conn, $sqlSolicitud, [$id_solicitud, $_SESSION['usuario_id']]); - $solicitud = sqlsrv_fetch_array($stmtSolicitud, SQLSRV_FETCH_ASSOC); + $solicitud = sqlsrv_fetch_array($stmtSolicitud, SQLSRV_FETCH_ASSOC); if (!$solicitud) { throw new Exception('Solicitud no encontrada o no tienes permisos para denegarla'); @@ -574,13 +525,12 @@ function denegarVinculacion() } // 2. Actualizar el estado de la solicitud a DENEGADO - $sqlActualizar = " - UPDATE solicitudes_vinculacion - SET estado = 'DENEGADO', - fecha_respuesta = GETDATE(), - respondido_por = ? - WHERE id_solicitud = ? - "; + $sqlActualizar = "UPDATE solicitudes_vinculacion + SET estado = 'DENEGADO', + fecha_respuesta = GETDATE(), + respondido_por = ? + WHERE id_solicitud = ? + "; $stmtActualizar = sqlsrv_query($conn, $sqlActualizar, [$_SESSION['usuario_id'], $id_solicitud]); if (!$stmtActualizar) { diff --git a/views/admin/alta_agencias.php b/views/admin/alta_agencias.php index f3b472c..81d5c1d 100644 --- a/views/admin/alta_agencias.php +++ b/views/admin/alta_agencias.php @@ -36,8 +36,8 @@ .card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.8s ease-out; } @@ -80,8 +80,8 @@ /* 5. Efecto de pulso en hover */ .input-pulse:hover { animation: inputPulse 0.6s ease-in-out; } @keyframes inputPulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.02); } + 0% { transform: scale(1); } + 50% { transform: scale(1.02); } 100% { transform: scale(1); } } /* 6. Gradiente animado en el borde */ @@ -92,8 +92,8 @@ /* 7. Efecto de brillo en validación exitosa */ .form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; } @keyframes successGlow { - 0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); } - 50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); } + 0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); } + 50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); } 100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); } } /* 8. Typing effect simulation */ @@ -101,7 +101,7 @@ .input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; } .input-typing:focus::after { opacity: 1; } @keyframes blink { - 0%, 50% { opacity: 1; } + 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } } /* 9. Efecto de ondas */ diff --git a/views/admin/alta_usuarios.php b/views/admin/alta_usuarios.php index b06d73a..ff97d35 100644 --- a/views/admin/alta_usuarios.php +++ b/views/admin/alta_usuarios.php @@ -214,8 +214,8 @@
-

✅ Usuarios Activos

-
+

✅ Usuarios Activos

+
diff --git a/views/admin/dashboard_admin.php b/views/admin/dashboard_admin.php index 0f7ed22..784a983 100644 --- a/views/admin/dashboard_admin.php +++ b/views/admin/dashboard_admin.php @@ -53,14 +53,14 @@ .card-hover:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.6s ease-out; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } - to { opacity: 1; transform: translateY(0); } + to { opacity: 1; transform: translateY(0); } } .loading-spinner { display: none; } .btn-loading .loading-spinner { display: inline-block; } @@ -69,13 +69,13 @@ .alert-animated { animation: slideInDown 0.5s ease-out; } @keyframes slideInDown { from { transform: translateY(-100%); opacity: 0; } - to { transform: translateY(0); opacity: 1; } + to { transform: translateY(0); opacity: 1; } } /* Efecto de parpadeo para elementos obligatorios */ .border-warning-animated { animation: borderGlow 2s ease-in-out infinite alternate; } @keyframes borderGlow { from { border-color: #ffc107; box-shadow: 0 0 5px rgba(255, 193, 7, 0.5); } - to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } + to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } } @@ -94,20 +94,20 @@ ?> -->
-
Aprobar agencias
+
Aprobar agencias

Aprueba las agencias que solicitaron un registro.

+ class="btn btn-teal btn-sm mt-2 "> Ver agencias solicitantes
-
Alta de agencias
+
Alta de agencias

Da de alta manualmente una agencia.

+ class="btn btn-lime btn-sm mt-2 "> Nueva agencia
@@ -115,10 +115,10 @@
-
Aprobar de usuarios
+
Aprobar de usuarios

Aprueba los usuarios que solicitaron un registro.

+ class="btn btn-success btn-sm mt-2 "> Ver usuarios solicitantes
@@ -126,10 +126,10 @@
-
Alta de usuarios
+
Alta de usuarios

Da de alta manualmente a un usuario.

+ class="btn btn-info btn-sm mt-2 "> Nuevo usuario
diff --git a/views/agencias/dashboard_agencias.php b/views/agencias/dashboard_agencias.php index 26c1801..bf1cf3b 100644 --- a/views/agencias/dashboard_agencias.php +++ b/views/agencias/dashboard_agencias.php @@ -53,14 +53,14 @@ .card-hover:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.6s ease-out; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } - to { opacity: 1; transform: translateY(0); } + to { opacity: 1; transform: translateY(0); } } .loading-spinner { display: none; } .btn-loading .loading-spinner { display: inline-block; } @@ -69,13 +69,13 @@ .alert-animated { animation: slideInDown 0.5s ease-out; } @keyframes slideInDown { from { transform: translateY(-100%); opacity: 0; } - to { transform: translateY(0); opacity: 1; } + to { transform: translateY(0); opacity: 1; } } /* Efecto de parpadeo para elementos obligatorios */ .border-warning-animated { animation: borderGlow 2s ease-in-out infinite alternate; } @keyframes borderGlow { from { border-color: #ffc107; box-shadow: 0 0 5px rgba(255, 193, 7, 0.5); } - to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } + to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } } @@ -94,10 +94,10 @@ ?> -->
-
Solicitudes de vinculación
+
Solicitudes de vinculación

Aprueba las solicitudes de vinculación de los importadores.

+ class="btn btn-teal btn-sm mt-2 "> Ver solicitudes
@@ -105,10 +105,10 @@
-
Usuarios vinculados
+
Usuarios vinculados

Consulta los que ya fueron autorizados.

+ class="btn btn-lime btn-sm mt-2 "> Ver usuarios
@@ -116,10 +116,10 @@
-
Alta de agentes
+
Alta de agentes

Da de alta a tus agentes aduanales.

+ class="btn btn-success btn-sm mt-2 "> Nuevo agente
@@ -127,15 +127,26 @@
-
Patentes
+
Patentes

Gestiona las patentes de la agencia.

+ class="btn btn-info btn-sm mt-2 "> Ver agentes
+
+
+
Locaciones
+

Gestiona la locaciones validas para nuevos registros.

+ + Gestionar locaciones + +
+
+
Configuración
@@ -147,17 +158,6 @@
-
-
-
Locaciones
-

Gestiona la locaciones validas para nuevos registros.

- - Gestionar locaciones - -
-
-
Cerrar sesión
diff --git a/views/agentes/dashboard_agentes.php b/views/agentes/dashboard_agentes.php index 563716a..eaf755b 100644 --- a/views/agentes/dashboard_agentes.php +++ b/views/agentes/dashboard_agentes.php @@ -56,14 +56,14 @@ include __DIR__ . '/../partials/sidebar_agente.php'; .card-hover:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.6s ease-out; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } - to { opacity: 1; transform: translateY(0); } + to { opacity: 1; transform: translateY(0); } } .loading-spinner { display: none; } .btn-loading .loading-spinner { display: inline-block; } @@ -72,13 +72,13 @@ include __DIR__ . '/../partials/sidebar_agente.php'; .alert-animated { animation: slideInDown 0.5s ease-out; } @keyframes slideInDown { from { transform: translateY(-100%); opacity: 0; } - to { transform: translateY(0); opacity: 1; } + to { transform: translateY(0); opacity: 1; } } /* Efecto de parpadeo para elementos obligatorios */ .border-warning-animated { animation: borderGlow 2s ease-in-out infinite alternate; } @keyframes borderGlow { from { border-color: #ffc107; box-shadow: 0 0 5px rgba(255, 193, 7, 0.5); } - to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } + to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } } @@ -97,10 +97,10 @@ include __DIR__ . '/../partials/sidebar_agente.php'; ?> -->
-
Importadores vinculados
+
Importadores vinculados

Consulta los que ya fueron autorizados.

+ class="btn btn-teal btn-sm mt-2 "> Ver importadores
@@ -108,10 +108,10 @@ include __DIR__ . '/../partials/sidebar_agente.php';
-
Patentes
+
Patentes

Gestiona las patentes de la agencia.

+ class="btn btn-lime btn-sm mt-2 "> Ver solicitudes
@@ -119,10 +119,10 @@ include __DIR__ . '/../partials/sidebar_agente.php';
-
Locaciones
+
Locaciones

Gestiona la locaciones validas para nuevos registros.

+ class="btn btn-success btn-sm mt-2 "> Gestionar locaciones
diff --git a/views/bitacoras/dashboard_bitacoras.php b/views/bitacoras/dashboard_bitacoras.php index 82e33f3..def5ccc 100644 --- a/views/bitacoras/dashboard_bitacoras.php +++ b/views/bitacoras/dashboard_bitacoras.php @@ -53,8 +53,8 @@ .card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.8s ease-out; } diff --git a/views/choferes/crear.php b/views/choferes/crear.php index 37c5d39..16b088b 100644 --- a/views/choferes/crear.php +++ b/views/choferes/crear.php @@ -14,6 +14,12 @@ + + + + + + @@ -68,61 +182,91 @@
-
- - -
+
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
-
- - -
+
+ +
+ + +
+
- -
- - -
+ +
+ +
+ +
+
- - Cancelar +
+ + Cancelar +
+
@@ -193,7 +337,7 @@ // VALIDAR FECHA DE INGRESO (solo si se proporciona) if (fecha_ingreso) { const fechaIngreso = new Date(fecha_ingreso); - const fechaActual = new Date(); + const fechaActual = new Date(); if (fechaIngreso > fechaActual) { Swal.fire({ icon: 'error', title: 'Fecha inválida', text: 'La fecha de ingreso no puede ser futura.', confirmButtonColor: '#dc3545' }); document.getElementById('fecha_ingreso').focus(); @@ -233,6 +377,160 @@ Swal.fire({ icon: 'error', title: 'Error de validación', text: 'No fue posible validar el número de gafete. Intenta de nuevo.', confirmButtonColor: '#dc3545' }); }); }); + + // Script para manejar las animaciones de validación + document.addEventListener('DOMContentLoaded', function() { + const inputs = document.querySelectorAll('input.form-control, select.form-select'); + + inputs.forEach(input => { + // Validación en tiempo real + input.addEventListener('input', function() { + if (this.checkValidity()) { + this.classList.remove('shake'); + this.classList.add('valid'); + } else { + this.classList.remove('valid'); + } + }); + + // Efecto shake en campos inválidos + input.addEventListener('invalid', function() { + this.classList.add('shake'); + setTimeout(() => { + this.classList.remove('shake'); + }, 500); + }); + }); + + // Validación del formulario + document.getElementById('formAltaChoferes').addEventListener('submit', function(e) { + e.preventDefault(); + + let isValid = true; + const form = this; + + inputs.forEach(input => { + if (!input.checkValidity()) { + input.classList.add('shake'); + isValid = false; + } + }); + + // Si todo es válido, enviar el formulario + if (isValid) { + // Mostrar indicador de carga + const submitBtn = form.querySelector('button[type="submit"]'); + const originalText = submitBtn.textContent; + submitBtn.disabled = true; + submitBtn.innerHTML = 'Guardando...'; + + // Aquí puedes enviar el formulario real + form.submit(); + } else { + // Mostrar mensaje de error + showNotification('Por favor, complete todos los campos obligatorios correctamente.', 'error'); + } + }); + }); + + // Manejo específico para selects + document.addEventListener('DOMContentLoaded', function() { + const selects = document.querySelectorAll('.form-select'); + + selects.forEach(select => { + // Manejar cambios en el select + select.addEventListener('change', function() { + updateSelectState(this); + }); + + // Estado inicial + updateSelectState(select); + }); + + function updateSelectState(select) { + // Actualizar el atributo value para que el CSS pueda detectarlo + select.setAttribute('value', select.value); + + // Agregar/quitar clase valid basado en si hay valor seleccionado + if (select.value && select.value !== '') { + select.classList.add('valid'); + select.classList.remove('invalid'); + } else { + select.classList.remove('valid'); + // Solo agregar invalid si el campo es required y se ha intentado enviar + if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) { + select.classList.add('invalid'); + } + } + } + }); + + // Validación específica para campos de texto + document.addEventListener('DOMContentLoaded', function() { + // Validación del número de licencia (solo números y letras) + const licenciaInput = document.getElementById('numero_licencia'); + if (licenciaInput) { + licenciaInput.addEventListener('input', function() { + this.value = this.value.replace(/[^A-Za-z0-9]/g, ''); + }); + } + + // Validación del teléfono (solo números) + const telefonoInput = document.getElementById('telefono'); + if (telefonoInput) { + telefonoInput.addEventListener('input', function() { + this.value = this.value.replace(/[^0-9]/g, ''); + }); + } + + // Validación del email en tiempo real + const emailInput = document.getElementById('email'); + if (emailInput) { + emailInput.addEventListener('input', function() { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (this.value && !emailRegex.test(this.value)) { + this.setCustomValidity('Por favor, ingrese un email válido'); + } else { + this.setCustomValidity(''); + } + }); + } + }); + + // Función para mostrar notificaciones + function showNotification(message, type = 'info') { + // Crear el elemento de notificación + const notification = document.createElement('div'); + notification.className = `alert alert-${type === 'error' ? 'danger' : type} alert-dismissible fade show position-fixed`; + notification.style.cssText = ` top: 20px; right: 20px; z-index: 9999; min-width: 300px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);`; + notification.innerHTML = `${message} `; + + document.body.appendChild(notification); + + // Auto-remover después de 5 segundos + setTimeout(() => { + if (notification.parentNode) { + notification.remove(); + } + }, 5000); + } + + // Inicializar Flatpickr para la fecha + flatpickr("#fecha_ingreso", { + dateFormat: "d/m/Y", + locale: "es", + maxDate: "today", + onChange: function(selectedDates, dateStr, instance) { + // Validar que la fecha no sea futura + const today = new Date(); + today.setHours(0, 0, 0, 0); + + if (selectedDates[0] > today) { + showNotification('La fecha de ingreso no puede ser futura.', 'error'); + instance.clear(); + } + } + }); diff --git a/views/configuracion/dashboard_configuracion.php b/views/configuracion/dashboard_configuracion.php index daff217..6c4bad7 100644 --- a/views/configuracion/dashboard_configuracion.php +++ b/views/configuracion/dashboard_configuracion.php @@ -35,8 +35,8 @@ .card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.8s ease-out; } diff --git a/views/importadores/dashboard_importador.php b/views/importadores/dashboard_importador.php index 825efd5..f176395 100644 --- a/views/importadores/dashboard_importador.php +++ b/views/importadores/dashboard_importador.php @@ -53,14 +53,14 @@ .card-hover:hover { transform: translateY(-8px) saqcle(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.8s ease-out; } @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } - to { opacity: 1; transform: translateY(0); } + to { opacity: 1; transform: translateY(0); } } .loading-spinner { display: none; } /* Botón con efecto de loading */ @@ -86,13 +86,13 @@ .alert-animated { animation: slideInDown 0.5s ease-out; } @keyframes slideInDown { from { transform: translateY(-100%); opacity: 0; } - to { transform: translateY(0); opacity: 1; } + to { transform: translateY(0); opacity: 1; } } /* Efecto de parpadeo para elementos obligatorios */ .border-warning-animated { animation: borderGlow 2s ease-in-out infinite alternate; } @keyframes borderGlow { from { border-color: #ffc107; box-shadow: 0 0 5px rgba(255, 193, 7, 0.5); } - to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } + to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); } } diff --git a/views/locaciones/alta_locaciones.php b/views/locaciones/alta_locaciones.php index d4fcb05..51a7c8e 100644 --- a/views/locaciones/alta_locaciones.php +++ b/views/locaciones/alta_locaciones.php @@ -97,10 +97,10 @@ if ($tipoUsuario === 'agente_aduanal') {


- - Cancelar + Cancelar
@@ -140,10 +140,10 @@ if ($tipoUsuario === 'agente_aduanal') {

- - Cancelar + Cancelar
diff --git a/views/partials/sidebar_agencia.php b/views/partials/sidebar_agencia.php index a8c183d..772d04d 100644 --- a/views/partials/sidebar_agencia.php +++ b/views/partials/sidebar_agencia.php @@ -38,11 +38,11 @@ diff --git a/views/partials/sidebar_agente.php b/views/partials/sidebar_agente.php index 78cc583..8ed44c7 100644 --- a/views/partials/sidebar_agente.php +++ b/views/partials/sidebar_agente.php @@ -40,9 +40,9 @@ // Detecta si estamos en alguna parte de locaciones $esVistaLocaciones = str_contains($_SERVER['REQUEST_URI'], '/locaciones'); // Detecta si estamos en alguna parte de agentes - $esVistaAgentes = str_contains($_SERVER['REQUEST_URI'], '/agentes'); + $esVistaAgentes = str_contains($_SERVER['REQUEST_URI'], '/agentes'); // Detecta si estamos en alguna parte de agente aduanal - $esVistaPatente = str_contains($_SERVER['REQUEST_URI'], '/patente'); + $esVistaPatente = str_contains($_SERVER['REQUEST_URI'], '/patente'); ?> diff --git a/views/preferencias/dashboard_preferencias.php b/views/preferencias/dashboard_preferencias.php index 46ab588..cb58582 100644 --- a/views/preferencias/dashboard_preferencias.php +++ b/views/preferencias/dashboard_preferencias.php @@ -35,8 +35,8 @@ .card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; } .btn-pulse { animation: pulse 2s infinite; } @keyframes pulse { - 0% { transform: scale(1); } - 50% { transform: scale(1.05); } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .fade-in-up { animation: fadeInUp 0.8s ease-out; } diff --git a/views/reset/change_password.php b/views/reset/change_password.php index 47f102a..754c839 100644 --- a/views/reset/change_password.php +++ b/views/reset/change_password.php @@ -190,9 +190,9 @@ $dos_factores_estado = obtenerEstadoDosFactores(); // Manejo de botones mostrar/ocultar contraseña toggleButtons.forEach(button => { button.addEventListener('click', function() { - const targetId = this.getAttribute('data-target'); + const targetId = this.getAttribute('data-target'); const targetInput = document.getElementById(targetId); - const icon = this.querySelector('i'); + const icon = this.querySelector('i'); if (targetInput.type === 'password') { targetInput.type = 'text'; @@ -220,8 +220,8 @@ $dos_factores_estado = obtenerEstadoDosFactores(); form.addEventListener('submit', function(e) { e.preventDefault(); - const passwordActual = inputActual.value.trim(); - const passwordNueva = inputNueva.value.trim(); + const passwordActual = inputActual.value.trim(); + const passwordNueva = inputNueva.value.trim(); const confirmarPassword = inputConfirmar.value.trim(); if (!validarFormulario(passwordActual, passwordNueva, confirmarPassword)) { @@ -233,7 +233,7 @@ $dos_factores_estado = obtenerEstadoDosFactores(); // Función para enviar cambio de contraseña function enviarCambioPassword(actual, nueva, confirmar) { // Mostrar estado de carga - btnCambiar.disabled = true; + btnCambiar.disabled = true; btnCambiar.classList.add('loading'); btnCambiar.innerHTML = 'Cambiando contraseña...'; @@ -243,46 +243,65 @@ $dos_factores_estado = obtenerEstadoDosFactores(); formData.append('confirmar_password', confirmar); fetch('/IMPORTADORES/reset/cambiarPasswordInterno', { - method: 'POST', - body: formData, + method: 'POST', + body: formData, credentials: 'same-origin' }) - .then(response => response.json()) - .then(data => { - if (data.success) { - // Éxito: mostrar mensaje y redirigir - mostrarExito(data.message); - - // Deshabilitar formulario - deshabilitarFormulario(); - - // Redirigir después de 2 segundos - setTimeout(() => { - if (data.redirect) { - window.location.href = data.redirect; - } else { - window.location.href = '/IMPORTADORES/login'; // Redirigir a login por defecto - } - }, 2000); + .then(response => { + // Primero verificar si la respuesta es exitosa + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + // Obtener el texto de la respuesta + return response.text(); + }) + .then(text => { + // Intentar parsear como JSON + let data; + try { + data = JSON.parse(text); + } catch (e) { + // Si no es JSON válido, mostrar el error HTML recibido + console.error('Respuesta no válida del servidor:', text); + throw new Error('El servidor devolvió una respuesta no válida. Revisa la consola para más detalles.'); + } + + // Procesar la respuesta JSON + if (data.success) { + // Éxito: mostrar mensaje y redirigir + mostrarExito(data.message); + + // Deshabilitar formulario + deshabilitarFormulario(); + + // Redirigir después de 2 segundos + setTimeout(() => { + if (data.redirect) { + window.location.href = data.redirect; } else { - // Error: mostrar mensaje - mostrarError(data.message); - - // Limpiar contraseña actual por seguridad - inputActual.value = ''; - inputActual.focus(); + window.location.href = '/IMPORTADORES/login'; // Redirigir a login por defecto } - }) - .catch(error => { - console.error('Error:', error); - mostrarError("❌ Error de conexión. Intenta nuevamente."); - }) - .finally(() => { - // Restaurar botón solo si no fue exitoso - if (!btnCambiar.classList.contains('success')) { - btnCambiar.disabled = false; - btnCambiar.classList.remove('loading'); - btnCambiar.innerHTML = 'Cambiar contraseña'; + }, 2000); + } else { + // Error: mostrar mensaje + mostrarError(data.message); + + // Limpiar contraseña actual por seguridad + inputActual.value = ''; + inputActual.focus(); + } + }) + .catch(error => { + console.error('Error:', error); + mostrarError("❌ Error de conexión. Intenta nuevamente."); + }) + .finally(() => { + // Restaurar botón solo si no fue exitoso + if (!btnCambiar.classList.contains('success')) { + btnCambiar.disabled = false; + btnCambiar.classList.remove('loading'); + btnCambiar.innerHTML = 'Cambiar contraseña'; } }); } @@ -372,12 +391,12 @@ $dos_factores_estado = obtenerEstadoDosFactores(); // Deshabilitar formulario tras éxito function deshabilitarFormulario() { - inputActual.disabled = true; - inputNueva.disabled = true; + inputActual.disabled = true; + inputNueva.disabled = true; inputConfirmar.disabled = true; - btnCambiar.disabled = true; + btnCambiar.disabled = true; btnCambiar.classList.add('success'); - btnCambiar.innerHTML = 'Contraseña cambiada exitosamente'; + btnCambiar.innerHTML = 'Contraseña cambiada exitosamente'; toggleButtons.forEach(btn => btn.disabled = true); } diff --git a/views/seguridad/agregar.php b/views/seguridad/agregar.php index 2398ca8..9513a4d 100644 --- a/views/seguridad/agregar.php +++ b/views/seguridad/agregar.php @@ -12,6 +12,8 @@ $dos_factores_estado = obtenerEstadoDosFactores(); + + @@ -33,6 +35,7 @@ $dos_factores_estado = obtenerEstadoDosFactores(); .sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; } } + .hide { display: none !important; } .card { border-radius: 12px; } .btn i { font-family: "Font Awesome 6 Free", sans-serif; margin-right: 0.5rem; } .btn { font-family: 'Segoe UI', sans-serif; } @@ -75,6 +78,68 @@ $dos_factores_estado = obtenerEstadoDosFactores(); .btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; } .btn-animated:hover::before { left: 100%; } + /* ========== ANIMACIONES PARA INPUTS ========== */ + /* 1. Animación al hacer focus */ + .form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; } + .form-control:focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px); } + /* 2. Animación al escribir */ + .form-control:not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; } + /* 3. Efecto de shake en validación */ + .form-control.shake { animation: shake 0.5s ease-in-out; } + @keyframes shake { + 0%, 100% { transform: translateX(0); } + 25% { transform: translateX(-5px); } + 75% { transform: translateX(5px); } + } + /* 4. Floating labels con animación */ + .form-floating-custom { position: relative; margin-bottom: 1.5rem; } + .form-floating-custom .form-control { padding: 1rem 0.75rem 0.5rem 0.75rem; height: auto; } + .form-floating-custom .form-label { position: absolute; top: 0.75rem; left: 0.75rem; transition: all 0.3s ease; pointer-events: none; color: #6c757d; z-index: 2; } + .form-floating-custom .form-control:focus ~ .form-label, + .form-floating-custom .form-control:not(:placeholder-shown) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; } + /* 5. Efecto de pulso en hover */ + .input-pulse:hover { animation: inputPulse 0.6s ease-in-out; } + @keyframes inputPulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.02); } + 100% { transform: scale(1); } + } + /* 6. Gradiente animado en el borde */ + .input-gradient { position: relative; overflow: hidden; } + .input-gradient::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; + background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; } + .input-gradient:focus::before { left: 100%; } + /* 7. Efecto de brillo en validación exitosa */ + .form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; } + @keyframes successGlow { + 0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); } + 50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); } + 100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); } + } + /* 8. Typing effect simulation */ + .input-typing { position: relative; } + .input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; } + .input-typing:focus::after { opacity: 1; } + @keyframes blink { + 0%, 50% { opacity: 1; } + 51%, 100% { opacity: 0; } + } + /* 9. Efecto de ondas */ + .input-ripple { position: relative; overflow: hidden; } + .input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2); + border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; } + .input-ripple:focus::before { width: 300px; height: 300px; } + /* 10. Slide-up animation para los campos */ + .form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; } + .form-group-animated:nth-child(1) { animation-delay: 0.1s; } + .form-group-animated:nth-child(2) { animation-delay: 0.2s; } + .form-group-animated:nth-child(3) { animation-delay: 0.3s; } + .form-group-animated:nth-child(4) { animation-delay: 0.4s; } + .form-group-animated:nth-child(5) { animation-delay: 0.5s; } + .form-group-animated:nth-child(6) { animation-delay: 0.6s; } + .form-group-animated:nth-child(7) { animation-delay: 0.7s; } + .form-group-animated:nth-child(8) { animation-delay: 0.8s; } + @keyframes slideUp { to { opacity: 1; transform: translateY(0); } } @@ -128,11 +193,14 @@ $dos_factores_estado = obtenerEstadoDosFactores();

-
-
- + +
+
+ + +
-
+
@@ -142,11 +210,16 @@ $dos_factores_estado = obtenerEstadoDosFactores();
-
-
- + +
+
+ + +
- +
+ +
@@ -163,23 +236,33 @@ $dos_factores_estado = obtenerEstadoDosFactores();

-
-
- + +
+
+ + +
+
+
+ +
- - -
-
- + +
+
+ + +
+
+
+
-
@@ -216,12 +299,12 @@ $dos_factores_estado = obtenerEstadoDosFactores();