diff --git a/.env b/.env index b16b6a0..e427a09 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -DB_HOST=localhost +DB_HOST=DESKTOP-22T88B6 DB_DATABASE=Importaciones_HC DB_USERNAME=sa DB_PASSWORD=Soluciones01 diff --git a/app/controllers/agentes.php b/app/controllers/agentes.php index d509fb1..616ea52 100644 --- a/app/controllers/agentes.php +++ b/app/controllers/agentes.php @@ -20,13 +20,9 @@ function dashboard() exit; } - // Aquí puedes conectar a la BD si vas a mostrar métricas - // Ejemplo: - // $conn = getConnection(); - // $sql = "SELECT COUNT(*) FROM solicitudes_importadores WHERE request_status = 'pending'"; - // ... + $nombreAgente = $_SESSION['usuario_nombre']; - include __DIR__ . '/../../views/agentes/dashboard.php'; + include __DIR__ . '/../../views/agentes/dashboard_agentes.php'; } function importadores_activos() @@ -270,4 +266,516 @@ function bitacora() } include __DIR__ . '/../../views/agentes/bitacora.php'; +} + +function lista() +{ + $conn = getConnection(); + $locaciones = []; + + // CONSULTA CORREGIDA - Agregamos abreviatura e iso2 + $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); + + if (!$stmt) { + $errors = sqlsrv_errors(); + error_log("Error en consulta lista(): " . print_r($errors, true)); + die("Error en la consulta"); + } + + 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"; + $stmt_paises_select = sqlsrv_query($conn, $sql_paises_select); + $paises = []; + while ($row = sqlsrv_fetch_array($stmt_paises_select, SQLSRV_FETCH_ASSOC)) { + $paises[] = $row; + } + + include __DIR__ . '/../../views/locaciones/gestion_locaciones.php'; +} + +function alta() +{ + $conn = getConnection(); + // 1) Cargar países + $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; + } + + include __DIR__ . '/../../views/locaciones/alta_locaciones.php'; +} + +// AJAX: devuelve los estados de un país dado +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"; + $stmt = sqlsrv_query($conn, $sql, [$pais]); + $out = []; + while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $out[] = $r; + } + echo json_encode($out); + exit; +} + +// Guardar nuevo estado +function guardarEstado() { + header('Content-Type: application/json; charset=utf-8'); + + try { + // Debug: Verificar qué se está recibiendo + error_log("POST data: " . print_r($_POST, true)); + + $pais_id = $_POST['pais'] ?? ''; + $entidad = trim($_POST['entidad'] ?? ''); + + // Debug: Verificar valores específicos + error_log("pais_id: '$pais_id', entidad: '$entidad'"); + + // Validaciones más específicas + if (empty($pais_id)) { + echo json_encode(['success' => false, 'message' => 'Debe seleccionar un país']); + exit; + } + + if (empty($entidad)) { + echo json_encode(['success' => false, 'message' => 'Debe ingresar el nombre del estado']); + exit; + } + + $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]); + $pais_exists = sqlsrv_fetch_array($stmt_pais, SQLSRV_FETCH_ASSOC); + + if ($pais_exists['count'] == 0) { + echo json_encode(['success' => false, 'message' => 'El país seleccionado no existe']); + exit; + } + + // Verificar si ya existe el estado en ese país + $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); + + if ($exists['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'Este estado ya existe en el país seleccionado']); + exit; + } + + // 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); + $next_id_row = sqlsrv_fetch_array($stmt_max, SQLSRV_FETCH_ASSOC); + $next_id = $next_id_row['next_id']; + + $sql = "INSERT INTO estados (id_estado, pais_id, nombre) VALUES (?, ?, ?)"; + $stmt = sqlsrv_query($conn, $sql, [$next_id, $pais_id, $entidad]); + + if ($stmt) { + echo json_encode(['success' => true, 'message' => 'Estado registrado exitosamente']); + } else { + // Obtener el error específico de SQL Server + $errors = sqlsrv_errors(); + $errorMessage = 'Error al registrar el estado'; + if ($errors) { + $errorMessage .= ': ' . $errors[0]['message']; + } + error_log("Error SQL: " . print_r($errors, true)); + echo json_encode(['success' => false, 'message' => $errorMessage]); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; +} + +// Guardar nueva ciudad +function guardarCiudad() { + header('Content-Type: application/json; charset=utf-8'); + + try { + $estado_id = $_POST['entidad'] ?? ''; + $ciudad = trim($_POST['ciudad'] ?? ''); + + // Validaciones + if (empty($estado_id) || empty($ciudad)) { + echo json_encode(['success' => false, 'message' => 'Todos los campos son obligatorios']); + exit; + } + + $conn = getConnection(); + + // Verificar si ya existe la ciudad en ese estado + $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); + + if ($exists['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'Esta ciudad ya existe en el estado seleccionado']); + exit; + } + + // Insertar nueva ciudad + $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']); + } else { + echo json_encode(['success' => false, 'message' => 'Error al registrar la ciudad']); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; +} + +// Función para obtener país por estado (necesaria para el modal de edición de ciudades) +function obtenerPaisPorEstado() { + header('Content-Type: application/json; charset=utf-8'); + + try { + $estado_id = $_GET['estado'] ?? ''; + + if (empty($estado_id)) { + echo json_encode(['success' => false, 'message' => 'ID de estado requerido']); + exit; + } + + $conn = getConnection(); + $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']]); + } else { + echo json_encode(['success' => false, 'message' => 'Estado no encontrado']); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; +} + +// FUNCIÓN DISPATCHER PARA EDICIÓN +function editar() { + $tipo = $_POST['tipo'] ?? ''; + + // Log para debugging + error_log("Función editar llamada con tipo: " . $tipo); + error_log("POST data: " . print_r($_POST, true)); + + switch ($tipo) { + case 'pais': + actualizarPais(); + break; + case 'estado': + actualizarEstado(); + break; + case 'ciudad': + actualizarCiudad(); + break; + default: + header('Content-Type: application/json; charset=utf-8'); + echo json_encode(['success' => false, 'message' => 'Tipo de elemento no válido: ' . $tipo]); + exit; + } +} + +// FUNCIÓN ESPECÍFICA PARA ACTUALIZAR PAÍSES +function actualizarPais() { + header('Content-Type: application/json; charset=utf-8'); + + try { + $id = $_POST['id'] ?? ''; + $nombre = trim($_POST['nombre'] ?? ''); + $iso2 = trim($_POST['iso2'] ?? ''); + $iso3 = trim($_POST['iso3'] ?? ''); + + // Validaciones + if (empty($id) || empty($nombre)) { + echo json_encode(['success' => false, 'message' => 'ID y nombre del país son obligatorios']); + exit; + } + + $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 != ?"; + $stmt_check = sqlsrv_query($conn, $sql_check, [$nombre, $id]); + + if (!$stmt_check) { + echo json_encode(['success' => false, 'message' => 'Error al verificar duplicados']); + exit; + } + + $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + if ($exists['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'Ya existe otro país con este nombre']); + exit; + } + + // Actualizar + $iso2_val = empty($iso2) ? null : $iso2; + $iso3_val = empty($iso3) ? null : $iso3; + + $sql = "UPDATE paises SET nombre = ?, iso2 = ?, iso3 = ? WHERE id_pais = ?"; + $params = [$nombre, $iso2_val, $iso3_val, $id]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt && sqlsrv_rows_affected($stmt) > 0) { + echo json_encode(['success' => true, 'message' => 'País actualizado exitosamente']); + } else { + echo json_encode(['success' => false, 'message' => 'No se pudo actualizar el país']); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; +} + +// FUNCIÓN ESPECÍFICA PARA ACTUALIZAR ESTADOS +function actualizarEstado() { + header('Content-Type: application/json; charset=utf-8'); + + try { + $id = $_POST['id'] ?? ''; + $nombre = trim($_POST['nombre'] ?? ''); + $abreviatura = trim($_POST['abreviatura'] ?? ''); + $pais_id = $_POST['pais_id'] ?? ''; + + // Validaciones + if (empty($id) || empty($nombre) || empty($pais_id)) { + echo json_encode(['success' => false, 'message' => 'ID, nombre del estado y país son obligatorios']); + exit; + } + + $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 != ?"; + $stmt_check = sqlsrv_query($conn, $sql_check, [$nombre, $pais_id, $id]); + + if (!$stmt_check) { + echo json_encode(['success' => false, 'message' => 'Error al verificar duplicados']); + exit; + } + + $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + if ($exists['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'Ya existe otro estado con este nombre en el país seleccionado']); + exit; + } + + // Actualizar + $abreviatura_val = empty($abreviatura) ? null : $abreviatura; + + $sql = "UPDATE estados SET nombre = ?, abreviatura = ?, pais_id = ? WHERE id_estado = ?"; + $params = [$nombre, $abreviatura_val, $pais_id, $id]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt && sqlsrv_rows_affected($stmt) > 0) { + echo json_encode(['success' => true, 'message' => 'Estado actualizado exitosamente']); + } else { + echo json_encode(['success' => false, 'message' => 'No se pudo actualizar el estado']); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; +} + +// FUNCIÓN ESPECÍFICA PARA ACTUALIZAR CIUDADES +function actualizarCiudad() { + header('Content-Type: application/json; charset=utf-8'); + + try { + $id = $_POST['id'] ?? ''; + $nombre = trim($_POST['nombre'] ?? ''); + $estado_id = $_POST['estado_id'] ?? ''; + + // Validaciones + if (empty($id) || empty($nombre) || empty($estado_id)) { + echo json_encode(['success' => false, 'message' => 'ID, nombre de la ciudad y estado son obligatorios']); + exit; + } + + $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 != ?"; + $stmt_check = sqlsrv_query($conn, $sql_check, [$nombre, $estado_id, $id]); + + if (!$stmt_check) { + echo json_encode(['success' => false, 'message' => 'Error al verificar duplicados']); + exit; + } + + $exists = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + if ($exists['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'Ya existe otra ciudad con este nombre en el estado seleccionado']); + exit; + } + + // Actualizar + $sql = "UPDATE ciudades SET nombre = ?, estado_id = ? WHERE id_ciudad = ?"; + $params = [$nombre, $estado_id, $id]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt && sqlsrv_rows_affected($stmt) > 0) { + echo json_encode(['success' => true, 'message' => 'Ciudad actualizada exitosamente']); + } else { + echo json_encode(['success' => false, 'message' => 'No se pudo actualizar la ciudad']); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; +} + +// Función para eliminar locaciones (países, estados, ciudades) +function eliminar() { + header('Content-Type: application/json; charset=utf-8'); + + try { + // Obtener datos del JSON enviado + $input = json_decode(file_get_contents('php://input'), true); + $tipo = $input['tipo'] ?? ''; + $id = $input['id'] ?? ''; + + if (empty($tipo) || empty($id)) { + echo json_encode(['success' => false, 'message' => 'Datos incompletos']); + exit; + } + + $conn = getConnection(); + + 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]); + $has_estados = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + + if ($has_estados['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'No se puede eliminar el país porque tiene estados asociados']); + exit; + } + + // Eliminar país + $sql = "DELETE FROM paises WHERE id_pais = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id]); + + if ($stmt) { + echo json_encode(['success' => true, 'message' => 'País eliminado exitosamente']); + } else { + $errors = sqlsrv_errors(); + $errorMessage = 'Error al eliminar el país'; + if ($errors) { + $errorMessage .= ': ' . $errors[0]['message']; + } + echo json_encode(['success' => false, 'message' => $errorMessage]); + } + break; + + 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]); + $has_ciudades = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + + if ($has_ciudades['count'] > 0) { + echo json_encode(['success' => false, 'message' => 'No se puede eliminar el estado porque tiene ciudades asociadas']); + exit; + } + + // Eliminar estado + $sql = "DELETE FROM estados WHERE id_estado = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id]); + + if ($stmt) { + echo json_encode(['success' => true, 'message' => 'Estado eliminado exitosamente']); + } else { + $errors = sqlsrv_errors(); + $errorMessage = 'Error al eliminar el estado'; + if ($errors) { + $errorMessage .= ': ' . $errors[0]['message']; + } + echo json_encode(['success' => false, 'message' => $errorMessage]); + } + break; + + case 'ciudad': + // Verificar si la ciudad está siendo utilizada en alguna relación + // (aquí puedes agregar más verificaciones según tu modelo de datos) + + // Eliminar ciudad + $sql = "DELETE FROM ciudades WHERE id_ciudad = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id]); + + if ($stmt) { + echo json_encode(['success' => true, 'message' => 'Ciudad eliminada exitosamente']); + } else { + $errors = sqlsrv_errors(); + $errorMessage = 'Error al eliminar la ciudad'; + if ($errors) { + $errorMessage .= ': ' . $errors[0]['message']; + } + echo json_encode(['success' => false, 'message' => $errorMessage]); + } + break; + + default: + echo json_encode(['success' => false, 'message' => 'Tipo de elemento no válido']); + break; + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]); + } + exit; } \ No newline at end of file diff --git a/app/controllers/importadores.php b/app/controllers/importadores.php index b0d660c..7548a6d 100644 --- a/app/controllers/importadores.php +++ b/app/controllers/importadores.php @@ -13,4 +13,37 @@ function dashboard() $nombreImportador = $_SESSION['usuario_nombre']; include __DIR__ . '/../../views/importadores/dashboard_importador.php'; +} + +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 + "; + + $stmt = sqlsrv_query($conn, $sql); + 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"; + $stmt_paises_select = sqlsrv_query($conn, $sql_paises_select); + $paises = []; + while ($row = sqlsrv_fetch_array($stmt_paises_select, SQLSRV_FETCH_ASSOC)) { + $paises[] = $row; + } + + include __DIR__ . '/../../views/locaciones/lista.php'; } \ No newline at end of file diff --git a/app/controllers/login.php b/app/controllers/login.php index fa5eac8..8be0084 100644 --- a/app/controllers/login.php +++ b/app/controllers/login.php @@ -156,7 +156,7 @@ function redirectByRole($tipoUsuario) header('Location: /IMPORTADORES/importadores/dashboard'); break; case 'agente_aduanal': - header('Location: /IMPORTADORES/AGENTES/dashboard'); + header('Location: /IMPORTADORES/agentes/dashboard'); break; default: header('Location: /IMPORTADORES/importadores/dashboard'); diff --git a/app/controllers/proveedores.php b/app/controllers/proveedores.php index 042c6a9..9b9218a 100644 --- a/app/controllers/proveedores.php +++ b/app/controllers/proveedores.php @@ -78,8 +78,6 @@ function lista() } /** GET /IMPORTADORES/proveedores/ajax_lista - * Devuelve JSON para DataTables - * GET /IMPORTADORES/proveedores/ajax_lista * Devuelve JSON para DataTables (siempre HTTP 200) **/ function ajax_lista() { diff --git a/app/controllers/solicitud_importacion.php b/app/controllers/solicitud_importacion.php index ae1563f..a8b6ef3 100644 --- a/app/controllers/solicitud_importacion.php +++ b/app/controllers/solicitud_importacion.php @@ -754,12 +754,27 @@ function ajax_lista() if ($status === 200 && ($json = json_decode($resp, true)) && is_array($json)) { foreach ($json as $p) { $clave = htmlspecialchars($p['Clave'] ?? '', ENT_QUOTES); + + // Construir dirección + $direccion = trim(implode(', ', array_filter([ + $p['Calles'] ?? '', + 'Num. Ext: ' . ($p['NumExt'] ?? ''), + 'Num. Int: ' . ($p['NumInt'] ?? ''), + $p['Colonia'] ?? '', + $p['Municipio'] ?? '', + $p['Ciudad'] ?? '', + 'C.P. ' . ($p['CodigoPostal'] ?? ''), + $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), // Acciones "✏️ " @@ -990,7 +1005,6 @@ function update_status() { exit; } - // Función para generar el PDF use Dompdf\Dompdf; use Dompdf\Options; @@ -1049,6 +1063,12 @@ function pdf() { return; } + // 2.5. Obtener información del proveedor desde API + $proveedor_info = null; + if (!empty($solicitud['proveedor_clave'])) { + $proveedor_info = obtenerProveedorPorClave($solicitud['proveedor_clave']); + } + // 3. Obtener partidas de la solicitud $sql = " SELECT @@ -1074,15 +1094,18 @@ function pdf() { sqlsrv_free_stmt($stmt); // 4. Configuración del sistema - global $config; - $nombre_sistema = $config['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos'; - $siglas = $config['siglas'] ?? 'SIIH'; - $logo_path = realpath(__DIR__ . '/../../public/assets/img/logo_siih.png'); - $logo_url = 'file://' . $logo_path; + $config = "SELECT * FROM configuracion_sistema"; + $stmt = sqlsrv_query($conn, $config); + + if ($stmt === false) { + throw new Exception("Error en la consulta: " . print_r(sqlsrv_errors(), true)); + } + + $configuracion = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); // 5. Generar HTML del PDF - $html = generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_url); + $html = generarHTMLPDF($solicitud, $partidas, $configuracion); // 6. Generar PDF usando DomPDF con Composer require_once __DIR__ . '/../../vendor/autoload.php'; // Ajusta ruta si es necesario @@ -1108,12 +1131,59 @@ function pdf() { } } -function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_url) { - // Formatear fecha - $fecha_expedicion = date('d/m/Y'); - $fecha_factura = $solicitud['fecha_factura']->format('d/m/Y'); - $fecha_vencimiento = (clone $solicitud['fecha_factura'])->modify('+30 days')->format('d/m/Y'); +// NUEVA FUNCIÓN: Obtener información del proveedor por clave +function obtenerProveedorPorClave($clave) { + // Obtener token de la API + $token = getApiToken(); + if (!$token) { + error_log('[obtenerProveedorPorClave] Sin token válido'); + return null; + } + // Construir URL de la API + $apiBase = rtrim($_ENV['API_URL'] ?? '', '/'); + $url = $apiBase . '/proveedores'; + + // Ejecutar cURL para obtener todos los proveedores + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_HTTPHEADER => ["Authorization: $token", 'Accept: application/json'], + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => 10, + ]); + + $resp = curl_exec($ch); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($status !== 200) { + error_log("[obtenerProveedorPorClave] Error HTTP $status al obtener proveedores"); + return null; + } + + $proveedores = json_decode($resp, true); + if (!is_array($proveedores)) { + error_log('[obtenerProveedorPorClave] Respuesta de API no es un array válido'); + return null; + } + + // Buscar el proveedor por clave + foreach ($proveedores as $proveedor) { + // Probar tanto 'Clave' como 'CLAVE' por si acaso + $proveedor_clave = $proveedor['CLAVE'] ?? $proveedor['Clave'] ?? null; + if ($proveedor_clave === $clave) { + return $proveedor; + } + } + + error_log("[obtenerProveedorPorClave] Proveedor con clave '$clave' no encontrado"); + return null; +} + +function generarHTMLPDF($solicitud, $partidas, $configuracion) { + // Formatear fecha + $fecha_expedicion = $solicitud['fecha_factura']->format('d/m/Y'); + $fecha_vencimiento = $solicitud['fecha_factura']->modify('+30 days')->format('d/m/Y'); // Construir dirección del importador $direccion_completa = trim( @@ -1126,6 +1196,37 @@ function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_u ($solicitud['codigo_postal'] ?? '') ); + // Construir información del proveedor + $proveedor_nombre = 'Proveedor no disponible'; + $proveedor_rfc = 'RFC no disponible'; + $proveedor_direccion = 'Dirección no disponible'; + $proveedor_telefono = 'Teléfono no disponible'; + + // 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'] ?? $proveedor_info['Nombre'] ?? 'Nombre no disponible'; + $proveedor_rfc = $proveedor_info['RFC'] ?? $proveedor_info['IDENTFISCAL'] ?? 'RFC no disponible'; + $proveedor_telefono = trim($proveedor_info['TELEFONO'] ?? $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['Calles'] ?? '', + ($proveedor_info['NUMEXT'] ?? $proveedor_info['NumExt'] ?? '') ? 'Num. Ext: ' . ($proveedor_info['NUMEXT'] ?? $proveedor_info['NumExt']) : '', + ($proveedor_info['NUMINT'] ?? $proveedor_info['NumInt'] ?? '') ? 'Num. Int: ' . ($proveedor_info['NUMINT'] ?? $proveedor_info['NumInt']) : '', + $proveedor_info['COLONIA'] ?? $proveedor_info['Colonia'] ?? '', + $proveedor_info['MUNICIPIO'] ?? $proveedor_info['Municipio'] ?? '', + $proveedor_info['CIUDAD'] ?? $proveedor_info['Ciudad'] ?? '', + ($proveedor_info['CODIGOPOSTAL'] ?? $proveedor_info['CodigoPostal'] ?? '') ? 'C.P. ' . ($proveedor_info['CODIGOPOSTAL'] ?? $proveedor_info['CodigoPostal']) : '', + $proveedor_info['ENTIDADFEDERATIVA'] ?? $proveedor_info['EntidadFederativa'] ?? '', + $proveedor_info['PAIS'] ?? $proveedor_info['Pais'] ?? '' + ]); + + if (!empty($direccion_partes)) { + $proveedor_direccion = implode(', ', $direccion_partes); + } + } + // Calcular el total sumando todas las partidas $total = 0; foreach ($partidas as $partida) { @@ -1189,16 +1290,37 @@ function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_u return trim($resultado); } + // Obtener la moneda de la solicitud o usar MXN por defecto + $moneda_codigo = $solicitud['tipo_moneda'] ?? 'MXN'; + + // 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']; + // Convertir total a texto $partes = explode('.', number_format($total, 2, '.', '')); - $pesos = (int)$partes[0]; - $centavos = (int)$partes[1]; + $enteros = (int)$partes[0]; + $decimales = (int)$partes[1]; - $total_texto = strtoupper(numeroATexto($pesos)) . ' PESOS'; - if ($centavos > 0) { - $total_texto .= ' CON ' . str_pad($centavos, 2, '0', STR_PAD_LEFT) . '/100 M.N.'; + $total_texto = strtoupper(numeroATexto($enteros)) . ' ' . $config_moneda['nombre']; + + // Para JPY no se usan decimales tradicionalmente + if ($moneda_codigo === 'JPY') { + $total_texto .= ' ' . $config_moneda['sufijo']; } else { - $total_texto .= ' 00/100 M.N.'; + if ($decimales > 0) { + $total_texto .= ' CON ' . str_pad($decimales, 2, '0', STR_PAD_LEFT) . '/100 ' . $config_moneda['sufijo']; + } else { + $total_texto .= ' 00/100 ' . $config_moneda['sufijo']; + } } $html = ' @@ -1209,30 +1331,38 @@ function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_u Solicitud de Importación @@ -1242,44 +1372,67 @@ function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_u
-
+
+
' . htmlspecialchars($configuracion['siglas'] ?? 'SIIH') . '
-
' . htmlspecialchars($nombre_sistema) . '
+
' . htmlspecialchars($solicitud['importador_nombre']) . '
' . htmlspecialchars($direccion_completa ?: 'Dirección no disponible') . '
RFC: ' . htmlspecialchars($solicitud['importador_rfc'] ?? 'No disponible') . '
Tel: ' . htmlspecialchars($solicitud['telefono'] ?? 'No disponible') . '
Email: ' . htmlspecialchars($solicitud['correo'] ?? 'No disponible') . '
+
' . htmlspecialchars($configuracion['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos') . '

