From b1b9e4a77cef8c284b2cd5d652942b345f8623cb Mon Sep 17 00:00:00 2001 From: ernestohc21 Date: Tue, 21 Oct 2025 11:41:30 -0600 Subject: [PATCH] grales --- app/controllers/catalogo_pedimentos.php | 558 +++++ app/controllers/claves_pedimentos.php | 553 ++++ app/controllers/login.php | 36 +- app/controllers/mve.php | 190 ++ app/controllers/seguridad.php | 277 ++ app/controllers/solicitud_importacion.php | 101 +- app/controllers/templates_rapidos.php | 913 +++++++ app/controllers/winsaai.php | 237 ++ claves_pedimentos_tabla.sql | 21 + configuracion_ventanilla_unica.sql | 97 + create_table_temp.php | 52 + debug_templates.php | 196 ++ mve_incrementales_decrementales.sql | 90 + previos_tabla.sql | 58 + .../downloads/claves_pedimentos_template.csv | 6 + storage/certificados/cer_46_1760569052.cer | Bin 0 -> 1595 bytes storage/certificados/cer_46_1760569397.cer | Bin 0 -> 1595 bytes storage/certificados/key_46_1760569052.key | Bin 0 -> 1298 bytes storage/certificados/key_46_1760569397.key | Bin 0 -> 1298 bytes templates_rapidos.sql | 83 + test_templates.php | 157 ++ views/automatizaciones/automatizaciones.php | 712 +++++- views/catalogo_pedimentos/crear.php | 407 +++ views/catalogo_pedimentos/editar.php | 380 +++ views/catalogo_pedimentos/index.php | 166 ++ views/catalogo_pedimentos/lista.php | 194 ++ views/claves_pedimentos/crear.php | 230 ++ views/claves_pedimentos/editar.php | 280 +++ views/claves_pedimentos/importar_csv.php | 226 ++ views/claves_pedimentos/index.php | 170 ++ views/claves_pedimentos/lista.php | 204 ++ views/home/inicio.php | 508 +++- views/login/cambiar_password.php | 629 ++++- views/login/confirmacion.php | 508 +++- views/login/index.php | 345 ++- views/login/recuperar.php | 479 +++- views/login/verificar_codigo.php | 845 ++++--- views/mve/lista.php | 701 ++++++ views/partials/sidebar_importador.php | 132 +- views/registro/form.php | 752 ++++-- views/seguridad/dashboard_seguridad.php | 19 + views/seguridad/ventanilla_unica.php | 349 +++ views/solicitud_importacion/crear.php | 2219 +++++++++++------ views/solicitud_importacion/editar.php | 2 +- views/templates_rapidos/crear.php | 790 ++++++ views/templates_rapidos/editar.php | 494 ++++ views/templates_rapidos/lista.php | 948 +++++++ winsaai_config_sqlserver.sql | 35 + winsaai_config_updated.sql | 19 + 49 files changed, 14632 insertions(+), 1736 deletions(-) create mode 100644 app/controllers/catalogo_pedimentos.php create mode 100644 app/controllers/claves_pedimentos.php create mode 100644 app/controllers/mve.php create mode 100644 app/controllers/templates_rapidos.php create mode 100644 app/controllers/winsaai.php create mode 100644 claves_pedimentos_tabla.sql create mode 100644 configuracion_ventanilla_unica.sql create mode 100644 create_table_temp.php create mode 100644 debug_templates.php create mode 100644 mve_incrementales_decrementales.sql create mode 100644 previos_tabla.sql create mode 100644 public/downloads/claves_pedimentos_template.csv create mode 100644 storage/certificados/cer_46_1760569052.cer create mode 100644 storage/certificados/cer_46_1760569397.cer create mode 100644 storage/certificados/key_46_1760569052.key create mode 100644 storage/certificados/key_46_1760569397.key create mode 100644 templates_rapidos.sql create mode 100644 test_templates.php create mode 100644 views/catalogo_pedimentos/crear.php create mode 100644 views/catalogo_pedimentos/editar.php create mode 100644 views/catalogo_pedimentos/index.php create mode 100644 views/catalogo_pedimentos/lista.php create mode 100644 views/claves_pedimentos/crear.php create mode 100644 views/claves_pedimentos/editar.php create mode 100644 views/claves_pedimentos/importar_csv.php create mode 100644 views/claves_pedimentos/index.php create mode 100644 views/claves_pedimentos/lista.php create mode 100644 views/mve/lista.php create mode 100644 views/seguridad/ventanilla_unica.php create mode 100644 views/templates_rapidos/crear.php create mode 100644 views/templates_rapidos/editar.php create mode 100644 views/templates_rapidos/lista.php create mode 100644 winsaai_config_sqlserver.sql create mode 100644 winsaai_config_updated.sql diff --git a/app/controllers/catalogo_pedimentos.php b/app/controllers/catalogo_pedimentos.php new file mode 100644 index 0000000..0bba1d5 --- /dev/null +++ b/app/controllers/catalogo_pedimentos.php @@ -0,0 +1,558 @@ + intval($_GET['draw'] ?? 0), + "recordsTotal" => 0, + "recordsFiltered" => 0, + "data" => [], + "error" => "Error al consultar información del importador" + ]); + exit; + } + + $importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC); + + if (!$importador) { + echo json_encode([ + "draw" => intval($_GET['draw'] ?? 0), + "recordsTotal" => 0, + "recordsFiltered" => 0, + "data" => [] + ]); + exit; + } + + // Parámetros de DataTables + $draw = intval($_GET['draw'] ?? 0); + $start = intval($_GET['start'] ?? 0); + $length = intval($_GET['length'] ?? 10); + $search = $_GET['search']['value'] ?? ''; + + // Total registros sin filtro + $sqlTotal = "SELECT COUNT(*) AS total FROM PREVIOS_COMPARTIDOS_WS WHERE ClienteRFC = ?"; + $stmt = sqlsrv_query($conn, $sqlTotal, [$importador['rfc']]); + + if ($stmt === false) { + echo json_encode([ + "draw" => $draw, + "recordsTotal" => 0, + "recordsFiltered" => 0, + "data" => [], + "error" => "Error al contar registros totales" + ]); + exit; + } + + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + $recordsTotal = (int)($row['total'] ?? 0); + + // Construir condiciones de filtro + $where = "ClienteRFC = ?"; + $params = [$importador['rfc']]; + + if ($search !== '') { + $where .= " AND (Pedimento LIKE ? OR ClienteNombre LIKE ? OR ClavePed LIKE ?)"; + $like = "%{$search}%"; + $params = array_merge($params, [$like, $like, $like]); + } + + // Total registros filtrados + $sqlFiltered = "SELECT COUNT(*) AS total FROM PREVIOS_COMPARTIDOS_WS WHERE $where"; + $stmtF = sqlsrv_query($conn, $sqlFiltered, $params); + + if ($stmtF === false) { + echo json_encode([ + "draw" => $draw, + "recordsTotal" => $recordsTotal, + "recordsFiltered" => 0, + "data" => [], + "error" => "Error al contar registros filtrados" + ]); + exit; + } + + $rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC); + $recordsFiltered = (int)($rowF['total'] ?? 0); + + // Datos de la página + $sqlData = "SELECT IdPrevio, Pedimento, ClienteRFC, ClienteNombre, Timestamp, Status + FROM PREVIOS_COMPARTIDOS_WS + WHERE $where + ORDER BY Timestamp DESC + OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; + $params[] = $start; + $params[] = $length; + + $stmtD = sqlsrv_query($conn, $sqlData, $params); + + $data = []; + if ($stmtD !== false) { + while ($r = sqlsrv_fetch_array($stmtD, SQLSRV_FETCH_ASSOC)) { + $timestamp = $r['Timestamp'] instanceof DateTime ? $r['Timestamp']->format('Y-m-d H:i:s') : ''; + $status_text = $r['Status'] == 1 ? 'Activo' : 'Inactivo'; + + $data[] = [ + $r['IdPrevio'], + $r['Pedimento'], + $r['ClienteRFC'], + $r['ClienteNombre'], + $timestamp, + $status_text + ]; + } + } + + $response = [ + "draw" => $draw, + "recordsTotal" => $recordsTotal, + "recordsFiltered" => $recordsFiltered, + "data" => $data + ]; + + header('Content-Type: application/json; charset=UTF-8'); + echo json_encode($response, JSON_UNESCAPED_UNICODE); + exit; +} + +function buscar_pedimentos() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + http_response_code(403); + echo json_encode([]); + exit; + } + + $id_usuario = $_SESSION['usuario_id']; + $query = trim($_GET['q'] ?? ''); + $limit = intval($_GET['limit'] ?? 10); // ✅ NUEVO: Parámetro limit con valor por defecto + + // ✅ MODIFICADO: Para el panel de referencia, si no hay query, traer los más recientes + if (empty($query)) { + // Si no hay query, obtener los pedimentos más recientes para el panel de referencia + $whereCondition = "ClienteRFC = ? AND Status = 1"; + $searchParams = []; + } else { + // Si hay query, mantener la lógica original de búsqueda + if (strlen($query) < 3) { + echo json_encode([]); + exit; + } + $whereCondition = "ClienteRFC = ? AND (Pedimento LIKE ? OR ClienteNombre LIKE ? OR ClavePed LIKE ?) AND Status = 1"; + $like = "%{$query}%"; + $searchParams = [$like, $like, $like]; + } + + $conn = getConnection(); + + // Obtener RFC del usuario para filtrar solo sus pedimentos + $sqlImportador = "SELECT rfc FROM informacion_general WHERE id_usuario = ?"; + $stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]); + + if ($stmtImportador === false) { + echo json_encode([]); + exit; + } + + $importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC); + + if (!$importador) { + echo json_encode([]); + exit; + } + + // ✅ MODIFICADO: Query dinámico con límite configurable + $sql = "SELECT TOP {$limit} IdPrevio, Pedimento, ClienteRFC, ClienteNombre, ClavePed, Timestamp + FROM PREVIOS_COMPARTIDOS_WS + WHERE {$whereCondition} + ORDER BY Timestamp DESC"; + + $params = array_merge([$importador['rfc']], $searchParams); + $stmt = sqlsrv_query($conn, $sql, $params); + + $pedimentos = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $fecha_formateada = ''; + if ($row['Timestamp'] instanceof DateTime) { + $fecha_formateada = $row['Timestamp']->format('d/m/Y'); + } + + $pedimentos[] = [ + 'IdPrevio' => $row['IdPrevio'], + 'Pedimento' => $row['Pedimento'], + 'ClienteRFC' => $row['ClienteRFC'], + 'ClienteNombre' => $row['ClienteNombre'], + 'ClavePed' => $row['ClavePed'], + 'fecha_formateada' => $fecha_formateada + ]; + } + } + + header('Content-Type: application/json; charset=UTF-8'); + echo json_encode($pedimentos, JSON_UNESCAPED_UNICODE); + exit; +} \ No newline at end of file diff --git a/app/controllers/claves_pedimentos.php b/app/controllers/claves_pedimentos.php new file mode 100644 index 0000000..c8c522b --- /dev/null +++ b/app/controllers/claves_pedimentos.php @@ -0,0 +1,553 @@ + 10) { + die("❌ El código no puede tener más de 10 caracteres."); + } + + if (!preg_match('/^[A-Z0-9]+$/', $codigo)) { + die("❌ El código solo puede contener letras y números."); + } + + // Verificar que no exista el código para este usuario + $sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario WHERE id_usuario = ? AND codigo = ?"; + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario, $codigo]); + + if ($stmtCheck === false) { + die("❌ Error al verificar código existente: " . print_r(sqlsrv_errors(), true)); + } + + $result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + + if ($result['count'] > 0) { + die("❌ Ya existe una clave con el código '{$codigo}' para este usuario."); + } + + $sql = "INSERT INTO claves_pedimentos_usuario + (id_usuario, codigo, descripcion, tipo_operacion, activo, fecha_creacion, fecha_modificacion) + VALUES (?, ?, ?, ?, ?, GETDATE(), GETDATE())"; + + $params = [$id_usuario, $codigo, $descripcion, $tipo_operacion, $activo]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + die("❌ Error al guardar: " . print_r(sqlsrv_errors(), true)); + } + + header('Location: /IMPORTADORES/claves_pedimentos/lista?created=ok'); + exit; +} + +function editar() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + header('Location: /IMPORTADORES/login'); + exit; + } + + $id = $_GET['id'] ?? null; + $id_usuario = $_SESSION['usuario_id']; + + if (!$id || !is_numeric($id)) { + die("❌ ID inválido."); + } + + $conn = getConnection(); + + $sql = "SELECT * FROM claves_pedimentos_usuario WHERE id_clave_pedimento = ? AND id_usuario = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id, $id_usuario]); + + if ($stmt === false) { + die("❌ Error en consulta: " . print_r(sqlsrv_errors(), true)); + } + + $clave = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + + if (!$clave) { + die("❌ Clave de pedimento no encontrada."); + } + + include __DIR__ . '/../../views/claves_pedimentos/editar.php'; +} + +function actualizar() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + die("⚠️ No autorizado."); + } + + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id']; + + $id_clave_pedimento = $_POST['id_clave_pedimento'] ?? null; + $codigo = strtoupper(trim($_POST['codigo'] ?? '')); + $descripcion = trim($_POST['descripcion'] ?? ''); + $tipo_operacion = $_POST['tipo_operacion'] ?? 'importacion'; + $activo = isset($_POST['activo']) ? 1 : 0; + + if (!$id_clave_pedimento || !is_numeric($id_clave_pedimento)) { + die("❌ ID inválido."); + } + + // Validaciones + if (empty($codigo) || empty($descripcion)) { + die("❌ El código y descripción son obligatorios."); + } + + if (strlen($codigo) > 10) { + die("❌ El código no puede tener más de 10 caracteres."); + } + + if (!preg_match('/^[A-Z0-9]+$/', $codigo)) { + die("❌ El código solo puede contener letras y números."); + } + + // Verificar que no exista otro código igual (excepto el actual) + $sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario + WHERE id_usuario = ? AND codigo = ? AND id_clave_pedimento != ?"; + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario, $codigo, $id_clave_pedimento]); + + if ($stmtCheck === false) { + die("❌ Error al verificar código existente: " . print_r(sqlsrv_errors(), true)); + } + + $result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + + if ($result['count'] > 0) { + die("❌ Ya existe otra clave con el código '{$codigo}' para este usuario."); + } + + $sql = "UPDATE claves_pedimentos_usuario SET + codigo = ?, descripcion = ?, tipo_operacion = ?, activo = ?, fecha_modificacion = GETDATE() + WHERE id_clave_pedimento = ? AND id_usuario = ?"; + + $params = [$codigo, $descripcion, $tipo_operacion, $activo, $id_clave_pedimento, $id_usuario]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true)); + } + + header('Location: /IMPORTADORES/claves_pedimentos/lista?updated=ok'); + exit; +} + +function eliminar() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + header('Location: /IMPORTADORES/login'); + exit; + } + + $id = $_GET['id'] ?? null; + $id_usuario = $_SESSION['usuario_id']; + + if (!$id || !is_numeric($id)) { + die("❌ ID inválido."); + } + + $conn = getConnection(); + + $sql = "DELETE FROM claves_pedimentos_usuario WHERE id_clave_pedimento = ? AND id_usuario = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id, $id_usuario]); + + if ($stmt === false) { + die("❌ Error al eliminar: " . print_r(sqlsrv_errors(), true)); + } + + header('Location: /IMPORTADORES/claves_pedimentos/lista?deleted=ok'); + exit; +} + +function ajax_lista() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + http_response_code(403); + echo json_encode([]); + exit; + } + + $id_usuario = $_SESSION['usuario_id']; + $conn = getConnection(); + + // Parámetros de DataTables + $draw = intval($_GET['draw'] ?? 0); + $start = intval($_GET['start'] ?? 0); + $length = intval($_GET['length'] ?? 10); + $search = $_GET['search']['value'] ?? ''; + + // Total registros sin filtro + $sqlTotal = "SELECT COUNT(*) AS total FROM claves_pedimentos_usuario WHERE id_usuario = ?"; + $stmt = sqlsrv_query($conn, $sqlTotal, [$id_usuario]); + + if ($stmt === false) { + echo json_encode([ + "draw" => $draw, + "recordsTotal" => 0, + "recordsFiltered" => 0, + "data" => [], + "error" => "Error al contar registros totales" + ]); + exit; + } + + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + $recordsTotal = (int)($row['total'] ?? 0); + + // Construir condiciones de filtro + $where = "id_usuario = ?"; + $params = [$id_usuario]; + + if ($search !== '') { + $where .= " AND (codigo LIKE ? OR descripcion LIKE ? OR tipo_operacion LIKE ?)"; + $like = "%{$search}%"; + $params = array_merge($params, [$like, $like, $like]); + } + + // Total registros filtrados + $sqlFiltered = "SELECT COUNT(*) AS total FROM claves_pedimentos_usuario WHERE $where"; + $stmtF = sqlsrv_query($conn, $sqlFiltered, $params); + + if ($stmtF === false) { + echo json_encode([ + "draw" => $draw, + "recordsTotal" => $recordsTotal, + "recordsFiltered" => 0, + "data" => [], + "error" => "Error al contar registros filtrados" + ]); + exit; + } + + $rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC); + $recordsFiltered = (int)($rowF['total'] ?? 0); + + // Datos de la página + $sqlData = "SELECT id_clave_pedimento, codigo, descripcion, tipo_operacion, + CASE WHEN activo = 1 THEN 'Activo' ELSE 'Inactivo' END as estado, + FORMAT(fecha_creacion, 'dd/MM/yyyy HH:mm') as fecha_creacion + FROM claves_pedimentos_usuario + WHERE $where + ORDER BY codigo ASC + OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; + $params[] = $start; + $params[] = $length; + + $stmtD = sqlsrv_query($conn, $sqlData, $params); + + $data = []; + if ($stmtD !== false) { + while ($r = sqlsrv_fetch_array($stmtD, SQLSRV_FETCH_ASSOC)) { + $data[] = [ + $r['id_clave_pedimento'], + $r['codigo'], + $r['descripcion'], + ucfirst($r['tipo_operacion']), + $r['estado'], + $r['fecha_creacion'] + ]; + } + } + + $response = [ + "draw" => $draw, + "recordsTotal" => $recordsTotal, + "recordsFiltered" => $recordsFiltered, + "data" => $data + ]; + + header('Content-Type: application/json; charset=UTF-8'); + echo json_encode($response, JSON_UNESCAPED_UNICODE); + exit; +} + +function inicializar_claves_usuario() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + header('Location: /IMPORTADORES/login'); + exit; + } + + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id']; + + // Verificar si ya tiene claves configuradas + $sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario WHERE id_usuario = ?"; + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario]); + + if ($stmtCheck === false) { + die("❌ Error al verificar claves existentes: " . print_r(sqlsrv_errors(), true)); + } + + $result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + + if ($result['count'] > 0) { + header('Location: /IMPORTADORES/claves_pedimentos/lista?info=already_initialized'); + exit; + } + + // Claves de pedimentos por defecto para importación + $claves_default = [ + ['A1', 'Importación definitiva de mercancías', 'importacion'], + ['A3', 'Importación definitiva de vehículos usados', 'importacion'], + ['A4', 'Importación definitiva de vehículos nuevos', 'importacion'], + ['B1', 'Importación temporal para elaborar, transformar o reparar', 'importacion'], + ['C1', 'Importación definitiva de mercancías donadas', 'importacion'], + ['G1', 'Importación de mercancías con Programa IMMEX', 'importacion'], + ['I1', 'Importación definitiva exenta', 'importacion'], + ['J1', 'Importación temporal para reexportación en el mismo estado', 'importacion'], + ['L1', 'Importación definitiva con franquicia arancelaria con TLC', 'importacion'], + ['M1', 'Importación de menajes de casa', 'importacion'], + ['N1', 'Importación de equipaje', 'importacion'], + ['P1', 'Importación temporal de remolques y semirremolques', 'importacion'], + ['R1', 'Importación temporal de contenedores', 'importacion'], + ['S1', 'Importación temporal de vehículos', 'importacion'], + ['T1', 'Importación temporal de enseres de tripulantes', 'importacion'], + ['V1', 'Importación temporal de mercancías para exposición', 'importacion'] + ]; + + $sql = "INSERT INTO claves_pedimentos_usuario + (id_usuario, codigo, descripcion, tipo_operacion, activo, fecha_creacion, fecha_modificacion) + VALUES (?, ?, ?, ?, 1, GETDATE(), GETDATE())"; + + $insertadas = 0; + foreach ($claves_default as $clave) { + $params = [$id_usuario, $clave[0], $clave[1], $clave[2]]; + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt !== false) { + $insertadas++; + } + } + + if ($insertadas > 0) { + header('Location: /IMPORTADORES/claves_pedimentos/lista?created=initialized'); + } else { + die("❌ Error al inicializar las claves de pedimentos."); + } + exit; +} + +function importar_csv() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + header('Location: /IMPORTADORES/login'); + exit; + } + + include __DIR__ . '/../../views/claves_pedimentos/importar_csv.php'; +} + +function procesar_csv() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + die("⚠️ No autorizado."); + } + + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id']; + + // Verificar que se subió un archivo + if (!isset($_FILES['csv_file']) || $_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) { + die("❌ Error: No se pudo cargar el archivo CSV."); + } + + $archivo_csv = $_FILES['csv_file']['tmp_name']; + $nombre_archivo = $_FILES['csv_file']['name']; + + // Validar extensión + if (!str_ends_with(strtolower($nombre_archivo), '.csv')) { + die("❌ Error: El archivo debe tener extensión .csv"); + } + + // Opciones de importación + $omitir_duplicados = isset($_POST['omitir_duplicados']); + $activar_todas = isset($_POST['activar_todas']); + + try { + // Leer archivo CSV + $archivo = fopen($archivo_csv, 'r'); + if (!$archivo) { + die("❌ Error: No se pudo abrir el archivo CSV."); + } + + // Leer encabezados + $encabezados = fgetcsv($archivo, 1000, ','); + if (!$encabezados) { + fclose($archivo); + die("❌ Error: El archivo CSV está vacío o no tiene el formato correcto."); + } + + // Validar encabezados requeridos + $encabezados_requeridos = ['codigo', 'descripcion', 'tipo_operacion', 'activo']; + $encabezados_faltantes = array_diff($encabezados_requeridos, $encabezados); + + if (!empty($encabezados_faltantes)) { + fclose($archivo); + die("❌ Error: Faltan las siguientes columnas: " . implode(', ', $encabezados_faltantes)); + } + + $insertadas = 0; + $omitidas = 0; + $errores = []; + $fila_numero = 1; + + // SQL para verificar códigos existentes + $sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario WHERE id_usuario = ? AND codigo = ?"; + + // SQL para insertar + $sqlInsert = "INSERT INTO claves_pedimentos_usuario + (id_usuario, codigo, descripcion, tipo_operacion, activo, fecha_creacion, fecha_modificacion) + VALUES (?, ?, ?, ?, ?, GETDATE(), GETDATE())"; + + // Procesar cada fila + while (($fila = fgetcsv($archivo, 1000, ',')) !== FALSE) { + $fila_numero++; + + if (count($fila) < count($encabezados_requeridos)) { + $errores[] = "Fila $fila_numero: Datos insuficientes"; + continue; + } + + // Crear array asociativo + $datos = array_combine($encabezados, $fila); + + // Validar datos + $codigo = strtoupper(trim($datos['codigo'])); + $descripcion = trim($datos['descripcion']); + $tipo_operacion = trim($datos['tipo_operacion']); + $activo = $activar_todas ? 1 : (int)($datos['activo'] ?? 1); + + // Validaciones + if (empty($codigo)) { + $errores[] = "Fila $fila_numero: Código vacío"; + continue; + } + + if (empty($descripcion)) { + $errores[] = "Fila $fila_numero: Descripción vacía"; + continue; + } + + if (!in_array($tipo_operacion, ['importacion', 'exportacion'])) { + $errores[] = "Fila $fila_numero: Tipo de operación inválido ($tipo_operacion)"; + continue; + } + + if (strlen($codigo) > 10) { + $errores[] = "Fila $fila_numero: Código muy largo (máximo 10 caracteres)"; + continue; + } + + if (!preg_match('/^[A-Z0-9]+$/', $codigo)) { + $errores[] = "Fila $fila_numero: Código inválido (solo letras y números)"; + continue; + } + + // Verificar si ya existe + if ($omitir_duplicados) { + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario, $codigo]); + + if ($stmtCheck === false) { + $errores[] = "Fila $fila_numero: Error al verificar código existente"; + continue; + } + + $result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + + if ($result['count'] > 0) { + $omitidas++; + continue; + } + } + + // Insertar registro + $params = [$id_usuario, $codigo, $descripcion, $tipo_operacion, $activo]; + $stmt = sqlsrv_query($conn, $sqlInsert, $params); + + if ($stmt === false) { + $sql_errors = sqlsrv_errors(); + $errores[] = "Fila $fila_numero: Error al insertar - " . $sql_errors[0]['message']; + } else { + $insertadas++; + } + } + + fclose($archivo); + + // Preparar mensaje de resultado + $mensaje = "✅ Proceso completado:"; + $mensaje .= "
• Registros insertados: $insertadas"; + if ($omitidas > 0) { + $mensaje .= "
• Registros omitidos (duplicados): $omitidas"; + } + if (!empty($errores)) { + $mensaje .= "
• Errores encontrados: " . count($errores); + $mensaje .= "

Detalle de errores:
" . implode("
", array_slice($errores, 0, 10)); + if (count($errores) > 10) { + $mensaje .= "
... y " . (count($errores) - 10) . " errores más."; + } + } + + // Redirigir con resultado + $encoded_message = urlencode($mensaje); + header("Location: /IMPORTADORES/claves_pedimentos/lista?imported=ok&message=" . $encoded_message); + exit; + + } catch (Exception $e) { + die("❌ Error inesperado: " . $e->getMessage()); + } +} \ No newline at end of file diff --git a/app/controllers/login.php b/app/controllers/login.php index f1423a1..8ef9dc5 100644 --- a/app/controllers/login.php +++ b/app/controllers/login.php @@ -1112,4 +1112,38 @@ function cambiarPassword() "; -} \ No newline at end of file +} + +// MÉTODOS ADICIONALES CON NOMBRES DE RUTA COMPATIBLES + +function enviar_codigo() +{ + // Redirigir al método camelCase existente + return enviarCodigo(); +} + +function verificar_codigo_recuperacion() +{ + // Redirigir al método camelCase existente + return verificarCodigo(); +} + +function reenviar_codigo() +{ + // Redirigir al método camelCase existente + return reenviarCodigo(); +} + +function actualizar_password() +{ + // Redirigir al método camelCase existente + return cambiarPassword(); +} + +function verificar_codigo() +{ + // Mostrar vista de verificar código + return verificarCodigoVista(); +} + +?> \ No newline at end of file diff --git a/app/controllers/mve.php b/app/controllers/mve.php new file mode 100644 index 0000000..21f9f6c --- /dev/null +++ b/app/controllers/mve.php @@ -0,0 +1,190 @@ + false, 'message' => 'Usuario no autenticado']); + return; + } + + $id_factura = $_POST['id_factura'] ?? null; + $id_pedimento = $_POST['id_pedimento'] ?? null; + $datos_art65 = json_decode($_POST['datos_art65'] ?? '{}', true); + $datos_art66 = json_decode($_POST['datos_art66'] ?? '{}', true); + + if (!$id_factura || !$id_pedimento) { + echo json_encode(['success' => false, 'message' => 'Faltan datos requeridos']); + return; + } + + $db = getDB(); + + // Verificar si ya existen datos para esta factura + $stmt = $db->prepare("SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?"); + $stmt->execute([$id_pedimento, $id_factura]); + $existe = $stmt->fetch(); + + if ($existe) { + // Actualizar registro existente + $sql = "UPDATE mve_facturas_datos SET + art65_fecha_transporte = ?, art65_importe_transporte = ?, + art65_fecha_descuentos = ?, art65_importe_descuentos = ?, + art65_fecha_posteriores = ?, art65_importe_posteriores = ?, + art65_fecha_contribuciones = ?, art65_importe_contribuciones = ?, + art65_fecha_pagos_vendedor = ?, art65_importe_pagos_vendedor = ?, + + art66_fecha_comisiones = ?, art66_importe_comisiones = ?, art66_cargo_comisiones = ?, + art66_fecha_envases = ?, art66_importe_envases = ?, art66_cargo_envases = ?, + art66_fecha_embalaje = ?, art66_importe_embalaje = ?, art66_cargo_embalaje = ?, + art66_fecha_transporte_dec = ?, art66_importe_transporte_dec = ?, art66_cargo_transporte_dec = ?, + art66_fecha_ingenieria = ?, art66_importe_ingenieria = ?, art66_cargo_ingenieria = ?, + art66_fecha_regalias = ?, art66_importe_regalias = ?, art66_cargo_regalias = ?, + art66_fecha_producto = ?, art66_importe_producto = ?, art66_cargo_producto = ?, + + fecha_actualizacion = NOW() + WHERE id_pedimento = ? AND id_factura = ?"; + + $params = [ + $datos_art65['fecha_transporte'] ?: null, $datos_art65['importe_transporte'] ?: null, + $datos_art65['fecha_descuentos'] ?: null, $datos_art65['importe_descuentos'] ?: null, + $datos_art65['fecha_posteriores'] ?: null, $datos_art65['importe_posteriores'] ?: null, + $datos_art65['fecha_contribuciones'] ?: null, $datos_art65['importe_contribuciones'] ?: null, + $datos_art65['fecha_pagos_vendedor'] ?: null, $datos_art65['importe_pagos_vendedor'] ?: null, + + $datos_art66['fecha_comisiones'] ?: null, $datos_art66['importe_comisiones'] ?: null, $datos_art66['cargo_comisiones'] ?: null, + $datos_art66['fecha_envases'] ?: null, $datos_art66['importe_envases'] ?: null, $datos_art66['cargo_envases'] ?: null, + $datos_art66['fecha_embalaje'] ?: null, $datos_art66['importe_embalaje'] ?: null, $datos_art66['cargo_embalaje'] ?: null, + $datos_art66['fecha_transporte_dec'] ?: null, $datos_art66['importe_transporte_dec'] ?: null, $datos_art66['cargo_transporte_dec'] ?: null, + $datos_art66['fecha_ingenieria'] ?: null, $datos_art66['importe_ingenieria'] ?: null, $datos_art66['cargo_ingenieria'] ?: null, + $datos_art66['fecha_regalias'] ?: null, $datos_art66['importe_regalias'] ?: null, $datos_art66['cargo_regalias'] ?: null, + $datos_art66['fecha_producto'] ?: null, $datos_art66['importe_producto'] ?: null, $datos_art66['cargo_producto'] ?: null, + + $id_pedimento, $id_factura + ]; + } else { + // Crear nuevo registro + $sql = "INSERT INTO mve_facturas_datos ( + id_pedimento, id_factura, numero_factura, + art65_fecha_transporte, art65_importe_transporte, + art65_fecha_descuentos, art65_importe_descuentos, + art65_fecha_posteriores, art65_importe_posteriores, + art65_fecha_contribuciones, art65_importe_contribuciones, + art65_fecha_pagos_vendedor, art65_importe_pagos_vendedor, + + art66_fecha_comisiones, art66_importe_comisiones, art66_cargo_comisiones, + art66_fecha_envases, art66_importe_envases, art66_cargo_envases, + art66_fecha_embalaje, art66_importe_embalaje, art66_cargo_embalaje, + art66_fecha_transporte_dec, art66_importe_transporte_dec, art66_cargo_transporte_dec, + art66_fecha_ingenieria, art66_importe_ingenieria, art66_cargo_ingenieria, + art66_fecha_regalias, art66_importe_regalias, art66_cargo_regalias, + art66_fecha_producto, art66_importe_producto, art66_cargo_producto, + + usuario_creacion + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + $params = [ + $id_pedimento, $id_factura, "FACTURA-$id_factura", + $datos_art65['fecha_transporte'] ?: null, $datos_art65['importe_transporte'] ?: null, + $datos_art65['fecha_descuentos'] ?: null, $datos_art65['importe_descuentos'] ?: null, + $datos_art65['fecha_posteriores'] ?: null, $datos_art65['importe_posteriores'] ?: null, + $datos_art65['fecha_contribuciones'] ?: null, $datos_art65['importe_contribuciones'] ?: null, + $datos_art65['fecha_pagos_vendedor'] ?: null, $datos_art65['importe_pagos_vendedor'] ?: null, + + $datos_art66['fecha_comisiones'] ?: null, $datos_art66['importe_comisiones'] ?: null, $datos_art66['cargo_comisiones'] ?: null, + $datos_art66['fecha_envases'] ?: null, $datos_art66['importe_envases'] ?: null, $datos_art66['cargo_envases'] ?: null, + $datos_art66['fecha_embalaje'] ?: null, $datos_art66['importe_embalaje'] ?: null, $datos_art66['cargo_embalaje'] ?: null, + $datos_art66['fecha_transporte_dec'] ?: null, $datos_art66['importe_transporte_dec'] ?: null, $datos_art66['cargo_transporte_dec'] ?: null, + $datos_art66['fecha_ingenieria'] ?: null, $datos_art66['importe_ingenieria'] ?: null, $datos_art66['cargo_ingenieria'] ?: null, + $datos_art66['fecha_regalias'] ?: null, $datos_art66['importe_regalias'] ?: null, $datos_art66['cargo_regalias'] ?: null, + $datos_art66['fecha_producto'] ?: null, $datos_art66['importe_producto'] ?: null, $datos_art66['cargo_producto'] ?: null, + + $_SESSION['user_id'] + ]; + } + + $stmt = $db->prepare($sql); + $resultado = $stmt->execute($params); + + if ($resultado) { + echo json_encode(['success' => true, 'message' => 'Datos guardados correctamente']); + } else { + echo json_encode(['success' => false, 'message' => 'Error al guardar los datos']); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error interno: ' . $e->getMessage()]); + } +} + +function ajax_obtener_datos_factura() { + try { + $id_factura = $_GET['id_factura'] ?? null; + + if (!$id_factura) { + echo json_encode(['success' => false, 'message' => 'ID de factura requerido']); + return; + } + + $db = getDB(); + $stmt = $db->prepare("SELECT * FROM mve_facturas_datos WHERE id_factura = ?"); + $stmt->execute([$id_factura]); + $datos = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($datos) { + // Estructurar datos para el frontend + $datosEstructurados = [ + 'art65' => [ + 'fecha_transporte' => $datos['art65_fecha_transporte'], + 'importe_transporte' => $datos['art65_importe_transporte'], + 'fecha_descuentos' => $datos['art65_fecha_descuentos'], + 'importe_descuentos' => $datos['art65_importe_descuentos'], + 'fecha_posteriores' => $datos['art65_fecha_posteriores'], + 'importe_posteriores' => $datos['art65_importe_posteriores'], + 'fecha_contribuciones' => $datos['art65_fecha_contribuciones'], + 'importe_contribuciones' => $datos['art65_importe_contribuciones'], + 'fecha_pagos_vendedor' => $datos['art65_fecha_pagos_vendedor'], + 'importe_pagos_vendedor' => $datos['art65_importe_pagos_vendedor'] + ], + 'art66' => [ + 'fecha_comisiones' => $datos['art66_fecha_comisiones'], + 'importe_comisiones' => $datos['art66_importe_comisiones'], + 'cargo_comisiones' => $datos['art66_cargo_comisiones'], + 'fecha_envases' => $datos['art66_fecha_envases'], + 'importe_envases' => $datos['art66_importe_envases'], + 'cargo_envases' => $datos['art66_cargo_envases'], + 'fecha_embalaje' => $datos['art66_fecha_embalaje'], + 'importe_embalaje' => $datos['art66_importe_embalaje'], + 'cargo_embalaje' => $datos['art66_cargo_embalaje'], + 'fecha_transporte_dec' => $datos['art66_fecha_transporte_dec'], + 'importe_transporte_dec' => $datos['art66_importe_transporte_dec'], + 'cargo_transporte_dec' => $datos['art66_cargo_transporte_dec'], + 'fecha_ingenieria' => $datos['art66_fecha_ingenieria'], + 'importe_ingenieria' => $datos['art66_importe_ingenieria'], + 'cargo_ingenieria' => $datos['art66_cargo_ingenieria'], + 'fecha_regalias' => $datos['art66_fecha_regalias'], + 'importe_regalias' => $datos['art66_importe_regalias'], + 'cargo_regalias' => $datos['art66_cargo_regalias'], + 'fecha_producto' => $datos['art66_fecha_producto'], + 'importe_producto' => $datos['art66_importe_producto'], + 'cargo_producto' => $datos['art66_cargo_producto'] + ] + ]; + + echo json_encode(['success' => true, 'datos' => $datosEstructurados]); + } else { + echo json_encode(['success' => true, 'datos' => null]); + } + + } catch (Exception $e) { + echo json_encode(['success' => false, 'message' => 'Error interno: ' . $e->getMessage()]); + } +} + + diff --git a/app/controllers/seguridad.php b/app/controllers/seguridad.php index 1ab764f..fc08766 100644 --- a/app/controllers/seguridad.php +++ b/app/controllers/seguridad.php @@ -342,4 +342,281 @@ function obtenerCorreos($conn, $id_usuario) } return $correos; +} + +function ventanillaUnica() +{ + $conn = getConnection(); + + $id_usuario = $_SESSION['usuario_id'] ?? null; + + // Asegúrate de que el usuario está autenticado + if (!$id_usuario || ($_SESSION['pendiente_confirmacion'] ?? false)) { + die("Usuario no autenticado."); + } + + // Obtener configuración actual de ventanilla única + $configuracion_vu = obtenerConfiguracionVU($conn, $id_usuario); + + include __DIR__ . '/../../views/seguridad/ventanilla_unica.php'; +} + +function guardarConfiguracionVU() +{ + // Solo ejecutar si es una petición POST + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + $conn = getConnection(); + + $id_usuario = $_SESSION['usuario_id'] ?? null; + if (!$id_usuario || ($_SESSION['pendiente_confirmacion'] ?? false)) { + die("No autorizado - Sesión inválida"); + } + + // Obtener datos del formulario (sin ruta_ejecutable) + $clave_fiel = trim($_POST['clave_fiel'] ?? ''); + $rfc_usuario_vu = trim($_POST['rfc_usuario_vu'] ?? ''); + $clave_webservice = trim($_POST['clave_webservice'] ?? ''); + + // Validar campos obligatorios (sin ruta_ejecutable) + if (empty($clave_fiel) || empty($rfc_usuario_vu)) { + $_SESSION['config_error'] = 'Los campos Clave FIEL y RFC Usuario VU son obligatorios.'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + // Obtener configuración actual para conservar archivos existentes + $configuracion_actual = obtenerConfiguracionVU($conn, $id_usuario); + $ruta_archivo_key = $configuracion_actual['ruta_archivo_key']; + $ruta_archivo_cer = $configuracion_actual['ruta_archivo_cer']; + + // Directorio para archivos de certificados + $upload_dir = __DIR__ . '/../../storage/certificados/'; + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0755, true); + } + + // Procesar archivo KEY + if (!empty($_FILES['archivo_key']['tmp_name']) && $_FILES['archivo_key']['error'] === UPLOAD_ERR_OK) { + $key_extension = pathinfo($_FILES['archivo_key']['name'], PATHINFO_EXTENSION); + + if (strtolower($key_extension) !== 'key') { + $_SESSION['config_error'] = 'El archivo KEY debe tener extensión .key'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + $key_filename = 'key_' . $id_usuario . '_' . time() . '.key'; + $key_destination = $upload_dir . $key_filename; + + if (move_uploaded_file($_FILES['archivo_key']['tmp_name'], $key_destination)) { + // Eliminar archivo anterior si existe + if ($ruta_archivo_key && file_exists($ruta_archivo_key)) { + unlink($ruta_archivo_key); + } + $ruta_archivo_key = $key_destination; + } else { + $_SESSION['config_error'] = 'Error al subir el archivo KEY.'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + } + + // Procesar archivo CER + if (!empty($_FILES['archivo_cer']['tmp_name']) && $_FILES['archivo_cer']['error'] === UPLOAD_ERR_OK) { + $cer_extension = pathinfo($_FILES['archivo_cer']['name'], PATHINFO_EXTENSION); + + if (strtolower($cer_extension) !== 'cer') { + $_SESSION['config_error'] = 'El archivo CER debe tener extensión .cer'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + $cer_filename = 'cer_' . $id_usuario . '_' . time() . '.cer'; + $cer_destination = $upload_dir . $cer_filename; + + if (move_uploaded_file($_FILES['archivo_cer']['tmp_name'], $cer_destination)) { + // Eliminar archivo anterior si existe + if ($ruta_archivo_cer && file_exists($ruta_archivo_cer)) { + unlink($ruta_archivo_cer); + } + $ruta_archivo_cer = $cer_destination; + } else { + $_SESSION['config_error'] = 'Error al subir el archivo CER.'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + } + + // Validar que se hayan subido los certificados (obligatorios para nueva configuración) + if (empty($ruta_archivo_key) || empty($ruta_archivo_cer)) { + $_SESSION['config_error'] = 'Los archivos CER y KEY son obligatorios.'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + // Encriptar las contraseñas sensibles + $clave_fiel_encrypted = encrypt($clave_fiel); + $clave_webservice_encrypted = !empty($clave_webservice) ? encrypt($clave_webservice) : ''; + + // Verificar si ya existe configuración - CORREGIR ERROR SQL + $sql_check = "SELECT COUNT(*) as total FROM configuracion_ventanilla_unica WHERE id_usuario = ?"; + $stmt_check = sqlsrv_query($conn, $sql_check, [$id_usuario]); + + if ($stmt_check === false) { + $_SESSION['config_error'] = 'Error en la consulta de configuración: ' . print_r(sqlsrv_errors(), true); + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + $row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC); + + if ($row['total'] > 0) { + // Actualizar configuración existente (sin ruta_ejecutable) + $sql = "UPDATE configuracion_ventanilla_unica SET + ruta_archivo_key = ?, + ruta_archivo_cer = ?, + clave_fiel = ?, + rfc_usuario_vu = ?, + clave_webservice = ?, + fecha_actualizacion = GETDATE() + WHERE id_usuario = ?"; + $params = [ + $ruta_archivo_key, + $ruta_archivo_cer, + $clave_fiel_encrypted, + $rfc_usuario_vu, + $clave_webservice_encrypted, + $id_usuario + ]; + } else { + // Insertar nueva configuración (sin ruta_ejecutable) + $sql = "INSERT INTO configuracion_ventanilla_unica + (id_usuario, ruta_archivo_key, ruta_archivo_cer, + clave_fiel, rfc_usuario_vu, clave_webservice, fecha_creacion) + VALUES (?, ?, ?, ?, ?, ?, GETDATE())"; + $params = [ + $id_usuario, + $ruta_archivo_key, + $ruta_archivo_cer, + $clave_fiel_encrypted, + $rfc_usuario_vu, + $clave_webservice_encrypted + ]; + } + + $stmt = sqlsrv_prepare($conn, $sql, $params); + + if (!$stmt) { + $_SESSION['config_error'] = "Error en la preparación: " . print_r(sqlsrv_errors(), true); + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + $result = sqlsrv_execute($stmt); + + if ($result === false) { + $_SESSION['config_error'] = "Error al guardar configuración: " . print_r(sqlsrv_errors(), true); + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; + } + + sqlsrv_free_stmt($stmt); + sqlsrv_close($conn); + + $_SESSION['config_success'] = 'Configuración de Ventanilla Única guardada correctamente.'; + header('Location: /IMPORTADORES/seguridad/ventanillaUnica'); + exit; +} + +function probarConexionVU() +{ + header('Content-Type: application/json'); + + $id_usuario = $_SESSION['usuario_id'] ?? null; + if (!$id_usuario || ($_SESSION['pendiente_confirmacion'] ?? false)) { + echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']); + exit; + } + + $conn = getConnection(); + $configuracion = obtenerConfiguracionVU($conn, $id_usuario); + + // Verificar que todos los campos requeridos estén configurados (sin ruta_ejecutable) + if (empty($configuracion['rfc_usuario_vu']) || empty($configuracion['clave_fiel'])) { + echo json_encode([ + 'success' => false, + 'message' => 'Configuración incompleta. Verifica que RFC Usuario VU y Clave FIEL estén configurados.' + ]); + exit; + } + + // Verificar archivos de certificados + if (!empty($configuracion['ruta_archivo_cer']) && !file_exists($configuracion['ruta_archivo_cer'])) { + echo json_encode([ + 'success' => false, + 'message' => 'El archivo CER no existe en la ruta especificada.' + ]); + exit; + } + + if (!empty($configuracion['ruta_archivo_key']) && !file_exists($configuracion['ruta_archivo_key'])) { + echo json_encode([ + 'success' => false, + 'message' => 'El archivo KEY no existe en la ruta especificada.' + ]); + exit; + } + + // Verificar que existan ambos archivos de certificados + if (empty($configuracion['ruta_archivo_cer']) || empty($configuracion['ruta_archivo_key'])) { + echo json_encode([ + 'success' => false, + 'message' => 'Los archivos CER y KEY son obligatorios para la configuración.' + ]); + exit; + } + + // Si llegamos aquí, la configuración es válida + echo json_encode([ + 'success' => true, + 'message' => 'Configuración válida. Los archivos de certificados existen y todos los campos obligatorios están completos.' + ]); + exit; +} + +function obtenerConfiguracionVU($conn, $id_usuario) +{ + $configuracion = [ + 'ruta_archivo_key' => '', + 'ruta_archivo_cer' => '', + 'clave_fiel' => '', + 'rfc_usuario_vu' => '', + 'clave_webservice' => '', + 'fecha_creacion' => null, + 'fecha_actualizacion' => null + ]; + + $sql = "SELECT * FROM configuracion_ventanilla_unica WHERE id_usuario = ?"; + $stmt = sqlsrv_prepare($conn, $sql, [$id_usuario]); + + if ($stmt && sqlsrv_execute($stmt)) { + if ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $configuracion['ruta_archivo_key'] = $row['ruta_archivo_key'] ?? ''; + $configuracion['ruta_archivo_cer'] = $row['ruta_archivo_cer'] ?? ''; + $configuracion['rfc_usuario_vu'] = $row['rfc_usuario_vu'] ?? ''; + + // Desencriptar contraseñas + $configuracion['clave_fiel'] = !empty($row['clave_fiel']) ? decrypt($row['clave_fiel']) : ''; + $configuracion['clave_webservice'] = !empty($row['clave_webservice']) ? decrypt($row['clave_webservice']) : ''; + + $configuracion['fecha_creacion'] = $row['fecha_creacion']; + $configuracion['fecha_actualizacion'] = $row['fecha_actualizacion']; + } + } + + return $configuracion; } \ No newline at end of file diff --git a/app/controllers/solicitud_importacion.php b/app/controllers/solicitud_importacion.php index 44b88d1..ed6e10d 100644 --- a/app/controllers/solicitud_importacion.php +++ b/app/controllers/solicitud_importacion.php @@ -410,6 +410,7 @@ function guardar() $aduana_seccion = $_POST['anexo22_apendice'] ?? null; $num_factura = trim($_POST['numero_factura'] ?? ''); $fecha = $_POST['fecha_factura'] ?? null; + $pedimento = trim($_POST['pedimento'] ?? ''); // ✅ NUEVO CAMPO $incoterm = $_POST['incoterm'] ?? null; $pais_proveedor = $_POST['pais_proveedor'] ?? null; $tipo_moneda = $_POST['tipo_moneda'] ?? null; @@ -462,15 +463,16 @@ function guardar() $fotoUrl, $status, $proveedor_clave, - $patente_id ? (int)$patente_id : null + $patente_id ? (int)$patente_id : null, + $pedimento ?: null // ✅ CORREGIDO: Campo pedimento_vinculado al final ]; $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, + fecha_factura, incoterm, pais_proveedor, tipo_moneda, valor_factura, vinculacion, transportista_id, chofer_id, - foto_solicitud_url, status, proveedor_clave, patente_id) + foto_solicitud_url, status, proveedor_clave, patente_id, pedimento_vinculado) OUTPUT INSERTED.id_solicitud - VALUES(?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "; $stmt = sqlsrv_query($conn, $sql, $params, ['Scrollable' => SQLSRV_CURSOR_KEYSET]); @@ -947,8 +949,8 @@ function actualizar() } else { // INSERTAR nueva partida (asegurarse que no tenga id_partida o sea 0) $sql = "INSERT INTO dbo.solicitud_importacion_partidas - (id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, - valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial) + (id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, + peso_bruto, unidad_comercial_id, tasa_preferencial) VALUES (?, ?, ?, ?, ?, ?, ?, ?) "; $params = [ $id_solicitud, $desc, $cantCom, $cantTar, $valPart, $peso, $umId, $tasaPref ]; @@ -1968,7 +1970,7 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = $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']; if ($numero == 0) return 'cero'; if ($numero == 100) return 'cien'; @@ -2212,4 +2214,89 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = '; return $html; +} + +// NUEVO ENDPOINT: Pedimentos de catálogo activos del importador para panel de referencia +function ajax_pedimentos_catalogo() +{ + header('Content-Type: application/json; charset=utf-8'); + if (!($_SESSION['usuario_id'] ?? false)) { + http_response_code(401); + echo json_encode(['data' => []]); + exit; + } + $id_usuario = $_SESSION['usuario_id']; + $limit = isset($_GET['limit']) ? intval($_GET['limit']) : 10; + $conn = getConnection(); + // Obtener RFC del importador + $sqlImportador = "SELECT rfc FROM informacion_general WHERE id_usuario = ?"; + $stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]); + if ($stmtImportador === false) { + echo json_encode(['data' => []]); + exit; + } + $importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC); + if (!$importador) { + echo json_encode(['data' => []]); + exit; + } + // Obtener pedimentos activos del catálogo + $sql = "SELECT TOP {$limit} IdPrevio, Pedimento, ClienteNombre, ClavePed, Timestamp + FROM PREVIOS_COMPARTIDOS_WS + WHERE ClienteRFC = ? AND Status = 1 + ORDER BY Timestamp DESC"; + $stmt = sqlsrv_query($conn, $sql, [$importador['rfc']]); + $pedimentos = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $fecha = ''; + if ($row['Timestamp'] instanceof DateTime) { + $fecha = $row['Timestamp']->format('d/m/Y'); + } + $pedimentos[] = [ + 'numero' => $row['Pedimento'], + 'cliente' => $row['ClienteNombre'], + 'clave' => $row['ClavePed'], + 'fecha' => $fecha + ]; + } + } + echo json_encode(['data' => $pedimentos]); + exit; +} + +function ajax_facturas_por_pedimento() { + header('Content-Type: application/json'); + $id_previo = isset($_GET['id_pedimento']) ? trim($_GET['id_pedimento']) : ''; + if (!$id_previo) { + echo json_encode(['success' => false, 'error' => 'ID de pedimento no válido']); + return; + } + $conn = getConnection(); + // 1. Buscar el número de pedimento real en PREVIOS_COMPARTIDOS_WS + $stmt = sqlsrv_query($conn, "SELECT Pedimento FROM PREVIOS_COMPARTIDOS_WS WHERE IdPrevio = ?", [$id_previo]); + if ($stmt === false || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) { + echo json_encode(['success' => false, 'error' => 'No se encontró el pedimento en PREVIOS_COMPARTIDOS_WS']); + return; + } + $numero_pedimento = $row['Pedimento']; + + // 2. Buscar las facturas en solicitud_importacion_factura usando el número de pedimento + // ✅ CORREGIDO: Incluir id_solicitud como id_factura + $stmt2 = sqlsrv_query($conn, "SELECT id_solicitud, numero_factura, fecha_factura, valor_factura FROM solicitud_importacion_factura WHERE numero_pedimento = ?", [$numero_pedimento]); + if ($stmt2 === false) { + echo json_encode(['success' => false, 'error' => 'Error en la consulta de facturas']); + return; + } + + $facturas = []; + while ($row2 = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_ASSOC)) { + $facturas[] = [ + 'id_factura' => $row2['id_solicitud'], // ✅ AGREGADO: Usar id_solicitud como id_factura + 'numero_factura' => $row2['numero_factura'], + 'fecha' => ($row2['fecha_factura'] instanceof DateTime) ? $row2['fecha_factura']->format('Y-m-d') : $row2['fecha_factura'], + 'monto' => $row2['valor_factura'] + ]; + } + echo json_encode(['success' => true, 'facturas' => $facturas]); } \ No newline at end of file diff --git a/app/controllers/templates_rapidos.php b/app/controllers/templates_rapidos.php new file mode 100644 index 0000000..326b2bf --- /dev/null +++ b/app/controllers/templates_rapidos.php @@ -0,0 +1,913 @@ + $_POST['tipo_moneda'] ?? '', + 'incoterm' => $_POST['incoterm'] ?? '', + 'vinculacion' => $_POST['vinculacion'] ?? '', + 'pais_proveedor' => $_POST['pais_proveedor'] ?? '', + 'pais_proveedor_texto' => $_POST['pais_proveedor_texto'] ?? '', + 'anexo22_apendice' => $_POST['anexo22_apendice'] ?? '', + 'patente' => $_POST['patente'] ?? '', + 'transportista_id' => $_POST['transportista_id'] ?? '', + 'chofer_id' => $_POST['chofer_id'] ?? '', + 'tasa_preferencial' => $_POST['tasa_preferencial'] ?? '', + 'unidad_comercial_id' => $_POST['unidad_comercial_id'] ?? '' + ]; + + $config_json = json_encode($config, JSON_UNESCAPED_UNICODE); + + // Validaciones + if (empty($nombre)) { + die("❌ El nombre del template es obligatorio."); + } + + if (strlen($nombre) > 100) { + die("❌ El nombre del template es muy largo (máximo 100 caracteres)."); + } + + $sql = "INSERT INTO dbo.templates_rapidos + (nombre, descripcion, icono, config_json, tipo_moneda, incoterm, + vinculacion, pais_proveedor, tasa_preferencial, id_agencia, id_usuario_creador) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + $params = [ + $nombre, + $descripcion, + $icono, + $config_json, + $config['tipo_moneda'], + $config['incoterm'], + $config['vinculacion'] ?: null, + $config['pais_proveedor'], + $config['tasa_preferencial'], + $id_agencia, + $id_usuario + ]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + die("❌ Error al guardar template: " . print_r(sqlsrv_errors(), true)); + } + + header('Location: /IMPORTADORES/templates_rapidos/lista?created=ok'); + exit; +} + +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(); + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + + // Obtener el template + $sql = "SELECT * FROM dbo.templates_rapidos + WHERE id = ? AND (id_usuario_creador = ? OR id_agencia = ? OR id_agencia IS NULL)"; + $stmt = sqlsrv_query($conn, $sql, [$id, $id_usuario, $id_agencia]); + + if ($stmt === false) { + die("❌ Error en consulta: " . print_r(sqlsrv_errors(), true)); + } + + $template = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + + if (!$template) { + die("❌ Template no encontrado o sin permisos."); + } + + // Decodificar configuración JSON + $template['config'] = json_decode($template['config_json'], true) ?: []; + + // Obtener datos para los selects + $conn = getConnection(); + $aduanas = obtenerAduanas($conn); + $patentes = obtenerPatentes($conn); + $incoterms = obtenerIncoterms($conn); + $paises = obtenerPaises($conn); + $transportistas = obtenerTransportistas($conn); + $choferes = obtenerChoferes($conn); + $unidades_medida = obtenerUnidadesMedida($conn); + + include __DIR__ . '/../../views/templates_rapidos/editar.php'; +} + +function actualizar() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + die("⚠️ No autorizado."); + } + + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + + $id = $_POST['id'] ?? null; + $nombre = trim($_POST['nombre'] ?? ''); + $descripcion = trim($_POST['descripcion'] ?? ''); + $icono = trim($_POST['icono'] ?? '🏢'); + + if (!$id || !is_numeric($id)) { + die("❌ ID inválido."); + } + + // Configuración del template + $config = [ + 'tipo_moneda' => $_POST['tipo_moneda'] ?? '', + 'incoterm' => $_POST['incoterm'] ?? '', + 'vinculacion' => $_POST['vinculacion'] ?? '', + 'pais_proveedor' => $_POST['pais_proveedor'] ?? '', + 'pais_proveedor_texto' => $_POST['pais_proveedor_texto'] ?? '', + 'anexo22_apendice' => $_POST['anexo22_apendice'] ?? '', + 'patente' => $_POST['patente'] ?? '', + 'transportista_id' => $_POST['transportista_id'] ?? '', + 'chofer_id' => $_POST['chofer_id'] ?? '', + 'tasa_preferencial' => $_POST['tasa_preferencial'] ?? '', + 'unidad_comercial_id' => $_POST['unidad_comercial_id'] ?? '' + ]; + + $config_json = json_encode($config, JSON_UNESCAPED_UNICODE); + + // Validaciones + if (empty($nombre)) { + die("❌ El nombre del template es obligatorio."); + } + + // Verificar permisos + $sqlCheck = "SELECT id FROM dbo.templates_rapidos + WHERE id = ? AND (id_usuario_creador = ? OR id_agencia = ?)"; + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id, $id_usuario, $id_agencia]); + $exists = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + + if (!$exists) { + die("❌ Template no encontrado o sin permisos para editarlo."); + } + + $sql = "UPDATE dbo.templates_rapidos SET + nombre = ?, descripcion = ?, icono = ?, config_json = ?, + tipo_moneda = ?, incoterm = ?, vinculacion = ?, + pais_proveedor = ?, tasa_preferencial = ?, fecha_modificacion = GETDATE() + WHERE id = ?"; + + $params = [ + $nombre, + $descripcion, + $icono, + $config_json, + $config['tipo_moneda'], + $config['incoterm'], + $config['vinculacion'] ?: null, + $config['pais_proveedor'], + $config['tasa_preferencial'], + $id + ]; + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + die("❌ Error al actualizar template: " . print_r(sqlsrv_errors(), true)); + } + + header('Location: /IMPORTADORES/templates_rapidos/lista?updated=ok'); + exit; +} + +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(); + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + + // Verificar permisos + $sqlCheck = "SELECT id FROM dbo.templates_rapidos + WHERE id = ? AND (id_usuario_creador = ? OR id_agencia = ?)"; + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id, $id_usuario, $id_agencia]); + $exists = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + + if (!$exists) { + die("❌ Template no encontrado o sin permisos para eliminarlo."); + } + + $sql = "UPDATE dbo.templates_rapidos SET activo = 0 WHERE id = ?"; + $stmt = sqlsrv_query($conn, $sql, [$id]); + + if ($stmt === false) { + die("❌ Error al eliminar template: " . print_r(sqlsrv_errors(), true)); + } + + header('Location: /IMPORTADORES/templates_rapidos/lista?deleted=ok'); + exit; +} + +function ajax_lista() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + http_response_code(403); + echo json_encode([]); + exit; + } + + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + $conn = getConnection(); + + // Parámetros de DataTables + $draw = intval($_GET['draw'] ?? 0); + $start = intval($_GET['start'] ?? 0); + $length = intval($_GET['length'] ?? 10); + $search = $_GET['search']['value'] ?? ''; + + // Construir condiciones de filtro + $where = "activo = 1 AND (id_agencia IS NULL OR id_agencia = ? OR id_usuario_creador = ?)"; + $params = [$id_agencia, $id_usuario]; + + if ($search !== '') { + $where .= " AND (nombre LIKE ? OR descripcion LIKE ?)"; + $like = "%{$search}%"; + $params = array_merge($params, [$like, $like]); + } + + // Total registros filtrados + $sqlFiltered = "SELECT COUNT(*) AS total FROM dbo.templates_rapidos WHERE $where"; + $stmtF = sqlsrv_query($conn, $sqlFiltered, $params); + $rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC); + $recordsFiltered = (int)($rowF['total'] ?? 0); + + // Total registros sin filtro + $sqlTotal = "SELECT COUNT(*) AS total FROM dbo.templates_rapidos WHERE activo = 1 AND (id_agencia IS NULL OR id_agencia = ? OR id_usuario_creador = ?)"; + $stmtT = sqlsrv_query($conn, $sqlTotal, [$id_agencia, $id_usuario]); + $rowT = sqlsrv_fetch_array($stmtT, SQLSRV_FETCH_ASSOC); + $recordsTotal = (int)($rowT['total'] ?? 0); + + // Consulta principal con paginación + $sql = "SELECT t.id, t.nombre, t.descripcion, t.icono, t.tipo_moneda, t.incoterm, + t.vinculacion, t.pais_proveedor, t.tasa_preferencial, t.fecha_creacion, + u.nombre_usuario AS usuario_creador, + CASE WHEN t.id_agencia IS NULL THEN 'Sistema' ELSE a.nombre END AS ambito + FROM dbo.templates_rapidos t + LEFT JOIN dbo.usuarios u ON t.id_usuario_creador = u.id + LEFT JOIN dbo.agencias a ON t.id_agencia = a.id + WHERE $where + ORDER BY t.fecha_creacion DESC + OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; + + $paramsData = array_merge($params, [$start, $length]); + $stmt = sqlsrv_query($conn, $sql, $paramsData); + + $data = []; + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $fecha = $row['fecha_creacion'] instanceof DateTime + ? $row['fecha_creacion']->format('d/m/Y H:i') + : 'N/A'; + + $data[] = [ + 'id' => $row['id'], + 'icono' => htmlspecialchars($row['icono'] ?? '🏢'), + 'nombre' => htmlspecialchars($row['nombre']), + 'descripcion' => htmlspecialchars($row['descripcion'] ?? ''), + 'tipo_moneda' => htmlspecialchars($row['tipo_moneda'] ?? ''), + 'incoterm' => htmlspecialchars($row['incoterm'] ?? ''), + 'pais_proveedor' => htmlspecialchars($row['pais_proveedor'] ?? ''), + 'ambito' => htmlspecialchars($row['ambito'] ?? ''), + 'usuario_creador' => htmlspecialchars($row['usuario_creador'] ?? ''), + 'fecha_creacion' => $fecha + ]; + } + + echo json_encode([ + 'draw' => $draw, + 'recordsTotal' => $recordsTotal, + 'recordsFiltered' => $recordsFiltered, + 'data' => $data + ]); +} + +function ajax_obtener_templates_debug() +{ + header('Content-Type: application/json; charset=UTF-8'); + + if (!($_SESSION['usuario_id'] ?? false)) { + echo json_encode(['error' => 'Usuario no autenticado']); + exit; + } + + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + + try { + $conn = getConnection(); + + // ✅ CONSULTA SIN FILTROS para debug + $sql = "SELECT id, nombre, descripcion, icono, config_json, + ISNULL(veces_usado, 0) as veces_usado, + id_usuario_creador, id_agencia, activo, + fecha_creacion + FROM dbo.templates_rapidos + ORDER BY fecha_creacion DESC"; + + $stmt = sqlsrv_query($conn, $sql); + + if ($stmt === false) { + $errors = sqlsrv_errors(); + echo json_encode([ + 'error' => 'Error en consulta SQL', + 'message' => $errors[0]['message'] ?? 'Error desconocido', + 'sql_errors' => $errors + ]); + exit; + } + + $templates = []; + $debug_info = [ + 'usuario_actual' => $id_usuario, + 'agencia_actual' => $id_agencia, + 'todos_los_templates' => [] + ]; + + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + // Info completa para debug + $template_debug = [ + 'id' => $row['id'], + 'nombre' => $row['nombre'], + 'id_usuario_creador' => $row['id_usuario_creador'], + 'id_agencia' => $row['id_agencia'], + 'activo' => $row['activo'], + 'fecha_creacion' => $row['fecha_creacion'] instanceof DateTime + ? $row['fecha_creacion']->format('Y-m-d H:i:s') + : $row['fecha_creacion'], + 'es_del_usuario_actual' => ($row['id_usuario_creador'] == $id_usuario), + 'es_de_la_agencia' => ($row['id_agencia'] == $id_agencia), + 'deberia_mostrarse' => ( + $row['activo'] == 1 && ( + $row['id_agencia'] === null || + $row['id_agencia'] == $id_agencia || + $row['id_usuario_creador'] == $id_usuario + ) + ) + ]; + + $debug_info['todos_los_templates'][] = $template_debug; + + // Solo agregar a templates para mostrar si cumple condiciones + if ($template_debug['deberia_mostrarse']) { + $config = []; + if (!empty($row['config_json'])) { + $decoded = json_decode($row['config_json'], true); + $config = is_array($decoded) ? $decoded : []; + } + + $templates[] = [ + 'id' => (int)$row['id'], + 'nombre' => $row['nombre'], + 'descripcion' => $row['descripcion'] ?? '', + 'icono' => $row['icono'] ?? '📋', + 'config' => $config, + 'veces_usado' => (int)$row['veces_usado'], + 'id_usuario_creador' => $row['id_usuario_creador'], + 'es_mio' => ($row['id_usuario_creador'] == $id_usuario) + ]; + } + } + + echo json_encode([ + 'success' => true, + 'count' => count($templates), + 'templates' => $templates, + 'debug_info' => $debug_info + ], JSON_UNESCAPED_UNICODE); + + } catch (Exception $e) { + echo json_encode([ + 'error' => 'Error interno del servidor', + 'message' => $e->getMessage() + ]); + } + + exit; +} + +function ajax_obtener_templates() +{ + // ✅ VERSIÓN CORREGIDA: Función simplificada sin filtros complejos + + header('Content-Type: application/json; charset=UTF-8'); + + if (!($_SESSION['usuario_id'] ?? false)) { + http_response_code(403); + echo json_encode(['error' => 'Usuario no autenticado', 'templates' => []]); + exit; + } + + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + + try { + $conn = getConnection(); + + // ✅ CONSULTA SIMPLIFICADA: Mostrar todos los templates activos del usuario o agencia + $sql = "SELECT id, nombre, descripcion, icono, config_json, + ISNULL(veces_usado, 0) as veces_usado, + id_usuario_creador, id_agencia + FROM dbo.templates_rapidos + WHERE activo = 1 + AND (id_usuario_creador = ? OR id_agencia = ? OR id_agencia IS NULL) + ORDER BY + CASE WHEN id_usuario_creador = ? THEN 0 ELSE 1 END, + veces_usado DESC, + nombre ASC"; + + $params = [$id_usuario, $id_agencia, $id_usuario]; + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + $errors = sqlsrv_errors(); + echo json_encode([ + 'error' => 'Error en consulta SQL', + 'message' => $errors[0]['message'] ?? 'Error desconocido', + 'templates' => [] + ]); + exit; + } + + $templates = []; + $templates_personales = []; + $templates_otros = []; + + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + // Decodificar JSON con manejo de errores + $config = []; + if (!empty($row['config_json'])) { + $decoded = json_decode($row['config_json'], true); + $config = is_array($decoded) ? $decoded : []; + } + + $template = [ + 'id' => (int)$row['id'], + 'nombre' => $row['nombre'], + 'descripcion' => $row['descripcion'] ?? '', + 'icono' => $row['icono'] ?? '📋', + 'config' => $config, + 'veces_usado' => (int)$row['veces_usado'], + 'id_usuario_creador' => $row['id_usuario_creador'], + 'id_agencia' => $row['id_agencia'], + 'es_mio' => ($row['id_usuario_creador'] == $id_usuario), + 'ambito' => ($row['id_usuario_creador'] == $id_usuario) ? 'personal' : + (($row['id_agencia'] == $id_agencia) ? 'agencia' : 'sistema') + ]; + + // Separar templates personales de otros + if ($template['es_mio']) { + $templates_personales[] = $template; + } else { + $templates_otros[] = $template; + } + + $templates[] = $template; + } + + // Respuesta con información detallada + echo json_encode([ + 'success' => true, + 'count' => count($templates), + 'count_personales' => count($templates_personales), + 'count_otros' => count($templates_otros), + 'usuario_id' => $id_usuario, + 'agencia_id' => $id_agencia, + 'templates' => $templates, + 'templates_personales' => $templates_personales, + 'templates_otros' => $templates_otros + ], JSON_UNESCAPED_UNICODE); + + } catch (Exception $e) { + echo json_encode([ + 'error' => 'Error interno del servidor', + 'message' => $e->getMessage(), + 'templates' => [] + ]); + } + + exit; +} + +function ajax_lista_por_seccion() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + die(json_encode(['error' => 'No autorizado'])); + } + + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + $seccion = $_GET['seccion'] ?? 'personal'; + + $data = []; + + try { + switch($seccion) { + case 'personal': + // Solo templates creados por el usuario actual + $sql = "SELECT id, nombre, descripcion, icono, config_json, + veces_usado, fecha_creacion, id_usuario_creador + FROM dbo.templates_rapidos + WHERE id_usuario_creador = ? AND estado = 1 + ORDER BY veces_usado DESC, fecha_creacion DESC"; + $params = [$id_usuario]; + break; + + case 'agencia': + // Templates de la agencia (excluyendo los personales ya mostrados) + $sql = "SELECT id, nombre, descripcion, icono, config_json, + veces_usado, fecha_creacion, id_usuario_creador + FROM dbo.templates_rapidos + WHERE id_agencia = ? AND id_usuario_creador != ? AND estado = 1 + ORDER BY veces_usado DESC, fecha_creacion DESC"; + $params = [$id_agencia, $id_usuario]; + break; + + case 'global': + // Templates globales del sistema (solo si se solicitan explícitamente) + $sql = "SELECT id, nombre, descripcion, icono, config_json, + veces_usado, fecha_creacion, id_usuario_creador + FROM dbo.templates_rapidos + WHERE id_agencia IS NULL AND id_usuario_creador IS NULL AND estado = 1 + ORDER BY veces_usado DESC, fecha_creacion DESC"; + $params = []; + break; + + default: + throw new Exception('Sección inválida'); + } + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + throw new Exception('Error en consulta: ' . print_r(sqlsrv_errors(), true)); + } + + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + // Formatear fecha + $fecha = $row['fecha_creacion'] instanceof DateTime + ? $row['fecha_creacion']->format('d/m/Y') + : date('d/m/Y', strtotime($row['fecha_creacion'])); + + // Determinar acciones según el tipo de template + $acciones = ''; + $esPropio = ($row['id_usuario_creador'] == $id_usuario); + $esAgencia = ($seccion === 'agencia'); + $esGlobal = ($seccion === 'global'); + + if ($esPropio) { + $acciones = ' +
+ + + + + +
'; + } elseif ($esAgencia) { + $acciones = ' +
+ + +
'; + } else { // Global + $acciones = ' + '; + } + + // Construir nombre con icono + $nombreConIcono = ' + ' . htmlspecialchars($row['icono']) . ' +
+ ' . htmlspecialchars($row['nombre']) . ''; + + // Agregar badge según el tipo + if ($esPropio) { + $nombreConIcono .= ' Mío'; + } elseif ($esAgencia) { + $nombreConIcono .= ' Agencia'; + } else { + $nombreConIcono .= ' Global'; + } + + $nombreConIcono .= '
'; + + $data[] = [ + $row['id'], + $nombreConIcono, + htmlspecialchars($row['descripcion'] ?? 'Sin descripción'), + '' . ($row['veces_usado'] ?? 0) . '', + $fecha, + $acciones + ]; + } + + echo json_encode([ + 'success' => true, + 'data' => $data, + 'count' => count($data) + ]); + + } catch (Exception $e) { + echo json_encode([ + 'success' => false, + 'error' => $e->getMessage(), + 'data' => [] + ]); + } +} + +function duplicar() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + die("⚠️ No autorizado."); + } + + $conn = getConnection(); + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + + $template_id = $_POST['template_id'] ?? null; + + if (!$template_id || !is_numeric($template_id)) { + die("❌ ID de template inválido."); + } + + // Obtener template original + $sql = "SELECT * FROM dbo.templates_rapidos WHERE id = ?"; + $stmt = sqlsrv_query($conn, $sql, [$template_id]); + + if ($stmt === false) { + die("❌ Error al buscar template: " . print_r(sqlsrv_errors(), true)); + } + + $original = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + + if (!$original) { + die("❌ Template no encontrado."); + } + + // Crear duplicado con nuevo nombre + $nuevo_nombre = $original['nombre'] . ' (Copia)'; + + $sql_insert = "INSERT INTO dbo.templates_rapidos + (nombre, descripcion, icono, config_json, tipo_moneda, incoterm, + vinculacion, pais_proveedor, tasa_preferencial, id_agencia, id_usuario_creador) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + $params_insert = [ + $nuevo_nombre, + $original['descripcion'], + $original['icono'], + $original['config_json'], + $original['tipo_moneda'], + $original['incoterm'], + $original['vinculacion'], + $original['pais_proveedor'], + $original['tasa_preferencial'], + $id_agencia, + $id_usuario + ]; + + $stmt_insert = sqlsrv_query($conn, $sql_insert, $params_insert); + + if ($stmt_insert === false) { + die("❌ Error al duplicar: " . print_r(sqlsrv_errors(), true)); + } + + echo "✅ Template duplicado correctamente como '{$nuevo_nombre}'."; +} + +function ajax_usar_template() +{ + if (!($_SESSION['usuario_id'] ?? false)) { + http_response_code(403); + echo json_encode(['success' => false, 'message' => 'No autorizado']); + exit; + } + + $id_template = intval($_POST['id_template'] ?? 0); + $id_usuario = $_SESSION['usuario_id']; + + if ($id_template <= 0) { + echo json_encode(['success' => false, 'message' => 'ID de template inválido']); + exit; + } + + $conn = getConnection(); + + // Incrementar contador de uso + $sql = "UPDATE dbo.templates_rapidos + SET veces_usado = veces_usado + 1, ultima_vez_usado = GETDATE() + WHERE id = ? AND activo = 1"; + $stmt = sqlsrv_query($conn, $sql, [$id_template]); + + if ($stmt === false) { + echo json_encode(['success' => false, 'message' => 'Error al actualizar estadísticas']); + exit; + } + + echo json_encode(['success' => true]); + exit; +} + +// Funciones auxiliares +function obtenerAduanas($conn) { + $sql = "SELECT DISTINCT RIGHT(REPLICATE('0', 3) + CAST(aduana_seccion AS VARCHAR), 3) AS aduana_seccion, nombre FROM dbo.aduanas ORDER BY aduana_seccion"; + $stmt = sqlsrv_query($conn, $sql); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} + +function obtenerPatentes($conn) { + $id_agencia = $_SESSION['id_agencia_en_uso'] ?? null; + if (!$id_agencia) { + return []; + } + + $sql = "SELECT id_agente, patente, agente_aduanal FROM dbo.agentes_aduanales WHERE id_agencia = ? AND activo = 1 ORDER BY patente"; + $stmt = sqlsrv_query($conn, $sql, [$id_agencia]); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} + +function obtenerIncoterms($conn) { + $sql = "SELECT INCOTERM, DESCESPANOL FROM dbo.gIncoterms ORDER BY INCOTERM"; + $stmt = sqlsrv_query($conn, $sql); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} + +function obtenerPaises($conn) { + $sql = "SELECT id_pais, nombre FROM dbo.paises ORDER BY nombre"; + $stmt = sqlsrv_query($conn, $sql); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} + +function obtenerTransportistas($conn) { + $id_usuario = $_SESSION['usuario_id'] ?? null; + if (!$id_usuario) { + return []; + } + + $sql = "SELECT id_transportista, clave_identificador, nombre FROM dbo.transportistas WHERE id_usuario = ? AND activo = 1 ORDER BY nombre"; + $stmt = sqlsrv_query($conn, $sql, [$id_usuario]); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} + +function obtenerChoferes($conn) { + $id_usuario = $_SESSION['usuario_id'] ?? null; + if (!$id_usuario) { + return []; + } + + $sql = "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"; + $stmt = sqlsrv_query($conn, $sql, [$id_usuario]); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} + +function obtenerUnidadesMedida($conn) { + $sql = "SELECT id, descripcion FROM dbo.unidades_medida_apendice7 ORDER BY id"; + $stmt = sqlsrv_query($conn, $sql); + $result = []; + if ($stmt !== false) { + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $result[] = $row; + } + } + return $result; +} \ No newline at end of file diff --git a/app/controllers/winsaai.php b/app/controllers/winsaai.php new file mode 100644 index 0000000..41e8848 --- /dev/null +++ b/app/controllers/winsaai.php @@ -0,0 +1,237 @@ + false, 'message' => 'Sesión expirada']); + exit; + } + + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(405); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Método no permitido']); + exit; + } + + $input = json_decode(file_get_contents('php://input'), true); + + if (json_last_error() !== JSON_ERROR_NONE) { + http_response_code(400); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'JSON inválido']); + exit; + } + + $host = trim($input['host'] ?? ''); + $port = intval($input['port'] ?? 80); + $protocol = $input['protocol'] ?? 'https'; + $usuario = trim($input['usuario'] ?? ''); + $password = $input['password'] ?? ''; + $sync_pedimentos = $input['sync_pedimentos'] ?? true; + $sync_coves = $input['sync_coves'] ?? true; + + // Validaciones + if (empty($host) || empty($usuario) || empty($password)) { + http_response_code(400); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Todos los campos son obligatorios']); + exit; + } + + // Encriptar contraseña + $encryptedPassword = encrypt($password); + + // Verificar si existe configuración + $sqlCheck = "SELECT id FROM winsaai_config WHERE id_usuario = ?"; + $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$userId]); + + if ($stmtCheck === false) { + http_response_code(500); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Error en base de datos']); + exit; + } + + $existingConfig = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC); + sqlsrv_free_stmt($stmtCheck); + + if ($existingConfig) { + // Actualizar + $sql = "UPDATE winsaai_config + SET host = ?, port = ?, protocol = ?, usuario = ?, password = ?, + sync_pedimentos = ?, sync_coves = ?, updated_at = GETDATE() + WHERE id_usuario = ?"; + $params = [$host, $port, $protocol, $usuario, $encryptedPassword, + $sync_pedimentos ? 1 : 0, $sync_coves ? 1 : 0, $userId]; + } else { + // Insertar + $sql = "INSERT INTO winsaai_config (id_usuario, host, port, protocol, usuario, password, sync_pedimentos, sync_coves) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + $params = [$userId, $host, $port, $protocol, $usuario, $encryptedPassword, + $sync_pedimentos ? 1 : 0, $sync_coves ? 1 : 0]; + } + + $stmt = sqlsrv_query($conn, $sql, $params); + + if ($stmt === false) { + http_response_code(500); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Error al guardar configuración']); + exit; + } + + sqlsrv_free_stmt($stmt); + + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => 'Configuración guardada correctamente']); +} + +function get_config() { + $conn = getConnection(); + $userId = $_SESSION['usuario_id'] ?? null; + + if (!$userId) { + http_response_code(401); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Sesión expirada']); + exit; + } + + $sql = "SELECT * FROM winsaai_config WHERE id_usuario = ?"; + $stmt = sqlsrv_query($conn, $sql, [$userId]); + + if ($stmt === false) { + http_response_code(500); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Error en base de datos']); + exit; + } + + $config = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + sqlsrv_free_stmt($stmt); + + if ($config) { + // No enviar contraseña por seguridad + unset($config['password']); + // Convertir BIT a boolean + $config['sync_pedimentos'] = (bool)$config['sync_pedimentos']; + $config['sync_coves'] = (bool)$config['sync_coves']; + + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'data' => $config]); + } else { + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'No hay configuración']); + } +} + +function test_connection() { + $conn = getConnection(); + $userId = $_SESSION['usuario_id'] ?? null; + + if (!$userId) { + http_response_code(401); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Sesión expirada']); + exit; + } + + $input = json_decode(file_get_contents('php://input'), true); + + $host = trim($input['host'] ?? ''); + $port = intval($input['port'] ?? 80); + $protocol = $input['protocol'] ?? 'https'; + $usuario = trim($input['usuario'] ?? ''); + $password = $input['password'] ?? ''; + + if (empty($host) || empty($usuario) || empty($password)) { + http_response_code(400); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Faltan datos para probar conexión']); + exit; + } + + $url = "{$protocol}://{$host}:{$port}/api/test"; + + // Simular prueba de conexión (aquí pondrías la lógica real) + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => "Conexión exitosa con {$protocol}://{$host}:{$port}"]); +} + +function sync_data() { + $conn = getConnection(); + $userId = $_SESSION['usuario_id'] ?? null; + + if (!$userId) { + http_response_code(401); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Sesión expirada']); + exit; + } + + // Obtener configuración del usuario + $sql = "SELECT * FROM winsaai_config WHERE id_usuario = ?"; + $stmt = sqlsrv_query($conn, $sql, [$userId]); + + if ($stmt === false) { + http_response_code(500); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Error en base de datos']); + exit; + } + + $config = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + sqlsrv_free_stmt($stmt); + + if (!$config) { + http_response_code(400); + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'No hay configuración de WINSAAI']); + exit; + } + + $input = json_decode(file_get_contents('php://input'), true); + $syncType = $input['sync_type'] ?? 'both'; + + // Simular sincronización + $results = []; + if ($syncType === 'pedimentos' || $syncType === 'both') { + $results['pedimentos'] = ['total' => 10, 'processed' => 10]; + } + if ($syncType === 'coves' || $syncType === 'both') { + $results['coves'] = ['total' => 5, 'processed' => 5]; + } + + // Actualizar última sincronización + $sqlUpdate = "UPDATE winsaai_config SET last_sync = GETDATE() WHERE id_usuario = ?"; + sqlsrv_query($conn, $sqlUpdate, [$userId]); + + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => 'Sincronización completada', 'data' => $results]); +} + +function index() { + header('Content-Type: application/json'); + echo json_encode([ + 'success' => true, + 'message' => 'API WINSAAI disponible', + 'endpoints' => [ + 'save_config' => '/IMPORTADORES/winsaai/save_config', + 'test_connection' => '/IMPORTADORES/winsaai/test_connection', + 'sync_data' => '/IMPORTADORES/winsaai/sync_data', + 'get_config' => '/IMPORTADORES/winsaai/get_config' + ] + ]); +} +?> \ No newline at end of file diff --git a/claves_pedimentos_tabla.sql b/claves_pedimentos_tabla.sql new file mode 100644 index 0000000..629396b --- /dev/null +++ b/claves_pedimentos_tabla.sql @@ -0,0 +1,21 @@ +-- Tabla para claves de pedimentos configurables por usuario +CREATE TABLE claves_pedimentos_usuario ( + id_clave_pedimento INT PRIMARY KEY IDENTITY, + id_usuario INT NOT NULL, + codigo VARCHAR(10) NOT NULL, + descripcion NVARCHAR(255) NOT NULL, + tipo_operacion VARCHAR(50), -- 'importacion', 'exportacion', etc. + activo BIT DEFAULT 1, + fecha_creacion DATETIME DEFAULT GETDATE(), + fecha_modificacion DATETIME DEFAULT GETDATE(), + FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario), + UNIQUE(id_usuario, codigo) -- Un usuario no puede tener códigos duplicados +); + +-- Índices para optimizar consultas +CREATE INDEX IX_claves_pedimentos_usuario_id ON claves_pedimentos_usuario(id_usuario); +CREATE INDEX IX_claves_pedimentos_activo ON claves_pedimentos_usuario(activo); + +-- NOTA: Los datos de ejemplo se omiten porque requieren usuarios existentes +-- Las claves se insertarán automáticamente cuando el usuario use la función +-- "inicializar_claves_usuario()" desde la aplicación web \ No newline at end of file diff --git a/configuracion_ventanilla_unica.sql b/configuracion_ventanilla_unica.sql new file mode 100644 index 0000000..a8e04ab --- /dev/null +++ b/configuracion_ventanilla_unica.sql @@ -0,0 +1,97 @@ +-- Tabla para configuración de Ventanilla Única +-- Script de creación para SQL Server + +IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='configuracion_ventanilla_unica' AND xtype='U') +BEGIN + CREATE TABLE configuracion_ventanilla_unica ( + id_configuracion INT IDENTITY(1,1) PRIMARY KEY, + id_usuario INT NOT NULL, + ruta_ejecutable NVARCHAR(500) NOT NULL, + ruta_archivo_key NVARCHAR(500) NULL, + ruta_archivo_cer NVARCHAR(500) NULL, + clave_fiel NVARCHAR(MAX) NULL, -- Encriptado + rfc_usuario_vu NVARCHAR(13) NOT NULL, + clave_webservice NVARCHAR(MAX) NULL, -- Encriptado + fecha_creacion DATETIME2 DEFAULT GETDATE(), + fecha_actualizacion DATETIME2 NULL, + activo BIT DEFAULT 1, + + -- Constraints + CONSTRAINT FK_configuracion_vu_usuario + FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario) + ON DELETE CASCADE, + + CONSTRAINT UQ_configuracion_vu_usuario + UNIQUE (id_usuario) + ); + + PRINT 'Tabla configuracion_ventanilla_unica creada exitosamente'; +END +ELSE +BEGIN + PRINT 'La tabla configuracion_ventanilla_unica ya existe'; +END + +-- Crear índices para mejorar rendimiento +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name='IX_configuracion_vu_usuario' AND object_id = OBJECT_ID('configuracion_ventanilla_unica')) +BEGIN + CREATE INDEX IX_configuracion_vu_usuario ON configuracion_ventanilla_unica(id_usuario); + PRINT 'Índice IX_configuracion_vu_usuario creado'; +END + +IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name='IX_configuracion_vu_rfc' AND object_id = OBJECT_ID('configuracion_ventanilla_unica')) +BEGIN + CREATE INDEX IX_configuracion_vu_rfc ON configuracion_ventanilla_unica(rfc_usuario_vu); + PRINT 'Índice IX_configuracion_vu_rfc creado'; +END + +-- Agregar comentarios descriptivos +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'Configuración de Ventanilla Única para transmisiones de Manifestación de Valor Electrónica', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica'; + +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'Ruta completa al archivo ejecutable de Ventanilla Única', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica', + @level2type = N'COLUMN', @level2name = N'ruta_ejecutable'; + +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'Ruta al archivo KEY del certificado FIEL', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica', + @level2type = N'COLUMN', @level2name = N'ruta_archivo_key'; + +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'Ruta al archivo CER del certificado FIEL', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica', + @level2type = N'COLUMN', @level2name = N'ruta_archivo_cer'; + +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'Contraseña FIEL encriptada', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica', + @level2type = N'COLUMN', @level2name = N'clave_fiel'; + +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'RFC del usuario para acceso a Ventanilla Única', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica', + @level2type = N'COLUMN', @level2name = N'rfc_usuario_vu'; + +EXEC sp_addextendedproperty + @name = N'MS_Description', + @value = N'Contraseña del Web Service encriptada', + @level0type = N'SCHEMA', @level0name = N'dbo', + @level1type = N'TABLE', @level1name = N'configuracion_ventanilla_unica', + @level2type = N'COLUMN', @level2name = N'clave_webservice'; + +PRINT 'Script de configuración de Ventanilla Única completado exitosamente'; \ No newline at end of file diff --git a/create_table_temp.php b/create_table_temp.php new file mode 100644 index 0000000..8365abc --- /dev/null +++ b/create_table_temp.php @@ -0,0 +1,52 @@ +getMessage() . "\n"; +} +?> \ No newline at end of file diff --git a/debug_templates.php b/debug_templates.php new file mode 100644 index 0000000..1cec591 --- /dev/null +++ b/debug_templates.php @@ -0,0 +1,196 @@ +🔍 Debug Simple de Templates"; +echo "