Solicitud de Importación
No. ' . htmlspecialchars($solicitud['id_solicitud']) . '
-



- - + +
- +
-
RAZÓN SOCIAL: ' . htmlspecialchars($solicitud['importador_nombre'] ?? 'No disponible') . '
-
DOMICILIO FISCAL: ' . htmlspecialchars($direccion_completa) . '
-
RFC: ' . htmlspecialchars($solicitud['importador_rfc'] ?? 'No disponible') . '
-
TELÉFONO: ' . htmlspecialchars($solicitud['telefono'] ?? 'No disponible') . '
-
RÉGIMEN FISCAL: 601-General de Ley Personas Morales
+ +
+ + + + + +
RAZÓN SOCIAL:' . htmlspecialchars($proveedor_nombre) . '
+ + + + + +
DIRECCIÓN:' . htmlspecialchars($proveedor_direccion) . '
+ + + + + +
RFC:' . htmlspecialchars($proveedor_rfc) . '
- - - - - +
FECHA DE EXPEDICIÓN
' . $fecha_expedicion . '
FECHA DE VENCIMIENTO
' . $fecha_vencimiento . '
+ + + +
FECHA DE EXPEDICIÓN
' . $fecha_expedicion . '
FECHA DE VENCIMIENTO
' . $fecha_vencimiento . '
-