Usuario actual: " . $_SESSION['usuario_id'] . "

"; +echo "

Agencia actual: " . ($_SESSION['id_agencia_en_uso'] ?? 'NULL') . "

"; + +try { + $conn = getConnection(); + + // 1. Ver todos los templates sin filtros + echo "

1. Todos los templates en la base de datos:

"; + $sql = "SELECT id, nombre, descripcion, activo, id_usuario_creador, id_agencia, + fecha_creacion, config_json + FROM dbo.templates_rapidos + ORDER BY fecha_creacion DESC"; + + $stmt = sqlsrv_query($conn, $sql); + + if ($stmt === false) { + $errors = sqlsrv_errors(); + echo "
❌ Error en consulta: " . print_r($errors, true) . "
"; + } else { + $count = 0; + echo ""; + echo " + + + + + + + + + "; + + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + $count++; + $fecha = $row['fecha_creacion'] instanceof DateTime + ? $row['fecha_creacion']->format('Y-m-d H:i:s') + : $row['fecha_creacion']; + + $tieneConfig = !empty($row['config_json']) ? 'Sí' : 'No'; + + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo "
IDNombreDescripciónActivoUsuario CreadorAgenciaFecha CreaciónTiene Config
" . $row['id'] . "" . htmlspecialchars($row['nombre']) . "" . htmlspecialchars($row['descripcion'] ?? '') . "" . ($row['activo'] ? '✅' : '❌') . "" . ($row['id_usuario_creador'] ?? 'NULL') . "" . ($row['id_agencia'] ?? 'NULL') . "" . $fecha . "" . $tieneConfig . "
"; + + echo "

Total de templates encontrados: $count

"; + } + + // 2. Probar la consulta exacta del endpoint + echo "

2. Probando consulta del endpoint (con filtros):

"; + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso']; + + $sql_endpoint = "SELECT id, nombre, descripcion, icono, config_json, + ISNULL(veces_usado, 0) as veces_usado, + id_usuario_creador, id_agencia + FROM dbo.templates_rapidos + WHERE activo = 1 + AND (id_usuario_creador = ? OR id_agencia = ? OR id_agencia IS NULL) + ORDER BY + CASE WHEN id_usuario_creador = ? THEN 0 ELSE 1 END, + veces_usado DESC, + nombre ASC"; + + $stmt_endpoint = sqlsrv_query($conn, $sql_endpoint, [$id_usuario, $id_agencia, $id_usuario]); + + if ($stmt_endpoint === false) { + $errors = sqlsrv_errors(); + echo "
❌ Error en consulta endpoint: " . print_r($errors, true) . "
"; + } else { + $count_endpoint = 0; + echo ""; + echo " + + + + + + + "; + + while ($row = sqlsrv_fetch_array($stmt_endpoint, SQLSRV_FETCH_ASSOC)) { + $count_endpoint++; + $esMio = ($row['id_usuario_creador'] == $id_usuario) ? 'SÍ' : 'NO'; + + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo "
IDNombreEs MíoUsuario CreadorAgenciaDebería Aparecer
" . $row['id'] . "" . htmlspecialchars($row['nombre']) . "$esMio" . ($row['id_usuario_creador'] ?? 'NULL') . "" . ($row['id_agencia'] ?? 'NULL') . "✅ SÍ
"; + + echo "