+ + + + + + + +
CLAVE:' . htmlspecialchars($solicitud['proveedor_clave'] ?? 'No disponible') . 'TELÉFONO:' . htmlspecialchars($proveedor_telefono) . '
@@ -1300,12 +1453,13 @@ function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_u $cantidad = (float)($partida['cantidad_comercial'] ?? 0); $valor_partida = (float)($partida['valor_factura'] ?? 0); - $html .= ' + $html .= ' + - + - + '; } @@ -1322,7 +1476,7 @@ function generarHTMLPDF($solicitud, $partidas, $nombre_sistema, $siglas, $logo_u
Total: - $' . number_format($total, 2) . ' + ' . $moneda_codigo . ' ' . number_format($total, 2) . '
diff --git a/app/controllers/transportistas.php b/app/controllers/transportistas.php index 2001c08..89a4c60 100644 --- a/app/controllers/transportistas.php +++ b/app/controllers/transportistas.php @@ -89,7 +89,7 @@ function ciudades() { function lista() { include __DIR__ . '/../../views/transportistas/lista.php'; - } +} /** Descarga la plantilla CSV para carga masiva **/ function template() { diff --git a/views/agentes/bitacora.php b/views/agentes/bitacora.php index 5ec545c..55b3269 100644 --- a/views/agentes/bitacora.php +++ b/views/agentes/bitacora.php @@ -14,7 +14,7 @@ - - - - -
-

Panel principal del agente

- -
-
-
-
Importadores activos
-

Consulta los que ya fueron autorizados.

- Ver importadores -
-
- -
-
-
Solicitudes pendientes
-

Valida nuevas solicitudes de registro.

- Ver solicitudes -
-
- -
-
-
Bitácora del sistema
-

Revisa los accesos y acciones recientes.

- Ver bitácora -
-
-
-
- - - diff --git a/views/agentes/dashboard_agentes.php b/views/agentes/dashboard_agentes.php new file mode 100644 index 0000000..0f2a753 --- /dev/null +++ b/views/agentes/dashboard_agentes.php @@ -0,0 +1,88 @@ + + + + + + + Dashboard | Agente Aduanal + + + + + + + + +
+

📦 Panel del Agente Aduanal

+ +
+
+
+
Importadores activos
+

Consulta los que ya fueron autorizados.

+ Ver importadores +
+
+ +
+
+
Solicitudes pendientes
+

Valida nuevas solicitudes de registro.

+ Ver solicitudes +
+
+ +
+
+
Bitácora del sistema
+

Revisa los accesos y acciones recientes.

+ Ver bitácora +
+
+ +
+
+
Locaciones
+

Gestiona la locaciones validas para nuevos registros.

+ Gestionar locaciones +
+
+ +
+
+
Cerrar sesión
+

Salir del sistema de forma segura.

+ Logout +
+
+
+ +
+ + + \ No newline at end of file diff --git a/views/agentes/importadores_activos.php b/views/agentes/importadores_activos.php index 1b43c4c..c77d8bd 100644 --- a/views/agentes/importadores_activos.php +++ b/views/agentes/importadores_activos.php @@ -1,7 +1,4 @@ - + @@ -12,47 +9,62 @@ include __DIR__ . '/../partials/sidebar_agente.php'; -
+

✅ Importadores Activos

-
' . htmlspecialchars($partida['descripcion']) . ' ' . htmlspecialchars($partida['unidad_descripcion'] ?? 'Unidad de servicio (E48)') . '$' . number_format($precio_unitario > 0 ? $precio_unitario : $valor_partida, 2) . '' . $moneda_codigo . ' ' . number_format($precio_unitario > 0 ? $precio_unitario : $valor_partida, 2) . ' ' . number_format($cantidad > 0 ? $cantidad : 1, 0) . '$' . number_format($valor_partida, 2) . '' . $moneda_codigo . ' ' . number_format($valor_partida, 2) . '
- - - - - - - - - - - - - - - - - - - - -
#NombreCorreoFecha RegistroAcciones
format('Y-m-d H:i') : '' ?> - - Suspender - - Activar - -
+
+
+ + + + + + + + + + + + + + + + + + + + + +
#NombreCorreoFecha RegistroAcciones
format('Y-m-d H:i') : '' ?> + + Suspender + + Activar + +
+
+
diff --git a/views/agentes/solicitudes_pendientes.php b/views/agentes/solicitudes_pendientes.php index dbe9f29..7886df0 100644 --- a/views/agentes/solicitudes_pendientes.php +++ b/views/agentes/solicitudes_pendientes.php @@ -1,7 +1,4 @@ - + @@ -11,55 +8,70 @@ include __DIR__ . '/../partials/sidebar_agente.php'; -
+

📥 Solicitudes Pendientes

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
#EmpresaRFCCorreoTeléfonoFechaArchivo SATAcción
format('Y-m-d H:i') : '' ?> - - Ver PDF - - No adjunto - - - Aprobar -
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
#EmpresaRFCCorreoTeléfonoFechaArchivo SATAcción
format('Y-m-d H:i') : '' ?> + + Ver PDF + + No adjunto + + + Aprobar +
+
+
diff --git a/views/bitacoras/bitacora_login.php b/views/bitacoras/bitacora_login.php index f6f2f37..38b64a4 100644 --- a/views/bitacoras/bitacora_login.php +++ b/views/bitacoras/bitacora_login.php @@ -75,7 +75,7 @@ $(document).ready(function () { $('#tabla-logins').DataTable({ language: { - url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json' + url: 'https://cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json' } }); }); diff --git a/views/importadores/dashboard_importador.php b/views/importadores/dashboard_importador.php index a28c49b..32ad700 100644 --- a/views/importadores/dashboard_importador.php +++ b/views/importadores/dashboard_importador.php @@ -18,7 +18,10 @@ .navbar { position: fixed; top: 0; width: 100%; z-index: 1050; } .btn-indigo { background-color: #6610f2; color: white;} .btn-indigo:hover { background-color: #520dc2; color: white;} - .text-indigo { color: #6610f2;} + .text-indigo { color: orangeRed;} + .btn-orange { background-color: orangeRed; color: white;} + .btn-orange:hover { background-color: #ff3600; color: white;} + .text-orange { color: orangeRed;} /* A partir de dispositivos medianos (>=768px), deja espacio lateral */ @media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } } /* En móviles, sin margen lateral */ @@ -92,6 +95,17 @@
+
+
+
Locaciones
+

Visualiza las locaciones registradas.

+ + Ver locaciones + +
+
+
Cerrar sesión
diff --git a/views/locaciones/alta_locaciones.php b/views/locaciones/alta_locaciones.php new file mode 100644 index 0000000..949b361 --- /dev/null +++ b/views/locaciones/alta_locaciones.php @@ -0,0 +1,286 @@ + + + + + + + Dashboard | Agente Aduanal + + + + + + + + +
+

🗺️ Nuevas Locaciones

+
+ + +
+
+
+

➕ Nuevo Estado


+ +
+ + +



+ + +
+ + +


+ +
+ + Cancelar +
+
+ +
+
+ + +
+
+
+

➕ Nueva Ciudad

+ +
+ + +

+ + +
+ + +

+ + +
+ + +

+ +
+ + Cancelar +
+
+
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/views/locaciones/gestion_locaciones.php b/views/locaciones/gestion_locaciones.php new file mode 100644 index 0000000..3ab8162 --- /dev/null +++ b/views/locaciones/gestion_locaciones.php @@ -0,0 +1,492 @@ + + + + + + + Dashboard | Agente Aduanal + + + + + + + + + + + + +
+

🌍 Locaciones

+ ➕ Agregar Locación +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID PaísPaísISO3ID EstadoEstadoID CiudadCiudadAcciones
+ + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/views/locaciones/lista.php b/views/locaciones/lista.php new file mode 100644 index 0000000..ff878f9 --- /dev/null +++ b/views/locaciones/lista.php @@ -0,0 +1,85 @@ + + + + + + + 🌍 Locaciones + + + + + + + + + + + + +
+

🗺️ Locaciones

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ID PaísPaísISO3ID EstadoEstadoID CiudadCiudad
+
+
+
+ + + + + \ No newline at end of file diff --git a/views/login/verificar_codigo.php b/views/login/verificar_codigo.php index a61a6d0..2f68e66 100644 --- a/views/login/verificar_codigo.php +++ b/views/login/verificar_codigo.php @@ -119,16 +119,7 @@ if (!isset($_SESSION['email_recuperacion'])) { Código de verificación
- + diff --git a/views/partials/sidebar_agente.php b/views/partials/sidebar_agente.php index 3a820a5..f4340fa 100644 --- a/views/partials/sidebar_agente.php +++ b/views/partials/sidebar_agente.php @@ -1,30 +1,146 @@ + + -
diff --git a/views/transportes/editar.php b/views/transportes/editar.php index 12ba27f..3cc62ed 100644 --- a/views/transportes/editar.php +++ b/views/transportes/editar.php @@ -75,6 +75,7 @@
+ Cancelar
diff --git a/views/transportes/importar_masivo.php b/views/transportes/importar_masivo.php index 8feaf9d..df0a5b5 100644 --- a/views/transportes/importar_masivo.php +++ b/views/transportes/importar_masivo.php @@ -62,6 +62,7 @@ 📥 Descargar plantilla
+ Cancelar diff --git a/views/transportistas/alta.php b/views/transportistas/alta.php index 422e66b..6f2933e 100644 --- a/views/transportistas/alta.php +++ b/views/transportistas/alta.php @@ -95,6 +95,7 @@
+ Cancelar
diff --git a/views/transportistas/bulk_upload.php b/views/transportistas/bulk_upload.php index 3410446..b9abbd9 100644 --- a/views/transportistas/bulk_upload.php +++ b/views/transportistas/bulk_upload.php @@ -61,6 +61,7 @@ unset($_SESSION['import_errors'], $_SESSION['import_success']); + Cancelar diff --git a/views/transportistas/editar.php b/views/transportistas/editar.php index 655256c..b62e953 100644 --- a/views/transportistas/editar.php +++ b/views/transportistas/editar.php @@ -110,6 +110,7 @@
+ Cancelar
diff --git a/views/transportistas/lista.php b/views/transportistas/lista.php index 8240576..982f2e1 100644 --- a/views/transportistas/lista.php +++ b/views/transportistas/lista.php @@ -1,4 +1,3 @@ -