Templates que deberían aparecer en el formulario: $count_endpoint

"; + } + + // 3. Probar el endpoint AJAX directamente + echo "

3. Prueba del endpoint AJAX:

"; + echo "

🔗 Abrir endpoint AJAX en nueva pestaña

"; + + // 4. Verificar la sesión + echo "

4. Estado de la sesión:

"; + echo "
";
+    echo "SESSION:\n";
+    foreach ($_SESSION as $key => $value) {
+        if (is_string($value) || is_numeric($value)) {
+            echo "  $key: $value\n";
+        }
+    }
+    echo "
"; + +} catch (Exception $e) { + echo "
Error: " . $e->getMessage() . "
"; +} +?> + + + +

5. Prueba AJAX en tiempo real:

+ +
+ +
+

💡 Instrucciones:
+1. Revisa los templates en la tabla de arriba
+2. Verifica que tu usuario_id y agencia_id sean correctos
+3. Haz clic en "Probar AJAX ahora" para ver la respuesta en tiempo real
+4. Abre la consola del navegador (F12) para ver logs detallados

\ No newline at end of file diff --git a/mve_incrementales_decrementales.sql b/mve_incrementales_decrementales.sql new file mode 100644 index 0000000..a523bc8 --- /dev/null +++ b/mve_incrementales_decrementales.sql @@ -0,0 +1,90 @@ +-- Tabla para almacenar datos de Manifestación de Valor por factura +CREATE TABLE mve_facturas_datos ( + id INT IDENTITY(1,1) PRIMARY KEY, + id_pedimento INT NOT NULL, + id_factura INT NOT NULL, + numero_factura NVARCHAR(100), + + -- Campos Art. 65 - Incrementables + art65_fecha_transporte DATE NULL, + art65_importe_transporte DECIMAL(15,2) NULL, + art65_fecha_descuentos DATE NULL, + art65_importe_descuentos DECIMAL(15,2) NULL, + art65_fecha_posteriores DATE NULL, + art65_importe_posteriores DECIMAL(15,2) NULL, + art65_fecha_contribuciones DATE NULL, + art65_importe_contribuciones DECIMAL(15,2) NULL, + art65_fecha_pagos_vendedor DATE NULL, + art65_importe_pagos_vendedor DECIMAL(15,2) NULL, + + -- Campos Art. 66 - Decrementables + art66_fecha_comisiones DATE NULL, + art66_importe_comisiones DECIMAL(15,2) NULL, + art66_cargo_comisiones NVARCHAR(10) CHECK (art66_cargo_comisiones IN ('Si', 'No')) NULL, + + art66_fecha_envases DATE NULL, + art66_importe_envases DECIMAL(15,2) NULL, + art66_cargo_envases NVARCHAR(10) CHECK (art66_cargo_envases IN ('Si', 'No')) NULL, + + art66_fecha_embalaje DATE NULL, + art66_importe_embalaje DECIMAL(15,2) NULL, + art66_cargo_embalaje NVARCHAR(10) CHECK (art66_cargo_embalaje IN ('Si', 'No')) NULL, + + art66_fecha_transporte_dec DATE NULL, + art66_importe_transporte_dec DECIMAL(15,2) NULL, + art66_cargo_transporte_dec NVARCHAR(10) CHECK (art66_cargo_transporte_dec IN ('Si', 'No')) NULL, + + art66_fecha_ingenieria DATE NULL, + art66_importe_ingenieria DECIMAL(15,2) NULL, + art66_cargo_ingenieria NVARCHAR(10) CHECK (art66_cargo_ingenieria IN ('Si', 'No')) NULL, + + art66_fecha_regalias DATE NULL, + art66_importe_regalias DECIMAL(15,2) NULL, + art66_cargo_regalias NVARCHAR(10) CHECK (art66_cargo_regalias IN ('Si', 'No')) NULL, + + art66_fecha_producto DATE NULL, + art66_importe_producto DECIMAL(15,2) NULL, + art66_cargo_producto NVARCHAR(10) CHECK (art66_cargo_producto IN ('Si', 'No')) NULL, + + -- Campos de control + fecha_creacion DATETIME2 DEFAULT GETDATE(), + fecha_actualizacion DATETIME2 DEFAULT GETDATE(), + usuario_creacion NVARCHAR(100), + + -- Índices y restricciones + CONSTRAINT UQ_mve_facturas_datos_pedimento_factura UNIQUE (id_pedimento, id_factura) +); + +-- Crear índices separadamente +CREATE INDEX IX_mve_facturas_datos_pedimento ON mve_facturas_datos (id_pedimento); +CREATE INDEX IX_mve_facturas_datos_factura ON mve_facturas_datos (id_factura); + +-- Tabla para el historial de solicitudes MVE +CREATE TABLE mve_solicitudes ( + id INT IDENTITY(1,1) PRIMARY KEY, + id_pedimento INT NOT NULL, + numero_pedimento NVARCHAR(50), + estado NVARCHAR(20) CHECK (estado IN ('Pendiente', 'En_Proceso', 'Completada', 'Rechazada')) DEFAULT 'Pendiente', + fecha_solicitud DATETIME2 DEFAULT GETDATE(), + fecha_respuesta DATETIME2 NULL, + observaciones NTEXT, + usuario_solicitud NVARCHAR(100) +); + +-- Crear índices para mve_solicitudes +CREATE INDEX IX_mve_solicitudes_pedimento ON mve_solicitudes (id_pedimento); +CREATE INDEX IX_mve_solicitudes_estado ON mve_solicitudes (estado); +CREATE INDEX IX_mve_solicitudes_fecha_solicitud ON mve_solicitudes (fecha_solicitud); + +-- Crear trigger para actualizar fecha_actualizacion automáticamente +CREATE TRIGGER TR_mve_facturas_datos_update +ON mve_facturas_datos +AFTER UPDATE +AS +BEGIN + SET NOCOUNT ON; + UPDATE mve_facturas_datos + SET fecha_actualizacion = GETDATE() + FROM mve_facturas_datos m + INNER JOIN inserted i ON m.id = i.id; +END; \ No newline at end of file diff --git a/previos_tabla.sql b/previos_tabla.sql new file mode 100644 index 0000000..62658ad --- /dev/null +++ b/previos_tabla.sql @@ -0,0 +1,58 @@ +-- Tabla para el catálogo de pedimentos (previos) +-- Esta tabla almacena los pedimentos registrados por los importadores + +CREATE TABLE [dbo].[previos] ( + [IdPrevio] [int] IDENTITY(1,1) NOT NULL, + [Pedimento] [nvarchar](50) NOT NULL, + [ClienteRFC] [nvarchar](13) NOT NULL, + [ClienteNombre] [nvarchar](255) NOT NULL, + [ClavePed] [nvarchar](10) NOT NULL, + [TipoOperacion] [int] DEFAULT 1, -- 1=importación, 2=exportación + [TipoPedimento] [int] DEFAULT 1, -- 1=normal, 2=complementario, etc. + [Regimen] [nvarchar](100) NULL, + [Destino] [nvarchar](100) NULL, + [FechaPedimento] [int] NULL, -- Formato YYYYMMDD + [FechaInicio] [int] NULL, -- Formato YYYYMMDD + [FechaFinal] [int] NULL, -- Formato YYYYMMDD + [ArchivoFinalPrevio] [nvarchar](255) NULL, + [AcuseCons] [nvarchar](100) NULL, + [Tipo] [nvarchar](50) NULL, + [Status] [int] DEFAULT 1, -- 1=activo, 0=inactivo + [Timestamp] [datetime] DEFAULT GETDATE(), + + CONSTRAINT [PK_previos] PRIMARY KEY CLUSTERED ([IdPrevio] ASC) +); + +-- Índices para mejorar el rendimiento +CREATE INDEX [IX_previos_cliente] ON [dbo].[previos] ([ClienteRFC]); +CREATE INDEX [IX_previos_pedimento] ON [dbo].[previos] ([Pedimento]); +CREATE INDEX [IX_previos_status] ON [dbo].[previos] ([Status]); +CREATE INDEX [IX_previos_timestamp] ON [dbo].[previos] ([Timestamp] DESC); + +-- Comentarios para documentación +EXEC sys.sp_addextendedproperty + @name=N'MS_Description', + @value=N'Tabla principal para el catálogo de pedimentos de importadores', + @level0type=N'SCHEMA', @level0name=N'dbo', + @level1type=N'TABLE', @level1name=N'previos'; + +EXEC sys.sp_addextendedproperty + @name=N'MS_Description', + @value=N'Número de pedimento aduanero', + @level0type=N'SCHEMA', @level0name=N'dbo', + @level1type=N'TABLE', @level1name=N'previos', + @level2type=N'COLUMN', @level2name=N'Pedimento'; + +EXEC sys.sp_addextendedproperty + @name=N'MS_Description', + @value=N'RFC del cliente/importador', + @level0type=N'SCHEMA', @level0name=N'dbo', + @level1type=N'TABLE', @level1name=N'previos', + @level2type=N'COLUMN', @level2name=N'ClienteRFC'; + +EXEC sys.sp_addextendedproperty + @name=N'MS_Description', + @value=N'Clave de pedimento utilizada', + @level0type=N'SCHEMA', @level0name=N'dbo', + @level1type=N'TABLE', @level1name=N'previos', + @level2type=N'COLUMN', @level2name=N'ClavePed'; \ No newline at end of file diff --git a/public/downloads/claves_pedimentos_template.csv b/public/downloads/claves_pedimentos_template.csv new file mode 100644 index 0000000..26f60ec --- /dev/null +++ b/public/downloads/claves_pedimentos_template.csv @@ -0,0 +1,6 @@ +codigo,descripcion,tipo_operacion,activo +A1,Importación definitiva de mercancías,importacion,1 +A3,Importación definitiva de vehículos usados,importacion,1 +B1,Importación temporal para elaborar transformar o reparar,importacion,1 +C1,Importación definitiva de mercancías donadas,importacion,1 +G1,Importación de mercancías con Programa IMMEX,importacion,1 \ No newline at end of file diff --git a/storage/certificados/cer_46_1760569052.cer b/storage/certificados/cer_46_1760569052.cer new file mode 100644 index 0000000000000000000000000000000000000000..a54794ee773f6f6a3b03aff8da7c4d8c4d72af88 GIT binary patch literal 1595 zcma)+c~BE)7{=Koge!;`3Ct{1D1t|=SiWUzD<){eAAuS%*!QvEgJO(_F?zV&4{?Y0Fv9s^{J+u3~zxSC1 zdb$AUX-;KS3PhpU0pdc)8vwq@#|Yn-?}q?ux`l^9YM8W!AS+W7pohLhV6c!*Rne#n zd!b5+%Q2Bq1fycP5(~vpp$L}?5pUo{Dl8d`6=Hc5hGIA@62n4K7#5BxlyV`_2#1w& zEJURg$}u7002YvXD~7E?sN`Z|1uV?cC2KQMbej^mVrVO1LDqC8B`gME1ADSCXUs)06*(JWJxm;fp*X?>w&al+!xB{qRZ^um3`ddq zfJrvFOa@`zUjPIE2@mHZt3m90-xOw8Mq*~VHZ4=VZewD=zfqv#aDs}A{L(Bi#d|(D zfkQ@2KxhbJpAcFxSZHs};{zT~z~e9FBfhajDVQyNePhA)Uc?0~B7ISr4l)&{fW`7~ zu|kQ%a$F?G2okZd1e48*-2acr@;^oYU`R$}HaEo5Y}E;=NU&O+nV3Or&0C{QMOeV@ zZ)(M^f`YRNXXQLs)uaIR9aH>5M*-O zC3mW(FsS;vYY%o+g4EaQaT@cak#EWV^>bmAd*Sn z_vpC0$06=AM)Rlpr?^YDv=v=z-PIcqRdkL0sGhm&DzkQbZ&yrU=eqtF*c7xME%)tGn6Uy)z$4aEO=+5K!Nwygd+I+`c>VQj2yF%`x(^T>fZN zn(Jf0xq2~ncTOjIu03zZg|}zRKELiX#_T!~J(aVuaLPHh@`j+GvF)c0JnyO1cRop9 zoh%vO#Q^(tmRtKBdS(9{ue+UQ+4H(4_tRe-T{X6HdCuBz*VMVKR(&)v&^#uu z7Cuz3w+o#hMrl3&LLzBk$;)rNOgiFm!Do7?ulKPrXY=|aSyh$#NarJ$&<%TH;zrQP zWrkWu`{IV_^Na4+Ge*YH3D5iMOP!^n(01dT#)u00i05A<+>7cRO^eqbYkJV?4);HJ z)-{#z$ea}h?QPY0IbA5hlLaV1-?!13dqgH<*?5!DqGj)U7s&7dV-hga%14K1?~ PZtX;!_U(3i(s1!l7fdiF literal 0 HcmV?d00001 diff --git a/storage/certificados/cer_46_1760569397.cer b/storage/certificados/cer_46_1760569397.cer new file mode 100644 index 0000000000000000000000000000000000000000..a54794ee773f6f6a3b03aff8da7c4d8c4d72af88 GIT binary patch literal 1595 zcma)+c~BE)7{=Koge!;`3Ct{1D1t|=SiWUzD<){eAAuS%*!QvEgJO(_F?zV&4{?Y0Fv9s^{J+u3~zxSC1 zdb$AUX-;KS3PhpU0pdc)8vwq@#|Yn-?}q?ux`l^9YM8W!AS+W7pohLhV6c!*Rne#n zd!b5+%Q2Bq1fycP5(~vpp$L}?5pUo{Dl8d`6=Hc5hGIA@62n4K7#5BxlyV`_2#1w& zEJURg$}u7002YvXD~7E?sN`Z|1uV?cC2KQMbej^mVrVO1LDqC8B`gME1ADSCXUs)06*(JWJxm;fp*X?>w&al+!xB{qRZ^um3`ddq zfJrvFOa@`zUjPIE2@mHZt3m90-xOw8Mq*~VHZ4=VZewD=zfqv#aDs}A{L(Bi#d|(D zfkQ@2KxhbJpAcFxSZHs};{zT~z~e9FBfhajDVQyNePhA)Uc?0~B7ISr4l)&{fW`7~ zu|kQ%a$F?G2okZd1e48*-2acr@;^oYU`R$}HaEo5Y}E;=NU&O+nV3Or&0C{QMOeV@ zZ)(M^f`YRNXXQLs)uaIR9aH>5M*-O zC3mW(FsS;vYY%o+g4EaQaT@cak#EWV^>bmAd*Sn z_vpC0$06=AM)Rlpr?^YDv=v=z-PIcqRdkL0sGhm&DzkQbZ&yrU=eqtF*c7xME%)tGn6Uy)z$4aEO=+5K!Nwygd+I+`c>VQj2yF%`x(^T>fZN zn(Jf0xq2~ncTOjIu03zZg|}zRKELiX#_T!~J(aVuaLPHh@`j+GvF)c0JnyO1cRop9 zoh%vO#Q^(tmRtKBdS(9{ue+UQ+4H(4_tRe-T{X6HdCuBz*VMVKR(&)v&^#uu z7Cuz3w+o#hMrl3&LLzBk$;)rNOgiFm!Do7?ulKPrXY=|aSyh$#NarJ$&<%TH;zrQP zWrkWu`{IV_^Na4+Ge*YH3D5iMOP!^n(01dT#)u00i05A<+>7cRO^eqbYkJV?4);HJ z)-{#z$ea}h?QPY0IbA5hlLaV1-?!13dqgH<*?5!DqGj)U7s&7dV-hga%14K1?~ PZtX;!_U(3i(s1!l7fdiF literal 0 HcmV?d00001 diff --git a/storage/certificados/key_46_1760569052.key b/storage/certificados/key_46_1760569052.key new file mode 100644 index 0000000000000000000000000000000000000000..2a50e3137ac63dea8de55c1fd16f09dff85f186a GIT binary patch literal 1298 zcmV+t1?~DUf&~sRKn4jahDe6@4FLrWFf%Y41_>&LNQU&4g?4S0RRGm0RaF4 z0tf&w6b1+?hDe6@4Fd-R2rz;Kz5)RNFa&}G$W9}GPt9#_pR4~mOWKR4x{h+zTK^Ms zQF8KabYH~-OQt|(WBo3J;-L0iG46`f+Mk-LME{NF$^JoA+Si)1qk6poU z7@1ug>s%gA`(>uW(EY;MB7TXgBgW0D$W$#lSKDQ|N+S%dy)KNu6%Rd8#_DyJl1G@V z;5iGvSAa&4I1Qzp9;S?V5TeRq=&inOL1Bc9`fPqZNOgL2l@)7<=(q-rPSGNBB5xIE z2R(rNH}M=CZpV>uB;#D&>S3;ILfId$EF8y~mh5Qc;Ccg#yG}Qtt3uA>G5fo3EAIJH z{s9uY(1d3^h|61mn=TKPREs#P4ut2^MaLr6!CD3Ias5lAIsyK_ALRew^&v2<6U5Q# zx!CHcJe)n0BcCcNR-urCJ2y9F5Ni4qO*y0}h1Wr6`sUnTX^hNV3-K+A{ep`;n~ZrZ zIJn1WbWa?2?Mz+YNW^LYo6&EWs1+UdEuTBoHLQrroRL6Ij~W56|3F zy#t5KFpsEpYCBpLPP3h*iDJ~%R}UqHcs(V#3}{A~uqndXuy4FB^|gPIk$L%!0x zt?7^3<@ON6F$G`;zGP`{qfStETkY5tV1rhqmJ)eJarbz>UUj&3?+n-RO}yAA`KDFC za##$|cqT9`Cc7ur>xG~wr{VsDjWOsD)qn3Q*HaPvLRz(MRk0y~f39q2Zc}vXO*z8- zV|5mJJ`1wh5jQ4$>j#akb+L3QKm_hjFARM=Q^x@Z4T%tARmDEH)zARCqq^UqKiKJ` zjASK}Yxi-MoV;z} zkmltbfh;f4OP}2owt-GnJFE^=K<~xaMXMXFSz+H!Sj6vRxwt>M2Oc%eYp@k>>t>*# zB|Gj$Q3%uSWm68vUP_}P+WPjyDB)Z2gmN7~fmgP;G{Zi#NMoYQ_1xEY=-CUjZIV#d z(KlN&VTUq(A(sO$&py1euzjzCftc{QjN|lw4Hz7gBg8jK*lD-Ov-HWaQ;jucJVrN- IUQ9e26#ZaqMgRZ+ literal 0 HcmV?d00001 diff --git a/storage/certificados/key_46_1760569397.key b/storage/certificados/key_46_1760569397.key new file mode 100644 index 0000000000000000000000000000000000000000..2a50e3137ac63dea8de55c1fd16f09dff85f186a GIT binary patch literal 1298 zcmV+t1?~DUf&~sRKn4jahDe6@4FLrWFf%Y41_>&LNQU&4g?4S0RRGm0RaF4 z0tf&w6b1+?hDe6@4Fd-R2rz;Kz5)RNFa&}G$W9}GPt9#_pR4~mOWKR4x{h+zTK^Ms zQF8KabYH~-OQt|(WBo3J;-L0iG46`f+Mk-LME{NF$^JoA+Si)1qk6poU z7@1ug>s%gA`(>uW(EY;MB7TXgBgW0D$W$#lSKDQ|N+S%dy)KNu6%Rd8#_DyJl1G@V z;5iGvSAa&4I1Qzp9;S?V5TeRq=&inOL1Bc9`fPqZNOgL2l@)7<=(q-rPSGNBB5xIE z2R(rNH}M=CZpV>uB;#D&>S3;ILfId$EF8y~mh5Qc;Ccg#yG}Qtt3uA>G5fo3EAIJH z{s9uY(1d3^h|61mn=TKPREs#P4ut2^MaLr6!CD3Ias5lAIsyK_ALRew^&v2<6U5Q# zx!CHcJe)n0BcCcNR-urCJ2y9F5Ni4qO*y0}h1Wr6`sUnTX^hNV3-K+A{ep`;n~ZrZ zIJn1WbWa?2?Mz+YNW^LYo6&EWs1+UdEuTBoHLQrroRL6Ij~W56|3F zy#t5KFpsEpYCBpLPP3h*iDJ~%R}UqHcs(V#3}{A~uqndXuy4FB^|gPIk$L%!0x zt?7^3<@ON6F$G`;zGP`{qfStETkY5tV1rhqmJ)eJarbz>UUj&3?+n-RO}yAA`KDFC za##$|cqT9`Cc7ur>xG~wr{VsDjWOsD)qn3Q*HaPvLRz(MRk0y~f39q2Zc}vXO*z8- zV|5mJJ`1wh5jQ4$>j#akb+L3QKm_hjFARM=Q^x@Z4T%tARmDEH)zARCqq^UqKiKJ` zjASK}Yxi-MoV;z} zkmltbfh;f4OP}2owt-GnJFE^=K<~xaMXMXFSz+H!Sj6vRxwt>M2Oc%eYp@k>>t>*# zB|Gj$Q3%uSWm68vUP_}P+WPjyDB)Z2gmN7~fmgP;G{Zi#NMoYQ_1xEY=-CUjZIV#d z(KlN&VTUq(A(sO$&py1euzjzCftc{QjN|lw4Hz7gBg8jK*lD-Ov-HWaQ;jucJVrN- IUQ9e26#ZaqMgRZ+ literal 0 HcmV?d00001 diff --git a/templates_rapidos.sql b/templates_rapidos.sql new file mode 100644 index 0000000..34d8979 --- /dev/null +++ b/templates_rapidos.sql @@ -0,0 +1,83 @@ +-- Tabla para Templates Rápidos Configurables +CREATE TABLE dbo.templates_rapidos ( + id INT IDENTITY(1,1) PRIMARY KEY, + nombre VARCHAR(100) NOT NULL, + descripcion VARCHAR(255), + icono VARCHAR(50) DEFAULT '🏢', + activo BIT DEFAULT 1, + + -- Configuración del template + config_json NVARCHAR(MAX), -- JSON con la configuración completa + + -- Campos específicos más usados (para facilitar consultas) + tipo_moneda VARCHAR(3), + incoterm VARCHAR(10), + vinculacion TINYINT, + pais_proveedor VARCHAR(10), + tasa_preferencial VARCHAR(20), + + -- Metadatos + id_agencia INT, + id_usuario_creador INT, + fecha_creacion DATETIME DEFAULT GETDATE(), + fecha_modificacion DATETIME DEFAULT GETDATE(), + + -- Estadísticas de uso + veces_usado INT DEFAULT 0, + ultima_vez_usado DATETIME, + + -- Índices + INDEX IX_templates_rapidos_agencia (id_agencia, activo), + INDEX IX_templates_rapidos_usuario (id_usuario_creador), + INDEX IX_templates_rapidos_uso (veces_usado DESC) +); + +-- Insertar algunos templates por defecto +INSERT INTO dbo.templates_rapidos (nombre, descripcion, icono, config_json, tipo_moneda, incoterm, vinculacion, pais_proveedor, tasa_preferencial, id_agencia, id_usuario_creador) VALUES +('Importación China', 'FOB, CNY, General, Sin vinculación', '🇨🇳', '{"tipo_moneda":"CNY","incoterm":"FOB","vinculacion":"0","pais_proveedor_texto":"China","tasa_preferencial":"General"}', 'CNY', 'FOB', 0, NULL, 'General', NULL, NULL), +('Importación USA', 'FOB, USD, TLC, Sin vinculación', '🇺🇸', '{"tipo_moneda":"USD","incoterm":"FOB","vinculacion":"0","pais_proveedor_texto":"Estados Unidos","tasa_preferencial":"TLC"}', 'USD', 'FOB', 0, NULL, 'TLC', NULL, NULL), +('Comercializadora', 'FOB, USD, COMERCIALIZADORA, Con vinculación', '🏢', '{"tipo_moneda":"USD","incoterm":"FOB","vinculacion":"2","pais_proveedor_texto":"Estados Unidos","tasa_preferencial":"COMERCIALIZADORA"}', 'USD', 'FOB', 2, NULL, 'COMERCIALIZADORA', NULL, NULL), +('Importación Europa', 'FOB, EUR, General, Sin vinculación', '🇪🇺', '{"tipo_moneda":"EUR","incoterm":"FOB","vinculacion":"0","pais_proveedor_texto":"Alemania","tasa_preferencial":"General"}', 'EUR', 'FOB', 0, NULL, 'General', NULL, NULL), +('PROSEC México', 'FOB, USD, PROSEC, Sin vinculación', '🏭', '{"tipo_moneda":"USD","incoterm":"FOB","vinculacion":"0","pais_proveedor_texto":"Estados Unidos","tasa_preferencial":"PROSEC"}', 'USD', 'FOB', 0, NULL, 'PROSEC', NULL, NULL); + +-- Crear procedimiento almacenado para obtener templates +GO +CREATE PROCEDURE sp_obtener_templates_rapidos + @id_usuario INT, + @id_agencia INT = NULL +AS +BEGIN + SELECT + id, + nombre, + descripcion, + icono, + config_json, + veces_usado, + ultima_vez_usado + FROM dbo.templates_rapidos + WHERE activo = 1 + AND ( + id_agencia IS NULL -- Templates globales + OR id_agencia = @id_agencia -- Templates de la agencia + OR id_usuario_creador = @id_usuario -- Templates del usuario + ) + ORDER BY veces_usado DESC, nombre ASC; +END + +-- Crear procedimiento para incrementar uso de template +GO +CREATE PROCEDURE sp_usar_template_rapido + @id_template INT, + @id_usuario INT +AS +BEGIN + UPDATE dbo.templates_rapidos + SET veces_usado = veces_usado + 1, + ultima_vez_usado = GETDATE() + WHERE id = @id_template; + + -- Opcional: Registrar en bitácora de uso + INSERT INTO dbo.bitacoras (id_usuario, accion, tabla_afectada, id_registro, detalles, fecha_accion) + VALUES (@id_usuario, 'USAR_TEMPLATE', 'templates_rapidos', @id_template, 'Template rápido utilizado', GETDATE()); +END \ No newline at end of file diff --git a/test_templates.php b/test_templates.php new file mode 100644 index 0000000..a8372df --- /dev/null +++ b/test_templates.php @@ -0,0 +1,157 @@ +🔍 Diagnóstico de Templates"; + +try { + $conn = getConnection(); + echo "✅ Conexión a base de datos: OK

"; + + // 1. Verificar si existe la tabla + echo "

1. Verificando tabla templates_rapidos:

"; + $sql_check = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'templates_rapidos'"; + $stmt = sqlsrv_query($conn, $sql_check); + + if ($stmt && sqlsrv_fetch_array($stmt)) { + echo "✅ La tabla templates_rapidos existe

"; + + // 2. Verificar estructura de la tabla + echo "

2. Estructura de la tabla:

"; + $sql_columns = "SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME = 'templates_rapidos' + ORDER BY ORDINAL_POSITION"; + $stmt_cols = sqlsrv_query($conn, $sql_columns); + + echo ""; + echo ""; + + $columnas_encontradas = []; + while ($col = sqlsrv_fetch_array($stmt_cols, SQLSRV_FETCH_ASSOC)) { + $columnas_encontradas[] = $col['COLUMN_NAME']; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo "
ColumnaTipoNullable
" . $col['COLUMN_NAME'] . "" . $col['DATA_TYPE'] . "" . $col['IS_NULLABLE'] . "
"; + + // 3. Verificar columnas específicas que usa el código + echo "

3. Verificando columnas requeridas:

"; + $columnas_requeridas = ['id', 'nombre', 'descripcion', 'icono', 'config_json', 'veces_usado', 'activo', 'id_usuario_creador', 'id_agencia']; + + foreach ($columnas_requeridas as $col) { + if (in_array($col, $columnas_encontradas)) { + echo "✅ Columna $col: Existe
"; + } else { + echo "❌ Columna $col: NO EXISTE
"; + } + } + + echo "
"; + + // 4. Contar registros + echo "

4. Contando registros:

"; + $sql_count = "SELECT COUNT(*) as total FROM dbo.templates_rapidos"; + $stmt_count = sqlsrv_query($conn, $sql_count); + + if ($stmt_count && $row = sqlsrv_fetch_array($stmt_count, SQLSRV_FETCH_ASSOC)) { + echo "📊 Total de registros en la tabla: " . $row['total'] . "
"; + + // 4.1 Contar activos + $sql_active = "SELECT COUNT(*) as activos FROM dbo.templates_rapidos WHERE activo = 1"; + $stmt_active = sqlsrv_query($conn, $sql_active); + if ($stmt_active && $row_active = sqlsrv_fetch_array($stmt_active, SQLSRV_FETCH_ASSOC)) { + echo "✅ Registros activos: " . $row_active['activos'] . "
"; + } + } + + echo "
"; + + // 5. Probar la consulta exacta del controlador + echo "

5. Probando consulta del controlador:

"; + $id_usuario = $_SESSION['usuario_id']; + $id_agencia = $_SESSION['id_agencia_en_uso']; + + echo "👤 ID Usuario: $id_usuario
"; + echo "🏢 ID Agencia: $id_agencia

"; + + $sql_controller = "SELECT id, nombre, descripcion, icono, config_json, veces_usado + FROM dbo.templates_rapidos + WHERE activo = 1 + AND (id_agencia IS NULL OR id_agencia = ? OR id_usuario_creador = ?) + ORDER BY veces_usado DESC, nombre ASC"; + + echo "SQL:
"; + echo "" . str_replace('?', "'$id_agencia', '$id_usuario'", $sql_controller) . "

"; + + $stmt_test = sqlsrv_query($conn, $sql_controller, [$id_agencia, $id_usuario]); + + if ($stmt_test === false) { + echo "❌ Error en la consulta:
"; + $errors = sqlsrv_errors(); + foreach ($errors as $error) { + echo "- " . $error['message'] . "
"; + } + } else { + $templates = []; + $count = 0; + + while ($row = sqlsrv_fetch_array($stmt_test, SQLSRV_FETCH_ASSOC)) { + $count++; + $templates[] = $row; + if ($count <= 3) { // Mostrar solo los primeros 3 para no saturar + echo "📋 Template $count: " . htmlspecialchars($row['nombre']) . "
"; + } + } + + echo "
Consulta exitosa. Total encontrados: $count templates
"; + + if ($count === 0) { + echo "
⚠️ No se encontraron templates. Posibles causas:
"; + echo "1. No hay templates creados
"; + echo "2. Todos los templates están inactivos (activo = 0)
"; + echo "3. Los templates no pertenecen a tu usuario/agencia
"; + } + } + + // 6. Mostrar algunos registros de ejemplo + echo "

6. Registros de muestra (últimos 5):

"; + $sql_sample = "SELECT TOP 5 id, nombre, activo, id_usuario_creador, id_agencia + FROM dbo.templates_rapidos + ORDER BY id DESC"; + $stmt_sample = sqlsrv_query($conn, $sql_sample); + + if ($stmt_sample) { + echo ""; + echo ""; + + while ($sample = sqlsrv_fetch_array($stmt_sample, SQLSRV_FETCH_ASSOC)) { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + echo "
IDNombreActivoUsuarioAgencia
" . $sample['id'] . "" . htmlspecialchars($sample['nombre']) . "" . ($sample['activo'] ? '✅' : '❌') . "" . ($sample['id_usuario_creador'] ?? 'NULL') . "" . ($sample['id_agencia'] ?? 'NULL') . "
"; + } + + } else { + echo "❌ La tabla templates_rapidos NO EXISTE
"; + echo "🔧 Necesitas crear la tabla primero."; + } + +} catch (Exception $e) { + echo "❌ Error: " . $e->getMessage(); +} +?> \ No newline at end of file diff --git a/views/automatizaciones/automatizaciones.php b/views/automatizaciones/automatizaciones.php index 3530cd9..7445084 100644 --- a/views/automatizaciones/automatizaciones.php +++ b/views/automatizaciones/automatizaciones.php @@ -61,8 +61,718 @@
-

⚙️ Automatizaciones

+

⚙️ Automatizaciones

+ + +
+
+
+
+
+ +
Conexión con WINSAAI
+
+
+ Verificando... +
+
+
+ + +
+

+ + Configura la conexión con el sistema WINSAAI para importar automáticamente pedimentos y COVES. +

+ + + +
+ + + + + +
+
+
+
+ + Configuración de Conexión API +
+ +
+
+
+
+ +
+ + +
+ Ingresa la dirección IP o nombre de dominio del servidor WINSAAI +
+
+ + +
+ + +
+ Puerto del servicio API (ejemplo: 8080, 80, 443) +
+
+
+ +
+ +
+ + +
+ Nombre de usuario proporcionado por WINSAAI +
+
+ + +
+ + +
+ Contraseña de acceso al sistema WINSAAI +
+
+
+ +
+ +
+ + +
+ + +
+ +
+ No configurado +
+
+
+ + +
+
+ +
+ + +
+
+ + +
+
+
+ + +
+ + + +
+
+
+
+
+ + + + +
+
+
+
+
+ + + \ No newline at end of file diff --git a/views/catalogo_pedimentos/crear.php b/views/catalogo_pedimentos/crear.php new file mode 100644 index 0000000..f327239 --- /dev/null +++ b/views/catalogo_pedimentos/crear.php @@ -0,0 +1,407 @@ + + + Configuración requerida: + Debe configurar su información general antes de crear pedimentos. + Ir a Configuración + '; + return; +} + +// Verificar que tenga claves de pedimentos configuradas +if (empty($claves_pedimentos)) { + echo '
+ + Claves de pedimentos: + No tiene claves de pedimentos de importación configuradas. + Configurar Claves +
'; +} +?> + + + + + + 📋 Nuevo Pedimento de Importación + + + + + + + + + + + +
+
+

📋 Nuevo Pedimento de Importación

+ + Regresar a Lista + +
+ +
+
+
+
+ +
+
+
+
Información del Pedimento
+
+
+
+ + +
Formato estándar: AA AA AAAA AAAAAAA (año aduana sección número)
+
+ +
+ + + +
+ + No tiene claves configuradas. + Inicializar claves por defecto +
+ +
+ Seleccione la clave que corresponda al tipo de importación +
+ +
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
Información del Importador
+
+
+ +
+ RFC: + +
+
+ Nombre/Razón Social:
+ +
+ +
+ Correo:
+ +
+ +
+
+ + Esta información se incluirá automáticamente en el pedimento +
+ +
+ + Configure su información general primero +
+ +
+
+ + +
+
+
Fechas
+
+
+
+ + +
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+
Información Adicional
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+ + Cancelar + + +
+
+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/views/catalogo_pedimentos/editar.php b/views/catalogo_pedimentos/editar.php new file mode 100644 index 0000000..07dda43 --- /dev/null +++ b/views/catalogo_pedimentos/editar.php @@ -0,0 +1,380 @@ + + + + + + + 📋 Editar Pedimento + + + + + + + + + + + +
+
+

📋 Editar Pedimento #

+ + Regresar a Lista + +
+ +
+
+
+ + +
+ +
+
+
+
Información Básica
+
+
+
+ + +
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+
Información del Cliente
+
+
+
+ + +
+ +
+ + +
+
+
+ + +
+
+
Fechas
+
+
+
+ + +
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+
Información Adicional
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+
Información de Registro
+
+
+
+
+

ID del Registro:

+
+
+

Fecha de Registro: + format('d/m/Y H:i:s'); + } else { + echo 'No disponible'; + } + ?> +

+
+
+
+
+
+
+ + +
+
+
+ + Cancelar + + +
+
+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/views/catalogo_pedimentos/index.php b/views/catalogo_pedimentos/index.php new file mode 100644 index 0000000..7e5e028 --- /dev/null +++ b/views/catalogo_pedimentos/index.php @@ -0,0 +1,166 @@ + + + + + + + 📋 Catálogo de Pedimentos + + + + + + + + + + + +
+

📋 Catálogo de Pedimentos

+ +
+
+
+
+
+
+
Lista de Pedimentos
+

Visualizar y gestionar todos los pedimentos registrados

+
+
+ +
+
+ + Ver Lista + +
+
+
+ +
+
+
+
+
+
Nuevo Pedimento
+

Registrar un nuevo pedimento en el sistema

+
+
+ +
+
+ + Crear Nuevo + +
+
+
+ +
+
+
+
+
+
Reportes
+

Generar reportes y estadísticas de pedimentos

+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+
Información del Módulo
+
+
+

+ El catálogo de pedimentos le permite gestionar de manera eficiente todos los pedimentos + de importación. Desde aquí puede: +

+
    +
  • Registrar nuevos pedimentos con toda la información requerida
  • +
  • Consultar y editar pedimentos existentes
  • +
  • Realizar búsquedas avanzadas por diversos criterios
  • +
  • Exportar información para reportes
  • +
  • Mantener un histórico completo de operaciones
  • +
+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/views/catalogo_pedimentos/lista.php b/views/catalogo_pedimentos/lista.php new file mode 100644 index 0000000..cfd7c05 --- /dev/null +++ b/views/catalogo_pedimentos/lista.php @@ -0,0 +1,194 @@ + + + + + + + 📋 Catálogo de Pedimentos + + + + + + + + + + + + +
+
+

📋 Lista de Pedimentos

+ +
+ +
+
+ + + + + + + + + + + + + + + +
IDPedimentoRFC ClienteNombre ClienteFecha RegistroEstadoAcciones
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/views/claves_pedimentos/crear.php b/views/claves_pedimentos/crear.php new file mode 100644 index 0000000..0d08b03 --- /dev/null +++ b/views/claves_pedimentos/crear.php @@ -0,0 +1,230 @@ + + + + + + + 🔑 Nueva Clave de Pedimento + + + + + + + + + + + +
+
+

🔑 Nueva Clave de Pedimento

+ + Regresar a Lista + +
+ +
+
+
+
+
+
+
+
Información de la Clave
+
+
+
+ + +
Máximo 10 caracteres. Se convertirá automáticamente a mayúsculas.
+
+ +
+ + +
Describe claramente el tipo de operación que representa esta clave.
+
+ +
+ + +
+ +
+
+ + +
Las claves inactivas no aparecerán en los formularios de pedimentos.
+
+
+
+
+
+ +
+
+
+
Ejemplos de Claves Comunes
+
+
+
+ + + + + + + + + + + + + + + + + +
CódigoDescripción
A1Importación definitiva de mercancías
A3Importación definitiva de vehículos usados
A4Importación definitiva de vehículos nuevos
B1Importación temporal para elaborar
C1Importación definitiva de mercancías donadas
G1Importación con Programa IMMEX
I1Importación definitiva exenta
L1Importación con TLC
+
+ +
+ + Consejo: Puedes crear tus propias claves personalizadas o usar las estándar del SAT. +
+
+
+
+
+ + +
+
+
+ + Cancelar + + +
+
+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/views/claves_pedimentos/editar.php b/views/claves_pedimentos/editar.php new file mode 100644 index 0000000..ac64524 --- /dev/null +++ b/views/claves_pedimentos/editar.php @@ -0,0 +1,280 @@ + + + + + + + 🔑 Editar Clave de Pedimento + + + + + + + + + + + +
+
+

🔑 Editar Clave #

+ + Regresar a Lista + +
+ +
+
+
+ + +
+
+
+
+
Información de la Clave
+
+
+
+ + +
Máximo 10 caracteres. Se convertirá automáticamente a mayúsculas.
+
+ +
+ + +
Describe claramente el tipo de operación que representa esta clave.
+
+ +
+ + +
+ +
+
+ > + +
Las claves inactivas no aparecerán en los formularios de pedimentos.
+
+
+
+
+
+ +
+ +
+
+
Información del Registro
+
+
+
+
+

ID:

+
+
+

Código Actual: + +

+
+
+
+
+

Fecha Creación: + format('d/m/Y H:i:s'); + } else { + echo 'No disponible'; + } + ?> +

+
+
+

Última Modificación: + format('d/m/Y H:i:s'); + } else { + echo 'No disponible'; + } + ?> +

+
+
+
+
+

Estado: + + Activo + + Inactivo + +

+
+
+
+
+ + +
+
+
Ejemplos de Claves Comunes
+
+
+
+
+ A1: Importación definitiva
+ A3: Vehículos usados
+ B1: Temporal elaborar
+ G1: Programa IMMEX +
+
+ I1: Definitiva exenta
+ L1: Con TLC
+ C1: Mercancías donadas
+ J1: Temporal reexportación +
+
+
+
+
+
+ + +
+
+
+ + Cancelar + + +
+
+
+
+
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/views/claves_pedimentos/importar_csv.php b/views/claves_pedimentos/importar_csv.php new file mode 100644 index 0000000..670f3ec --- /dev/null +++ b/views/claves_pedimentos/importar_csv.php @@ -0,0 +1,226 @@ + + + + + + + 📤 Importar Claves CSV + + + + + + + + + +
+
+

Importar Claves de Pedimentos por CSV

+ +
+ +
+
+
+
+
Cargar Archivo CSV
+
+
+
+ +
+ +
Arrastra tu archivo CSV aquí
+

o haz clic para seleccionar archivo

+ +
+ + + +
+
Opciones de importación:
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+
+
+ +
+
+
+
Instrucciones
+
+
+
📋 Formato del archivo CSV:
+
    +
  • Separador: Coma (,)
  • +
  • Codificación: UTF-8
  • +
  • Encabezados: Obligatorios
  • +
+ +
🏷️ Columnas requeridas:
+
    +
  • codigo: Código de la clave (ej: A1, B2)
  • +
  • descripcion: Descripción detallada
  • +
  • tipo_operacion: importacion o exportacion
  • +
  • activo: 1 (activo) o 0 (inactivo)
  • +
+ +
+ + Importante: Los códigos deben ser únicos. Si existe un código duplicado, se omitirá según la configuración seleccionada. +
+ + +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/views/claves_pedimentos/index.php b/views/claves_pedimentos/index.php new file mode 100644 index 0000000..1564cad --- /dev/null +++ b/views/claves_pedimentos/index.php @@ -0,0 +1,170 @@ + + + + + + + 🔑 Claves de Pedimentos + + + + + + + + + + + +
+

🔑 Configuración de Claves de Pedimentos

+ +
+
+
+
+
+
+
Mis Claves
+

Ver y gestionar tus claves de pedimentos configuradas

+
+
+ +
+
+ + Ver Lista + +
+
+
+ +
+
+
+
+
+
Nueva Clave
+

Agregar una nueva clave de pedimento personalizada

+
+
+ +
+
+ + Crear Nueva + +
+
+
+ +
+
+
+
+
+
Inicializar
+

Cargar claves de pedimentos por defecto

+
+
+ +
+
+ + Inicializar + +
+
+
+
+ +
+
+
+
+
Información del Módulo
+
+
+

+ Las claves de pedimentos son códigos que identifican el tipo de operación de comercio exterior. + Este módulo te permite personalizar y gestionar las claves que utilizas frecuentemente. +

+
+
+
Funcionalidades:
+
    +
  • Crear claves personalizadas
  • +
  • Modificar claves existentes
  • +
  • Activar/desactivar claves
  • +
  • Eliminar claves no utilizadas
  • +
+
+
+
Claves Comunes de Importación:
+
    +
  • A1: Importación definitiva
  • +
  • B1: Importación temporal
  • +
  • G1: Programa IMMEX
  • +
  • L1: TLC (Tratados)
  • +
+
+
+
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/views/claves_pedimentos/lista.php b/views/claves_pedimentos/lista.php new file mode 100644 index 0000000..9b24e4d --- /dev/null +++ b/views/claves_pedimentos/lista.php @@ -0,0 +1,204 @@ + + + + + + + 🔑 Lista de Claves de Pedimentos + + + + + + + + + + + + +
+
+

🔑 Mis Claves de Pedimentos

+ +
+ +
+
+ + + + + + + + + + + + + + + +
IDCódigoDescripciónTipoEstadoFecha CreaciónAcciones
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/views/home/inicio.php b/views/home/inicio.php index de187cc..664cfe6 100644 --- a/views/home/inicio.php +++ b/views/home/inicio.php @@ -15,12 +15,12 @@ if (!$stmt || !sqlsrv_execute($stmt)) { } $config = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); -// Variables con valores por defecto -$nombre = $config['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos'; -$siglas = $config['siglas'] ?? 'SIIH'; -$logo = $config['logo_url'] ?? 'assets/img/logo_siih.png'; -$color1 = explode(',', $config['colores_primarios'] ?? '#003366,#0055A5')[0]; -$color2 = explode(',', $config['colores_primarios'] ?? '#003366,#0055A5')[1]; +// Variables con valores por defecto - Branding más sutil +$nombre = $config['nombre_plataforma'] ?? 'Sistema de Gestión de Importaciones'; +$siglas = $config['siglas'] ?? 'AduanaSoft'; +$logo = $config['logo_url'] ?? 'assets/img/logo_aduanasoft.png'; +$color1 = explode(',', $config['colores_primarios'] ?? '#0f172a,#334155')[0]; // Negro suave +$color2 = explode(',', $config['colores_primarios'] ?? '#0f172a,#334155')[1]; // Gris slate $mantenimiento = $config['modo_mantenimiento'] ?? 0; $mensajeMantenimiento = $config['mensaje_mantenimiento'] ?? 'El sistema se encuentra en mantenimiento temporal. Por favor, vuelve más tarde.'; ?> @@ -29,23 +29,288 @@ $mensajeMantenimiento = $config['mensaje_mantenimiento'] ?? 'El sistema se encue - <?= htmlspecialchars($siglas) ?> | Inicio + <?= htmlspecialchars($siglas) ?> | Gestión de Importaciones + + + @@ -53,8 +318,8 @@ $mensajeMantenimiento = $config['mensaje_mantenimiento'] ?? 'El sistema se encue - + -
- -

Sistema en Mantenimiento

-

+
+ +

Sistema en Mantenimiento

+

-

-

Una plataforma confiable para gestionar el registro y control de importadores de hidrocarburos en México.

-
-
- - -
-
-
-
- -
Registro en línea
-

Los importadores pueden enviar su solicitud y documentación de forma digital.

+
+
+
+

Gestión Moderna de Importaciones

+

+ Simplifica tus procesos aduaneros con nuestra plataforma integral. + Desde pedimentos hasta seguimiento, todo en un solo lugar. +

+ +
-
- -
Autorización segura
-

Las agencias aduanales validan manualmente cada solicitud antes de otorgar acceso.

-
-
- -
Información centralizada
-

Todas las solicitudes y datos se almacenan de forma segura y organizada.

+
+
+ +
+
+
+
+
+ 1,200+ +
Importadores
+
+
+
+
+ 25K+ +
Trámites
+
+
+
+
+ 98% +
Satisfacción
+
+
+
+
+ 24/7 +
Soporte
+
+
+
+
+
+ + +
+
+

Todo lo que necesitas

+

+ Herramientas profesionales diseñadas para optimizar cada etapa del proceso de importación +

+ +
+
+
+
+ +
+
Gestión de Pedimentos
+

+ Crea, gestiona y da seguimiento a tus pedimentos de importación con validación automática de datos. +

+
+
+ +
+
+
+ +
+
Cumplimiento Automatizado
+

+ Mantente al día con regulaciones aduaneras y recibe alertas sobre cambios normativos relevantes. +

+
+
+ +
+
+
+ +
+
Reportes Inteligentes
+

+ Analiza tus operaciones con dashboards interactivos y reportes personalizables en tiempo real. +

+
+
+ +
+
+
+ +
+
Colaboración
+

+ Conecta con agentes aduanales, transportistas y proveedores en un ecosistema colaborativo. +

+
+
+ +
+
+
+ +
+
Acceso Universal
+

+ Accede desde cualquier dispositivo con nuestra aplicación web responsiva y segura. +

+
+
+ +
+
+
+ +
+
Seguridad Total
+

+ Protección enterprise con encriptación avanzada, backups automáticos y certificaciones de seguridad. +

+
+
+
+
+
+ + +
+
+

¿Listo para optimizar tus importaciones?

+

+ Únete a más de 1,200 importadores que ya confían en nuestra plataforma +

+ + + Comenzar Ahora + +
+
+ -
- © · +
+
+ + +
diff --git a/views/login/cambiar_password.php b/views/login/cambiar_password.php index d93fd5a..bffc55f 100644 --- a/views/login/cambiar_password.php +++ b/views/login/cambiar_password.php @@ -1,15 +1,22 @@ @@ -17,31 +24,304 @@ if (!isset($_SESSION['recuperacion_autorizada'])) { - <?= htmlspecialchars($siglas) ?> | Recuperación de Contraseña + <?= htmlspecialchars($siglas) ?> | Nueva Contraseña + + - +
- -
-