diff --git a/.env b/.env
index b16b6a0..782fdc2 100644
--- a/.env
+++ b/.env
@@ -1,7 +1,7 @@
DB_HOST=localhost
DB_DATABASE=Importaciones_HC
-DB_USERNAME=sa
-DB_PASSWORD=Soluciones01
+DB_USERNAME=progra
+DB_PASSWORD=soluciones
ENCRYPTION_KEY=6a7f92d3c8d1e5b3b0ac23ff1926a7c9
ENCRYPTION_IV=7c9f4a2d1e3b5f7a
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..f0e99ee
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,8 @@
+# Copia este archivo a .env y completa tus credenciales de base de datos
+DB_HOST=localhost\\SQLEXPRESS
+DB_DATABASE=TuBaseDeDatos
+DB_USERNAME=TuUsuario
+DB_PASSWORD=TuPassword
+
+# Opcional: configuración adicional
+# DB_PORT=1433
diff --git a/agencias.txt b/agencias.txt
deleted file mode 100644
index e8a62ac..0000000
--- a/agencias.txt
+++ /dev/null
@@ -1,266 +0,0 @@
-Sistemas -- Administrador General
-INSERT INTO [Importaciones_HC].[dbo].[usuarios_sistema]
-([nombre], [email], [password_hash], [tipo_usuario], [activo], [creado_en], [dos_factores], [notificaciones], [notificaciones_extra])
-VALUES (
- '4a77Tj9XtOCnvkUrxuxLCg==', -- nombre encriptado
- 'QVaqkaWSvUtgAfKN51JNDkoyUiZGVQs3+ARpoGtdD/I=', -- email encriptado
- '$2y$10$.8CI5zuJ6MICQRRGqksYjOyuIYnln4xgUKJiQkZdEpLWfvUpg1f9m', -- password hash bcrypt
- 'super_admin', 1, GETDATE(), 0, 0, 0
-);
-
-
-CREATE TABLE solicitudes_agencias(
- [request_id] [int] IDENTITY(1,1) NOT NULL,
- [agencia_name] [varchar](255) NULL,
- [rfc] [varchar](100) NULL,
- [email] [varchar](255) NULL,
- [phone] [varchar](20) NULL,
- [direccion] [varchar](100) NULL,
- [opinion_file] [varchar](500) NULL,
- [admin_name] [varchar](255) NULL,
- [admin_email] [varchar](255) NULL,
- [request_status] [varchar](20) NULL,
- [request_date] [datetime] NULL,
- [approval_date] [datetime] NULL,
- [approved_by] [int] NULL,
- [timestamp_request] [timestamp] NOT NULL
-);
-
-
--- Tabla de Agencias Aduanales
-
-CREATE TABLE [dbo].[agencias_aduanales](
- [id_agencia] [int] IDENTITY(1,1) NOT NULL,
- [nombre_agencia] [nvarchar](255) NOT NULL,
- [rfc_agencia] [nvarchar](13) NOT NULL,
- [direccion] [nvarchar](500) NULL,
- [telefono] [nvarchar](20) NULL,
- [email] [nvarchar](255) NULL,
- [id_administrador] [int] NULL, -- Usuario administrador de la agencia
- [activo] [bit] NOT NULL DEFAULT 1,
- [creado_en] [datetime] NOT NULL DEFAULT GETDATE(),
- [actualizado_en] [datetime] NULL,
- [creado_por] [int] NULL, -- Super admin que creó la agencia
- CONSTRAINT [PK_agencias_aduanales] PRIMARY KEY CLUSTERED ([id_agencia] ASC)
-);
-
--- Agregar foreign key para administrador de agencia
-
-ALTER TABLE [dbo].[agencias_aduanales]
-ADD CONSTRAINT [FK_agencias_administrador]
-FOREIGN KEY ([id_administrador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]);
-
-CREATE TABLE [dbo].[credenciales_db_agencias] (
- [id_credencial] INT IDENTITY(1,1) NOT NULL,
- [id_agencia] INT NOT NULL,
- [db_instance] NVARCHAR(255) NOT NULL,
- [db_ip] NVARCHAR(50) NOT NULL,
- [db_user] NVARCHAR(100) NOT NULL,
- [db_password] NVARCHAR(255) NOT NULL, -- Considera encriptar o manejar de forma segura
- [db_port] INT NOT NULL DEFAULT 1433, -- Default SQL Server port
- [creado_en] DATETIME NOT NULL DEFAULT GETDATE(),
- [actualizado_en] DATETIME NULL,
-
- CONSTRAINT [PK_credenciales_db_agencias] PRIMARY KEY CLUSTERED ([id_credencial] ASC),
- CONSTRAINT [FK_credenciales_db_agencia]
- FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia])
-);
-
-CREATE UNIQUE INDEX [IX_credenciales_db_agencias_id_agencia]
-ON [dbo].[credenciales_db_agencias]([id_agencia]);
-
-
--- Actualizar tipos de usuario válidos
-
--- Los tipos de usuario ahora serán:
-
--- 'super_admin' - Administrador del sistema completo
--- 'admin_agencia' - Administrador de una agencia específica
--- 'agente_aduanal' - Agente que trabaja para una agencia
--- 'importador' - Cliente que puede trabajar con múltiples agencias
-
--- Campos de auditoría para usuarios_sistema
-ALTER TABLE [dbo].[usuarios_sistema]
-ADD [creado_por] [int] NULL;
-
-
--- Tabla de relación importador-agencia (many-to-many)
-
-CREATE TABLE [dbo].[importador_agencia](
- [id_relacion] [int] IDENTITY(1,1) NOT NULL,
- [id_importador] [int] NOT NULL,
- [id_agencia] [int] NOT NULL,
- [activo] [bit] NOT NULL DEFAULT 1,
- [fecha_vinculacion] [datetime] NOT NULL DEFAULT GETDATE(),
- [fecha_desvinculacion] [datetime] NULL,
- [creado_por] [int] NULL, -- ID del usuario que creó la relación
- [aprobado_por] [int] NULL, -- Admin de agencia que aprobó la vinculación
- [estado] [varchar](20) NOT NULL DEFAULT 'PENDIENTE', -- 'PENDIENTE', 'APROBADO', 'RECHAZADO'
- CONSTRAINT [PK_importador_agencia] PRIMARY KEY CLUSTERED ([id_relacion] ASC),
- CONSTRAINT [FK_importador_agencia_usuario]
- FOREIGN KEY ([id_importador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
- CONSTRAINT [FK_importador_agencia_agencia]
- FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]),
- CONSTRAINT [FK_importador_agencia_creador]
- FOREIGN KEY ([creado_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
- CONSTRAINT [FK_importador_agencia_aprobador]
- FOREIGN KEY ([aprobado_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario])
-);
-
--- Índice único para evitar duplicados activos
-
-CREATE UNIQUE INDEX [IX_importador_agencia_unique]
-ON [dbo].[importador_agencia] ([id_importador], [id_agencia])
-WHERE [activo] = 1;
-
-
--- Tabla de relación agente-agencia
-
-CREATE TABLE [dbo].[agente_agencia](
- [id_relacion] INT IDENTITY(1,1) NOT NULL,
- [id_agente] INT NOT NULL,
- [id_agencia] INT NOT NULL,
- [fecha_asignacion] DATETIME NOT NULL DEFAULT GETDATE(),
- [activo] BIT NOT NULL DEFAULT 1,
- [asignado_por] INT NULL, -- quien lo asignó (admin agencia o super admin)
- CONSTRAINT [PK_agente_agencia] PRIMARY KEY CLUSTERED ([id_relacion]),
- CONSTRAINT [FK_agente_agencia_usuario]
- FOREIGN KEY ([id_agente]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
- CONSTRAINT [FK_agente_agencia_agencia]
- FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia])
-);
-
--- Luego creas el índice filtrado:
-
-CREATE UNIQUE INDEX [UQ_agente_activo]
-ON [dbo].[agente_agencia]([id_agente])
-WHERE [activo] = 1;
-
--- Índice único para evitar duplicados activos
-
-CREATE UNIQUE INDEX [IX_agente_agencia_unique]
-ON [dbo].[agente_agencia] ([id_agente], [id_agencia])
-WHERE [activo] = 1;
-
-
--- Tabla para solicitudes de vinculación de importadores
-
-CREATE TABLE [dbo].[solicitudes_vinculacion](
- [id_solicitud] [int] IDENTITY(1,1) NOT NULL,
- [id_importador] [int] NOT NULL,
- [id_agencia] [int] NOT NULL,
- [mensaje] [nvarchar](1000) NULL,
- [estado] [varchar](20) NOT NULL DEFAULT 'PENDIENTE', -- 'PENDIENTE', 'APROBADA', 'RECHAZADA'
- [fecha_solicitud] [datetime] NOT NULL DEFAULT GETDATE(),
- [fecha_respuesta] [datetime] NULL,
- [respondido_por] [int] NULL, -- Admin de agencia que respondió
- [comentarios_respuesta] [nvarchar](1000) NULL,
- CONSTRAINT [PK_solicitudes_vinculacion] PRIMARY KEY CLUSTERED ([id_solicitud] ASC),
- CONSTRAINT [FK_solicitudes_importador]
- FOREIGN KEY ([id_importador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]),
- CONSTRAINT [FK_solicitudes_agencia]
- FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]),
- CONSTRAINT [FK_solicitudes_respondido]
- FOREIGN KEY ([respondido_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario])
-);
-
-
--- Tabla para auditoría de cambios de agencia
-
-CREATE TABLE [dbo].[bitacora_agencias](
- [id_bitacora] [int] IDENTITY(1,1) NOT NULL,
- [id_agencia] [int] NULL,
- [nombre] [varchar](100) NULL,
- [accion] [varchar](50) NOT NULL, -- 'CREACION', 'DESACTIVACION'
- [realizado_por] [int] NOT NULL,
- [fecha] [datetime] NOT NULL DEFAULT GETDATE(),
- CONSTRAINT [PK_bitacora_agenciaS] PRIMARY KEY CLUSTERED ([id_bitacora] ASC)
-);
-
-ALTER TABLE [dbo].[bitacora_agencias]
-ADD CONSTRAINT [FK_bitacora_agencias_agencia]
-FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]);
-
-ALTER TABLE [dbo].[bitacora_agencias]
-ADD CONSTRAINT [FK_bitacora_agencias_administrador]
-FOREIGN KEY ([realizado_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]);
-
-ALTER TABLE [dbo].[bitacora_agencias]
-ADD CONSTRAINT [CK_bitacora_agencias_accion]
-CHECK ([accion] IN ('CREACION', 'DESACTIVACION'));
-
-
--- Índices adicionales para mejorar rendimiento
-
-CREATE INDEX [IX_importador_agencia_importador] ON [dbo].[importador_agencia] ([id_importador]);
-
-CREATE INDEX [IX_importador_agencia_agencia] ON [dbo].[importador_agencia] ([id_agencia]);
-
-CREATE INDEX [IX_importador_agencia_estado] ON [dbo].[importador_agencia] ([estado], [activo]);
-
-CREATE INDEX [IX_agencias_activo] ON [dbo].[agencias_aduanales] ([activo]);
-
-CREATE INDEX [IX_agencias_administrador] ON [dbo].[agencias_aduanales] ([id_administrador]);
-
-CREATE INDEX [IX_solicitudes_estado] ON [dbo].[solicitudes_vinculacion] ([estado], [id_agencia]);
-
-
-== MODIFICACIONES MULLTI-AGENCIA ==
-ALTER TABLE usuarios_sistema
-ADD id_agencia_en_uso INT NULL;
-
-ALTER TABLE usuarios_sistema
-ADD CONSTRAINT FK_usuario_agencia_uso
-FOREIGN KEY (id_agencia_en_uso) REFERENCES agencias_aduanales(id_agencia);
-
-
--- 1. Modificar la tabla de solicitudes para incluir la relación con agencia
-ALTER TABLE [dbo].[solicitud_importacion_factura]
-ADD [id_agencia] [int] NULL;
-
--- Agregar foreign key para la agencia
-ALTER TABLE [dbo].[solicitud_importacion_factura]
-ADD CONSTRAINT [FK_solicitud_agencia]
-FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]);
-
--- 2. Crear índices para mejorar el rendimiento
-CREATE INDEX [IX_solicitud_importador_agencia]
-ON [dbo].[solicitud_importacion_factura] ([id_importador], [id_agencia]);
-
-CREATE INDEX [IX_solicitud_agencia_status]
-ON [dbo].[solicitud_importacion_factura] ([id_agencia], [status]);
-
-
--- 3. Agregar campos adicionales a la tabla expediente_archivos existente para mejor control
-ALTER TABLE [dbo].[expediente_archivos]
-ADD [estado_archivo] [varchar](20) NULL DEFAULT 'ACTIVO', -- ACTIVO, INACTIVO, ELIMINADO
- [subido_por] [int] NULL, -- ID del usuario que subió el archivo
- [observaciones] [nvarchar](500) NULL,
- [fecha_modificacion] [datetime] NULL;
-
--- Agregar foreign key para el usuario que subió el archivo
-ALTER TABLE [dbo].[expediente_archivos]
-ADD CONSTRAINT [FK_expediente_archivos_usuario]
-FOREIGN KEY ([subido_por]) REFERENCES [dbo].[usuarios_sistema]([id_usuario]);
-
-
--- 1. Modificar la tabla de patentes para incluir la relación con agencia
-ALTER TABLE [dbo].[agentes_aduanales]
-ADD [id_agencia] [int] NULL;
-
--- Agregar foreign key para la agencia
-ALTER TABLE [dbo].[agentes_aduanales]
-ADD CONSTRAINT [FK_agente_agencia]
-FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]);
-
-
-ALTER TABLE [dbo].[solicitud_importacion_factura]
-ADD [patente_id] INT NULL;
-
-CREATE INDEX IX_solicitud_importacion_factura_patente_id
-ON [dbo].[solicitud_importacion_factura] ([patente_id]);
-
--- Opcional: Agregar foreign key constraint
-ALTER TABLE [dbo].[solicitud_importacion_factura]
-ADD CONSTRAINT FK_solicitud_patente
-FOREIGN KEY ([patente_id]) REFERENCES [dbo].[agentes_aduanales]([id_agente]);
\ No newline at end of file
diff --git a/app/controllers/ImportadorPedimentos.php b/app/controllers/ImportadorPedimentos.php
new file mode 100644
index 0000000..6892fd8
--- /dev/null
+++ b/app/controllers/ImportadorPedimentos.php
@@ -0,0 +1,303 @@
+ 0,
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'errores' => 0,
+ 'duplicados' => 0
+ ];
+
+ private $errores_detalle = [];
+ private $pedimentos_creados = [];
+
+ public function __construct($connection) {
+ $this->conn = $connection;
+ }
+
+ public function procesarArchivo($archivo_path, $validar_duplicados = true, $timestamp_importacion = null) {
+ $inicio_tiempo = time();
+ $nombre_archivo = basename($archivo_path);
+
+ if ($timestamp_importacion === null) {
+ $timestamp_importacion = date('Y-m-d H:i:s');
+ }
+
+ try {
+ $contenido = file_get_contents($archivo_path);
+ if ($contenido === false) {
+ throw new Exception("No se pudo leer el archivo");
+ }
+
+ // Convertir encoding si es necesario
+ if (!mb_check_encoding($contenido, 'UTF-8')) {
+ $contenido = mb_convert_encoding($contenido, 'UTF-8', 'ISO-8859-1');
+ }
+
+ $lineas = explode("\n", $contenido);
+ $this->estadisticas['total_lineas'] = count($lineas);
+
+ $pedimento_actual = null;
+ $facturas_pedimento = [];
+ $partidas_pedimento = [];
+
+ foreach ($lineas as $numero_linea => $linea) {
+ $linea = trim($linea);
+ if (empty($linea)) continue;
+
+ try {
+ $codigo = substr($linea, 0, 3);
+
+ switch ($codigo) {
+ case '500':
+ // Header - ignorar
+ break;
+
+ case '501':
+ // Si hay un pedimento anterior, procesarlo
+ if ($pedimento_actual) {
+ $this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
+ $facturas_pedimento = [];
+ $partidas_pedimento = [];
+ }
+ $pedimento_actual = $this->parsearLinea501Real($linea, $timestamp_importacion);
+ break;
+
+ case '505':
+ if ($pedimento_actual) {
+ $factura = $this->parsearLinea505Real($linea);
+ $facturas_pedimento[] = $factura;
+ }
+ break;
+
+ case '551':
+ if ($pedimento_actual) {
+ $partida = $this->parsearLinea551Real($linea);
+ $partidas_pedimento[] = $partida;
+ }
+ break;
+ }
+ } catch (Exception $e) {
+ $this->errores_detalle[] = "Línea " . ($numero_linea + 1) . ": " . $e->getMessage();
+ $this->estadisticas['errores']++;
+ }
+ }
+
+ // Procesar el último pedimento
+ if ($pedimento_actual) {
+ $this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
+ }
+
+ return [
+ 'success' => true,
+ 'estadisticas' => $this->estadisticas,
+ 'errores' => $this->errores_detalle,
+ 'pedimentos_creados' => $this->pedimentos_creados
+ ];
+
+ } catch (Exception $e) {
+ return [
+ 'success' => false,
+ 'message' => $e->getMessage()
+ ];
+ }
+ }
+
+ private function parsearLinea501Real($linea, $timestamp_importacion) {
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 10) {
+ throw new Exception("Formato inválido en línea 501");
+ }
+
+ return [
+ 'numero_pedimento' => trim($campos[2]),
+ 'patente' => trim($campos[1]),
+ 'aduana' => trim($campos[3]),
+ 'anio' => date('Y'),
+ 'clave_documento' => trim($campos[5]),
+ 'rfc_importador' => trim($campos[8]),
+ 'fecha_creacion' => $timestamp_importacion,
+ 'usuario_id' => $_SESSION['usuario_id']
+ ];
+ }
+
+ private function parsearLinea505Real($linea) {
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 12) {
+ throw new Exception("Formato inválido en línea 505");
+ }
+
+ return [
+ 'numero_factura' => trim($campos[3]),
+ 'fecha_factura' => $this->convertirFechaReal(trim($campos[2])),
+ 'valor_dolares' => floatval(trim($campos[6])),
+ 'valor_factura' => floatval(trim($campos[7])),
+ 'cove' => trim($campos[3]),
+ 'moneda' => trim($campos[5]),
+ 'proveedor' => trim($campos[11])
+ ];
+ }
+
+ private function parsearLinea551Real($linea) {
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 12) {
+ throw new Exception("Formato inválido en línea 551");
+ }
+
+ static $contador = 1;
+
+ return [
+ 'secuencia' => $contador++,
+ 'fraccion_arancelaria' => trim($campos[2]) ?: 'PENDIENTE',
+ 'descripcion' => trim($campos[5]) ?: 'DESCRIPCIÓN PENDIENTE',
+ 'cantidad' => floatval(trim($campos[10])) ?: 1.0,
+ 'unidad' => trim($campos[11]) ?: 'PZ',
+ 'valor_unitario' => floatval(trim($campos[6])),
+ 'peso_neto' => null,
+ 'peso_bruto' => null
+ ];
+ }
+
+ private function procesarPedimento($pedimento, $facturas, $partidas, $validar_duplicados) {
+ try {
+ if ($validar_duplicados && $this->existePedimento($pedimento['numero_pedimento'])) {
+ $this->estadisticas['duplicados']++;
+ return;
+ }
+
+ sqlsrv_begin_transaction($this->conn);
+
+ // Insertar pedimento
+ $sql = "INSERT INTO pedimentos (numero_pedimento, patente, aduana, anio, clave_documento,
+ rfc_importador, fecha_creacion, usuario_id, estado)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'activo'); SELECT SCOPE_IDENTITY() AS id;";
+
+ $params = [
+ $pedimento['numero_pedimento'],
+ $pedimento['patente'],
+ $pedimento['aduana'],
+ $pedimento['anio'],
+ $pedimento['clave_documento'],
+ $pedimento['rfc_importador'],
+ $pedimento['fecha_creacion'],
+ $pedimento['usuario_id']
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar pedimento");
+ }
+
+ sqlsrv_next_result($stmt);
+ sqlsrv_fetch($stmt);
+ $pedimento_id = sqlsrv_get_field($stmt, 0);
+ sqlsrv_free_stmt($stmt);
+
+ // Insertar facturas
+ foreach ($facturas as $factura) {
+ $sql = "INSERT INTO pedimento_facturas (pedimento_id, numero_factura, fecha_factura,
+ valor_dolares, valor_factura, cove, moneda, proveedor)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $params = [
+ $pedimento_id,
+ $factura['numero_factura'],
+ $factura['fecha_factura'],
+ $factura['valor_dolares'],
+ $factura['valor_factura'],
+ $factura['cove'],
+ $factura['moneda'],
+ $factura['proveedor']
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar factura");
+ }
+ sqlsrv_free_stmt($stmt);
+
+ $this->estadisticas['facturas_procesadas']++;
+ }
+
+ // Insertar partidas
+ foreach ($partidas as $partida) {
+ $sql = "INSERT INTO pedimento_partidas (pedimento_id, secuencia, fraccion_arancelaria,
+ descripcion, cantidad, unidad, valor_unitario,
+ peso_neto, peso_bruto)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $params = [
+ $pedimento_id,
+ $partida['secuencia'],
+ $partida['fraccion_arancelaria'],
+ $partida['descripcion'],
+ $partida['cantidad'],
+ $partida['unidad'],
+ $partida['valor_unitario'],
+ $partida['peso_neto'],
+ $partida['peso_bruto']
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar partida");
+ }
+ sqlsrv_free_stmt($stmt);
+
+ $this->estadisticas['partidas_procesadas']++;
+ }
+
+ sqlsrv_commit($this->conn);
+
+ $this->estadisticas['pedimentos_procesados']++;
+ $this->pedimentos_creados[] = $pedimento['numero_pedimento'];
+
+ } catch (Exception $e) {
+ sqlsrv_rollback($this->conn);
+ $this->errores_detalle[] = "Error procesando pedimento {$pedimento['numero_pedimento']}: " . $e->getMessage();
+ $this->estadisticas['errores']++;
+ }
+ }
+
+ private function existePedimento($numero_pedimento) {
+ $sql = "SELECT id FROM pedimentos WHERE numero_pedimento = ?";
+ $stmt = sqlsrv_query($this->conn, $sql, [$numero_pedimento]);
+ if ($stmt === false) {
+ return false;
+ }
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ sqlsrv_free_stmt($stmt);
+
+ return $row !== false;
+ }
+
+ private function convertirFechaReal($fecha_str) {
+ if (empty($fecha_str) || strlen($fecha_str) !== 8) {
+ return date('Y-m-d');
+ }
+
+ if (substr($fecha_str, 0, 2) === '20') {
+ $anio = substr($fecha_str, 0, 4);
+ $mes = substr($fecha_str, 4, 2);
+ $dia = substr($fecha_str, 6, 2);
+ } else {
+ $dia = substr($fecha_str, 0, 2);
+ $mes = substr($fecha_str, 2, 2);
+ $anio = substr($fecha_str, 4, 4);
+ }
+
+ if (checkdate($mes, $dia, $anio)) {
+ return "$anio-$mes-$dia";
+ }
+
+ return date('Y-m-d');
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/app/controllers/catalogo_pedimentos.php b/app/controllers/catalogo_pedimentos.php
index 0bba1d5..5ebe41b 100644
--- a/app/controllers/catalogo_pedimentos.php
+++ b/app/controllers/catalogo_pedimentos.php
@@ -359,44 +359,16 @@ function ajax_lista()
$id_usuario = $_SESSION['usuario_id'];
$conn = getConnection();
- // Obtener RFC del importador 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([
- "draw" => 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) {
+ // Total registros sin filtro en nuevas tablas
+ $sqlTotal = "SELECT COUNT(*) AS total FROM pedimentos WHERE usuario_id = ?";
+ $stmtTotal = sqlsrv_query($conn, $sqlTotal, [$id_usuario]);
+ if ($stmtTotal === false) {
echo json_encode([
"draw" => $draw,
"recordsTotal" => 0,
@@ -406,24 +378,21 @@ function ajax_lista()
]);
exit;
}
-
- $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
- $recordsTotal = (int)($row['total'] ?? 0);
-
- // Construir condiciones de filtro
- $where = "ClienteRFC = ?";
- $params = [$importador['rfc']];
+ $rowT = sqlsrv_fetch_array($stmtTotal, SQLSRV_FETCH_ASSOC);
+ $recordsTotal = (int)($rowT['total'] ?? 0);
+ // Filtro y búsqueda
+ $where = "p.usuario_id = ?";
+ $params = [$id_usuario];
if ($search !== '') {
- $where .= " AND (Pedimento LIKE ? OR ClienteNombre LIKE ? OR ClavePed LIKE ?)";
+ $where .= " AND (p.numero_pedimento LIKE ? OR p.rfc_importador LIKE ? OR p.clave_documento LIKE ? OR p.patente LIKE ? OR p.aduana LIKE ?)";
$like = "%{$search}%";
- $params = array_merge($params, [$like, $like, $like]);
+ $params = array_merge($params, [$like, $like, $like, $like, $like]);
}
- // Total registros filtrados
- $sqlFiltered = "SELECT COUNT(*) AS total FROM PREVIOS_COMPARTIDOS_WS WHERE $where";
+ // Total filtrado
+ $sqlFiltered = "SELECT COUNT(*) AS total FROM pedimentos p WHERE $where";
$stmtF = sqlsrv_query($conn, $sqlFiltered, $params);
-
if ($stmtF === false) {
echo json_encode([
"draw" => $draw,
@@ -434,34 +403,41 @@ function ajax_lista()
]);
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
+ // Datos paginados
+ $sqlData = "SELECT p.id, p.numero_pedimento, p.rfc_importador, p.fecha_creacion, p.estado,
+ ig.nombre AS nombre_importador
+ FROM pedimentos p
+ LEFT JOIN informacion_general ig ON ig.id_usuario = p.usuario_id
+ WHERE $where
+ ORDER BY p.fecha_creacion DESC
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
- $params[] = $start;
- $params[] = $length;
-
- $stmtD = sqlsrv_query($conn, $sqlData, $params);
+ $paramsData = array_merge($params, [$start, $length]);
+ $stmtD = sqlsrv_query($conn, $sqlData, $paramsData);
$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';
-
+ $fecha = '';
+ if (isset($r['fecha_creacion'])) {
+ if ($r['fecha_creacion'] instanceof DateTime) {
+ $fecha = $r['fecha_creacion']->format('Y-m-d H:i:s');
+ } elseif (is_array($r['fecha_creacion']) && isset($r['fecha_creacion']['date'])) {
+ // Por si viene como array (SQLSRV con print_r)
+ $fecha = substr($r['fecha_creacion']['date'], 0, 19);
+ }
+ }
+ $estado = strtolower((string)$r['estado']) === 'activo' || $r['estado'] === 1 ? 'Activo' : 'Inactivo';
+
$data[] = [
- $r['IdPrevio'],
- $r['Pedimento'],
- $r['ClienteRFC'],
- $r['ClienteNombre'],
- $timestamp,
- $status_text
+ $r['id'],
+ $r['numero_pedimento'],
+ $r['rfc_importador'],
+ $r['nombre_importador'] ?? '',
+ $fecha,
+ $estado
];
}
}
@@ -555,4 +531,157 @@ function buscar_pedimentos()
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($pedimentos, JSON_UNESCAPED_UNICODE);
exit;
+}
+
+/**
+ * Devuelve información general del pedimento (cabecera)
+ * GET /IMPORTADORES/catalogo_pedimentos/ajax_pedimento?id=123
+ */
+function ajax_pedimento()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ http_response_code(403);
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ exit;
+ }
+
+ $id_usuario = $_SESSION['usuario_id'];
+ $pedimento_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
+ if ($pedimento_id <= 0) {
+ http_response_code(400);
+ echo json_encode(['success' => false, 'message' => 'ID inválido']);
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT p.id, p.numero_pedimento, p.patente, p.aduana, p.anio, p.clave_documento,
+ p.rfc_importador, p.fecha_creacion, p.estado
+ FROM pedimentos p
+ WHERE p.id = ? AND p.usuario_id = ?";
+ $stmt = sqlsrv_query($conn, $sql, [$pedimento_id, $id_usuario]);
+ if ($stmt === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
+ exit;
+ }
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ sqlsrv_free_stmt($stmt);
+
+ if (!$row) {
+ echo json_encode(['success' => false, 'message' => 'No encontrado']);
+ exit;
+ }
+
+ // Formatear fecha si es DateTime
+ if (isset($row['fecha_creacion']) && $row['fecha_creacion'] instanceof DateTime) {
+ $row['fecha_creacion'] = $row['fecha_creacion']->format('Y-m-d H:i:s');
+ }
+
+ echo json_encode(['success' => true, 'data' => $row]);
+ exit;
+}
+
+/**
+ * Devuelve las facturas del pedimento
+ * GET /IMPORTADORES/catalogo_pedimentos/ajax_facturas?pedimento_id=123
+ */
+function ajax_facturas()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ http_response_code(403);
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ exit;
+ }
+
+ $id_usuario = $_SESSION['usuario_id'];
+ $pedimento_id = isset($_GET['pedimento_id']) ? (int)$_GET['pedimento_id'] : 0;
+ if ($pedimento_id <= 0) {
+ http_response_code(400);
+ echo json_encode(['success' => false, 'message' => 'ID inválido']);
+ exit;
+ }
+
+ $conn = getConnection();
+ // Verificar propiedad
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_usuario]);
+ $own = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$own) {
+ http_response_code(404);
+ echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
+ exit;
+ }
+
+ $sql = "SELECT id, numero_factura, fecha_factura, valor_dolares, valor_factura, cove, moneda, proveedor
+ FROM pedimento_facturas
+ WHERE pedimento_id = ?
+ ORDER BY fecha_factura ASC, id ASC";
+ $stmt = sqlsrv_query($conn, $sql, [$pedimento_id]);
+ if ($stmt === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
+ exit;
+ }
+ $items = [];
+ while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ if ($r['fecha_factura'] instanceof DateTime) {
+ $r['fecha_factura'] = $r['fecha_factura']->format('Y-m-d');
+ }
+ $items[] = $r;
+ }
+ sqlsrv_free_stmt($stmt);
+
+ echo json_encode(['success' => true, 'data' => $items]);
+ exit;
+}
+
+/**
+ * Devuelve las partidas del pedimento
+ * GET /IMPORTADORES/catalogo_pedimentos/ajax_partidas?pedimento_id=123
+ */
+function ajax_partidas()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ http_response_code(403);
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ exit;
+ }
+
+ $id_usuario = $_SESSION['usuario_id'];
+ $pedimento_id = isset($_GET['pedimento_id']) ? (int)$_GET['pedimento_id'] : 0;
+ if ($pedimento_id <= 0) {
+ http_response_code(400);
+ echo json_encode(['success' => false, 'message' => 'ID inválido']);
+ exit;
+ }
+
+ $conn = getConnection();
+ // Verificar propiedad
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_usuario]);
+ $own = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$own) {
+ http_response_code(404);
+ echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
+ exit;
+ }
+
+ $sql = "SELECT id, secuencia, fraccion_arancelaria, descripcion, cantidad, unidad, valor_unitario, peso_neto, peso_bruto
+ FROM pedimento_partidas
+ WHERE pedimento_id = ?
+ ORDER BY secuencia ASC, id ASC";
+ $stmt = sqlsrv_query($conn, $sql, [$pedimento_id]);
+ if ($stmt === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
+ exit;
+ }
+ $items = [];
+ while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $items[] = $r;
+ }
+ sqlsrv_free_stmt($stmt);
+
+ echo json_encode(['success' => true, 'data' => $items]);
+ exit;
}
\ No newline at end of file
diff --git a/app/controllers/cove.php b/app/controllers/cove.php
new file mode 100644
index 0000000..2d12206
--- /dev/null
+++ b/app/controllers/cove.php
@@ -0,0 +1,170 @@
+ false, 'message' => 'No autorizado']);
+ exit;
+ }
+
+ $usuario_id = (int)$_SESSION['usuario_id'];
+ $pedimento_id = isset($_GET['pedimento_id']) ? (int)$_GET['pedimento_id'] : 0;
+ if ($pedimento_id <= 0) {
+ http_response_code(400);
+ echo json_encode(['success' => false, 'message' => 'ID inválido']);
+ exit;
+ }
+
+ $conn = getConnection();
+ // Verificar propiedad del pedimento
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $usuario_id]);
+ $own = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$own) {
+ http_response_code(404);
+ echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
+ exit;
+ }
+
+ $sql = "SELECT f.id AS factura_id,
+ CASE WHEN cr.id IS NULL THEN 0 ELSE 1 END AS respondido,
+ cr.estado AS estado,
+ cr.fecha_actualizacion AS fecha
+ FROM pedimento_facturas f
+ LEFT JOIN cove_respuestas cr
+ ON cr.factura_id = f.id AND cr.usuario_id = ?
+ WHERE f.pedimento_id = ?
+ ORDER BY f.id";
+ $stmt = sqlsrv_query($conn, $sql, [$usuario_id, $pedimento_id]);
+ if ($stmt === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
+ exit;
+ }
+ $data = [];
+ while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ if (isset($r['fecha']) && $r['fecha'] instanceof DateTime) {
+ $r['fecha'] = $r['fecha']->format('Y-m-d H:i:s');
+ }
+ $data[] = $r;
+ }
+ sqlsrv_free_stmt($stmt);
+
+ echo json_encode(['success' => true, 'data' => $data]);
+ exit;
+}
+
+/**
+ * POST /IMPORTADORES/cove/ajax_guardar_respuestas
+ * Guarda/actualiza respuestas de COVE para una factura concreta.
+ * Body: pedimento_id, factura_id, respuestas (JSON string), estado (opcional)
+ */
+function ajax_guardar_respuestas()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ http_response_code(403);
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ exit;
+ }
+
+ $usuario_id = (int)$_SESSION['usuario_id'];
+ $pedimento_id = isset($_POST['pedimento_id']) ? (int)$_POST['pedimento_id'] : 0;
+ $factura_id = isset($_POST['factura_id']) ? (int)$_POST['factura_id'] : 0;
+ $respuestas = $_POST['respuestas'] ?? '{}';
+ $estado = $_POST['estado'] ?? 'respondido';
+ if ($pedimento_id <= 0 || $factura_id <= 0) {
+ http_response_code(400);
+ echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
+ exit;
+ }
+
+ $conn = getConnection();
+ // Verificar propiedad del pedimento
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $usuario_id]);
+ $own = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$own) {
+ http_response_code(404);
+ echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
+ exit;
+ }
+
+ // Upsert manual: si existe update, si no insert
+ $sel = sqlsrv_query($conn, "SELECT id FROM cove_respuestas WHERE factura_id = ? AND usuario_id = ?", [$factura_id, $usuario_id]);
+ $row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null;
+ if ($sel) sqlsrv_free_stmt($sel);
+
+ if ($row) {
+ $sql = "UPDATE cove_respuestas
+ SET respuestas = ?, estado = ?, fecha_actualizacion = SYSDATETIME()
+ WHERE id = ?";
+ $stmt = sqlsrv_query($conn, $sql, [$respuestas, $estado, $row['id']]);
+ } else {
+ $sql = "INSERT INTO cove_respuestas (pedimento_id, factura_id, usuario_id, respuestas, estado, fecha_creacion)
+ VALUES (?, ?, ?, ?, ?, SYSDATETIME())";
+ $stmt = sqlsrv_query($conn, $sql, [$pedimento_id, $factura_id, $usuario_id, $respuestas, $estado]);
+ }
+
+ if ($stmt === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'No se pudieron guardar las respuestas']);
+ exit;
+ }
+
+ echo json_encode(['success' => true]);
+ exit;
+}
+
+// Estado agregado por pedimento: total de facturas vs respondidas/solicitadas
+function ajax_estado_pedimentos()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ http_response_code(403);
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ exit;
+ }
+
+ $usuario_id = (int)$_SESSION['usuario_id'];
+ $conn = getConnection();
+
+ $sql = "
+ SELECT p.id AS pedimento_id,
+ COUNT(f.id) AS total_facturas,
+ SUM(CASE WHEN cr.estado IN ('respondido','solicitado') THEN 1 ELSE 0 END) AS respondidas
+ FROM pedimentos p
+ LEFT JOIN pedimento_facturas f ON f.pedimento_id = p.id
+ LEFT JOIN cove_respuestas cr ON cr.factura_id = f.id AND cr.usuario_id = p.usuario_id
+ WHERE p.usuario_id = ?
+ GROUP BY p.id
+ ";
+ $stmt = sqlsrv_query($conn, $sql, [$usuario_id]);
+ if ($stmt === false) {
+ http_response_code(500);
+ echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
+ exit;
+ }
+
+ $data = [];
+ while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $total = (int)($r['total_facturas'] ?? 0);
+ $resp = (int)($r['respondidas'] ?? 0);
+ $completo = ($total > 0 && $resp >= $total) ? 1 : 0;
+ $data[] = [
+ 'pedimento_id' => (int)$r['pedimento_id'],
+ 'total_facturas' => $total,
+ 'respondidas' => $resp,
+ 'completo' => $completo
+ ];
+ }
+ sqlsrv_free_stmt($stmt);
+
+ echo json_encode(['success' => true, 'data' => $data]);
+ exit;
+}
diff --git a/app/controllers/debug_paths.php b/app/controllers/debug_paths.php
new file mode 100644
index 0000000..c96a187
--- /dev/null
+++ b/app/controllers/debug_paths.php
@@ -0,0 +1,22 @@
+Información de rutas del servidor:";
+echo "
DOCUMENT_ROOT: " . $_SERVER['DOCUMENT_ROOT'] . "
";
+echo "SCRIPT_NAME: " . $_SERVER['SCRIPT_NAME'] . "
";
+echo "REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "
";
+echo "HTTP_HOST: " . $_SERVER['HTTP_HOST'] . "
";
+echo "__FILE__: " . __FILE__ . "
";
+echo "__DIR__: " . __DIR__ . "
";
+
+// Verificar si los archivos existen
+$test_file = __DIR__ . '/test_connection.php';
+$import_file = __DIR__ . '/importar_pedimentos.php';
+
+echo "Verificación de archivos: ";
+echo "test_connection.php: " . (file_exists($test_file) ? '✅ Existe' : '❌ No existe') . "
";
+echo "importar_pedimentos.php: " . (file_exists($import_file) ? '✅ Existe' : '❌ No existe') . "
";
+
+echo "URLs sugeridas: ";
+$base_url = "http" . (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on" ? "s" : "") . "://" . $_SERVER["HTTP_HOST"];
+echo "Test URL: {$base_url}/IMPORTADORES/app/controllers/test_connection.php
";
+?>
\ No newline at end of file
diff --git a/app/controllers/expediente.php b/app/controllers/expediente.php
index ae1ab0d..ec51b1b 100644
--- a/app/controllers/expediente.php
+++ b/app/controllers/expediente.php
@@ -3,6 +3,29 @@ require_once __DIR__ . '/../helpers/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/env.php';
+// Formatea el pedimento como: YY-AA-PPPP-PPPPPPP
+function format_pedimento_display($anio, $aduana, $patente, $numero)
+{
+ $yy = substr((string)$anio, -2);
+ $ad = substr(preg_replace('/\D/', '', (string)$aduana), 0, 2);
+ $pat = str_pad(preg_replace('/\D/', '', (string)$patente), 4, '0', STR_PAD_LEFT);
+ $num = str_pad(preg_replace('/\D/', '', (string)$numero), 7, '0', STR_PAD_LEFT);
+ $yy = $yy !== '' ? $yy : '00';
+ $ad = str_pad($ad, 2, '0', STR_PAD_LEFT);
+ return "$yy-$ad-$pat-$num";
+}
+
+function ensure_expediente_schema($conn) {
+ // Agregar columna pedimento_id si no existe (compatibilidad con esquema nuevo)
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'expediente_archivos' AND COLUMN_NAME = 'pedimento_id'");
+ $exists = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$exists) {
+ @sqlsrv_query($conn, "ALTER TABLE expediente_archivos ADD pedimento_id INT NULL");
+ @sqlsrv_query($conn, "CREATE INDEX IX_expediente_archivos_pedimento ON expediente_archivos(pedimento_id)");
+ }
+}
+
// Mostrar tabla de expedientes
function index()
{
@@ -12,29 +35,50 @@ function index()
}
$conn = getConnection();
+ ensure_expediente_schema($conn);
$id_importador = $_SESSION['usuario_id'];
- $sql = "SELECT
- sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave,
- COUNT(ea.id) AS total_archivos,
- ISNULL(SUM(ea.tamano_archivo), 0) AS total_tamano
- FROM solicitud_importacion_factura sif
- LEFT JOIN expediente_archivos ea
- ON ea.id_solicitud = sif.id_solicitud
- WHERE sif.numero_pedimento IS NOT NULL
- AND sif.id_importador = ?
- AND sif.status > 0
- GROUP BY sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave
- ORDER BY sif.fecha_factura DESC
- ";
+ // Nuevo origen: pedimentos (cabecera) + facturas para fecha/proveedor + archivos por pedimento
+ $sql = "
+ WITH fact AS (
+ SELECT
+ f.pedimento_id,
+ MAX(f.fecha_factura) AS fecha_factura,
+ MIN(COALESCE(NULLIF(LTRIM(RTRIM(f.proveedor)), ''), '-')) AS proveedor
+ FROM pedimento_facturas f
+ GROUP BY f.pedimento_id
+ ), arch AS (
+ SELECT pedimento_id, COUNT(*) AS total_archivos, ISNULL(SUM(tamano_archivo), 0) AS total_tamano
+ FROM expediente_archivos
+ WHERE pedimento_id IS NOT NULL
+ GROUP BY pedimento_id
+ )
+ SELECT
+ p.id AS pedimento_id,
+ p.numero_pedimento,
+ p.patente,
+ p.aduana,
+ p.anio,
+ f.fecha_factura,
+ f.proveedor,
+ ISNULL(a.total_archivos, 0) AS total_archivos,
+ ISNULL(a.total_tamano, 0) AS total_tamano
+ FROM pedimentos p
+ LEFT JOIN fact f ON f.pedimento_id = p.id
+ LEFT JOIN arch a ON a.pedimento_id = p.id
+ WHERE p.usuario_id = ?
+ ORDER BY COALESCE(f.fecha_factura, p.fecha_creacion) DESC, p.id DESC
+ ";
$stmt = sqlsrv_query($conn, $sql, [$id_importador]);
$expedientes = [];
if ($stmt) {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $row['pedimento_display'] = format_pedimento_display($row['anio'] ?? '', $row['aduana'] ?? '', $row['patente'] ?? '', $row['numero_pedimento'] ?? '');
$expedientes[] = $row;
}
+ sqlsrv_free_stmt($stmt);
}
include __DIR__ . '/../../views/expediente/index.php';
@@ -45,27 +89,50 @@ function subir($id_solicitud)
include __DIR__ . '/../../views/expediente/subir.php';
}
+// Vista subir para pedimento nuevo
+function subir_pedimento($pedimento_id)
+{
+ if (!isset($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; }
+ $conn = getConnection();
+ // Validar propiedad del pedimento
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $_SESSION['usuario_id']]);
+ if (!$chk || !sqlsrv_fetch($chk)) { http_response_code(403); echo "No autorizado"; exit; }
+ if ($chk) sqlsrv_free_stmt($chk);
+ $GLOBALS['pedimento_id'] = (int)$pedimento_id;
+ include __DIR__ . '/../../views/expediente/subir.php';
+}
+
function subir_handler()
{
- if (!isset($_POST['id_solicitud']) || !isset($_FILES['archivos']) || !isset($_SESSION['usuario_id'])) {
- die("❌ Solicitud inválida.");
- }
+ if (!isset($_FILES['archivos']) || !isset($_SESSION['usuario_id'])) { die("❌ Solicitud inválida."); }
$conn = getConnection();
+ ensure_expediente_schema($conn);
- $id_solicitud = (int) $_POST['id_solicitud'];
$id_importador = $_SESSION['usuario_id'];
- // Validar propiedad de la solicitud
- $validStmt = sqlsrv_query($conn, "SELECT 1 FROM solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ?", [$id_solicitud, $id_importador]);
- if (!sqlsrv_fetch($validStmt)) {
- die("❌ No tienes permisos para esta solicitud.");
+ $id_solicitud = isset($_POST['id_solicitud']) ? (int) $_POST['id_solicitud'] : null;
+ $pedimento_id = isset($_POST['pedimento_id']) ? (int) $_POST['pedimento_id'] : null;
+
+ if ($pedimento_id) {
+ // Validar propiedad del pedimento
+ $validStmt = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_importador]);
+ if (!$validStmt || !sqlsrv_fetch($validStmt)) { die("❌ No tienes permisos para este pedimento."); }
+ if ($validStmt) sqlsrv_free_stmt($validStmt);
+ } elseif ($id_solicitud) {
+ // Validar propiedad de la solicitud (legacy)
+ $validStmt = sqlsrv_query($conn, "SELECT 1 FROM solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ?", [$id_solicitud, $id_importador]);
+ if (!$validStmt || !sqlsrv_fetch($validStmt)) { die("❌ No tienes permisos para esta solicitud."); }
+ if ($validStmt) sqlsrv_free_stmt($validStmt);
+ } else {
+ die("❌ Falta identificador de pedimento.");
}
$archivos = $_FILES['archivos'];
$usuario = $_SESSION['usuario_nombre'] ?? 'sistema';
- $uploadDir = __DIR__ . '/../../uploads/expedientes/' . $id_solicitud;
+ $folderKey = $pedimento_id ? ('pedimento_' . $pedimento_id) : ('solicitud_' . $id_solicitud);
+ $uploadDir = __DIR__ . '/../../uploads/expedientes/' . $folderKey;
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0775, true);
}
@@ -79,19 +146,29 @@ function subir_handler()
move_uploaded_file($archivos['tmp_name'][$i], $rutaFinal);
- $rutaDb = "uploads/expedientes/$id_solicitud/$nombreSeguro";
+ $rutaDb = "uploads/expedientes/$folderKey/$nombreSeguro";
$tamanoKb = round(filesize($rutaFinal) / 1024, 2);
$tipoArchivo = mime_content_type($rutaFinal);
- $sql = "INSERT INTO expediente_archivos
- (id_solicitud, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por)
- VALUES (?, ?, ?, ?, ?, ?)
- ";
- $params = [$id_solicitud, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario];
+ if ($pedimento_id) {
+ $sql = "INSERT INTO expediente_archivos
+ (pedimento_id, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por)
+ VALUES (?, ?, ?, ?, ?, ?)";
+ $params = [$pedimento_id, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario];
+ } else {
+ $sql = "INSERT INTO expediente_archivos
+ (id_solicitud, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por)
+ VALUES (?, ?, ?, ?, ?, ?)";
+ $params = [$id_solicitud, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario];
+ }
sqlsrv_query($conn, $sql, $params);
}
- header("Location: /IMPORTADORES/expediente/ver/$id_solicitud");
+ if ($pedimento_id) {
+ header("Location: /IMPORTADORES/expediente/ver_pedimento/$pedimento_id");
+ } else {
+ header("Location: /IMPORTADORES/expediente/ver/$id_solicitud");
+ }
exit;
}
@@ -119,6 +196,51 @@ function ver($id_solicitud)
}
}
+ $GLOBALS['pedimento'] = null; // vista usa variable opcional
+ include __DIR__ . '/../../views/expediente/ver.php';
+}
+
+function ver_pedimento($pedimento_id)
+{
+ if (!isset($_SESSION['usuario_id'])) {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ ensure_expediente_schema($conn);
+
+ $id_importador = $_SESSION['usuario_id'];
+
+ // Validar propiedad
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_importador]);
+ if (!$chk || !sqlsrv_fetch($chk)) { http_response_code(404); echo "No autorizado o no encontrado"; exit; }
+ if ($chk) sqlsrv_free_stmt($chk);
+
+ // Datos del pedimento para cabecera
+ $stmtPed = sqlsrv_query($conn, "SELECT id, numero_pedimento, patente, aduana, anio, clave_documento, rfc_importador, fecha_creacion FROM pedimentos WHERE id = ?", [$pedimento_id]);
+ $pedimento = $stmtPed ? sqlsrv_fetch_array($stmtPed, SQLSRV_FETCH_ASSOC) : null;
+ if ($stmtPed) sqlsrv_free_stmt($stmtPed);
+ if ($pedimento) {
+ $pedimento['pedimento_display'] = format_pedimento_display($pedimento['anio'] ?? '', $pedimento['aduana'] ?? '', $pedimento['patente'] ?? '', $pedimento['numero_pedimento'] ?? '');
+ }
+
+ $sql = "SELECT * FROM expediente_archivos WHERE pedimento_id = ? ORDER BY creado_en DESC";
+ $stmt = sqlsrv_query($conn, $sql, [$pedimento_id]);
+
+ $archivos = [];
+ if ($stmt) {
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ if (isset($row['creado_en']) && is_string($row['creado_en'])) {
+ $row['creado_en'] = new DateTime($row['creado_en']);
+ }
+ $archivos[] = $row;
+ }
+ sqlsrv_free_stmt($stmt);
+ }
+
+ $GLOBALS['pedimento_id'] = (int)$pedimento_id;
+ $GLOBALS['pedimento'] = $pedimento;
include __DIR__ . '/../../views/expediente/ver.php';
}
@@ -131,9 +253,24 @@ function ver_archivo($id_archivo)
$conn = getConnection();
- $sql = "SELECT ea.*, sif.id_importador FROM expediente_archivos ea JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud WHERE ea.id = ?";
- $stmt = sqlsrv_query($conn, $sql, [$id_archivo]);
- $archivo = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ ensure_expediente_schema($conn);
+ // Intentar resolver por pedimento (nuevo) y si no, por solicitud (legacy)
+ $sql = "SELECT ea.*, p.usuario_id AS id_importador
+ FROM expediente_archivos ea
+ JOIN pedimentos p ON p.id = ea.pedimento_id
+ WHERE ea.id = ? AND ea.pedimento_id IS NOT NULL";
+ $stmt = sqlsrv_query($conn, $sql, [$id_archivo]);
+ $archivo = $stmt ? sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) : null;
+ if ($stmt) sqlsrv_free_stmt($stmt);
+ if (!$archivo) {
+ $sqlL = "SELECT ea.*, sif.id_importador
+ FROM expediente_archivos ea
+ JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud
+ WHERE ea.id = ?";
+ $stmtL = sqlsrv_query($conn, $sqlL, [$id_archivo]);
+ $archivo = $stmtL ? sqlsrv_fetch_array($stmtL, SQLSRV_FETCH_ASSOC) : null;
+ if ($stmtL) sqlsrv_free_stmt($stmtL);
+ }
if (!$archivo || $archivo['id_importador'] != $_SESSION['usuario_id']) {
http_response_code(403);
@@ -224,4 +361,50 @@ function descargar_zip($id_solicitud)
readfile($zip_file);
unlink($zip_file);
exit;
+}
+
+function descargar_zip_pedimento($pedimento_id)
+{
+ if (!isset($_SESSION['usuario_id'])) {
+ http_response_code(403);
+ echo "No autorizado.";
+ exit;
+ }
+
+ $conn = getConnection();
+ ensure_expediente_schema($conn);
+
+ $id_importador = $_SESSION['usuario_id'];
+
+ // Validar propiedad
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_importador]);
+ if (!$chk || !sqlsrv_fetch($chk)) { http_response_code(404); echo "No autorizado"; exit; }
+ if ($chk) sqlsrv_free_stmt($chk);
+
+ $stmt = sqlsrv_query($conn, "SELECT nombre_archivo, ruta_archivo FROM expediente_archivos WHERE pedimento_id = ?", [$pedimento_id]);
+ if (!$stmt) { http_response_code(500); echo "Error al consultar archivos."; exit; }
+
+ $archivos = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $ruta_absoluta = __DIR__ . '/../../' . $row['ruta_archivo'];
+ if (file_exists($ruta_absoluta)) {
+ $archivos[] = [ 'ruta' => $ruta_absoluta, 'nombre' => $row['nombre_archivo'] ];
+ }
+ }
+ sqlsrv_free_stmt($stmt);
+
+ if (empty($archivos)) { http_response_code(404); echo "No hay archivos válidos para comprimir."; exit; }
+
+ $zip_file = tempnam(sys_get_temp_dir(), 'expediente_') . '.zip';
+ $zip = new ZipArchive();
+ if ($zip->open($zip_file, ZipArchive::CREATE) !== true) { http_response_code(500); echo "No se pudo crear el archivo ZIP."; exit; }
+ foreach ($archivos as $a) { $zip->addFile($a['ruta'], $a['nombre']); }
+ $zip->close();
+
+ header('Content-Type: application/zip');
+ header('Content-Disposition: attachment; filename="expediente_pedimento_' . $pedimento_id . '.zip"');
+ header('Content-Length: ' . filesize($zip_file));
+ readfile($zip_file);
+ unlink($zip_file);
+ exit;
}
\ No newline at end of file
diff --git a/app/controllers/importadores.php b/app/controllers/importadores.php
index 2080886..6527ef4 100644
--- a/app/controllers/importadores.php
+++ b/app/controllers/importadores.php
@@ -142,20 +142,22 @@ function obtenerCatalogosVisibles($idUsuario)
function obtenerIconoCatalogo($nombre)
{
$iconos = [
- 'Locaciones' => '📍',
- 'Vinculación' => '🔗',
- 'Transportistas' => '🚚',
- 'Transportes' => '🚛',
- 'Choferes' => '👨✈️',
- 'Proveedores' => '🏭',
- 'Productos frecuentes' => '⭐',
- 'Solicitudes importación' => '📄',
- 'Expediente electrónico' => '📁',
- 'Configuración' => '⚙️',
- 'Cerrar sesión' => '🚪'
+ 'Locaciones' => 'fas fa-map-marker-alt',
+ 'Vinculación' => 'fas fa-link',
+ 'Transportistas' => 'fas fa-truck',
+ 'Transportes' => 'fas fa-shipping-fast',
+ 'Choferes' => 'fas fa-user-tie',
+ 'Proveedores' => 'fas fa-industry',
+ 'Productos frecuentes' => 'fas fa-star',
+ 'Solicitudes importación' => 'fas fa-file-alt',
+ 'Expediente electrónico' => 'fas fa-folder',
+ 'Configuración' => 'fas fa-cog',
+ 'Cerrar sesión' => 'fas fa-sign-out-alt',
+ 'Agencias' => 'fas fa-building',
+ 'Importadores' => 'fas fa-boxes'
];
- return $iconos[$nombre] ?? '📁';
+ return $iconos[$nombre] ?? 'fas fa-folder';
}
// Función para el dashboard del importador
diff --git a/app/controllers/importar_pedimentos.php b/app/controllers/importar_pedimentos.php
new file mode 100644
index 0000000..3fe60a2
--- /dev/null
+++ b/app/controllers/importar_pedimentos.php
@@ -0,0 +1,636 @@
+ false, 'message' => 'Usuario no autenticado']);
+ exit;
+}
+
+// Verificar que sea una petición POST
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode(['success' => false, 'message' => 'Método no permitido']);
+ exit;
+}
+
+// Verificar que se haya subido un archivo
+if (!isset($_FILES['archivo']) || $_FILES['archivo']['error'] !== UPLOAD_ERR_OK) {
+ http_response_code(400);
+ echo json_encode(['success' => false, 'message' => 'No se ha recibido ningún archivo válido']);
+ exit;
+}
+
+class ImportadorPedimentos {
+ private $conn;
+ private $estadisticas = [
+ 'total_lineas' => 0,
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'errores' => 0,
+ 'duplicados' => 0
+ ];
+
+ private $errores_detalle = [];
+ private $pedimentos_creados = [];
+
+ public function __construct($connection) {
+ $this->conn = $connection;
+ }
+
+ public function procesarArchivo($archivo_path, $validar_duplicados = true) {
+ $inicio_tiempo = time();
+ $nombre_archivo = basename($archivo_path);
+
+ try {
+ $contenido = file_get_contents($archivo_path);
+ if ($contenido === false) {
+ throw new Exception("No se pudo leer el archivo");
+ }
+
+ // Convertir encoding si es necesario (muchos archivos julianos usan Latin1)
+ if (!mb_check_encoding($contenido, 'UTF-8')) {
+ $contenido = mb_convert_encoding($contenido, 'UTF-8', 'ISO-8859-1');
+ }
+
+ $lineas = explode("\n", $contenido);
+ $this->estadisticas['total_lineas'] = count($lineas);
+
+ $pedimento_actual = null;
+ $facturas_pedimento = [];
+ $partidas_pedimento = [];
+
+ foreach ($lineas as $numero_linea => $linea) {
+ $linea = trim($linea);
+ if (empty($linea)) continue;
+
+ try {
+ $codigo = substr($linea, 0, 3);
+
+ switch ($codigo) {
+ case '500':
+ // Línea de header - ignorar por ahora
+ break;
+
+ case '501':
+ // Si hay un pedimento anterior, procesarlo
+ if ($pedimento_actual) {
+ $this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
+ $facturas_pedimento = [];
+ $partidas_pedimento = [];
+ }
+ $pedimento_actual = $this->parsearLinea501Real($linea);
+ break;
+
+ case '505':
+ if ($pedimento_actual) {
+ try {
+ $factura = $this->parsearLinea505Real($linea);
+ $facturas_pedimento[] = $factura;
+ error_log("Factura 505 procesada exitosamente: " . $factura['numero_factura']);
+ } catch (Exception $e) {
+ error_log("ERROR procesando línea 505: " . $e->getMessage());
+ error_log("Línea problemática: " . $linea);
+ $this->estadisticas['errores']++;
+ // Continuar con la siguiente línea
+ }
+ }
+ break;
+
+ case '551':
+ if ($pedimento_actual) {
+ try {
+ $partida = $this->parsearLinea551Real($linea);
+ $partidas_pedimento[] = $partida;
+ error_log("Partida 551 procesada exitosamente: secuencia " . $partida['secuencia']);
+ } catch (Exception $e) {
+ error_log("ERROR procesando línea 551: " . $e->getMessage());
+ error_log("Línea problemática: " . $linea);
+ $this->estadisticas['errores']++;
+ // Continuar con la siguiente línea en lugar de fallar completamente
+ }
+ }
+ break;
+
+ case '506':
+ case '509':
+ case '510':
+ case '511':
+ case '553':
+ case '554':
+ case '556':
+ case '557':
+ case '558':
+ case '800':
+ case '801':
+ // Otros códigos del formato real - ignorar por ahora
+ break;
+ }
+ } catch (Exception $e) {
+ $this->errores_detalle[] = "Línea " . ($numero_linea + 1) . ": " . $e->getMessage();
+ $this->estadisticas['errores']++;
+ }
+ }
+
+ // Procesar el último pedimento
+ if ($pedimento_actual) {
+ $this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
+ }
+
+ // Registrar log de importación
+ $tiempo_procesamiento = time() - $inicio_tiempo;
+ $this->registrarLog($nombre_archivo, $tiempo_procesamiento,
+ count($this->errores_detalle) > 0 ? 'con_errores' : 'exitoso');
+
+ return [
+ 'success' => true,
+ 'estadisticas' => $this->estadisticas,
+ 'errores' => $this->errores_detalle,
+ 'pedimentos_creados' => $this->pedimentos_creados
+ ];
+
+ } catch (Exception $e) {
+ // Registrar log de error
+ $tiempo_procesamiento = time() - $inicio_tiempo;
+ $this->registrarLog($nombre_archivo, $tiempo_procesamiento, 'fallido', $e->getMessage());
+
+ return [
+ 'success' => false,
+ 'message' => $e->getMessage()
+ ];
+ }
+ }
+
+ private function registrarLog($archivo_nombre, $tiempo_procesamiento, $estado, $error_mensaje = null) {
+ try {
+ $sql = "INSERT INTO importacion_logs (
+ usuario_id, archivo_nombre, total_lineas, pedimentos_procesados,
+ facturas_procesadas, partidas_procesadas, errores, duplicados,
+ tiempo_procesamiento, estado, detalles_errores
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $detalles_errores = null;
+ if (!empty($this->errores_detalle)) {
+ $detalles_errores = implode("\n", $this->errores_detalle);
+ } else if ($error_mensaje) {
+ $detalles_errores = $error_mensaje;
+ }
+
+ $params = [
+ isset($_SESSION['usuario_id']) ? $_SESSION['usuario_id'] : null,
+ $archivo_nombre,
+ $this->estadisticas['total_lineas'],
+ $this->estadisticas['pedimentos_procesados'],
+ $this->estadisticas['facturas_procesadas'],
+ $this->estadisticas['partidas_procesadas'],
+ $this->estadisticas['errores'],
+ $this->estadisticas['duplicados'],
+ $tiempo_procesamiento,
+ $estado,
+ $detalles_errores
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt) {
+ sqlsrv_free_stmt($stmt);
+ }
+ } catch (Exception $e) {
+ // No hacer nada si falla el log, no queremos interrumpir el proceso principal
+ }
+ }
+
+ private function parsearLinea501($linea) {
+ // Formato: 501|numero_pedimento|patente|aduana|anio|clave_documento|rfc_importador|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 7) {
+ throw new Exception("Formato inválido en línea 501");
+ }
+
+ return [
+ 'numero_pedimento' => trim($campos[1]),
+ 'patente' => trim($campos[2]),
+ 'aduana' => trim($campos[3]),
+ 'anio' => trim($campos[4]),
+ 'clave_documento' => trim($campos[5]),
+ 'rfc_importador' => trim($campos[6]),
+ 'fecha_creacion' => date('Y-m-d H:i:s'),
+ 'usuario_id' => $_SESSION['usuario_id']
+ ];
+ }
+
+ private function parsearLinea501Real($linea) {
+ // Formato real: 501|patente|numero_pedimento|aduana|tipo|clave_documento|aduana2||rfc_importador|nombre_importador|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 10) {
+ throw new Exception("Formato inválido en línea 501 real - campos insuficientes: " . count($campos));
+ }
+
+ error_log("Parseando 501 real: " . $linea);
+ error_log("Campos: " . print_r(array_slice($campos, 0, 10), true));
+
+ return [
+ 'numero_pedimento' => trim($campos[2]), // Campo 2: numero de pedimento
+ 'patente' => trim($campos[1]), // Campo 1: patente
+ 'aduana' => trim($campos[3]), // Campo 3: aduana
+ 'anio' => date('Y'), // Usar año actual
+ 'clave_documento' => trim($campos[5]), // Campo 5: clave documento
+ 'rfc_importador' => trim($campos[8]), // Campo 8: RFC importador
+ 'fecha_creacion' => date('Y-m-d H:i:s'),
+ 'usuario_id' => $_SESSION['usuario_id']
+ ];
+ }
+
+ private function parsearLinea505($linea) {
+ // Formato: 505|numero_factura|fecha_factura|valor_dolares|valor_factura|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 5) {
+ throw new Exception("Formato inválido en línea 505");
+ }
+
+ return [
+ 'numero_factura' => trim($campos[1]),
+ 'fecha_factura' => $this->convertirFecha(trim($campos[2])),
+ 'valor_dolares' => floatval(trim($campos[3])),
+ 'valor_factura' => floatval(trim($campos[4]))
+ ];
+ }
+
+ private function parsearLinea505Real($linea) {
+ // Formato oficial 505: 505|numero_pedimento|fecha_cfdi|numero_cfdi_cove|termino_facturacion|moneda|valor_dolares|valor_total|pais|entidad_federativa|rfc_proveedor|nombre_proveedor|calle|num_int|num_ext|cp|municipio|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 12) {
+ throw new Exception("Formato inválido en línea 505 - campos insuficientes: " . count($campos) . " (mínimo: 12)");
+ }
+
+ error_log("DEBUG 505 - Total campos: " . count($campos));
+ error_log("DEBUG 505 - Primeros 12 campos: " . implode(' | ', array_slice($campos, 0, 12)));
+
+ // Extraer datos según documentación oficial SAT
+ $numero_pedimento = trim($campos[1]); // Campo 1: Número de Pedimento
+ $fecha_cfdi = trim($campos[2]); // Campo 2: Fecha de CFDI
+ $numero_cfdi_cove = trim($campos[3]); // Campo 3: Número de CFDI (COVE) - 40 caracteres max
+ $termino_facturacion = trim($campos[4]); // Campo 4: Término de Facturación - 3 caracteres
+ $moneda = trim($campos[5]); // Campo 5: Moneda - 3 caracteres
+ $valor_dolares = floatval(trim($campos[6])); // Campo 6: Valor Total en Dólares USD
+ $valor_total = floatval(trim($campos[7])); // Campo 7: Valor Total en moneda del CFDI
+ $pais = trim($campos[8]); // Campo 8: País del CFDI - 3 caracteres
+ $entidad_federativa = trim($campos[9]); // Campo 9: Entidad Federativa - 3 caracteres
+ $rfc_proveedor = trim($campos[10]); // Campo 10: RFC Proveedor - 30 caracteres max
+ $nombre_proveedor = trim($campos[11]); // Campo 11: Nombre Proveedor - 120 caracteres max
+
+ error_log("DEBUG 505 - Datos oficiales extraídos:");
+ error_log(" - Número CFDI/COVE: '$numero_cfdi_cove'");
+ error_log(" - Fecha CFDI: '$fecha_cfdi'");
+ error_log(" - Término facturación: '$termino_facturacion'");
+ error_log(" - Moneda: '$moneda'");
+ error_log(" - Valor USD: $valor_dolares");
+ error_log(" - Valor total: $valor_total");
+ error_log(" - RFC Proveedor: '$rfc_proveedor'");
+ error_log(" - Nombre Proveedor: '$nombre_proveedor'");
+
+ return [
+ 'numero_factura' => $numero_cfdi_cove, // Campo 3: Número de CFDI/COVE
+ 'fecha_factura' => $this->convertirFechaReal($fecha_cfdi), // Campo 2: Fecha CFDI
+ 'valor_dolares' => $valor_dolares, // Campo 6: Valor en USD
+ 'valor_factura' => $valor_total, // Campo 7: Valor total en moneda CFDI
+ 'cove' => $numero_cfdi_cove, // Campo 3: COVE (mismo que número factura)
+ 'moneda' => $moneda, // Campo 5: Moneda
+ 'proveedor' => $nombre_proveedor // Campo 11: Nombre del proveedor
+ ];
+ }
+
+ private function parsearLinea551($linea) {
+ // Formato: 551|secuencia|fraccion_arancelaria|descripcion|cantidad|unidad|valor_unitario|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 7) {
+ throw new Exception("Formato inválido en línea 551");
+ }
+
+ return [
+ 'secuencia' => intval(trim($campos[1])),
+ 'fraccion_arancelaria' => trim($campos[2]),
+ 'descripcion' => trim($campos[3]),
+ 'cantidad' => floatval(trim($campos[4])),
+ 'unidad' => trim($campos[5]),
+ 'valor_unitario' => floatval(trim($campos[6]))
+ ];
+ }
+
+ private function parsearLinea551Real($linea) {
+ // Formato oficial 551: 551|numero_pedimento|fraccion_arancelaria|numero_partida|subdivision|descripcion|precio_unitario|valor_aduana|valor_comercial|valor_dolares|cantidad_umc|unidad_comercial|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 12) {
+ throw new Exception("Formato inválido en línea 551 - campos insuficientes: " . count($campos) . " (mínimo: 12)");
+ }
+
+ error_log("DEBUG 551 - Total campos: " . count($campos));
+ error_log("DEBUG 551 - Primeros 12 campos: " . implode(' | ', array_slice($campos, 0, 12)));
+
+ // Extraer datos según documentación oficial
+ $numero_pedimento = isset($campos[1]) ? trim($campos[1]) : '';
+ $fraccion_arancelaria = isset($campos[2]) ? trim($campos[2]) : '';
+ $numero_partida = isset($campos[3]) ? intval(trim($campos[3])) : 0;
+ $subdivision = isset($campos[4]) ? trim($campos[4]) : '';
+ $descripcion = isset($campos[5]) ? trim($campos[5]) : '';
+ $precio_unitario = isset($campos[6]) ? floatval(trim($campos[6])) : 0;
+ $valor_aduana = isset($campos[7]) ? floatval(trim($campos[7])) : 0;
+ $valor_comercial = isset($campos[8]) ? floatval(trim($campos[8])) : 0;
+ $valor_dolares = isset($campos[9]) ? floatval(trim($campos[9])) : 0;
+ $cantidad_umc = isset($campos[10]) ? floatval(trim($campos[10])) : 0;
+ $unidad_comercial = isset($campos[11]) ? trim($campos[11]) : '';
+
+ // Aplicar valores por defecto según documentación oficial
+ if (empty($fraccion_arancelaria)) {
+ error_log("WARNING 551: Fracción arancelaria vacía, usando valor por defecto");
+ $fraccion_arancelaria = 'PENDIENTE';
+ }
+
+ if ($numero_partida <= 0) {
+ error_log("WARNING 551: Número de partida inválido, generando secuencial");
+ static $contador_partida = 1;
+ $numero_partida = $contador_partida++;
+ }
+
+ if (empty($descripcion)) {
+ error_log("WARNING 551: Descripción vacía, usando valor por defecto");
+ $descripcion = 'DESCRIPCIÓN PENDIENTE';
+ }
+
+ if ($cantidad_umc <= 0) {
+ error_log("WARNING 551: Cantidad UMC inválida ($cantidad_umc), usando 1.0000");
+ $cantidad_umc = 1.0000;
+ }
+
+ if (empty($unidad_comercial)) {
+ error_log("WARNING 551: Unidad comercial vacía, usando 'PZ'");
+ $unidad_comercial = 'PZ'; // Pieza como unidad por defecto
+ }
+
+ // Calcular precio unitario si no existe pero hay valores
+ if ($precio_unitario == 0) {
+ if ($valor_dolares > 0 && $cantidad_umc > 0) {
+ $precio_unitario = $valor_dolares / $cantidad_umc;
+ error_log("DEBUG 551: Precio unitario calculado: $precio_unitario");
+ } elseif ($valor_comercial > 0 && $cantidad_umc > 0) {
+ $precio_unitario = $valor_comercial / $cantidad_umc;
+ error_log("DEBUG 551: Precio unitario calculado desde valor comercial: $precio_unitario");
+ }
+ }
+
+ error_log("DEBUG 551 - Datos procesados:");
+ error_log(" - Partida: $numero_partida");
+ error_log(" - Fracción: '$fraccion_arancelaria'");
+ error_log(" - Descripción: '" . substr($descripcion, 0, 50) . "...'");
+ error_log(" - Cantidad: $cantidad_umc");
+ error_log(" - Unidad: '$unidad_comercial'");
+ error_log(" - Precio unitario: $precio_unitario");
+ error_log(" - Valor dólares: $valor_dolares");
+
+ return [
+ 'secuencia' => $numero_partida,
+ 'fraccion_arancelaria' => $fraccion_arancelaria,
+ 'descripcion' => $descripcion,
+ 'cantidad' => $cantidad_umc,
+ 'unidad' => $unidad_comercial,
+ 'valor_unitario' => $precio_unitario,
+ 'peso_neto' => null,
+ 'peso_bruto' => null
+ ];
+ }
+
+ private function procesarPedimento($pedimento, $facturas, $partidas, $validar_duplicados) {
+ try {
+ error_log("Procesando pedimento: " . $pedimento['numero_pedimento']);
+ error_log("Validar duplicados: " . ($validar_duplicados ? 'SÍ' : 'NO'));
+
+ // Validar duplicados si está habilitado
+ if ($validar_duplicados && $this->existePedimento($pedimento['numero_pedimento'])) {
+ error_log("Pedimento {$pedimento['numero_pedimento']} marcado como duplicado, omitiendo...");
+ $this->estadisticas['duplicados']++;
+ return;
+ }
+
+ error_log("Insertando pedimento nuevo: " . $pedimento['numero_pedimento']);
+
+ // Iniciar transacción
+ sqlsrv_begin_transaction($this->conn);
+
+ // Insertar pedimento
+ $sql = "INSERT INTO pedimentos (numero_pedimento, patente, aduana, anio, clave_documento,
+ rfc_importador, fecha_creacion, usuario_id, estado)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'activo'); SELECT SCOPE_IDENTITY() AS id;";
+
+ $params = [
+ $pedimento['numero_pedimento'],
+ $pedimento['patente'],
+ $pedimento['aduana'],
+ $pedimento['anio'],
+ $pedimento['clave_documento'],
+ $pedimento['rfc_importador'],
+ $pedimento['fecha_creacion'],
+ $pedimento['usuario_id']
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar pedimento: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Obtener el ID del pedimento insertado
+ sqlsrv_next_result($stmt);
+ sqlsrv_fetch($stmt);
+ $pedimento_id = sqlsrv_get_field($stmt, 0);
+ sqlsrv_free_stmt($stmt);
+
+ // Insertar facturas
+ foreach ($facturas as $factura) {
+ $sql = "INSERT INTO pedimento_facturas (pedimento_id, numero_factura, fecha_factura,
+ valor_dolares, valor_factura, cove)
+ VALUES (?, ?, ?, ?, ?, ?)";
+
+ $params = [
+ $pedimento_id,
+ $factura['numero_factura'],
+ $factura['fecha_factura'],
+ $factura['valor_dolares'],
+ $factura['valor_factura'],
+ isset($factura['cove']) ? $factura['cove'] : null
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar factura: " . print_r(sqlsrv_errors(), true));
+ }
+ sqlsrv_free_stmt($stmt);
+
+ $this->estadisticas['facturas_procesadas']++;
+ }
+
+ // Insertar partidas
+ foreach ($partidas as $partida) {
+ error_log("INSERTANDO PARTIDA: " . print_r($partida, true));
+
+ $sql = "INSERT INTO pedimento_partidas (pedimento_id, secuencia, fraccion_arancelaria,
+ descripcion, cantidad, unidad, valor_unitario,
+ peso_neto, peso_bruto)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $params = [
+ $pedimento_id,
+ $partida['secuencia'],
+ $partida['fraccion_arancelaria'],
+ $partida['descripcion'],
+ $partida['cantidad'],
+ $partida['unidad'],
+ $partida['valor_unitario'],
+ isset($partida['peso_neto']) ? $partida['peso_neto'] : null,
+ isset($partida['peso_bruto']) ? $partida['peso_bruto'] : null
+ ];
+
+ error_log("PARÁMETROS SQL: " . print_r($params, true));
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ $error = print_r(sqlsrv_errors(), true);
+ error_log("ERROR AL INSERTAR PARTIDA: " . $error);
+ throw new Exception("Error al insertar partida: " . $error);
+ }
+ sqlsrv_free_stmt($stmt);
+
+ $this->estadisticas['partidas_procesadas']++;
+ error_log("Partida insertada exitosamente - Total procesadas: " . $this->estadisticas['partidas_procesadas']);
+ }
+
+ // Confirmar transacción
+ sqlsrv_commit($this->conn);
+
+ $this->estadisticas['pedimentos_procesados']++;
+ $this->pedimentos_creados[] = $pedimento['numero_pedimento'];
+
+ } catch (Exception $e) {
+ sqlsrv_rollback($this->conn);
+ $this->errores_detalle[] = "Error procesando pedimento {$pedimento['numero_pedimento']}: " . $e->getMessage();
+ $this->estadisticas['errores']++;
+ }
+ }
+
+ private function existePedimento($numero_pedimento) {
+ $sql = "SELECT id, fecha_creacion FROM pedimentos WHERE numero_pedimento = ?";
+ $stmt = sqlsrv_query($this->conn, $sql, [$numero_pedimento]);
+ if ($stmt === false) {
+ error_log("Error al verificar duplicado: " . print_r(sqlsrv_errors(), true));
+ return false;
+ }
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ sqlsrv_free_stmt($stmt);
+
+ if ($row) {
+ error_log("Pedimento duplicado encontrado: {$numero_pedimento} (ID: {$row['id']})");
+ return true;
+ }
+
+ return false;
+ }
+
+ private function convertirFecha($fecha_str) {
+ // Convertir formato DDMMYYYY a YYYY-MM-DD
+ if (strlen($fecha_str) === 8) {
+ $dia = substr($fecha_str, 0, 2);
+ $mes = substr($fecha_str, 2, 2);
+ $anio = substr($fecha_str, 4, 4);
+ return "$anio-$mes-$dia";
+ }
+ return date('Y-m-d'); // Fecha por defecto
+ }
+
+ private function convertirFechaReal($fecha_str) {
+ // Convertir fecha del archivo real - puede venir en formato YYYYMMDD o DDMMYYYY
+ if (empty($fecha_str) || strlen($fecha_str) !== 8) {
+ return date('Y-m-d'); // Fecha por defecto
+ }
+
+ // Intentar formato YYYYMMDD primero
+ if (substr($fecha_str, 0, 2) === '20') {
+ $anio = substr($fecha_str, 0, 4);
+ $mes = substr($fecha_str, 4, 2);
+ $dia = substr($fecha_str, 6, 2);
+ } else {
+ // Formato DDMMYYYY
+ $dia = substr($fecha_str, 0, 2);
+ $mes = substr($fecha_str, 2, 2);
+ $anio = substr($fecha_str, 4, 4);
+ }
+
+ // Validar fecha
+ if (checkdate($mes, $dia, $anio)) {
+ return "$anio-$mes-$dia";
+ }
+
+ return date('Y-m-d'); // Fecha por defecto si no es válida
+ }
+}
+
+// Procesar la importación
+try {
+ $archivo = $_FILES['archivo'];
+ $validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
+
+ // Crear directorio temporal si no existe
+ $upload_dir = __DIR__ . '/../storage/temp/';
+ if (!is_dir($upload_dir)) {
+ mkdir($upload_dir, 0755, true);
+ }
+
+ // Mover archivo a directorio temporal
+ $archivo_temporal = $upload_dir . 'import_' . time() . '_' . $archivo['name'];
+ if (!move_uploaded_file($archivo['tmp_name'], $archivo_temporal)) {
+ throw new Exception("Error al procesar el archivo subido");
+ }
+
+ // Obtener conexión a SQL Server
+ $conn = getConnection();
+
+ // Procesar archivo
+ $importador = new ImportadorPedimentos($conn);
+ $resultado = $importador->procesarArchivo($archivo_temporal, $validar_duplicados);
+
+ // Cerrar conexión
+ sqlsrv_close($conn);
+
+ // Limpiar archivo temporal
+ unlink($archivo_temporal);
+
+ // Enviar respuesta
+ echo json_encode($resultado);
+
+} catch (Exception $e) {
+ http_response_code(500);
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Error del servidor: ' . $e->getMessage()
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/app/controllers/mve.php b/app/controllers/mve.php
index 21f9f6c..b1252f7 100644
--- a/app/controllers/mve.php
+++ b/app/controllers/mve.php
@@ -2,44 +2,163 @@
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/session.php';
-function index() {
+// Formatea el pedimento como: YY-AA-PPPP-PPPPPPP
+function mve_format_pedimento_display($anio, $aduana, $patente, $numero)
+{
+ $yy = substr((string)$anio, -2);
+ $ad = substr(preg_replace('/\D/', '', (string)$aduana), 0, 2);
+ $pat = str_pad(preg_replace('/\D/', '', (string)$patente), 4, '0', STR_PAD_LEFT);
+ $num = str_pad(preg_replace('/\D/', '', (string)$numero), 7, '0', STR_PAD_LEFT);
+ $yy = $yy !== '' ? $yy : '00';
+ $ad = str_pad($ad, 2, '0', STR_PAD_LEFT);
+ return "$yy-$ad-$pat-$num";
+}
+
+// Garantiza que expediente_archivos tenga la columna pedimento_id
+function mve_ensure_expediente_schema($conn)
+{
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'expediente_archivos' AND COLUMN_NAME = 'pedimento_id'");
+ $exists = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$exists) {
+ @sqlsrv_query($conn, "ALTER TABLE expediente_archivos ADD pedimento_id INT NULL");
+ @sqlsrv_query($conn, "CREATE INDEX IX_expediente_archivos_pedimento ON expediente_archivos(pedimento_id)");
+ }
+}
+
+// Genera documentos de prueba (Acuse y Detalle) en el expediente del pedimento
+function mve_generar_documentos_expediente($conn, $pedimento_id, $usuario_nombre = 'sistema')
+{
+ mve_ensure_expediente_schema($conn);
+
+ // Obtener datos del pedimento para el encabezado
+ $stmt = sqlsrv_query($conn, "SELECT numero_pedimento, patente, aduana, anio, rfc_importador, clave_documento, fecha_creacion FROM pedimentos WHERE id = ?", [$pedimento_id]);
+ $ped = $stmt ? sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) : null;
+ if ($stmt) sqlsrv_free_stmt($stmt);
+ if (!$ped) return; // nada que hacer
+
+ $display = mve_format_pedimento_display($ped['anio'] ?? '', $ped['aduana'] ?? '', $ped['patente'] ?? '', $ped['numero_pedimento'] ?? '');
+
+ // Directorio destino
+ $folderKey = 'pedimento_' . (int)$pedimento_id;
+ $uploadDir = __DIR__ . '/../../uploads/expedientes/' . $folderKey;
+ if (!is_dir($uploadDir)) { @mkdir($uploadDir, 0775, true); }
+
+ // Contenidos HTML simples
+ $now = date('Y-m-d H:i');
+ $htmlAcuse = " "
+ ."Acuse de Manifestación de Valor "
+ ."Pedimento: {$display}
"
+ ."RFC: ".htmlspecialchars($ped['rfc_importador'] ?? '-', ENT_QUOTES, 'UTF-8')."
"
+ ."Clave: ".htmlspecialchars($ped['clave_documento'] ?? '-', ENT_QUOTES, 'UTF-8')."
"
+ ."Generado: {$now}
"
+ ."Documento de prueba generado automáticamente.
"
+ ."";
+
+ $htmlDetalle = " "
+ ."Detalle de Manifestación de Valor "
+ ."Pedimento: {$display}
"
+ ."Este es un detalle de ejemplo para pruebas.
"
+ ."Sección 65/66 capturada (mock) Precios pagados y por pagar (mock) Compensaciones (mock) "
+ ."Generado: {$now}
"
+ ."";
+
+ // Intentar generar PDF con Dompdf; fallback a .txt si no está disponible
+ $docs = [
+ [ 'nombre' => 'Acuse Manifestacion de Valor', 'html' => $htmlAcuse ],
+ [ 'nombre' => 'Detalle Manifestacion de Valor', 'html' => $htmlDetalle ],
+ ];
+
+ $dompdfOk = false;
+ try {
+ @require_once __DIR__ . '/../../vendor/autoload.php';
+ if (class_exists('Dompdf\\Dompdf')) { $dompdfOk = true; }
+ } catch (\Throwable $e) { $dompdfOk = false; }
+
+ foreach ($docs as $d) {
+ $safeBase = preg_replace('/[^A-Za-z0-9._\- ]/', '_', $d['nombre']);
+ $filename = $safeBase . '_' . time() . ($dompdfOk ? '.pdf' : '.txt');
+ $fullPath = $uploadDir . '/' . $filename;
+ $rutaDb = 'uploads/expedientes/' . $folderKey . '/' . $filename;
+
+ if ($dompdfOk) {
+ try {
+ $dompdf = new Dompdf\Dompdf([ 'isRemoteEnabled' => false ]);
+ $dompdf->loadHtml($d['html']);
+ $dompdf->setPaper('letter', 'portrait');
+ $dompdf->render();
+ file_put_contents($fullPath, $dompdf->output());
+ $tipo = 'application/pdf';
+ } catch (\Throwable $e) {
+ // Fallback a texto
+ file_put_contents($fullPath, strip_tags($d['html']));
+ $tipo = 'text/plain';
+ }
+ } else {
+ file_put_contents($fullPath, strip_tags($d['html']));
+ $tipo = 'text/plain';
+ }
+
+ $tamanoKb = file_exists($fullPath) ? round(filesize($fullPath) / 1024, 2) : 0;
+ // Insertar en expediente_archivos
+ sqlsrv_query($conn,
+ "INSERT INTO expediente_archivos (pedimento_id, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por) VALUES (?,?,?,?,?,?)",
+ [$pedimento_id, $d['nombre'] . ($dompdfOk ? '.pdf' : '.txt'), $rutaDb, $tipo, $tamanoKb, $usuario_nombre]
+ );
+ }
+}
+function index()
+{
include __DIR__ . '/../../views/mve/lista.php';
}
-function ajax_guardar_datos_factura() {
- try {
- // Validar que el usuario esté autenticado
- if (!isset($_SESSION['user_id'])) {
- echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
- return;
- }
+// Guarda en bloque los datos enviados (se usa por el botón Guardar)
+function ajax_guardar_datos_factura()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ 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);
+ $usuario_id = (int)$_SESSION['usuario_id'];
+ $id_factura = isset($_POST['id_factura']) ? (int)$_POST['id_factura'] : 0;
+ $id_pedimento = isset($_POST['id_pedimento']) ? (int)$_POST['id_pedimento'] : 0;
+ $datos_art65 = json_decode($_POST['datos_art65'] ?? '{}', true);
+ $datos_art66 = json_decode($_POST['datos_art66'] ?? '{}', true);
+ $datos_precio_pagado = json_decode($_POST['datos_precio_pagado'] ?? '{}', true);
+ $datos_precio_pagar = json_decode($_POST['datos_precio_pagar'] ?? '{}', true);
+ $datos_compenso = json_decode($_POST['datos_compenso'] ?? '{}', true);
- if (!$id_factura || !$id_pedimento) {
- echo json_encode(['success' => false, 'message' => 'Faltan datos requeridos']);
- return;
- }
+ if ($id_factura <= 0 || $id_pedimento <= 0) {
+ echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
+ 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();
+ $conn = getConnection();
- if ($existe) {
- // Actualizar registro existente
- $sql = "UPDATE mve_facturas_datos SET
+ // Verificar propiedad del pedimento y que la factura le pertenezca
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos p JOIN pedimento_facturas f ON f.pedimento_id = p.id WHERE p.id = ? AND f.id = ? AND p.usuario_id = ?", [$id_pedimento, $id_factura, $usuario_id]);
+ $own = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$own) {
+ echo json_encode(['success' => false, 'message' => 'No autorizado o no encontrado']);
+ return;
+ }
+
+ // ¿Existe registro para esta factura?
+ $sel = sqlsrv_query($conn, "SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?", [$id_pedimento, $id_factura]);
+ $row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null;
+ if ($sel) sqlsrv_free_stmt($sel);
+
+ if ($row) {
+ // UPDATE
+ $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 = ?,
@@ -47,37 +166,64 @@ function ajax_guardar_datos_factura() {
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 (
+
+ precio_pagado_fecha_pago = ?, precio_pagado_importe = ?, precio_pagado_moneda = ?,
+ precio_pagado_forma_pago = ?, precio_pagado_referencia = ?,
+
+ precio_pagar_fecha_limite = ?, precio_pagar_importe = ?, precio_pagar_moneda = ?,
+ precio_pagar_terminos = ?, precio_pagar_observaciones = ?,
+
+ compenso_fecha = ?, compenso_importe = ?, compenso_tipo = ?,
+ compenso_motivo = ?, compenso_documentos = ?, compenso_descripcion = ?
+ WHERE id = ?";
+
+ $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,
+
+ $datos_precio_pagado['fecha_precio_pagado'] ?? null,
+ $datos_precio_pagado['importe_precio_pagado'] ?? null,
+ $datos_precio_pagado['moneda_precio_pagado'] ?? null,
+ $datos_precio_pagado['forma_pago_precio_pagado'] ?? null,
+ $datos_precio_pagado['referencia_precio_pagado'] ?? null,
+
+ $datos_precio_pagar['fecha_limite_pago'] ?? null,
+ $datos_precio_pagar['importe_precio_pagar'] ?? null,
+ $datos_precio_pagar['moneda_precio_pagar'] ?? null,
+ $datos_precio_pagar['terminos_precio_pagar'] ?? null,
+ $datos_precio_pagar['observaciones_precio_pagar'] ?? null,
+
+ $datos_compenso['fecha_compenso'] ?? null,
+ $datos_compenso['importe_compenso'] ?? null,
+ $datos_compenso['tipo_compenso'] ?? null,
+ $datos_compenso['motivo_compenso'] ?? null,
+ $datos_compenso['documentos_compenso'] ?? null,
+ $datos_compenso['descripcion_compenso'] ?? null,
+ $row['id']
+ ];
+
+ $stmt = sqlsrv_query($conn, $sql, $params);
+ } else {
+ // INSERT
+ $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,
@@ -85,106 +231,447 @@ function ajax_guardar_datos_factura() {
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,
-
+
+ precio_pagado_fecha_pago, precio_pagado_importe, precio_pagado_moneda,
+ precio_pagado_forma_pago, precio_pagado_referencia,
+
+ precio_pagar_fecha_limite, precio_pagar_importe, precio_pagar_moneda,
+ precio_pagar_terminos, precio_pagar_observaciones,
+
+ compenso_fecha, compenso_importe, compenso_tipo,
+ compenso_motivo, compenso_documentos, compenso_descripcion,
+
usuario_creacion
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
-
+ ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
+
+ // Obtener número de factura opcional
+ $num = null;
+ $nf = sqlsrv_query($conn, "SELECT numero_factura FROM pedimento_facturas WHERE id = ?", [$id_factura]);
+ if ($nf && ($r = sqlsrv_fetch_array($nf, SQLSRV_FETCH_ASSOC))) { $num = $r['numero_factura']; }
+ if ($nf) sqlsrv_free_stmt($nf);
+
+ $params = [
+ $id_pedimento, $id_factura, $num,
+ $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,
+
+ $datos_precio_pagado['fecha_precio_pagado'] ?? null,
+ $datos_precio_pagado['importe_precio_pagado'] ?? null,
+ $datos_precio_pagado['moneda_precio_pagado'] ?? null,
+ $datos_precio_pagado['forma_pago_precio_pagado'] ?? null,
+ $datos_precio_pagado['referencia_precio_pagado'] ?? null,
+
+ $datos_precio_pagar['fecha_limite_pago'] ?? null,
+ $datos_precio_pagar['importe_precio_pagar'] ?? null,
+ $datos_precio_pagar['moneda_precio_pagar'] ?? null,
+ $datos_precio_pagar['terminos_precio_pagar'] ?? null,
+ $datos_precio_pagar['observaciones_precio_pagar'] ?? null,
+
+ $datos_compenso['fecha_compenso'] ?? null,
+ $datos_compenso['importe_compenso'] ?? null,
+ $datos_compenso['tipo_compenso'] ?? null,
+ $datos_compenso['motivo_compenso'] ?? null,
+ $datos_compenso['documentos_compenso'] ?? null,
+ $datos_compenso['descripcion_compenso'] ?? null,
+
+ (string)$usuario_id
+ ];
+
+ $stmt = sqlsrv_query($conn, $sql, $params);
+ }
+
+ if ($stmt === false) {
+ echo json_encode(['success' => false, 'message' => 'Error al guardar']);
+ return;
+ }
+
+ // Marcar estado de MVE/COVE como respondido (para el badge)
+ upsert_cove_respuesta_min($conn, $id_pedimento, $id_factura, $usuario_id);
+
+ echo json_encode(['success' => true]);
+}
+
+// Autosave por sección: seccion in ['65','66','precio_pagado','precio_pagar','compenso']
+function ajax_guardar_seccion()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ return;
+ }
+
+ $usuario_id = (int)$_SESSION['usuario_id'];
+ $id_factura = isset($_POST['id_factura']) ? (int)$_POST['id_factura'] : 0;
+ $id_pedimento = isset($_POST['id_pedimento']) ? (int)$_POST['id_pedimento'] : 0;
+ $seccion = $_POST['seccion'] ?? '';
+ $datos = json_decode($_POST['datos'] ?? '{}', true);
+ if ($id_factura <= 0 || $id_pedimento <= 0 || !$seccion) {
+ echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
+ return;
+ }
+
+ $conn = getConnection();
+ // Verificar propiedad
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos p JOIN pedimento_facturas f ON f.pedimento_id = p.id WHERE p.id = ? AND f.id = ? AND p.usuario_id = ?", [$id_pedimento, $id_factura, $usuario_id]);
+ $own = $chk && sqlsrv_fetch_array($chk) ? true : false;
+ if ($chk) sqlsrv_free_stmt($chk);
+ if (!$own) { echo json_encode(['success' => false, 'message' => 'No autorizado']); return; }
+
+ // Garantizar que exista el registro base
+ $sel = sqlsrv_query($conn, "SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?", [$id_pedimento, $id_factura]);
+ $row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null; if ($sel) sqlsrv_free_stmt($sel);
+ if (!$row) {
+ // Crear registro vacío
+ $num = null; $nf = sqlsrv_query($conn, "SELECT numero_factura FROM pedimento_facturas WHERE id = ?", [$id_factura]);
+ if ($nf && ($r = sqlsrv_fetch_array($nf, SQLSRV_FETCH_ASSOC))) { $num = $r['numero_factura']; }
+ if ($nf) sqlsrv_free_stmt($nf);
+ $ins = sqlsrv_query($conn, "INSERT INTO mve_facturas_datos (id_pedimento, id_factura, numero_factura, usuario_creacion) VALUES (?,?,?,?)", [$id_pedimento, $id_factura, $num, (string)$usuario_id]);
+ if ($ins === false) { echo json_encode(['success' => false, 'message' => 'Error al iniciar registro']); return; }
+ $sel2 = sqlsrv_query($conn, "SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?", [$id_pedimento, $id_factura]);
+ $row = $sel2 ? sqlsrv_fetch_array($sel2, SQLSRV_FETCH_ASSOC) : null; if ($sel2) sqlsrv_free_stmt($sel2);
+ }
+
+ if (!$row) { echo json_encode(['success' => false, 'message' => 'No se pudo crear el registro']); return; }
+
+ $id = (int)$row['id'];
+ $sql = '';
+ $params = [];
+ switch ($seccion) {
+ case '65':
+ $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 = ?
+ WHERE id = ?";
$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']
+ $datos['fecha_transporte'] ?? null, $datos['importe_transporte'] ?? null,
+ $datos['fecha_descuentos'] ?? null, $datos['importe_descuentos'] ?? null,
+ $datos['fecha_posteriores'] ?? null, $datos['importe_posteriores'] ?? null,
+ $datos['fecha_contribuciones'] ?? null, $datos['importe_contribuciones'] ?? null,
+ $datos['fecha_pagos_vendedor'] ?? null, $datos['importe_pagos_vendedor'] ?? null,
+ $id
];
+ break;
+ case '66':
+ $sql = "UPDATE mve_facturas_datos SET
+ 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 = ?
+ WHERE id = ?";
+ $params = [
+ $datos['fecha_comisiones'] ?? null, $datos['importe_comisiones'] ?? null, $datos['cargo_comisiones'] ?? null,
+ $datos['fecha_envases'] ?? null, $datos['importe_envases'] ?? null, $datos['cargo_envases'] ?? null,
+ $datos['fecha_embalaje'] ?? null, $datos['importe_embalaje'] ?? null, $datos['cargo_embalaje'] ?? null,
+ $datos['fecha_transporte_dec'] ?? null, $datos['importe_transporte_dec'] ?? null, $datos['cargo_transporte_dec'] ?? null,
+ $datos['fecha_ingenieria'] ?? null, $datos['importe_ingenieria'] ?? null, $datos['cargo_ingenieria'] ?? null,
+ $datos['fecha_regalias'] ?? null, $datos['importe_regalias'] ?? null, $datos['cargo_regalias'] ?? null,
+ $datos['fecha_producto'] ?? null, $datos['importe_producto'] ?? null, $datos['cargo_producto'] ?? null,
+ $id
+ ];
+ break;
+ case 'precio_pagado':
+ $sql = "UPDATE mve_facturas_datos SET
+ precio_pagado_fecha_pago = ?, precio_pagado_importe = ?, precio_pagado_moneda = ?,
+ precio_pagado_forma_pago = ?, precio_pagado_referencia = ?
+ WHERE id = ?";
+ $params = [
+ $datos['fecha_precio_pagado'] ?? null,
+ $datos['importe_precio_pagado'] ?? null,
+ $datos['moneda_precio_pagado'] ?? null,
+ $datos['forma_pago_precio_pagado'] ?? null,
+ $datos['referencia_precio_pagado'] ?? null,
+ $id
+ ];
+ break;
+ case 'precio_pagar':
+ $sql = "UPDATE mve_facturas_datos SET
+ precio_pagar_fecha_limite = ?, precio_pagar_importe = ?, precio_pagar_moneda = ?,
+ precio_pagar_terminos = ?, precio_pagar_observaciones = ?
+ WHERE id = ?";
+ $params = [
+ $datos['fecha_limite_pago'] ?? null,
+ $datos['importe_precio_pagar'] ?? null,
+ $datos['moneda_precio_pagar'] ?? null,
+ $datos['terminos_precio_pagar'] ?? null,
+ $datos['observaciones_precio_pagar'] ?? null,
+ $id
+ ];
+ break;
+ case 'compenso':
+ $sql = "UPDATE mve_facturas_datos SET
+ compenso_fecha = ?, compenso_importe = ?, compenso_tipo = ?,
+ compenso_motivo = ?, compenso_documentos = ?, compenso_descripcion = ?
+ WHERE id = ?";
+ $params = [
+ $datos['fecha_compenso'] ?? null,
+ $datos['importe_compenso'] ?? null,
+ $datos['tipo_compenso'] ?? null,
+ $datos['motivo_compenso'] ?? null,
+ $datos['documentos_compenso'] ?? null,
+ $datos['descripcion_compenso'] ?? null,
+ $id
+ ];
+ break;
+ default:
+ echo json_encode(['success' => false, 'message' => 'Sección inválida']);
+ return;
+ }
+
+ $stmt = sqlsrv_query($conn, $sql, $params);
+ if ($stmt === false) {
+ echo json_encode(['success' => false, 'message' => 'Error al guardar sección']);
+ return;
+ }
+
+ // Marcar estado para badge
+ upsert_cove_respuesta_min($conn, $id_pedimento, $id_factura, $usuario_id);
+
+ echo json_encode(['success' => true]);
+}
+
+function ajax_obtener_datos_factura()
+{
+ $id_factura = isset($_GET['id_factura']) ? (int)$_GET['id_factura'] : 0;
+ if ($id_factura <= 0) { echo json_encode(['success' => false, 'message' => 'ID inválido']); return; }
+
+ $conn = getConnection();
+ $stmt = sqlsrv_query($conn, "SELECT * FROM mve_facturas_datos WHERE id_factura = ?", [$id_factura]);
+ if ($stmt === false) { echo json_encode(['success' => false, 'message' => 'Error DB']); return; }
+ $datos = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ if ($stmt) sqlsrv_free_stmt($stmt);
+
+ if ($datos) {
+ // Formateador de fechas seguro para JSON
+ $fmtDate = function($v) {
+ if ($v instanceof DateTime) return $v->format('Y-m-d');
+ if (is_string($v)) return substr($v, 0, 10);
+ return $v ?: null;
+ };
+ if (isset($datos['fecha_actualizacion']) && $datos['fecha_actualizacion'] instanceof DateTime) {
+ $datos['fecha_actualizacion'] = $datos['fecha_actualizacion']->format('Y-m-d H:i:s');
}
+ $datosEstructurados = [
+ 'art65' => [
+ 'fecha_transporte' => $fmtDate($datos['art65_fecha_transporte'] ?? null),
+ 'importe_transporte' => $datos['art65_importe_transporte'] ?? null,
+ 'fecha_descuentos' => $fmtDate($datos['art65_fecha_descuentos'] ?? null),
+ 'importe_descuentos' => $datos['art65_importe_descuentos'] ?? null,
+ 'fecha_posteriores' => $fmtDate($datos['art65_fecha_posteriores'] ?? null),
+ 'importe_posteriores' => $datos['art65_importe_posteriores'] ?? null,
+ 'fecha_contribuciones' => $fmtDate($datos['art65_fecha_contribuciones'] ?? null),
+ 'importe_contribuciones' => $datos['art65_importe_contribuciones'] ?? null,
+ 'fecha_pagos_vendedor' => $fmtDate($datos['art65_fecha_pagos_vendedor'] ?? null),
+ 'importe_pagos_vendedor' => $datos['art65_importe_pagos_vendedor'] ?? null,
+ ],
+ 'art66' => [
+ 'fecha_comisiones' => $fmtDate($datos['art66_fecha_comisiones'] ?? null),
+ 'importe_comisiones' => $datos['art66_importe_comisiones'] ?? null,
+ 'cargo_comisiones' => $datos['art66_cargo_comisiones'] ?? null,
+ 'fecha_envases' => $fmtDate($datos['art66_fecha_envases'] ?? null),
+ 'importe_envases' => $datos['art66_importe_envases'] ?? null,
+ 'cargo_envases' => $datos['art66_cargo_envases'] ?? null,
+ 'fecha_embalaje' => $fmtDate($datos['art66_fecha_embalaje'] ?? null),
+ 'importe_embalaje' => $datos['art66_importe_embalaje'] ?? null,
+ 'cargo_embalaje' => $datos['art66_cargo_embalaje'] ?? null,
+ 'fecha_transporte_dec' => $fmtDate($datos['art66_fecha_transporte_dec'] ?? null),
+ 'importe_transporte_dec' => $datos['art66_importe_transporte_dec'] ?? null,
+ 'cargo_transporte_dec' => $datos['art66_cargo_transporte_dec'] ?? null,
+ 'fecha_ingenieria' => $fmtDate($datos['art66_fecha_ingenieria'] ?? null),
+ 'importe_ingenieria' => $datos['art66_importe_ingenieria'] ?? null,
+ 'cargo_ingenieria' => $datos['art66_cargo_ingenieria'] ?? null,
+ 'fecha_regalias' => $fmtDate($datos['art66_fecha_regalias'] ?? null),
+ 'importe_regalias' => $datos['art66_importe_regalias'] ?? null,
+ 'cargo_regalias' => $datos['art66_cargo_regalias'] ?? null,
+ 'fecha_producto' => $fmtDate($datos['art66_fecha_producto'] ?? null),
+ 'importe_producto' => $datos['art66_importe_producto'] ?? null,
+ 'cargo_producto' => $datos['art66_cargo_producto'] ?? null,
+ ],
+ 'precio_pagado' => [
+ 'fecha_precio_pagado' => $fmtDate($datos['precio_pagado_fecha_pago'] ?? null),
+ 'importe_precio_pagado' => $datos['precio_pagado_importe'] ?? null,
+ 'moneda_precio_pagado' => $datos['precio_pagado_moneda'] ?? null,
+ 'forma_pago_precio_pagado' => $datos['precio_pagado_forma_pago'] ?? null,
+ 'referencia_precio_pagado' => $datos['precio_pagado_referencia'] ?? null,
+ ],
+ 'precio_pagar' => [
+ 'fecha_limite_pago' => $fmtDate($datos['precio_pagar_fecha_limite'] ?? null),
+ 'importe_precio_pagar' => $datos['precio_pagar_importe'] ?? null,
+ 'moneda_precio_pagar' => $datos['precio_pagar_moneda'] ?? null,
+ 'terminos_precio_pagar' => $datos['precio_pagar_terminos'] ?? null,
+ 'observaciones_precio_pagar' => $datos['precio_pagar_observaciones'] ?? null,
+ ],
+ 'compenso' => [
+ 'fecha_compenso' => $fmtDate($datos['compenso_fecha'] ?? null),
+ 'importe_compenso' => $datos['compenso_importe'] ?? null,
+ 'tipo_compenso' => $datos['compenso_tipo'] ?? null,
+ 'motivo_compenso' => $datos['compenso_motivo'] ?? null,
+ 'documentos_compenso' => $datos['compenso_documentos'] ?? null,
+ 'descripcion_compenso' => $datos['compenso_descripcion'] ?? null,
+ ]
+ ];
- $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()]);
+ echo json_encode(['success' => true, 'datos' => $datosEstructurados]);
+ } else {
+ echo json_encode(['success' => true, 'datos' => null]);
}
}
-function ajax_obtener_datos_factura() {
- try {
- $id_factura = $_GET['id_factura'] ?? null;
+// Utilidad: marca/crea un registro mínimo en cove_respuestas para encender el badge
+function upsert_cove_respuesta_min($conn, $pedimento_id, $factura_id, $usuario_id)
+{
+ $sel = sqlsrv_query($conn, "SELECT id FROM cove_respuestas WHERE factura_id = ? AND usuario_id = ?", [$factura_id, $usuario_id]);
+ $row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null; if ($sel) sqlsrv_free_stmt($sel);
+ if ($row) {
+ sqlsrv_query($conn, "UPDATE cove_respuestas SET estado = 'respondido', fecha_actualizacion = SYSDATETIME() WHERE id = ?", [$row['id']]);
+ } else {
+ sqlsrv_query($conn, "INSERT INTO cove_respuestas (pedimento_id, factura_id, usuario_id, respuestas, estado, fecha_creacion) VALUES (?,?,?,?,?,SYSDATETIME())",
+ [$pedimento_id, $factura_id, $usuario_id, '{}', 'respondido']);
+ }
+}
- if (!$id_factura) {
- echo json_encode(['success' => false, 'message' => 'ID de factura requerido']);
+// Registra la solicitud de MVE con aceptación de declaración del importador
+function ajax_registrar_solicitud()
+{
+ header('Content-Type: application/json; charset=UTF-8');
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ http_response_code(403);
+ echo json_encode(['success' => false, 'message' => 'No autorizado']);
+ return;
+ }
+
+ $usuario_id = (int)$_SESSION['usuario_id'];
+ $pedimento_id = isset($_POST['pedimento_id']) ? (int)$_POST['pedimento_id'] : 0;
+ $factura_id = isset($_POST['factura_id']) ? (int)$_POST['factura_id'] : 0;
+ $acepto = isset($_POST['acepto']) ? (int)$_POST['acepto'] : 0;
+ $rfc_importador = isset($_POST['rfc_importador']) ? trim($_POST['rfc_importador']) : null;
+ $firma_base64 = isset($_POST['firma_base64']) ? $_POST['firma_base64'] : null;
+ $firmante = isset($_POST['firmante']) ? trim($_POST['firmante']) : null;
+ $ip = $_SERVER['REMOTE_ADDR'] ?? null;
+
+ if ($pedimento_id <= 0 || $factura_id <= 0) { echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']); return; }
+ if ($acepto !== 1) { echo json_encode(['success' => false, 'message' => 'Debes aceptar la declaración']); return; }
+
+ $conn = getConnection();
+
+ // Verificar propiedad y relación factura-pedimento
+ $chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos p JOIN pedimento_facturas f ON f.pedimento_id = p.id WHERE p.id = ? AND f.id = ? AND p.usuario_id = ?", [$pedimento_id, $factura_id, $usuario_id]);
+ $ok = $chk && sqlsrv_fetch_array($chk) ? true : false; if ($chk) sqlsrv_free_stmt($chk);
+ if (!$ok) { echo json_encode(['success' => false, 'message' => 'No autorizado o relación inválida']); return; }
+
+ // Asegurar tabla mve_solicitudes
+ $sqlEnsure = "
+ IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[mve_solicitudes]') AND type in (N'U'))
+ BEGIN
+ CREATE TABLE dbo.mve_solicitudes (
+ id INT IDENTITY(1,1) PRIMARY KEY,
+ pedimento_id INT NOT NULL,
+ factura_id INT NOT NULL,
+ usuario_id INT NOT NULL,
+ acepto_declaracion BIT NOT NULL,
+ rfc_importador NVARCHAR(20) NULL,
+ ip NVARCHAR(64) NULL,
+ fecha_solicitud DATETIME2 NOT NULL DEFAULT SYSDATETIME(),
+ comentario NVARCHAR(400) NULL,
+ firma_base64 NVARCHAR(MAX) NULL,
+ firmante NVARCHAR(200) NULL
+ );
+ CREATE INDEX IX_mve_solicitudes_factura ON dbo.mve_solicitudes(factura_id);
+ END;
+ -- Ensure all expected columns exist on legacy tables
+ IF COL_LENGTH('dbo.mve_solicitudes','pedimento_id') IS NULL ALTER TABLE dbo.mve_solicitudes ADD pedimento_id INT NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','factura_id') IS NULL ALTER TABLE dbo.mve_solicitudes ADD factura_id INT NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','usuario_id') IS NULL ALTER TABLE dbo.mve_solicitudes ADD usuario_id INT NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','acepto_declaracion') IS NULL ALTER TABLE dbo.mve_solicitudes ADD acepto_declaracion BIT NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','rfc_importador') IS NULL ALTER TABLE dbo.mve_solicitudes ADD rfc_importador NVARCHAR(20) NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','ip') IS NULL ALTER TABLE dbo.mve_solicitudes ADD ip NVARCHAR(64) NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','fecha_solicitud') IS NULL ALTER TABLE dbo.mve_solicitudes ADD fecha_solicitud DATETIME2 NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes','comentario') IS NULL ALTER TABLE dbo.mve_solicitudes ADD comentario NVARCHAR(400) NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes', 'firma_base64') IS NULL ALTER TABLE dbo.mve_solicitudes ADD firma_base64 NVARCHAR(MAX) NULL;
+ IF COL_LENGTH('dbo.mve_solicitudes', 'firmante') IS NULL ALTER TABLE dbo.mve_solicitudes ADD firmante NVARCHAR(200) NULL;
+ IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_mve_solicitudes_factura' AND object_id = OBJECT_ID('dbo.mve_solicitudes'))
+ CREATE INDEX IX_mve_solicitudes_factura ON dbo.mve_solicitudes(factura_id);
+ ";
+ $ensureOk = sqlsrv_query($conn, $sqlEnsure);
+ if ($ensureOk === false) {
+ $err = sqlsrv_errors();
+ echo json_encode(['success' => false, 'message' => 'Error al preparar tabla de solicitudes', 'detail' => $err]);
+ return;
+ }
+
+ // Determinar columnas legacy (id_*) y nuevas (*_id) disponibles
+ $has_id_ped = false; $has_id_fac = false; $has_id_usr = false;
+ $chkCols = sqlsrv_query($conn, "SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('dbo.mve_solicitudes') AND name IN ('id_pedimento','id_factura','id_usuario','pedimento_id','factura_id','usuario_id')");
+ if ($chkCols) {
+ while ($c = sqlsrv_fetch_array($chkCols, SQLSRV_FETCH_ASSOC)) {
+ if ($c['name'] === 'id_pedimento') $has_id_ped = true;
+ if ($c['name'] === 'id_factura') $has_id_fac = true;
+ if ($c['name'] === 'id_usuario') $has_id_usr = true;
+ }
+ sqlsrv_free_stmt($chkCols);
+ }
+
+ // Validar firma obligatoria
+ if (!$firma_base64 || trim($firma_base64) === '') {
+ echo json_encode(['success' => false, 'message' => 'La firma es obligatoria']);
return;
}
- $db = getDB();
- $stmt = $db->prepare("SELECT * FROM mve_facturas_datos WHERE id_factura = ?");
- $stmt->execute([$id_factura]);
- $datos = $stmt->fetch(PDO::FETCH_ASSOC);
+ // Construir INSERT dinámico para soportar ambos esquemas
+ $cols = [];
+ $vals = [];
+ $paramsIns = [];
+ // IDs
+ $cols[] = 'pedimento_id'; $vals[] = '?'; $paramsIns[] = $pedimento_id;
+ if ($has_id_ped) { $cols[] = 'id_pedimento'; $vals[] = '?'; $paramsIns[] = $pedimento_id; }
+ $cols[] = 'factura_id'; $vals[] = '?'; $paramsIns[] = $factura_id;
+ if ($has_id_fac) { $cols[] = 'id_factura'; $vals[] = '?'; $paramsIns[] = $factura_id; }
+ $cols[] = 'usuario_id'; $vals[] = '?'; $paramsIns[] = $usuario_id;
+ if ($has_id_usr) { $cols[] = 'id_usuario'; $vals[] = '?'; $paramsIns[] = $usuario_id; }
+ // Resto de columnas
+ $cols = array_merge($cols, ['acepto_declaracion','rfc_importador','ip','firma_base64','firmante']);
+ $vals = array_merge($vals, array_fill(0, 5, '?'));
+ $paramsIns = array_merge($paramsIns, [1, $rfc_importador, $ip, $firma_base64, $firmante]);
- 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]);
+ $sqlIns = 'INSERT INTO mve_solicitudes (' . implode(',', $cols) . ') VALUES (' . implode(',', $vals) . ')';
+ $ins = sqlsrv_query($conn, $sqlIns, $paramsIns);
+ if ($ins === false) {
+ $err = sqlsrv_errors();
+ $msg = 'No se pudo registrar la solicitud';
+ if ($err && isset($err[0]['message'])) { $msg .= ': ' . $err[0]['message']; }
+ echo json_encode(['success' => false, 'message' => $msg]);
+ return;
}
- } catch (Exception $e) {
- echo json_encode(['success' => false, 'message' => 'Error interno: ' . $e->getMessage()]);
- }
+ // Actualizar estado en cove_respuestas a 'solicitado'
+ $sel = sqlsrv_query($conn, "SELECT id FROM cove_respuestas WHERE factura_id = ? AND usuario_id = ?", [$factura_id, $usuario_id]);
+ $row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null; if ($sel) sqlsrv_free_stmt($sel);
+ if ($row) {
+ sqlsrv_query($conn, "UPDATE cove_respuestas SET estado = 'solicitado', fecha_actualizacion = SYSDATETIME() WHERE id = ?", [$row['id']]);
+ } else {
+ sqlsrv_query($conn, "INSERT INTO cove_respuestas (usuario_id, pedimento_id, factura_id, estado, fecha_actualizacion) VALUES (?, ?, ?, 'solicitado', SYSDATETIME())", [$usuario_id, $pedimento_id, $factura_id]);
+ }
+
+ // Generar documentos de prueba (acuse y detalle) en el expediente del pedimento
+ $usuario_nombre = $_SESSION['usuario_nombre'] ?? 'sistema';
+ mve_generar_documentos_expediente($conn, $pedimento_id, $usuario_nombre);
+
+ echo json_encode(['success' => true]);
}
diff --git a/app/controllers/test_connection.php b/app/controllers/test_connection.php
new file mode 100644
index 0000000..fbc1e47
--- /dev/null
+++ b/app/controllers/test_connection.php
@@ -0,0 +1,19 @@
+ true,
+ 'message' => 'Conexión exitosa',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'usuario' => isset($_SESSION['usuario']) ? $_SESSION['usuario']['nombre'] ?? 'Usuario logueado' : 'No hay usuario',
+ 'post_data' => $_POST,
+ 'files_data' => isset($_FILES['archivo']) ? [
+ 'nombre' => $_FILES['archivo']['name'],
+ 'tamaño' => $_FILES['archivo']['size'],
+ 'tipo' => $_FILES['archivo']['type'],
+ 'error' => $_FILES['archivo']['error']
+ ] : 'No hay archivo'
+]);
+?>
\ No newline at end of file
diff --git a/catalogos.txt b/catalogos.txt
deleted file mode 100644
index 4a76364..0000000
--- a/catalogos.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-CREATE TABLE preferencias_catalogos_usuario (
- id_preferencia INT IDENTITY(1,1) NOT NULL,
- id_usuario INT NOT NULL,
- locaciones BIT DEFAULT 0,
- vinculacion BIT DEFAULT 0,
- transportistas BIT DEFAULT 0,
- transportes BIT DEFAULT 0,
- choferes BIT DEFAULT 0,
- proveedores BIT DEFAULT 0,
- productos_frecuentes BIT DEFAULT 0,
- solicitudes_importacion BIT DEFAULT 0,
- expediente_electronico BIT DEFAULT 0,
- configuracion BIT DEFAULT 0,
- cerrar_sesion BIT DEFAULT 0,
- FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
-);
-
-ALTER TABLE usuarios_sistema
-ADD [preferencias_catalogos] BIT DEFAULT 1;
-
-CREATE TABLE tipos_catalogos (
- id INT PRIMARY KEY IDENTITY,
- tipo_usuario VARCHAR(20) NOT NULL,
- nombre VARCHAR(255) NOT NULL,
- descripcion VARCHAR(500) NULL,
- color VARCHAR(20) NOT NULL,
- ruta VARCHAR(100) NOT NULL,
- accion VARCAHR(50) NOT NULL
-);
-
-INSERT INTO tipos_catalogos (tipo_usuario, nombre, descripcion, color, ruta, accion) VALUES
-('importador', 'Locaciones', 'Visualiza las locaciones registradas.', 'lime', '/IMPORTADORES/importadores/lista', 'Ver locaciones'),
-('importador', 'Vinculación', 'Visualiza o establece nuevas vinculaciones con agencias aduanales.', 'teal', '/IMPORTADORES/vinculaciones/vinculacionesUsuario', 'Ver vinculaciones'),
-('importador', 'Transportistas', 'Agrega o consulta los choferes que colaboran contigo.', 'success', '/IMPORTADORES/transportistas/lista', 'Ver transportistas'),
-('importador', 'Transportes', 'Gestiona y carga tus unidades de transporte.', 'info', '/IMPORTADORES/transportes/lista', 'Ver transportes'),
-('importador', 'Choferes', 'Gestiona y carga a tus choferes.', 'cyan', '/IMPORTADORES/choferes/lista', 'Ver choferes'),
-('importador', 'Proveedores', 'Agrega tus proveedores.', 'primary', '/IMPORTADORES/proveedores/crear', 'Nuevo proveedor'),
-('importador', 'Productos frecuentes', 'Agrega productos frecuentes de tu interez.', 'violet', '/IMPORTADORES/productos_frecuentes/alta', 'Nuevo producto'),
-('importador', 'Solicitudes importación', 'Inicia nuevas solicitudes de pedimentos.', 'indigo', '/IMPORTADORES/solicitud_importacion/crear', 'Nueva solicitud'),
-('importador', 'Expediente electrónico', 'Revisa el expediente electrónico para tus solicitudes.', 'warning', '/IMPORTADORES/expediente/index', 'Ver expediente'),
-('importador', 'Configuración', 'Administra los datos de tu empresa y preferencias.', 'orange', '/IMPORTADORES/configuracion', 'Ir a configuración'),
-('importador', 'Cerrar sesión', 'Salir del sistema de forma segura.', 'danger', '/IMPORTADORES/sistemas/logout', 'Cerrar sesión');
-
-
-
-UPDATE usuarios_sistema
-SET preferencias_catalogos = 1
-WHERE preferencias_catalogos IS NULL OR preferencias_catalogos = 0;
-
--- 2. Insertar en preferencias_catalogos_usuario solo para los que aún no tienen registro
-INSERT INTO preferencias_catalogos_usuario (
- id_usuario, locaciones, vinculacion, transportistas, transportes, choferes, proveedores,
- productos_frecuentes, solicitudes_importacion, expediente_electronico, configuracion, cerrar_sesion
-)
-SELECT u.id_usuario, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
-FROM usuarios_sistema u
-WHERE u.tipo_usuario = 'importador'
- AND NOT EXISTS (
- SELECT 1 FROM preferencias_catalogos_usuario p
- WHERE p.id_usuario = u.id_usuario
- );
\ No newline at end of file
diff --git a/claves_pedimentos_tabla.sql b/claves_pedimentos_tabla.sql
deleted file mode 100644
index 629396b..0000000
--- a/claves_pedimentos_tabla.sql
+++ /dev/null
@@ -1,21 +0,0 @@
--- 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
deleted file mode 100644
index a8e04ab..0000000
--- a/configuracion_ventanilla_unica.sql
+++ /dev/null
@@ -1,97 +0,0 @@
--- 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
deleted file mode 100644
index 8365abc..0000000
--- a/create_table_temp.php
+++ /dev/null
@@ -1,52 +0,0 @@
-getMessage() . "\n";
-}
-?>
\ No newline at end of file
diff --git a/debug_templates.php b/debug_templates.php
deleted file mode 100644
index 1cec591..0000000
--- a/debug_templates.php
+++ /dev/null
@@ -1,196 +0,0 @@
-🔍 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 "
- ID
- Nombre
- Descripción
- Activo
- Usuario Creador
- Agencia
- Fecha Creación
- Tiene Config
- ";
-
- 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 "" . $row['id'] . " ";
- echo "" . htmlspecialchars($row['nombre']) . " ";
- echo "" . htmlspecialchars($row['descripcion'] ?? '') . " ";
- echo "" . ($row['activo'] ? '✅' : '❌') . " ";
- echo "" . ($row['id_usuario_creador'] ?? 'NULL') . " ";
- echo "" . ($row['id_agencia'] ?? 'NULL') . " ";
- echo "" . $fecha . " ";
- echo "" . $tieneConfig . " ";
- echo " ";
- }
- echo "
";
-
- 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 "
- ID
- Nombre
- Es Mío
- Usuario Creador
- Agencia
- Debería Aparecer
- ";
-
- while ($row = sqlsrv_fetch_array($stmt_endpoint, SQLSRV_FETCH_ASSOC)) {
- $count_endpoint++;
- $esMio = ($row['id_usuario_creador'] == $id_usuario) ? 'SÍ' : 'NO';
-
- echo "";
- echo "" . $row['id'] . " ";
- echo "" . htmlspecialchars($row['nombre']) . " ";
- echo "$esMio ";
- echo "" . ($row['id_usuario_creador'] ?? 'NULL') . " ";
- echo "" . ($row['id_agencia'] ?? 'NULL') . " ";
- echo "✅ SÍ ";
- echo " ";
- }
- echo "
";
-
- 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:
-
- 🧪 Probar AJAX ahora
-
-
-
-
-💡 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/emails_tables.txt b/emails_tables.txt
deleted file mode 100644
index 45ca74c..0000000
--- a/emails_tables.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-CREATE TABLE verificaciones (
- id INT IDENTITY(1,1) PRIMARY KEY,
- id_usuario INT NOT NULL,
- codigo VARCHAR(10) NOT NULL,
- expiracion DATETIME NOT NULL,
- tipo VARCHAR(50) DEFAULT 'login',
- creado_en DATETIME DEFAULT GETDATE(),
- FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
-);
-
-
-CREATE TABLE correo_extra (
- id INT IDENTITY(1,1) PRIMARY KEY,
- id_usuario INT NOT NULL,
- correo VARCHAR(255) NOT NULL,
- fecha_registro DATETIME DEFAULT GETDATE(),
- FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
-);
-
-CREATE TABLE correo_respaldo (
- id INT IDENTITY(1,1) PRIMARY KEY,
- id_usuario INT NOT NULL,
- correo VARCHAR(255) NOT NULL,
- fecha_registro DATETIME DEFAULT GETDATE(),
- FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
-);
diff --git a/informacion_general.txt b/informacion_general.txt
deleted file mode 100644
index 3ce2885..0000000
--- a/informacion_general.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-CREATE TABLE informacion_general (
- id_info INT PRIMARY KEY IDENTITY,
- id_usuario INT,
- clave VARCHAR(100),
- tipo_identificador VARCHAR(100),
- nombre NVARCHAR(255),
- rfc NVARCHAR(13),
- curp VARCHAR(18),
- calle NVARCHAR(255),
- num_exterior VARCHAR(20),
- num_interior VARCHAR(20),
- ciudad NVARCHAR(100),
- colonia NVARCHAR(100),
- pais NVARCHAR(100),
- codigo_postal VARCHAR(10),
- municipio NVARCHAR(100),
- estado NVARCHAR(100),
- telefono VARCHAR(50),
- fax VARCHAR(50),
- correo NVARCHAR(100),
- observaciones TEXT,
- FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
-);
-
-ALTER TABLE informacion_general
-ALTER COLUMN tipo_identificador INT;
-
-ALTER TABLE informacion_general
-ALTER COLUMN num_exterior INT;
-
-ALTER TABLE informacion_general
-ALTER COLUMN codigo_postal INT;
\ No newline at end of file
diff --git a/mve_incrementales_decrementales.sql b/mve_incrementales_decrementales.sql
deleted file mode 100644
index a523bc8..0000000
--- a/mve_incrementales_decrementales.sql
+++ /dev/null
@@ -1,90 +0,0 @@
--- 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/notificaciones_table.txt b/notificaciones_table.txt
deleted file mode 100644
index e05364f..0000000
--- a/notificaciones_table.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-ALTER TABLE usuarios_sistema
-ADD notificaciones BIT DEFAULT 0,
- notificaciones_extra BIT DEFAULT 0;
-
-CREATE TABLE tipos_notificaciones (
- id INT PRIMARY KEY IDENTITY,
- nombre NVARCHAR(255) NOT NULL,
- descripcion NVARCHAR(500) NULL
-);
-
-INSERT INTO tipos_notificaciones (nombre, descripcion) VALUES
-('nuevas_solicitudes', 'Creación de nuevas solicitudes de importación'),
-('registro_solicitud', 'Notificación inmediata al registrar una solicitud'),
-('cambio_estado', 'Cambio de estado de solicitudes de importación'),
-('resumen_diario', 'Resumen diario de solicitudes de importación'),
-('alertas_tiempo', 'Alertas por tiempo excedido en estados críticos'),
-('documentos_expediente', 'Incorporación de documentos al expediente electrónico'),
-('nuevos_archivos', 'Aviso al agregarse nuevos archivos o documentos'),
-('intentos_fallidos', 'Intentos fallidos de acceso'),
-('bloqueo_cuenta', 'Bloqueo de cuenta');
-
-CREATE TABLE preferencias_notificaciones_usuario (
- id_usuario INT PRIMARY KEY,
- nuevas_solicitudes BIT DEFAULT 0,
- registro_solicitud BIT DEFAULT 0,
- cambio_estado BIT DEFAULT 0,
- resumen_diario BIT DEFAULT 0,
- alertas_tiempo BIT DEFAULT 0,
- documentos_expediente BIT DEFAULT 0,
- nuevos_archivos BIT DEFAULT 0,
- intentos_fallidos BIT DEFAULT 0,
- bloqueo_cuenta BIT DEFAULT 0,
- FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
-);
-
-ALTER TABLE preferencias_notificaciones_usuario
-ADD resumen_diario_hora TIME DEFAULT '08:00:00',
- resumen_diario_dias NVARCHAR(20) DEFAULT 'L-V'; -- L-V = Lunes a Viernes, o 'TODOS' para todos los días
\ No newline at end of file
diff --git a/previos_tabla.sql b/previos_tabla.sql
deleted file mode 100644
index 62658ad..0000000
--- a/previos_tabla.sql
+++ /dev/null
@@ -1,58 +0,0 @@
--- 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/productos_frecuentes.sql b/productos_frecuentes.sql
deleted file mode 100644
index 66f2325..0000000
--- a/productos_frecuentes.sql
+++ /dev/null
@@ -1,35 +0,0 @@
-CREATE TABLE dbo.productos_frecuentes (
- id_producto_frecuente INT IDENTITY(1,1) PRIMARY KEY,
- sinonimo NVARCHAR(255) NOT NULL,
- fraccion NVARCHAR(50) NOT NULL,
- nico NVARCHAR(50) NOT NULL,
- numero_parte NVARCHAR(300) NULL,
- descripcion NVARCHAR(MAX) NULL,
- umc_id INT NOT NULL, -- FK a unidades_medida_apendice7(id)
- pais_origen_destino NVARCHAR(100) NULL,
- pais_comprador_vendedor NVARCHAR(100) NULL,
- uso_mercancia NVARCHAR(100) NULL,
- estado_mercancia NVARCHAR(100) NULL,
- vinculacion NVARCHAR(100) NULL,
- observaciones NVARCHAR(MAX) NULL,
- preferencia NVARCHAR(100) NULL,
- criterio_preferencia NVARCHAR(100) NULL,
- uso_producto NVARCHAR(100) NULL,
- descripcion_producto NVARCHAR(MAX) NULL,
- certificado_origen BIT NOT NULL DEFAULT 0,
- tipo_mercancia NVARCHAR(100) NULL,
- documento_en_original BIT NOT NULL DEFAULT 0,
- proveedor NVARCHAR(255) NULL,
- id_importador INT NOT NULL, -- FK a usuarios_sistema(id_usuario)
- fecha_alta DATETIME2 NOT NULL DEFAULT GETDATE(),
- status INT NOT NULL DEFAULT 1,
- frecuencia_uso INT NOT NULL DEFAULT 1, -- cuántas veces se ha utilizado
-
- CONSTRAINT FK_prodFreq_UMC
- FOREIGN KEY (umc_id)
- REFERENCES dbo.unidades_medida_apendice7(id),
-
- CONSTRAINT FK_prodFreq_Importador
- FOREIGN KEY (id_importador)
- REFERENCES dbo.usuarios_sistema(id_usuario)
-);
\ No newline at end of file
diff --git a/productos_frecuentes.txt b/productos_frecuentes.txt
deleted file mode 100644
index 5ed9682..0000000
--- a/productos_frecuentes.txt
+++ /dev/null
@@ -1,11 +0,0 @@
--- 1. Elimina la restricción DEFAULT
-ALTER TABLE [Importaciones_HC].[dbo].[productos_frecuentes]
-DROP CONSTRAINT [DF__productos__certi__3EDC53F0];
-
--- 2. Modifica el tipo de dato
-ALTER TABLE [Importaciones_HC].[dbo].[productos_frecuentes]
-ALTER COLUMN [certificado_origen] NVARCHAR(100);
-
--- 3. (Opcional) Si quieres volver a agregar un valor por defecto
-ALTER TABLE [Importaciones_HC].[dbo].[productos_frecuentes]
-ADD CONSTRAINT DF_productos_certificado_origen DEFAULT '' FOR [certificado_origen];
\ No newline at end of file
diff --git a/public/check_session.php b/public/check_session.php
new file mode 100644
index 0000000..bc42bb6
--- /dev/null
+++ b/public/check_session.php
@@ -0,0 +1,13 @@
+ isset($_SESSION['usuario']),
+ 'usuario_datos' => $_SESSION['usuario'] ?? null,
+ 'session_id' => session_id(),
+ 'session_status' => session_status(),
+ 'cookie_params' => session_get_cookie_params(),
+ 'todas_las_sesiones' => $_SESSION ?? []
+], JSON_PRETTY_PRINT);
+?>
\ No newline at end of file
diff --git a/public/debug.php b/public/debug.php
new file mode 100644
index 0000000..afb40c7
--- /dev/null
+++ b/public/debug.php
@@ -0,0 +1,26 @@
+getMessage() . "\n";
+}
+
+echo "=== FIN DEBUG ===\n";
+?>
\ No newline at end of file
diff --git a/public/debug_partidas.php b/public/debug_partidas.php
new file mode 100644
index 0000000..759c88c
--- /dev/null
+++ b/public/debug_partidas.php
@@ -0,0 +1,152 @@
+
+
+
+
+
+ Debug - Partidas de Pedimentos
+
+
+
+
+
Debug - Últimas Partidas Insertadas ";
+
+try {
+ $conn = conectarBD();
+
+ // Obtener las últimas partidas con información del pedimento
+ $sql = "SELECT TOP 20
+ pp.id,
+ pp.secuencia,
+ pp.fraccion_arancelaria,
+ pp.descripcion,
+ pp.cantidad,
+ pp.unidad,
+ pp.valor_unitario,
+ pp.valor_total,
+ pp.peso_neto,
+ pp.peso_bruto,
+ pp.fecha_creacion,
+ p.numero_pedimento
+ FROM pedimento_partidas pp
+ INNER JOIN pedimentos p ON pp.pedimento_id = p.id
+ ORDER BY pp.fecha_creacion DESC";
+
+ $stmt = sqlsrv_query($conn, $sql);
+
+ if ($stmt === false) {
+ throw new Exception("Error en consulta: " . print_r(sqlsrv_errors(), true));
+ }
+
+ echo "
+
+
+
+ ID
+ Pedimento
+ Secuencia
+ Fracción
+ Descripción
+ Cantidad
+ Unidad
+ Valor Unit.
+ Valor Total
+ Peso Neto
+ Peso Bruto
+ Fecha
+
+
+ ";
+
+ $contador = 0;
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $contador++;
+
+ echo "
+ {$row['id']}
+ {$row['numero_pedimento']}
+ {$row['secuencia']}
+ {$row['fraccion_arancelaria']}
+ " . (strlen($row['descripcion']) > 50 ? substr($row['descripcion'], 0, 50) . '...' : $row['descripcion']) . "
+ " . number_format($row['cantidad'], 4) . "
+ {$row['unidad']}
+ " . number_format($row['valor_unitario'], 4) . "
+ " . number_format($row['valor_total'], 4) . "
+ " . ($row['peso_neto'] ? number_format($row['peso_neto'], 4) : 'NULL') . "
+ " . ($row['peso_bruto'] ? number_format($row['peso_bruto'], 4) : 'NULL') . "
+ {$row['fecha_creacion']->format('Y-m-d H:i:s')}
+ ";
+ }
+
+ echo "
";
+
+ if ($contador == 0) {
+ echo "
No se encontraron partidas en la base de datos.
";
+ } else {
+ echo "
Se encontraron $contador partidas.
";
+ }
+
+ // Estadísticas adicionales
+ $sql_stats = "SELECT
+ COUNT(*) as total_partidas,
+ COUNT(DISTINCT pedimento_id) as total_pedimentos,
+ AVG(cantidad) as promedio_cantidad,
+ AVG(valor_unitario) as promedio_valor_unitario
+ FROM pedimento_partidas";
+
+ $stmt_stats = sqlsrv_query($conn, $sql_stats);
+ if ($stmt_stats && $stats = sqlsrv_fetch_array($stmt_stats, SQLSRV_FETCH_ASSOC)) {
+ echo "
+
+
+
+
Total Partidas
+
{$stats['total_partidas']}
+
+
+
+
+
+
+
Total Pedimentos
+
{$stats['total_pedimentos']}
+
+
+
+
+
+
+
Promedio Cantidad
+
" . number_format($stats['promedio_cantidad'], 2) . "
+
+
+
+
+
+
+
Promedio Valor Unit.
+
" . number_format($stats['promedio_valor_unitario'], 2) . "
+
+
+
+
";
+ }
+
+ sqlsrv_close($conn);
+
+} catch (Exception $e) {
+ echo "
Error: " . $e->getMessage() . "
";
+}
+
+echo "
+
+
+";
+?>
\ No newline at end of file
diff --git a/public/diagnostico_importacion.php b/public/diagnostico_importacion.php
new file mode 100644
index 0000000..bc80d96
--- /dev/null
+++ b/public/diagnostico_importacion.php
@@ -0,0 +1,134 @@
+ true,
+ 'diagnostico' => 'Análisis completado',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'checks' => [
+ 'sesion' => isset($_SESSION['usuario_id']),
+ 'usuario_id' => $_SESSION['usuario_id'] ?? null,
+ 'tipo_usuario' => $_SESSION['tipo_usuario'] ?? null,
+ 'metodo_post' => $_SERVER['REQUEST_METHOD'] === 'POST',
+ 'archivo_recibido' => isset($_FILES['archivo']),
+ 'archivo_nombre' => $_FILES['archivo']['name'] ?? null,
+ 'archivo_error' => $_FILES['archivo']['error'] ?? null,
+ 'conexion_db' => $conn !== false,
+ 'directorio_temp_existe' => is_dir($temp_dir),
+ 'directorio_temp_escribible' => is_writable($temp_dir)
+ ],
+ 'errores_potenciales' => []
+ ];
+
+ // Detectar problemas
+ if (!isset($_SESSION['usuario_id'])) {
+ $respuesta['errores_potenciales'][] = "No hay usuario_id en sesión";
+ }
+
+ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ $respuesta['errores_potenciales'][] = "Método no es POST";
+ }
+
+ if (!isset($_FILES['archivo'])) {
+ $respuesta['errores_potenciales'][] = "No se recibió archivo";
+ } elseif ($_FILES['archivo']['error'] !== UPLOAD_ERR_OK) {
+ $respuesta['errores_potenciales'][] = "Error en upload: " . $_FILES['archivo']['error'];
+ }
+
+ if (!$conn) {
+ $respuesta['errores_potenciales'][] = "Error de conexión a base de datos";
+ }
+
+ if (!is_dir($temp_dir)) {
+ $respuesta['errores_potenciales'][] = "Directorio temporal no existe";
+ } elseif (!is_writable($temp_dir)) {
+ $respuesta['errores_potenciales'][] = "Directorio temporal no tiene permisos de escritura";
+ }
+
+ // Si no hay errores potenciales, intentar procesar
+ if (empty($respuesta['errores_potenciales']) && isset($_FILES['archivo'])) {
+ logDebug("Intentando procesar archivo...");
+
+ // Mover archivo temporal
+ $archivo_temporal = $temp_dir . 'test_' . time() . '_' . $_FILES['archivo']['name'];
+ if (move_uploaded_file($_FILES['archivo']['tmp_name'], $archivo_temporal)) {
+ $respuesta['archivo_procesado'] = true;
+ $respuesta['archivo_temporal'] = $archivo_temporal;
+
+ // Leer primeras líneas
+ $contenido = file_get_contents($archivo_temporal);
+ if ($contenido !== false) {
+ $lineas = explode("\n", array_slice(explode("\n", $contenido), 0, 5));
+ $respuesta['primeras_lineas'] = $lineas;
+ $respuesta['total_lineas'] = count(explode("\n", $contenido));
+ }
+
+ // Limpiar archivo
+ unlink($archivo_temporal);
+ } else {
+ $respuesta['errores_potenciales'][] = "No se pudo mover archivo temporal";
+ }
+ }
+
+ logDebug("Respuesta: " . json_encode($respuesta));
+ echo json_encode($respuesta, JSON_PRETTY_PRINT);
+
+} catch (Exception $e) {
+ logDebug("EXCEPCIÓN: " . $e->getMessage());
+ logDebug("Stack trace: " . $e->getTraceAsString());
+
+ http_response_code(500);
+ echo json_encode([
+ 'success' => false,
+ 'error' => $e->getMessage(),
+ 'trace' => $e->getTraceAsString()
+ ], JSON_PRETTY_PRINT);
+}
+?>
\ No newline at end of file
diff --git a/public/importar_funcional.php b/public/importar_funcional.php
new file mode 100644
index 0000000..40c9e84
--- /dev/null
+++ b/public/importar_funcional.php
@@ -0,0 +1,89 @@
+ $total_archivos * 2,
+ 'facturas_procesadas' => $total_archivos * 3,
+ 'partidas_procesadas' => $total_archivos * 5,
+ 'duplicados' => 0,
+ 'errores' => 0,
+ 'total_lineas' => $total_archivos * 100
+ ];
+
+ $respuesta = [
+ 'success' => true,
+ 'message' => 'Archivos procesados correctamente (MODO SIMULACIÓN)',
+ 'estadisticas' => $estadisticas,
+ 'archivos_procesados' => $total_archivos,
+ 'archivos_con_errores' => [],
+ 'debug_info' => [
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'total_archivos_recibidos' => $total_archivos,
+ 'validar_duplicados' => $validar_duplicados
+ ]
+ ];
+
+ error_log("Enviando respuesta exitosa: " . json_encode($respuesta));
+ echo json_encode($respuesta);
+
+} catch (Exception $e) {
+ error_log("ERROR: " . $e->getMessage());
+
+ $respuesta_error = [
+ 'success' => false,
+ 'message' => $e->getMessage(),
+ 'debug_info' => [
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'error_file' => $e->getFile(),
+ 'error_line' => $e->getLine()
+ ]
+ ];
+
+ http_response_code(500);
+ echo json_encode($respuesta_error);
+}
+?>
\ No newline at end of file
diff --git a/public/importar_pedimentos.php b/public/importar_pedimentos.php
new file mode 100644
index 0000000..dfe5b95
--- /dev/null
+++ b/public/importar_pedimentos.php
@@ -0,0 +1,739 @@
+ false, 'message' => 'Usuario no autenticado']);
+ exit;
+}
+
+// Verificar que sea una petición POST
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode(['success' => false, 'message' => 'Método no permitido']);
+ exit;
+}
+
+// Verificar que se haya subido un archivo (individual o múltiple)
+if (!isset($_FILES['archivo']) && !isset($_FILES['archivos'])) {
+ error_log("ERROR: No se encontraron archivos. FILES: " . print_r($_FILES, true));
+ http_response_code(400);
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'No se ha recibido ningún archivo válido',
+ 'debug' => $_FILES
+ ]);
+ exit;
+}
+
+class ImportadorPedimentos {
+ private $conn;
+ private $estadisticas = [
+ 'total_lineas' => 0,
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'errores' => 0,
+ 'duplicados' => 0
+ ];
+
+ private $errores_detalle = [];
+ private $pedimentos_creados = [];
+
+ public function __construct($connection) {
+ $this->conn = $connection;
+ }
+
+ public function procesarArchivo($archivo_path, $validar_duplicados = true) {
+ // Reiniciar estadísticas y acumuladores por archivo para evitar sobreconteo entre múltiples archivos
+ $this->estadisticas = [
+ 'total_lineas' => 0,
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'errores' => 0,
+ 'duplicados' => 0
+ ];
+ $this->errores_detalle = [];
+ $this->pedimentos_creados = [];
+
+ $inicio_tiempo = time();
+ $nombre_archivo = basename($archivo_path);
+
+ try {
+ $contenido = file_get_contents($archivo_path);
+ if ($contenido === false) {
+ throw new Exception("No se pudo leer el archivo");
+ }
+
+ // Convertir encoding si es necesario (muchos archivos julianos usan Latin1)
+ if (!mb_check_encoding($contenido, 'UTF-8')) {
+ $contenido = mb_convert_encoding($contenido, 'UTF-8', 'ISO-8859-1');
+ }
+
+ $lineas = explode("\n", $contenido);
+ $this->estadisticas['total_lineas'] = count($lineas);
+
+ $pedimento_actual = null;
+ $facturas_pedimento = [];
+ $partidas_pedimento = [];
+
+ foreach ($lineas as $numero_linea => $linea) {
+ $linea = trim($linea);
+ if (empty($linea)) continue;
+
+ try {
+ $codigo = substr($linea, 0, 3);
+
+ switch ($codigo) {
+ case '500':
+ // Línea de header - ignorar por ahora
+ break;
+
+ case '501':
+ // Si hay un pedimento anterior, procesarlo
+ if ($pedimento_actual) {
+ $this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
+ $facturas_pedimento = [];
+ $partidas_pedimento = [];
+ }
+ $pedimento_actual = $this->parsearLinea501Real($linea);
+ break;
+
+ case '505':
+ if ($pedimento_actual) {
+ try {
+ $factura = $this->parsearLinea505Real($linea);
+ $facturas_pedimento[] = $factura;
+ error_log("Factura 505 procesada exitosamente: " . $factura['numero_factura']);
+ } catch (Exception $e) {
+ error_log("ERROR procesando línea 505: " . $e->getMessage());
+ error_log("Línea problemática: " . $linea);
+ $this->estadisticas['errores']++;
+ // Continuar con la siguiente línea
+ }
+ }
+ break;
+
+ case '551':
+ if ($pedimento_actual) {
+ try {
+ $partida = $this->parsearLinea551Real($linea);
+ $partidas_pedimento[] = $partida;
+ error_log("Partida 551 procesada exitosamente: secuencia " . $partida['secuencia']);
+ } catch (Exception $e) {
+ error_log("ERROR procesando línea 551: " . $e->getMessage());
+ error_log("Línea problemática: " . $linea);
+ $this->estadisticas['errores']++;
+ // Continuar con la siguiente línea en lugar de fallar completamente
+ }
+ }
+ break;
+
+ case '506':
+ case '509':
+ case '510':
+ case '511':
+ case '553':
+ case '554':
+ case '556':
+ case '557':
+ case '558':
+ case '800':
+ case '801':
+ // Otros códigos del formato real - ignorar por ahora
+ break;
+ }
+ } catch (Exception $e) {
+ $this->errores_detalle[] = "Línea " . ($numero_linea + 1) . ": " . $e->getMessage();
+ $this->estadisticas['errores']++;
+ }
+ }
+
+ // Procesar el último pedimento
+ if ($pedimento_actual) {
+ $this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
+ }
+
+ // Registrar log de importación
+ $tiempo_procesamiento = time() - $inicio_tiempo;
+ $this->registrarLog($nombre_archivo, $tiempo_procesamiento,
+ count($this->errores_detalle) > 0 ? 'con_errores' : 'exitoso');
+
+ return [
+ 'success' => true,
+ 'estadisticas' => $this->estadisticas,
+ 'errores' => $this->errores_detalle,
+ 'pedimentos_creados' => $this->pedimentos_creados
+ ];
+
+ } catch (Exception $e) {
+ // Registrar log de error
+ $tiempo_procesamiento = time() - $inicio_tiempo;
+ $this->registrarLog($nombre_archivo, $tiempo_procesamiento, 'fallido', $e->getMessage());
+
+ return [
+ 'success' => false,
+ 'message' => $e->getMessage()
+ ];
+ }
+ }
+
+ private function registrarLog($archivo_nombre, $tiempo_procesamiento, $estado, $error_mensaje = null) {
+ try {
+ $sql = "INSERT INTO importacion_logs (
+ usuario_id, archivo_nombre, total_lineas, pedimentos_procesados,
+ facturas_procesadas, partidas_procesadas, errores, duplicados,
+ tiempo_procesamiento, estado, detalles_errores
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $detalles_errores = null;
+ if (!empty($this->errores_detalle)) {
+ $detalles_errores = implode("\n", $this->errores_detalle);
+ } else if ($error_mensaje) {
+ $detalles_errores = $error_mensaje;
+ }
+
+ $params = [
+ isset($_SESSION['usuario_id']) ? $_SESSION['usuario_id'] : null,
+ $archivo_nombre,
+ $this->estadisticas['total_lineas'],
+ $this->estadisticas['pedimentos_procesados'],
+ $this->estadisticas['facturas_procesadas'],
+ $this->estadisticas['partidas_procesadas'],
+ $this->estadisticas['errores'],
+ $this->estadisticas['duplicados'],
+ $tiempo_procesamiento,
+ $estado,
+ $detalles_errores
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt) {
+ sqlsrv_free_stmt($stmt);
+ }
+ } catch (Exception $e) {
+ // No hacer nada si falla el log, no queremos interrumpir el proceso principal
+ }
+ }
+
+ private function parsearLinea501($linea) {
+ // Formato: 501|numero_pedimento|patente|aduana|anio|clave_documento|rfc_importador|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 7) {
+ throw new Exception("Formato inválido en línea 501");
+ }
+
+ return [
+ 'numero_pedimento' => trim($campos[1]),
+ 'patente' => trim($campos[2]),
+ 'aduana' => trim($campos[3]),
+ 'anio' => trim($campos[4]),
+ 'clave_documento' => trim($campos[5]),
+ 'rfc_importador' => trim($campos[6]),
+ 'fecha_creacion' => date('Y-m-d H:i:s'),
+ 'usuario_id' => $_SESSION['usuario_id']
+ ];
+ }
+
+ private function parsearLinea501Real($linea) {
+ // Formato real: 501|patente|numero_pedimento|aduana|tipo|clave_documento|aduana2||rfc_importador|nombre_importador|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 10) {
+ throw new Exception("Formato inválido en línea 501 real - campos insuficientes: " . count($campos));
+ }
+
+ error_log("Parseando 501 real: " . $linea);
+ error_log("Campos: " . print_r(array_slice($campos, 0, 10), true));
+
+ return [
+ 'numero_pedimento' => trim($campos[2]), // Campo 2: numero de pedimento
+ 'patente' => trim($campos[1]), // Campo 1: patente
+ 'aduana' => trim($campos[3]), // Campo 3: aduana
+ 'anio' => date('Y'), // Usar año actual
+ 'clave_documento' => trim($campos[5]), // Campo 5: clave documento
+ 'rfc_importador' => trim($campos[8]), // Campo 8: RFC importador
+ 'fecha_creacion' => date('Y-m-d H:i:s'),
+ 'usuario_id' => $_SESSION['usuario_id']
+ ];
+ }
+
+ private function parsearLinea505($linea) {
+ // Formato: 505|numero_factura|fecha_factura|valor_dolares|valor_factura|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 5) {
+ throw new Exception("Formato inválido en línea 505");
+ }
+
+ return [
+ 'numero_factura' => trim($campos[1]),
+ 'fecha_factura' => $this->convertirFecha(trim($campos[2])),
+ 'valor_dolares' => floatval(trim($campos[3])),
+ 'valor_factura' => floatval(trim($campos[4]))
+ ];
+ }
+
+ private function parsearLinea505Real($linea) {
+ // Formato oficial 505: 505|numero_pedimento|fecha_cfdi|numero_cfdi_cove|termino_facturacion|moneda|valor_dolares|valor_total|pais|entidad_federativa|rfc_proveedor|nombre_proveedor|calle|num_int|num_ext|cp|municipio|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 12) {
+ throw new Exception("Formato inválido en línea 505 - campos insuficientes: " . count($campos) . " (mínimo: 12)");
+ }
+
+ error_log("DEBUG 505 - Total campos: " . count($campos));
+ error_log("DEBUG 505 - Primeros 12 campos: " . implode(' | ', array_slice($campos, 0, 12)));
+
+ // Extraer datos según documentación oficial SAT
+ $numero_pedimento = trim($campos[1]); // Campo 1: Número de Pedimento
+ $fecha_cfdi = trim($campos[2]); // Campo 2: Fecha de CFDI
+ $numero_cfdi_cove = trim($campos[3]); // Campo 3: Número de CFDI (COVE) - 40 caracteres max
+ $termino_facturacion = trim($campos[4]); // Campo 4: Término de Facturación - 3 caracteres
+ $moneda = trim($campos[5]); // Campo 5: Moneda - 3 caracteres
+ $valor_dolares = floatval(trim($campos[6])); // Campo 6: Valor Total en Dólares USD
+ $valor_total = floatval(trim($campos[7])); // Campo 7: Valor Total en moneda del CFDI
+ $pais = trim($campos[8]); // Campo 8: País del CFDI - 3 caracteres
+ $entidad_federativa = trim($campos[9]); // Campo 9: Entidad Federativa - 3 caracteres
+ $rfc_proveedor = trim($campos[10]); // Campo 10: RFC Proveedor - 30 caracteres max
+ $nombre_proveedor = trim($campos[11]); // Campo 11: Nombre Proveedor - 120 caracteres max
+
+ error_log("DEBUG 505 - Datos oficiales extraídos:");
+ error_log(" - Número CFDI/COVE: '$numero_cfdi_cove'");
+ error_log(" - Fecha CFDI: '$fecha_cfdi'");
+ error_log(" - Término facturación: '$termino_facturacion'");
+ error_log(" - Moneda: '$moneda'");
+ error_log(" - Valor USD: $valor_dolares");
+ error_log(" - Valor total: $valor_total");
+ error_log(" - RFC Proveedor: '$rfc_proveedor'");
+ error_log(" - Nombre Proveedor: '$nombre_proveedor'");
+
+ return [
+ 'numero_factura' => $numero_cfdi_cove, // Campo 3: Número de CFDI/COVE
+ 'fecha_factura' => $this->convertirFechaReal($fecha_cfdi), // Campo 2: Fecha CFDI
+ 'valor_dolares' => $valor_dolares, // Campo 6: Valor en USD
+ 'valor_factura' => $valor_total, // Campo 7: Valor total en moneda CFDI
+ 'cove' => $numero_cfdi_cove, // Campo 3: COVE (mismo que número factura)
+ 'moneda' => $moneda, // Campo 5: Moneda
+ 'proveedor' => $nombre_proveedor // Campo 11: Nombre del proveedor
+ ];
+ }
+
+ private function parsearLinea551($linea) {
+ // Formato: 551|secuencia|fraccion_arancelaria|descripcion|cantidad|unidad|valor_unitario|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 7) {
+ throw new Exception("Formato inválido en línea 551");
+ }
+
+ return [
+ 'secuencia' => intval(trim($campos[1])),
+ 'fraccion_arancelaria' => trim($campos[2]),
+ 'descripcion' => trim($campos[3]),
+ 'cantidad' => floatval(trim($campos[4])),
+ 'unidad' => trim($campos[5]),
+ 'valor_unitario' => floatval(trim($campos[6]))
+ ];
+ }
+
+ private function parsearLinea551Real($linea) {
+ // Formato oficial 551: 551|numero_pedimento|fraccion_arancelaria|numero_partida|subdivision|descripcion|precio_unitario|valor_aduana|valor_comercial|valor_dolares|cantidad_umc|unidad_comercial|...
+ $campos = explode('|', $linea);
+
+ if (count($campos) < 12) {
+ throw new Exception("Formato inválido en línea 551 - campos insuficientes: " . count($campos) . " (mínimo: 12)");
+ }
+
+ error_log("DEBUG 551 - Total campos: " . count($campos));
+ error_log("DEBUG 551 - Primeros 12 campos: " . implode(' | ', array_slice($campos, 0, 12)));
+
+ // Extraer datos según documentación oficial
+ $numero_pedimento = isset($campos[1]) ? trim($campos[1]) : '';
+ $fraccion_arancelaria = isset($campos[2]) ? trim($campos[2]) : '';
+ $numero_partida = isset($campos[3]) ? intval(trim($campos[3])) : 0;
+ $subdivision = isset($campos[4]) ? trim($campos[4]) : '';
+ $descripcion = isset($campos[5]) ? trim($campos[5]) : '';
+ $precio_unitario = isset($campos[6]) ? floatval(trim($campos[6])) : 0;
+ $valor_aduana = isset($campos[7]) ? floatval(trim($campos[7])) : 0;
+ $valor_comercial = isset($campos[8]) ? floatval(trim($campos[8])) : 0;
+ $valor_dolares = isset($campos[9]) ? floatval(trim($campos[9])) : 0;
+ $cantidad_umc = isset($campos[10]) ? floatval(trim($campos[10])) : 0;
+ $unidad_comercial = isset($campos[11]) ? trim($campos[11]) : '';
+
+ // Aplicar valores por defecto según documentación oficial
+ if (empty($fraccion_arancelaria)) {
+ error_log("WARNING 551: Fracción arancelaria vacía, usando valor por defecto");
+ $fraccion_arancelaria = 'PENDIENTE';
+ }
+
+ if ($numero_partida <= 0) {
+ error_log("WARNING 551: Número de partida inválido, generando secuencial");
+ static $contador_partida = 1;
+ $numero_partida = $contador_partida++;
+ }
+
+ if (empty($descripcion)) {
+ error_log("WARNING 551: Descripción vacía, usando valor por defecto");
+ $descripcion = 'DESCRIPCIÓN PENDIENTE';
+ }
+
+ if ($cantidad_umc <= 0) {
+ error_log("WARNING 551: Cantidad UMC inválida ($cantidad_umc), usando 1.0000");
+ $cantidad_umc = 1.0000;
+ }
+
+ if (empty($unidad_comercial)) {
+ error_log("WARNING 551: Unidad comercial vacía, usando 'PZ'");
+ $unidad_comercial = 'PZ'; // Pieza como unidad por defecto
+ }
+
+ // Calcular precio unitario si no existe pero hay valores
+ if ($precio_unitario == 0) {
+ if ($valor_dolares > 0 && $cantidad_umc > 0) {
+ $precio_unitario = $valor_dolares / $cantidad_umc;
+ error_log("DEBUG 551: Precio unitario calculado: $precio_unitario");
+ } elseif ($valor_comercial > 0 && $cantidad_umc > 0) {
+ $precio_unitario = $valor_comercial / $cantidad_umc;
+ error_log("DEBUG 551: Precio unitario calculado desde valor comercial: $precio_unitario");
+ }
+ }
+
+ error_log("DEBUG 551 - Datos procesados:");
+ error_log(" - Partida: $numero_partida");
+ error_log(" - Fracción: '$fraccion_arancelaria'");
+ error_log(" - Descripción: '" . substr($descripcion, 0, 50) . "...'");
+ error_log(" - Cantidad: $cantidad_umc");
+ error_log(" - Unidad: '$unidad_comercial'");
+ error_log(" - Precio unitario: $precio_unitario");
+ error_log(" - Valor dólares: $valor_dolares");
+
+ return [
+ 'secuencia' => $numero_partida,
+ 'fraccion_arancelaria' => $fraccion_arancelaria,
+ 'descripcion' => $descripcion,
+ 'cantidad' => $cantidad_umc,
+ 'unidad' => $unidad_comercial,
+ 'valor_unitario' => $precio_unitario,
+ 'peso_neto' => null,
+ 'peso_bruto' => null
+ ];
+ }
+
+ private function procesarPedimento($pedimento, $facturas, $partidas, $validar_duplicados) {
+ try {
+ error_log("Procesando pedimento: " . $pedimento['numero_pedimento']);
+ error_log("Validar duplicados: " . ($validar_duplicados ? 'SÍ' : 'NO'));
+
+ // Validar duplicados si está habilitado
+ if ($validar_duplicados && $this->existePedimento($pedimento['numero_pedimento'])) {
+ error_log("Pedimento {$pedimento['numero_pedimento']} marcado como duplicado, omitiendo...");
+ $this->estadisticas['duplicados']++;
+ return;
+ }
+
+ error_log("Insertando pedimento nuevo: " . $pedimento['numero_pedimento']);
+
+ // Iniciar transacción
+ sqlsrv_begin_transaction($this->conn);
+
+ // Insertar pedimento
+ $sql = "INSERT INTO pedimentos (numero_pedimento, patente, aduana, anio, clave_documento,
+ rfc_importador, fecha_creacion, usuario_id, estado)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'activo'); SELECT SCOPE_IDENTITY() AS id;";
+
+ $params = [
+ $pedimento['numero_pedimento'],
+ $pedimento['patente'],
+ $pedimento['aduana'],
+ $pedimento['anio'],
+ $pedimento['clave_documento'],
+ $pedimento['rfc_importador'],
+ $pedimento['fecha_creacion'],
+ $pedimento['usuario_id']
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar pedimento: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Obtener el ID del pedimento insertado
+ sqlsrv_next_result($stmt);
+ sqlsrv_fetch($stmt);
+ $pedimento_id = sqlsrv_get_field($stmt, 0);
+ sqlsrv_free_stmt($stmt);
+
+ // Insertar facturas
+ foreach ($facturas as $factura) {
+ $sql = "INSERT INTO pedimento_facturas (pedimento_id, numero_factura, fecha_factura,
+ valor_dolares, valor_factura, cove, moneda, proveedor)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $params = [
+ $pedimento_id,
+ $factura['numero_factura'],
+ $factura['fecha_factura'],
+ $factura['valor_dolares'],
+ $factura['valor_factura'],
+ isset($factura['cove']) ? $factura['cove'] : null,
+ isset($factura['moneda']) ? $factura['moneda'] : 'USD',
+ isset($factura['proveedor']) ? $factura['proveedor'] : null
+ ];
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ throw new Exception("Error al insertar factura: " . print_r(sqlsrv_errors(), true));
+ }
+ sqlsrv_free_stmt($stmt);
+
+ $this->estadisticas['facturas_procesadas']++;
+ }
+
+ // Insertar partidas
+ foreach ($partidas as $partida) {
+ error_log("INSERTANDO PARTIDA: " . print_r($partida, true));
+
+ $sql = "INSERT INTO pedimento_partidas (pedimento_id, secuencia, fraccion_arancelaria,
+ descripcion, cantidad, unidad, valor_unitario,
+ peso_neto, peso_bruto)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+ $params = [
+ $pedimento_id,
+ $partida['secuencia'],
+ $partida['fraccion_arancelaria'],
+ $partida['descripcion'],
+ $partida['cantidad'],
+ $partida['unidad'],
+ $partida['valor_unitario'],
+ isset($partida['peso_neto']) ? $partida['peso_neto'] : null,
+ isset($partida['peso_bruto']) ? $partida['peso_bruto'] : null
+ ];
+
+ error_log("PARÁMETROS SQL: " . print_r($params, true));
+
+ $stmt = sqlsrv_query($this->conn, $sql, $params);
+ if ($stmt === false) {
+ $error = print_r(sqlsrv_errors(), true);
+ error_log("ERROR AL INSERTAR PARTIDA: " . $error);
+ throw new Exception("Error al insertar partida: " . $error);
+ }
+ sqlsrv_free_stmt($stmt);
+
+ $this->estadisticas['partidas_procesadas']++;
+ error_log("Partida insertada exitosamente - Total procesadas: " . $this->estadisticas['partidas_procesadas']);
+ }
+
+ // Confirmar transacción
+ sqlsrv_commit($this->conn);
+
+ $this->estadisticas['pedimentos_procesados']++;
+ $this->pedimentos_creados[] = $pedimento['numero_pedimento'];
+
+ } catch (Exception $e) {
+ sqlsrv_rollback($this->conn);
+ $this->errores_detalle[] = "Error procesando pedimento {$pedimento['numero_pedimento']}: " . $e->getMessage();
+ $this->estadisticas['errores']++;
+ }
+ }
+
+ private function existePedimento($numero_pedimento) {
+ $sql = "SELECT id, fecha_creacion FROM pedimentos WHERE numero_pedimento = ?";
+ $stmt = sqlsrv_query($this->conn, $sql, [$numero_pedimento]);
+ if ($stmt === false) {
+ error_log("Error al verificar duplicado: " . print_r(sqlsrv_errors(), true));
+ return false;
+ }
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ sqlsrv_free_stmt($stmt);
+
+ if ($row) {
+ error_log("Pedimento duplicado encontrado: {$numero_pedimento} (ID: {$row['id']})");
+ return true;
+ }
+
+ return false;
+ }
+
+ private function convertirFecha($fecha_str) {
+ // Convertir formato DDMMYYYY a YYYY-MM-DD
+ if (strlen($fecha_str) === 8) {
+ $dia = substr($fecha_str, 0, 2);
+ $mes = substr($fecha_str, 2, 2);
+ $anio = substr($fecha_str, 4, 4);
+ return "$anio-$mes-$dia";
+ }
+ return date('Y-m-d'); // Fecha por defecto
+ }
+
+ private function convertirFechaReal($fecha_str) {
+ // Convertir fecha del archivo real - puede venir en formato YYYYMMDD o DDMMYYYY
+ if (empty($fecha_str) || strlen($fecha_str) !== 8) {
+ return date('Y-m-d'); // Fecha por defecto
+ }
+
+ // Intentar formato YYYYMMDD primero
+ if (substr($fecha_str, 0, 2) === '20') {
+ $anio = substr($fecha_str, 0, 4);
+ $mes = substr($fecha_str, 4, 2);
+ $dia = substr($fecha_str, 6, 2);
+ } else {
+ // Formato DDMMYYYY
+ $dia = substr($fecha_str, 0, 2);
+ $mes = substr($fecha_str, 2, 2);
+ $anio = substr($fecha_str, 4, 4);
+ }
+
+ // Validar fecha
+ if (checkdate($mes, $dia, $anio)) {
+ return "$anio-$mes-$dia";
+ }
+
+ return date('Y-m-d'); // Fecha por defecto si no es válida
+ }
+}
+
+// Procesamiento de archivos (individual o múltiple)
+try {
+ error_log("=== PROCESAMIENTO DE ARCHIVOS ===");
+ error_log("POST: " . print_r($_POST, true));
+ error_log("FILES: " . print_r($_FILES, true));
+
+ $validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
+ error_log("Validar duplicados: " . ($validar_duplicados ? 'SÍ' : 'NO'));
+
+ // Validar variables de entorno requeridas ANTES de intentar conectar (evita die() dentro de getConnection)
+ $requiredEnv = ['DB_HOST','DB_DATABASE','DB_USERNAME','DB_PASSWORD'];
+ foreach ($requiredEnv as $envKey) {
+ if (!isset($_ENV[$envKey]) || $_ENV[$envKey] === '') {
+ throw new Exception("Falta configurar la variable de entorno $envKey en el archivo .env");
+ }
+ }
+
+ // Obtener conexión a SQL Server
+ $conn = getConnection();
+ $importador = new ImportadorPedimentos($conn);
+
+ $resultado_final = null;
+
+ // Verificar si es archivo individual
+ if (isset($_FILES['archivo'])) {
+ error_log("=== PROCESAMIENTO INDIVIDUAL ===");
+ $archivo_temporal = $_FILES['archivo']['tmp_name'];
+ $nombre_archivo = $_FILES['archivo']['name'];
+
+ $resultado_final = $importador->procesarArchivo($archivo_temporal, $validar_duplicados);
+
+ } else if (isset($_FILES['archivos']) && is_array($_FILES['archivos']['name'])) {
+ error_log("=== PROCESAMIENTO MÚLTIPLE FORMATO NORMAL ===");
+
+ $archivos = $_FILES['archivos'];
+ $estadisticas_globales = [
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'duplicados' => 0,
+ 'errores' => 0,
+ 'total_lineas' => 0
+ ];
+
+ $archivos_procesados = 0;
+ $archivos_con_errores = [];
+
+ // Procesar cada archivo individualmente
+ for ($i = 0; $i < count($archivos['name']); $i++) {
+ if ($archivos['error'][$i] !== UPLOAD_ERR_OK) {
+ $archivos_con_errores[] = [
+ 'archivo' => $archivos['name'][$i],
+ 'error' => 'Error en la subida del archivo (código: ' . $archivos['error'][$i] . ')'
+ ];
+ continue;
+ }
+
+ $nombre_archivo = $archivos['name'][$i];
+ $archivo_temporal = $archivos['tmp_name'][$i];
+
+ error_log("Procesando archivo: $nombre_archivo");
+
+ try {
+ $resultado = $importador->procesarArchivo($archivo_temporal, $validar_duplicados);
+
+ if ($resultado['success']) {
+ $estadisticas_globales['pedimentos_procesados'] += $resultado['estadisticas']['pedimentos_procesados'];
+ $estadisticas_globales['facturas_procesadas'] += $resultado['estadisticas']['facturas_procesadas'];
+ $estadisticas_globales['partidas_procesadas'] += $resultado['estadisticas']['partidas_procesadas'];
+ $estadisticas_globales['duplicados'] += $resultado['estadisticas']['duplicados'];
+ $estadisticas_globales['errores'] += $resultado['estadisticas']['errores'];
+ $estadisticas_globales['total_lineas'] += $resultado['estadisticas']['total_lineas'];
+
+ $archivos_procesados++;
+ error_log("Archivo procesado exitosamente: $nombre_archivo");
+ } else {
+ $archivos_con_errores[] = [
+ 'archivo' => $nombre_archivo,
+ 'error' => $resultado['message'] ?? 'Error desconocido'
+ ];
+ }
+
+ } catch (Exception $e) {
+ $archivos_con_errores[] = [
+ 'archivo' => $nombre_archivo,
+ 'error' => $e->getMessage()
+ ];
+ error_log("Excepción procesando archivo: $nombre_archivo - " . $e->getMessage());
+ }
+ }
+
+ $resultado_final = [
+ 'success' => $archivos_procesados > 0,
+ 'estadisticas' => $estadisticas_globales,
+ 'archivos_procesados' => $archivos_procesados,
+ 'total_archivos' => count($archivos['name']),
+ 'archivos_con_errores' => $archivos_con_errores
+ ];
+
+ if ($archivos_procesados === 0) {
+ $resultado_final['message'] = 'No se pudo procesar ningún archivo correctamente';
+ }
+
+ } else {
+ throw new Exception("No se recibieron archivos para procesar");
+ }
+
+ // Cerrar conexión
+ sqlsrv_close($conn);
+
+ // Enviar respuesta
+ echo json_encode($resultado_final);
+
+} catch (Exception $e) {
+ error_log("ERROR GENERAL: " . $e->getMessage());
+ http_response_code(500);
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Error del servidor: ' . $e->getMessage()
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/public/importar_pedimentos_simple.php b/public/importar_pedimentos_simple.php
new file mode 100644
index 0000000..3c40eb5
--- /dev/null
+++ b/public/importar_pedimentos_simple.php
@@ -0,0 +1,255 @@
+ false, 'message' => 'Usuario no autenticado']);
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ echo json_encode(['success' => false, 'message' => 'Método no permitido']);
+ exit;
+}
+
+// Incluir la clase ImportadorPedimentos
+include_once __DIR__ . '/../app/controllers/ImportadorPedimentos.php';
+
+// Función segura para obtener conexión
+function getSafeConnection() {
+ require_once __DIR__ . '/../app/helpers/env.php';
+ loadEnv();
+
+ $serverName = $_ENV['DB_HOST'];
+ $connectionOptions = [
+ "Database" => $_ENV['DB_DATABASE'],
+ "Uid" => $_ENV['DB_USERNAME'],
+ "PWD" => $_ENV['DB_PASSWORD'],
+ "CharacterSet" => "UTF-8"
+ ];
+
+ $conn = sqlsrv_connect($serverName, $connectionOptions);
+
+ if (!$conn) {
+ $errors = sqlsrv_errors();
+ $errorMsg = "Error de conexión SQL Server";
+ if ($errors) {
+ $errorMsg .= ": " . $errors[0]['message'];
+ }
+ throw new Exception($errorMsg);
+ }
+
+ return $conn;
+}
+
+try {
+ $validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
+
+ // Crear timestamp único para esta importación
+ $timestamp_importacion = date('Y-m-d H:i:s');
+
+ // Verificar conexión a la base de datos
+ $conn = null;
+ try {
+ $conn = getSafeConnection();
+ if (!$conn) {
+ throw new Exception("No se pudo establecer conexión con la base de datos");
+ }
+ } catch (Exception $e) {
+ error_log("Error de conexión a BD: " . $e->getMessage());
+ throw new Exception("Error de conexión a la base de datos: " . $e->getMessage());
+ }
+
+ $importador = new ImportadorPedimentos($conn);
+
+ $estadisticas_globales = [
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'duplicados' => 0,
+ 'errores' => 0,
+ 'total_lineas' => 0
+ ];
+
+ $archivos_procesados = 0;
+ $archivos_con_errores = [];
+
+ // Manejar archivos múltiples enviados como archivos[]
+ if (isset($_FILES)) {
+ error_log("INICIANDO BUCLE DE ARCHIVOS...");
+ foreach ($_FILES as $key => $archivo_info) {
+ error_log("Procesando key: $key");
+ error_log("Archivo info: " . print_r($archivo_info, true));
+
+ if (is_array($archivo_info['name'])) {
+ // Múltiples archivos
+ for ($i = 0; $i < count($archivo_info['name']); $i++) {
+ if ($archivo_info['error'][$i] !== UPLOAD_ERR_OK) {
+ continue;
+ }
+
+ $nombre = $archivo_info['name'][$i];
+ $tmp_name = $archivo_info['tmp_name'][$i];
+
+ error_log("Procesando archivo múltiple: $nombre");
+
+ try {
+ $resultado = $importador->procesarArchivo($tmp_name, $validar_duplicados, $timestamp_importacion);
+
+ if ($resultado['success']) {
+ $estadisticas_globales['pedimentos_procesados'] += $resultado['estadisticas']['pedimentos_procesados'];
+ $estadisticas_globales['facturas_procesadas'] += $resultado['estadisticas']['facturas_procesadas'];
+ $estadisticas_globales['partidas_procesadas'] += $resultado['estadisticas']['partidas_procesadas'];
+ $estadisticas_globales['duplicados'] += $resultado['estadisticas']['duplicados'];
+ $estadisticas_globales['errores'] += $resultado['estadisticas']['errores'];
+ $estadisticas_globales['total_lineas'] += $resultado['estadisticas']['total_lineas'];
+ $archivos_procesados++;
+ } else {
+ $archivos_con_errores[] = [
+ 'archivo' => $nombre,
+ 'error' => $resultado['message'] ?? 'Error desconocido'
+ ];
+ }
+ } catch (Exception $e) {
+ $archivos_con_errores[] = [
+ 'archivo' => $nombre,
+ 'error' => $e->getMessage()
+ ];
+ }
+ }
+ } else {
+ // Archivo individual
+ if ($archivo_info['error'] === UPLOAD_ERR_OK) {
+ $nombre = $archivo_info['name'];
+ $tmp_name = $archivo_info['tmp_name'];
+
+ error_log("Procesando archivo individual: $nombre");
+
+ try {
+ $resultado = $importador->procesarArchivo($tmp_name, $validar_duplicados, $timestamp_importacion);
+
+ if ($resultado['success']) {
+ $estadisticas_globales = $resultado['estadisticas'];
+ $archivos_procesados = 1;
+ } else {
+ $archivos_con_errores[] = [
+ 'archivo' => $nombre,
+ 'error' => $resultado['message'] ?? 'Error desconocido'
+ ];
+ }
+ } catch (Exception $e) {
+ $archivos_con_errores[] = [
+ 'archivo' => $nombre,
+ 'error' => $e->getMessage()
+ ];
+ }
+ }
+ }
+ }
+ }
+
+ sqlsrv_close($conn);
+
+ // Verificar los datos realmente insertados en la base de datos
+ $estadisticas_reales = verificarEstadisticasReales($estadisticas_globales, $timestamp_importacion);
+
+ echo json_encode([
+ 'success' => $archivos_procesados > 0,
+ 'estadisticas' => $estadisticas_reales,
+ 'archivos_procesados' => $archivos_procesados,
+ 'archivos_con_errores' => $archivos_con_errores,
+ 'message' => $archivos_procesados > 0 ? 'Archivos procesados correctamente' : 'No se pudo procesar ningún archivo'
+ ]);
+
+} catch (Exception $e) {
+ error_log("ERROR GENERAL: " . $e->getMessage());
+ error_log("STACK TRACE: " . $e->getTraceAsString());
+
+ // Asegurar que se devuelve JSON válido
+ http_response_code(500);
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Error del servidor: ' . $e->getMessage(),
+ 'debug' => [
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'timestamp' => date('Y-m-d H:i:s')
+ ]
+ ]);
+}
+
+function verificarEstadisticasReales($estadisticas_reportadas, $timestamp_importacion) {
+ try {
+ $conn = getSafeConnection();
+
+ // Obtener estadísticas reales de la base de datos para esta importación específica
+ $usuario_id = $_SESSION['usuario_id'];
+
+ // Contar pedimentos insertados en esta sesión (últimos 2 minutos)
+ $timestamp_desde = date('Y-m-d H:i:s', strtotime($timestamp_importacion . ' -2 minutes'));
+
+ $sql = "SELECT COUNT(*) as total FROM pedimentos WHERE usuario_id = ? AND fecha_creacion >= ?";
+ $stmt = sqlsrv_query($conn, $sql, [$usuario_id, $timestamp_desde]);
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ $pedimentos_reales = $row ? $row['total'] : 0;
+ sqlsrv_free_stmt($stmt);
+
+ // Contar facturas insertadas en esta sesión
+ $sql = "SELECT COUNT(f.*) as total
+ FROM pedimento_facturas f
+ INNER JOIN pedimentos p ON f.pedimento_id = p.id
+ WHERE p.usuario_id = ? AND p.fecha_creacion >= ?";
+ $stmt = sqlsrv_query($conn, $sql, [$usuario_id, $timestamp_desde]);
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ $facturas_reales = $row ? $row['total'] : 0;
+ sqlsrv_free_stmt($stmt);
+
+ // Contar partidas insertadas en esta sesión
+ $sql = "SELECT COUNT(pa.*) as total
+ FROM pedimento_partidas pa
+ INNER JOIN pedimentos p ON pa.pedimento_id = p.id
+ WHERE p.usuario_id = ? AND p.fecha_creacion >= ?";
+ $stmt = sqlsrv_query($conn, $sql, [$usuario_id, $timestamp_desde]);
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ $partidas_reales = $row ? $row['total'] : 0;
+ sqlsrv_free_stmt($stmt);
+
+ sqlsrv_close($conn);
+
+ error_log("=== VERIFICACIÓN DE ESTADÍSTICAS ===");
+ error_log("Timestamp importación: $timestamp_importacion");
+ error_log("Timestamp desde: $timestamp_desde");
+ error_log("Reportadas - Pedimentos: {$estadisticas_reportadas['pedimentos_procesados']}, Facturas: {$estadisticas_reportadas['facturas_procesadas']}, Partidas: {$estadisticas_reportadas['partidas_procesadas']}");
+ error_log("Reales BD - Pedimentos: $pedimentos_reales, Facturas: $facturas_reales, Partidas: $partidas_reales");
+
+ // Retornar las estadísticas reales de la base de datos
+ return [
+ 'total_lineas' => $estadisticas_reportadas['total_lineas'],
+ 'pedimentos_procesados' => $pedimentos_reales,
+ 'facturas_procesadas' => $facturas_reales,
+ 'partidas_procesadas' => $partidas_reales,
+ 'errores' => $estadisticas_reportadas['errores'],
+ 'duplicados' => $estadisticas_reportadas['duplicados']
+ ];
+
+ } catch (Exception $e) {
+ error_log("Error verificando estadísticas reales: " . $e->getMessage());
+ // En caso de error, retornar las estadísticas originales
+ return $estadisticas_reportadas;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/public/importar_test_simple.php b/public/importar_test_simple.php
new file mode 100644
index 0000000..aff033e
--- /dev/null
+++ b/public/importar_test_simple.php
@@ -0,0 +1,128 @@
+ false, 'message' => 'Usuario no autenticado']);
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ echo json_encode(['success' => false, 'message' => 'Método no permitido']);
+ exit;
+}
+
+// Función de conexión directa
+function getDirectConnection() {
+ // Cargar variables de entorno manualmente
+ $env_file = __DIR__ . '/../.env';
+ if (file_exists($env_file)) {
+ $lines = file($env_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ foreach ($lines as $line) {
+ if (strpos($line, '=') !== false && substr($line, 0, 1) !== '#') {
+ list($key, $value) = explode('=', $line, 2);
+ $_ENV[trim($key)] = trim($value);
+ }
+ }
+ }
+
+ $serverName = $_ENV['DB_HOST'] ?? 'localhost';
+ $connectionOptions = [
+ "Database" => $_ENV['DB_DATABASE'] ?? 'importadores',
+ "Uid" => $_ENV['DB_USERNAME'] ?? 'sa',
+ "PWD" => $_ENV['DB_PASSWORD'] ?? '',
+ "CharacterSet" => "UTF-8"
+ ];
+
+ $conn = sqlsrv_connect($serverName, $connectionOptions);
+
+ if (!$conn) {
+ $errors = sqlsrv_errors();
+ $errorMsg = "Error de conexión SQL Server";
+ if ($errors) {
+ $errorMsg .= ": " . $errors[0]['message'];
+ }
+ throw new Exception($errorMsg);
+ }
+
+ return $conn;
+}
+
+try {
+ $validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
+
+ // Crear timestamp único para esta importación
+ $timestamp_importacion = date('Y-m-d H:i:s');
+
+ $conn = getDirectConnection();
+
+ $estadisticas_globales = [
+ 'pedimentos_procesados' => 0,
+ 'facturas_procesadas' => 0,
+ 'partidas_procesadas' => 0,
+ 'duplicados' => 0,
+ 'errores' => 0,
+ 'total_lineas' => 0
+ ];
+
+ $archivos_procesados = 0;
+ $archivos_con_errores = [];
+
+ // Simulación de procesamiento (por ahora)
+ if (isset($_FILES)) {
+ foreach ($_FILES as $key => $archivo_info) {
+ error_log("Procesando key: $key");
+
+ if (is_array($archivo_info['name'])) {
+ // Múltiples archivos
+ $archivos_procesados = count($archivo_info['name']);
+ $estadisticas_globales['pedimentos_procesados'] = $archivos_procesados * 2; // Simulado
+ $estadisticas_globales['facturas_procesadas'] = $archivos_procesados * 3; // Simulado
+ $estadisticas_globales['partidas_procesadas'] = $archivos_procesados * 5; // Simulado
+ } else {
+ // Archivo individual
+ $archivos_procesados = 1;
+ $estadisticas_globales['pedimentos_procesados'] = 1;
+ $estadisticas_globales['facturas_procesadas'] = 2;
+ $estadisticas_globales['partidas_procesadas'] = 3;
+ }
+ }
+ }
+
+ sqlsrv_close($conn);
+
+ echo json_encode([
+ 'success' => $archivos_procesados > 0,
+ 'estadisticas' => $estadisticas_globales,
+ 'archivos_procesados' => $archivos_procesados,
+ 'archivos_con_errores' => $archivos_con_errores,
+ 'message' => $archivos_procesados > 0 ? 'Archivos procesados correctamente (MODO TEST)' : 'No se pudo procesar ningún archivo'
+ ]);
+
+} catch (Exception $e) {
+ error_log("ERROR GENERAL: " . $e->getMessage());
+ error_log("STACK TRACE: " . $e->getTraceAsString());
+
+ http_response_code(500);
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Error del servidor: ' . $e->getMessage(),
+ 'debug' => [
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'timestamp' => date('Y-m-d H:i:s')
+ ]
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/public/limpiar_pedimentos.php b/public/limpiar_pedimentos.php
new file mode 100644
index 0000000..0654c09
--- /dev/null
+++ b/public/limpiar_pedimentos.php
@@ -0,0 +1,66 @@
+ false, 'message' => 'Usuario no autenticado']);
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ echo json_encode(['success' => false, 'message' => 'Método no permitido']);
+ exit;
+}
+
+try {
+ $conn = getConnection();
+
+ // Iniciar transacción
+ sqlsrv_begin_transaction($conn);
+
+ // Eliminar en orden correcto (por las foreign keys)
+ $sql1 = "DELETE FROM pedimento_partidas";
+ $sql2 = "DELETE FROM pedimento_facturas";
+ $sql3 = "DELETE FROM pedimentos";
+ $sql4 = "DELETE FROM importacion_logs";
+
+ $stmt1 = sqlsrv_query($conn, $sql1);
+ $stmt2 = sqlsrv_query($conn, $sql2);
+ $stmt3 = sqlsrv_query($conn, $sql3);
+ $stmt4 = sqlsrv_query($conn, $sql4);
+
+ if ($stmt1 && $stmt2 && $stmt3 && $stmt4) {
+ // Resetear los IDENTITY
+ sqlsrv_query($conn, "DBCC CHECKIDENT ('pedimentos', RESEED, 0)");
+ sqlsrv_query($conn, "DBCC CHECKIDENT ('pedimento_facturas', RESEED, 0)");
+ sqlsrv_query($conn, "DBCC CHECKIDENT ('pedimento_partidas', RESEED, 0)");
+ sqlsrv_query($conn, "DBCC CHECKIDENT ('importacion_logs', RESEED, 0)");
+
+ sqlsrv_commit($conn);
+
+ echo json_encode([
+ 'success' => true,
+ 'message' => 'Base de datos limpiada exitosamente',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'usuario_id' => $_SESSION['usuario_id']
+ ]);
+ } else {
+ sqlsrv_rollback($conn);
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Error al limpiar la base de datos',
+ 'errors' => sqlsrv_errors()
+ ]);
+ }
+
+ sqlsrv_close($conn);
+
+} catch (Exception $e) {
+ echo json_encode([
+ 'success' => false,
+ 'error' => $e->getMessage()
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/public/test_import.php b/public/test_import.php
new file mode 100644
index 0000000..51d65e1
--- /dev/null
+++ b/public/test_import.php
@@ -0,0 +1,36 @@
+ true,
+ 'message' => 'Conexión exitosa desde public',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'method' => $_SERVER['REQUEST_METHOD'],
+ 'usuario' => isset($_SESSION['usuario']) ? $_SESSION['usuario']['nombre'] ?? 'Usuario logueado' : 'No hay usuario',
+ 'post_data' => $_POST,
+ 'get_data' => $_GET,
+ 'server_info' => [
+ 'HTTP_HOST' => $_SERVER['HTTP_HOST'],
+ 'REQUEST_URI' => $_SERVER['REQUEST_URI'],
+ 'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME']
+ ]
+];
+
+if (isset($_FILES['archivo'])) {
+ $response['files_data'] = [
+ 'nombre' => $_FILES['archivo']['name'],
+ 'tamaño' => $_FILES['archivo']['size'],
+ 'tipo' => $_FILES['archivo']['type'],
+ 'error' => $_FILES['archivo']['error']
+ ];
+} else {
+ $response['files_data'] = 'No hay archivo';
+}
+
+echo json_encode($response, JSON_PRETTY_PRINT);
+?>
\ No newline at end of file
diff --git a/public/test_json.php b/public/test_json.php
new file mode 100644
index 0000000..e6824b6
--- /dev/null
+++ b/public/test_json.php
@@ -0,0 +1,10 @@
+ true,
+ 'message' => 'Test exitoso',
+ 'timestamp' => date('Y-m-d H:i:s')
+]);
+?>
\ No newline at end of file
diff --git a/public/test_ultra_simple.php b/public/test_ultra_simple.php
new file mode 100644
index 0000000..80ec75b
--- /dev/null
+++ b/public/test_ultra_simple.php
@@ -0,0 +1,26 @@
+ true,
+ 'message' => 'Test básico funcionando',
+ 'estadisticas' => [
+ 'pedimentos_procesados' => 5,
+ 'facturas_procesadas' => 10,
+ 'partidas_procesadas' => 15,
+ 'duplicados' => 0,
+ 'errores' => 0,
+ 'total_lineas' => 100
+ ],
+ 'archivos_procesados' => 3,
+ 'archivos_con_errores' => []
+ ]);
+} catch (Exception $e) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => $e->getMessage()
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/public/verificar_pedimentos.php b/public/verificar_pedimentos.php
new file mode 100644
index 0000000..3d47b22
--- /dev/null
+++ b/public/verificar_pedimentos.php
@@ -0,0 +1,46 @@
+ true,
+ 'pedimentos_existentes' => $pedimentos_existentes,
+ 'estadisticas' => $stats,
+ 'total_encontrados' => count($pedimentos_existentes)
+ ], JSON_PRETTY_PRINT);
+
+} catch (Exception $e) {
+ echo json_encode([
+ 'success' => false,
+ 'error' => $e->getMessage()
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/script_tabla_um.sql b/script_tabla_um.sql
deleted file mode 100644
index 9d4afa7..0000000
--- a/script_tabla_um.sql
+++ /dev/null
@@ -1,27 +0,0 @@
-CREATE TABLE unidades_medida_apendice7 (
- id INT PRIMARY KEY,
- descripcion NVARCHAR(100)
-);
-
-INSERT INTO unidades_medida_apendice7 (id, descripcion) VALUES
-(1, 'KILO'),
-(2, 'GRAMO'),
-(3, 'METRO LINEAL'),
-(4, 'METRO CUADRADO'),
-(5, 'METRO CUBICO'),
-(6, 'PIEZA'),
-(7, 'CABEZA'),
-(8, 'LITRO'),
-(9, 'PAR'),
-(10, 'KILOWATT'),
-(11, 'MILLAR'),
-(12, 'JUEGO'),
-(13, 'KILOWATT/HORA'),
-(14, 'TONELADA'),
-(15, 'BARRIL'),
-(16, 'GRAMO NETO'),
-(17, 'DECENAS'),
-(18, 'CIENTOS'),
-(19, 'DOCENAS'),
-(20, 'CAJA'),
-(21, 'BOTELLA');
diff --git a/script_table.txt b/script_table.txt
deleted file mode 100644
index 9433ccd..0000000
--- a/script_table.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-CREATE TABLE recuperacion_password (
- id INT IDENTITY(1,1) PRIMARY KEY,
- email NVARCHAR(255) NOT NULL,
- codigo NVARCHAR(10) NOT NULL,
- expiracion DATETIME NOT NULL
-);
-
-ALTER TABLE recuperacion_password
-ADD estatus INT NOT NULL DEFAULT 0;
diff --git a/tabla_expediente.sql b/tabla_expediente.sql
deleted file mode 100644
index b92f1ba..0000000
--- a/tabla_expediente.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-CREATE TABLE expediente_archivos (
- id INT IDENTITY(1,1) PRIMARY KEY,
- id_solicitud INT NOT NULL,
- nombre_archivo NVARCHAR(255),
- ruta_archivo NVARCHAR(500),
- tipo_archivo NVARCHAR(50),
- tamano_archivo DECIMAL(18,2),
- creado_por NVARCHAR(100),
- creado_en DATETIME DEFAULT GETDATE(),
- FOREIGN KEY (id_solicitud) REFERENCES solicitud_importacion_factura(id_solicitud)
-);
diff --git a/templates_rapidos.sql b/templates_rapidos.sql
deleted file mode 100644
index 34d8979..0000000
--- a/templates_rapidos.sql
+++ /dev/null
@@ -1,83 +0,0 @@
--- 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
deleted file mode 100644
index a8372df..0000000
--- a/test_templates.php
+++ /dev/null
@@ -1,157 +0,0 @@
-🔍 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 "Columna Tipo Nullable ";
-
- $columnas_encontradas = [];
- while ($col = sqlsrv_fetch_array($stmt_cols, SQLSRV_FETCH_ASSOC)) {
- $columnas_encontradas[] = $col['COLUMN_NAME'];
- echo "";
- echo "" . $col['COLUMN_NAME'] . " ";
- echo "" . $col['DATA_TYPE'] . " ";
- echo "" . $col['IS_NULLABLE'] . " ";
- echo " ";
- }
- echo "
";
-
- // 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 "ID Nombre Activo Usuario Agencia ";
-
- while ($sample = sqlsrv_fetch_array($stmt_sample, SQLSRV_FETCH_ASSOC)) {
- echo "";
- echo "" . $sample['id'] . " ";
- echo "" . htmlspecialchars($sample['nombre']) . " ";
- echo "" . ($sample['activo'] ? '✅' : '❌') . " ";
- echo "" . ($sample['id_usuario_creador'] ?? 'NULL') . " ";
- echo "" . ($sample['id_agencia'] ?? 'NULL') . " ";
- echo " ";
- }
- echo "
";
- }
-
- } 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/uploads/expedientes/pedimento_5/68f95df6cea0d_m3726414.262 b/uploads/expedientes/pedimento_5/68f95df6cea0d_m3726414.262
new file mode 100644
index 0000000..b2fb9cf
--- /dev/null
+++ b/uploads/expedientes/pedimento_5/68f95df6cea0d_m3726414.262
@@ -0,0 +1,211 @@
+500|1|3726|8015881|071||
+701|3726|8015881|071|A1|14092018|8015740|3726|071|A1|14092018|
+501|3726|8015881|071|1|R1|071||AIC9010115YA|NUAJ680527HCHXLS05|19.05110|0|0|0|0||1301.5|7|7|7|9|AUTOMOTRIZ E INDUSTRIAL DE CHIHUAHUA S.A DE C.V|PERIFERICO DE LA JUVENTUD||9537|31126|CHIHUAHUA||MEX|CAI040913544|0|0|0|0|0|
+502|8015881|DMT061227879||DON MIGUEL TRANSPORTE S. DE R.L. DE C.V.|MEX|3939|0|CALLE OCTAVIO PAZ COMPLEJO INDUSTRIAL CHIHUAHUA No. 140 C.P. 31136|
+516|8015881|3939|NTh18010691|
+504|8015881|3939|55|
+505|8015881|05092018|COVE182LOBNI1|DAP|USD|7883.65|7883.65|USA||59-2402583|SAP USA TRUCK & AUTO PARTS|NW 74 AVE||5301|33166|MIAMI|
+505|8015881|05092018|COVE182LOBOH3|DAP|USD|67.50|67.50|USA||59-2402583|SAP USA TRUCK & AUTO PARTS|NW 74 AVE||5301|33166|MIAMI|
+506|8015881|1|14092018|
+506|8015881|2|14092018|
+507|8015881|ED|04281805BT2H7|||
+507|8015881|ED|04361807X9OB3|||
+509|8015881|1|8.00000|7|
+509|8015881|15|240.00000|2|
+509|8015881|21|20.00000|2|
+510|8015881|1|0|1212|
+510|8015881|15|0|240|
+702|8015881|1|0|305|
+511|8015881|1|LOS DATOS DE IDENTIFICACION, LAS MARCAS, MODELOS Y NUMEROS DE SERIE SE DECLARAN EN RELACION ANEXA DE CONFORMIDAD CON EL|
+511|8015881|2|ART 36-A DE LA LEY ADUANERA EN VIGOR Y LA REGLA 3.1.7.|
+551|8015881|84133002|1||BOMBA DE AGUA|171.46667|5144|5144|270.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|1|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|1|MA||||
+556|8015881|84133002|1|3|16.0000000000|1|
+557|8015881|84133002|1|3|0|830|
+558|8015881|84133002|1|1|MARCA: T&J, ID: 11003|
+551|8015881|84133002|2||BOMBA DE AGUA|303.86667|9116|9116|478.50|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|2|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|2|MA||||
+556|8015881|84133002|2|3|16.0000000000|1|
+557|8015881|84133002|2|3|0|1470|
+558|8015881|84133002|2|1|MARCA: T&J, ID: 11010|
+551|8015881|84133002|3||BOMBA DE AGUA|159.85000|3197|3197|167.80|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|3|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|3|MA||||
+556|8015881|84133002|3|3|16.0000000000|1|
+557|8015881|84133002|3|3|0|516|
+558|8015881|84133002|3|1|MARCA: T&J, ID: 11032|
+551|8015881|84133002|4||BOMBA DE AGUA|241.55000|4831|4831|253.60|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|4|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|4|MA||||
+556|8015881|84133002|4|3|16.0000000000|1|
+557|8015881|84133002|4|3|0|779|
+558|8015881|84133002|4|1|MARCA: T&J, ID: 11184|
+551|8015881|84133002|5||BOMBA DE AGUA|152.96667|4589|4589|240.90|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|5|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|5|MA||||
+556|8015881|84133002|5|3|16.0000000000|1|
+557|8015881|84133002|5|3|0|740|
+558|8015881|84133002|5|1|MARCA: T&J, ID: 12115|
+551|8015881|84133002|6||BOMBA DE AGUA|142.90000|1429|1429|75.00|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|6|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|6|MA||||
+556|8015881|84133002|6|3|16.0000000000|1|
+557|8015881|84133002|6|3|0|230|
+558|8015881|84133002|6|1|MARCA: T&J, ID: 13126|
+551|8015881|84133002|7||BOMBA DE AGUA|180.40000|2706|2706|142.05|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|7|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|7|MA||||
+556|8015881|84133002|7|3|16.0000000000|1|
+557|8015881|84133002|7|3|0|437|
+558|8015881|84133002|7|1|MARCA: T&J, ID: 13165|
+551|8015881|84133002|8||BOMBA DE AGUA|135.45000|5418|5418|284.40|40.000|6|40.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|8|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|8|MA||||
+556|8015881|84133002|8|3|16.0000000000|1|
+557|8015881|84133002|8|3|0|874|
+558|8015881|84133002|8|1|MARCA: T&J, ID: 16206|
+551|8015881|84133002|9||BOMBA DE AGUA|133.35000|5334|5334|280.00|40.000|6|40.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|9|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|9|MA||||
+556|8015881|84133002|9|3|16.0000000000|1|
+557|8015881|84133002|9|3|0|860|
+558|8015881|84133002|9|1|MARCA: T&J, ID: 16214|
+551|8015881|84133002|10||BOMBA DE AGUA|157.18000|7859|7859|412.50|50.000|6|50.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|10|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|10|MA||||
+556|8015881|84133002|10|3|16.0000000000|1|
+557|8015881|84133002|10|3|0|1267|
+558|8015881|84133002|10|1|MARCA: T&J, ID: 16503|
+551|8015881|84133002|11||BOMBA DE AGUA|152.40000|4572|4572|240.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|11|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|11|MA||||
+556|8015881|84133002|11|3|16.0000000000|1|
+557|8015881|84133002|11|3|0|737|
+558|8015881|84133002|11|1|MARCA: T&J, ID: 18377|
+551|8015881|84133002|12||BOMBA DE AGUA|249.40000|4988|4988|261.80|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|12|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|12|MA||||
+556|8015881|84133002|12|3|16.0000000000|1|
+557|8015881|84133002|12|3|0|804|
+558|8015881|84133002|12|1|MARCA: T&J, ID: 22093|
+551|8015881|84133002|13||BOMBA DE AGUA|166.66667|2500|2500|131.25|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|13|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|13|MA||||
+556|8015881|84133002|13|3|16.0000000000|1|
+557|8015881|84133002|13|3|0|403|
+558|8015881|84133002|13|1|MARCA: T&J, ID: 23300|
+551|8015881|84133002|14||BOMBA DE AGUA|129.36667|3881|3881|203.70|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|14|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|14|MA||||
+556|8015881|84133002|14|3|16.0000000000|1|
+557|8015881|84133002|14|3|0|626|
+558|8015881|84133002|14|1|MARCA: T&J, ID: 28065|
+551|8015881|84133002|15||BOMBA DE AGUA|389.58824|13246|13246|695.30|34.000|6|34.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|15|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|15|MA||||
+556|8015881|84133002|15|3|16.0000000000|1|
+557|8015881|84133002|15|3|0|2136|
+558|8015881|84133002|15|1|MARCA: T&J, ID: 31010|
+551|8015881|84133002|16||BOMBA DE AGUA|233.40000|3501|3501|183.75|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|16|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|16|MA||||
+556|8015881|84133002|16|3|16.0000000000|1|
+557|8015881|84133002|16|3|0|565|
+558|8015881|84133002|16|1|MARCA: T&J, ID: 32066|
+551|8015881|84133002|17||BOMBA DE AGUA|266.70000|8001|8001|420.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|17|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|17|MA||||
+556|8015881|84133002|17|3|16.0000000000|1|
+557|8015881|84133002|17|3|0|1290|
+558|8015881|84133002|17|1|MARCA: T&J, ID: 32102|
+551|8015881|84133002|18||BOMBA DE AGUA|325.76667|9773|9773|513.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|18|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|18|MA||||
+556|8015881|84133002|18|3|16.0000000000|1|
+557|8015881|84133002|18|3|0|1576|
+558|8015881|84133002|18|1|MARCA: T&J, ID: 41077|
+551|8015881|84133002|19||BOMBA DE AGUA|303.85000|6077|6077|319.00|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|19|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|19|MA||||
+556|8015881|84133002|19|3|16.0000000000|1|
+557|8015881|84133002|19|3|0|980|
+558|8015881|84133002|19|1|MARCA: T&J, ID: 42095|
+551|8015881|84133002|20||BOMBA DE AGUA|360.05000|7201|7201|378.00|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|20|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|20|MA||||
+556|8015881|84133002|20|3|16.0000000000|1|
+557|8015881|84133002|20|3|0|1161|
+558|8015881|84133002|20|1|MARCA: T&J, ID: 42108|
+551|8015881|84133002|21||BOMBA DE AGUA|321.00000|9630|9630|505.50|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|21|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|21|MA||||
+556|8015881|84133002|21|3|16.0000000000|1|
+557|8015881|84133002|21|3|0|1553|
+558|8015881|84133002|21|1|MARCA: T&J, ID: 43163|
+551|8015881|84133002|22||BOMBA DE AGUA|152.40000|3048|3048|160.00|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|22|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|22|MA||||
+556|8015881|84133002|22|3|16.0000000000|1|
+557|8015881|84133002|22|3|0|492|
+558|8015881|84133002|22|1|MARCA: T&J, ID: 11001|
+551|8015881|84133002|23||BOMBA DE AGUA|144.60000|1446|1446|75.90|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|23|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|23|MA||||
+556|8015881|84133002|23|3|16.0000000000|1|
+557|8015881|84133002|23|3|0|233|
+558|8015881|84133002|23|1|MARCA: T&J, ID: 11033|
+551|8015881|84133002|24||BOMBA DE AGUA|121.53333|1823|1823|95.70|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|24|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|24|MA||||
+556|8015881|84133002|24|3|16.0000000000|1|
+557|8015881|84133002|24|3|0|294|
+558|8015881|84133002|24|1|MARCA: T&J, ID: 11057|
+551|8015881|84133002|25||BOMBA DE AGUA|171.50000|1715|1715|90.00|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|25|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|25|MA||||
+556|8015881|84133002|25|3|16.0000000000|1|
+557|8015881|84133002|25|3|0|277|
+558|8015881|84133002|25|1|MARCA: T&J, ID: 26800|
+551|8015881|84133002|26||BOMBA DE AGUA|846.10000|8461|8461|444.10|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|26|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|26|MA||||
+556|8015881|84133002|26|3|16.0000000000|1|
+557|8015881|84133002|26|3|0|1365|
+558|8015881|84133002|26|1|MARCA: T&J, ID: 71616|
+551|8015881|84133002|27||BOMBA DE AGUA|923.00000|9230|9230|484.50|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|27|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|27|MA||||
+556|8015881|84133002|27|3|16.0000000000|1|
+557|8015881|84133002|27|3|0|1489|
+558|8015881|84133002|27|1|MARCA: T&J, ID: 71617|
+551|8015881|84133002|28||BOMBA DE AGUA|147.50000|1475|1475|77.40|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|28|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|28|MA||||
+556|8015881|84133002|28|3|16.0000000000|1|
+557|8015881|84133002|28|3|0|238|
+558|8015881|84133002|28|1|MARCA: T&J, ID: 82001|
+551|8015881|49111099|29||CATALOGOS|19.06000|953|953|50.00|50.000|6|12.50000|1||0|1||||CHN|USA|||||
+554|8015881|49111099|29|MA||||
+556|8015881|49111099|29|3|16.0000000000|1|
+556|8015881|49111099|29|6|15.0000000000|1|
+557|8015881|49111099|29|3|0|177|
+557|8015881|49111099|29|6|0|143|
+558|8015881|49111099|29|1|MARCA: T&J, ID: TJ-CWP02|
+551|8015881|48211001|30||ETIQUETAS|4.76000|238|238|12.50|50.000|6|50.00000|1||0|1||||CHN|USA|||||
+554|8015881|48211001|30|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|48211001|30|MA||||
+556|8015881|48211001|30|3|16.0000000000|1|
+557|8015881|48211001|30|3|0|38|
+558|8015881|48211001|30|1|MARCA: T&J, ID: TJ-SR01|
+551|8015881|49119199|31||POSTER|9.50000|95|95|5.00|10.000|6|0.50000|1||0|1||||CHN|USA|||||
+554|8015881|49119199|31|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|49119199|31|MA||||
+556|8015881|49119199|31|3|16.0000000000|1|
+556|8015881|49119199|31|6|15.0000000000|1|
+557|8015881|49119199|31|3|0|18|
+557|8015881|49119199|31|6|0|14|
+558|8015881|49119199|31|1|MARCA: T&J, ID: TJ-CWP04|
+800|8015881|1|ITpVy/oo8quhd9LbXLHh+XXw1615VFZ9BH20k4l+whJeWsiieHmDsqmhGcCoAN82Relm1GazjOhNREeu7qkp27AKT/VQxl3RqoHZfhXGlB/Wob2pqCAqzXXSKMzcNhIxawoViRGwPcxncLhWjP/xZsiUvvFgT9afYVDEtGsaxA0MubY+/w5feBm8Ny3Nj50LfXkeNiZlBshsuCUy7XDAktm3aguSFeCUDipmLp0XHMWPDns14WaHsUYqYw8bOAk0KNxl9C7jyd5UJAZpfruzC4sPnI/r0LKMBw46sdE//1t2rSxUjbn7/Z10sTwRtz+HbqT3h2b1hKKmuPebgVcryg==|00001000000517049032|
+801|m3726414.262|1|210|010|
diff --git a/uploads/expedientes/pedimento_5/68f96d9552e13_m3726413.261 b/uploads/expedientes/pedimento_5/68f96d9552e13_m3726413.261
new file mode 100644
index 0000000..e54a459
--- /dev/null
+++ b/uploads/expedientes/pedimento_5/68f96d9552e13_m3726413.261
@@ -0,0 +1,52 @@
+500|1|3726|1010560|071||
+501|3726|1010560|071|1|A1|071||OIM060801GH5|NUAJ680527HCHXLS05|21.16500|0|0|0|0||27|7|7|7|9|OPERADORA IPC DE MEXICO S.A DE C.V.|LAZARO CARDENAS||999|64780|MONTERREY||MEX|CAI040913544|0|0|0|0|0|
+505|1010560|02112021|COVE214UAW8T3|EXW|USD|2410.95|2410.95|USA||93-1047803|RIDE DEVELOPMENT COMPANY|INDEPENDENCE HWY||4770|97351|OREGON|
+506|1010560|1|16122021|
+506|1010560|2|16122021|
+509|1010560|15|240.00000|2|
+509|1010560|23|16.00000|1|
+510|1010560|15|0|240|
+510|1010560|23|0|38|
+511|1010560|1|SIN PRECINTO FISCAL POR DE CONFORMIDAD CON EL ARTICULO 65 DEL REGLAMENTO DE LA LEY ADUANERA DEL PRESENTE COVE214U5Z1P6|
+511|1010560|2|NO SE IMPORTAN 2 PIEZAS CON UN VALOR DE $577.50 DLLS. QUEDANDO LA FACTURA CON UN VALOR TOTAL DE $1,833.45 DLLS.|
+551|1010560|63079099|1|00|CUBIERTA TEXTIL PARA JUEGO MECANICO|6111.50000|12223|12223|577.50|2.000|6|2.00000|1||0|1||||USA|USA|||||
+553|1010560|63079099|1|N3||NOM-004-SCFI-2006|0.00||
+554|1010560|63079099|1|EX||||
+554|1010560|63079099|1|TL|USA|||
+554|1010560|63079099|1|PO|12223|RIDE DEVELOPMENT COMPANY|26949|
+556|1010560|63079099|1|3|16.0000000000|1|
+557|1010560|63079099|1|3|0|1956|
+551|1010560|84136099|2|99|BOMBA HIDRAULICA|13001.00000|13001|13001|614.25|1.000|6|1.00000|6||0|1||||USA|USA|||||
+554|1010560|84136099|2|EN|U|NOM-004-ENER-2014||
+554|1010560|84136099|2|TL|USA|||
+554|1010560|84136099|2|PO|13001|RIDE DEVELOPMENT COMPANY|26949|
+554|1010560|84136099|2|ES|N|||
+554|1010560|84136099|2|MA||||
+556|1010560|84136099|2|3|16.0000000000|1|
+557|1010560|84136099|2|3|0|2080|
+558|1010560|84136099|2|1|Marca: EATON Modelo: 700-000 Serie: 0421006497|
+551|1010560|84136099|3|99|BOMBA HIDRAULICA|13001.00000|13001|13001|614.25|1.000|6|1.00000|6||0|1||||USA|USA|||||
+554|1010560|84136099|3|EN|U|NOM-004-ENER-2014||
+554|1010560|84136099|3|TL|USA|||
+554|1010560|84136099|3|PO|13001|RIDE DEVELOPMENT COMPANY|26949|
+554|1010560|84136099|3|ES|N|||
+554|1010560|84136099|3|MA||||
+556|1010560|84136099|3|3|16.0000000000|1|
+557|1010560|84136099|3|3|0|2080|
+558|1010560|84136099|3|1|Marca: EATON Modelo: 700-001 Serie: 0421006645|
+551|1010560|85452001|4|00|ESCOBILLA DE CARBON ID: KCE2-054B|186.25000|4470|4470|211.20|24.000|6|1.00000|1||0|1||||USA|USA|||||
+554|1010560|85452001|4|TL|USA|||
+554|1010560|85452001|4|PO|4470|RIDE DEVELOPMENT COMPANY|211102-1r|
+554|1010560|85452001|4|ES|N|||
+554|1010560|85452001|4|MA||||
+556|1010560|85452001|4|3|16.0000000000|1|
+557|1010560|85452001|4|3|0|715|
+551|1010560|84139113|5|99|GUIA METALICA PARA BOMBA ID: R4010|8334.00000|8334|8334|393.75|1.000|6|4.00000|1||0|1||||USA|USA|||||
+554|1010560|84139113|5|TL|USA|||
+554|1010560|84139113|5|PO|8334|RIDE DEVELOPMENT COMPANY|26949|
+554|1010560|84139113|5|ES|N|||
+554|1010560|84139113|5|MA||||
+556|1010560|84139113|5|3|16.0000000000|1|
+557|1010560|84139113|5|3|0|1333|
+800|1010560|1|enhVX2Pyk1PCqd/rl8l1mL32esx5yd51Zky9EmDVyAa2x3di6g6T17dCu+H/eaHZxP6XVQ7CnHuY6FL9ZKSXjrf/v2nsk98w8kezryrVI345bcfZSStF2KTYYQ30C7/fFZ4x3ga57N1ObhKWzkF9pzC88jR1IR1LFqn7VUnY4/BuZ75cfl8CKW5DlsmN1efeqMpK9fGoN4cTddEst7enI+U7xuevkPDcGaprL4pODtQBgLpxYgHWWfr9oap8rGJ2KAw9+a/K6ugEurouD80121p25Y9nu+B4p+8k67CCx2kw41bHo2gNArjAmDpCzfNrX9Iht2apU2EXrp83l9f5mQ==|00001000000517049032|
+801|m3726413.261|1|51|010|
diff --git a/uploads/expedientes/pedimento_5/68f96d95539d4_m3726414.262 b/uploads/expedientes/pedimento_5/68f96d95539d4_m3726414.262
new file mode 100644
index 0000000..b2fb9cf
--- /dev/null
+++ b/uploads/expedientes/pedimento_5/68f96d95539d4_m3726414.262
@@ -0,0 +1,211 @@
+500|1|3726|8015881|071||
+701|3726|8015881|071|A1|14092018|8015740|3726|071|A1|14092018|
+501|3726|8015881|071|1|R1|071||AIC9010115YA|NUAJ680527HCHXLS05|19.05110|0|0|0|0||1301.5|7|7|7|9|AUTOMOTRIZ E INDUSTRIAL DE CHIHUAHUA S.A DE C.V|PERIFERICO DE LA JUVENTUD||9537|31126|CHIHUAHUA||MEX|CAI040913544|0|0|0|0|0|
+502|8015881|DMT061227879||DON MIGUEL TRANSPORTE S. DE R.L. DE C.V.|MEX|3939|0|CALLE OCTAVIO PAZ COMPLEJO INDUSTRIAL CHIHUAHUA No. 140 C.P. 31136|
+516|8015881|3939|NTh18010691|
+504|8015881|3939|55|
+505|8015881|05092018|COVE182LOBNI1|DAP|USD|7883.65|7883.65|USA||59-2402583|SAP USA TRUCK & AUTO PARTS|NW 74 AVE||5301|33166|MIAMI|
+505|8015881|05092018|COVE182LOBOH3|DAP|USD|67.50|67.50|USA||59-2402583|SAP USA TRUCK & AUTO PARTS|NW 74 AVE||5301|33166|MIAMI|
+506|8015881|1|14092018|
+506|8015881|2|14092018|
+507|8015881|ED|04281805BT2H7|||
+507|8015881|ED|04361807X9OB3|||
+509|8015881|1|8.00000|7|
+509|8015881|15|240.00000|2|
+509|8015881|21|20.00000|2|
+510|8015881|1|0|1212|
+510|8015881|15|0|240|
+702|8015881|1|0|305|
+511|8015881|1|LOS DATOS DE IDENTIFICACION, LAS MARCAS, MODELOS Y NUMEROS DE SERIE SE DECLARAN EN RELACION ANEXA DE CONFORMIDAD CON EL|
+511|8015881|2|ART 36-A DE LA LEY ADUANERA EN VIGOR Y LA REGLA 3.1.7.|
+551|8015881|84133002|1||BOMBA DE AGUA|171.46667|5144|5144|270.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|1|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|1|MA||||
+556|8015881|84133002|1|3|16.0000000000|1|
+557|8015881|84133002|1|3|0|830|
+558|8015881|84133002|1|1|MARCA: T&J, ID: 11003|
+551|8015881|84133002|2||BOMBA DE AGUA|303.86667|9116|9116|478.50|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|2|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|2|MA||||
+556|8015881|84133002|2|3|16.0000000000|1|
+557|8015881|84133002|2|3|0|1470|
+558|8015881|84133002|2|1|MARCA: T&J, ID: 11010|
+551|8015881|84133002|3||BOMBA DE AGUA|159.85000|3197|3197|167.80|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|3|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|3|MA||||
+556|8015881|84133002|3|3|16.0000000000|1|
+557|8015881|84133002|3|3|0|516|
+558|8015881|84133002|3|1|MARCA: T&J, ID: 11032|
+551|8015881|84133002|4||BOMBA DE AGUA|241.55000|4831|4831|253.60|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|4|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|4|MA||||
+556|8015881|84133002|4|3|16.0000000000|1|
+557|8015881|84133002|4|3|0|779|
+558|8015881|84133002|4|1|MARCA: T&J, ID: 11184|
+551|8015881|84133002|5||BOMBA DE AGUA|152.96667|4589|4589|240.90|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|5|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|5|MA||||
+556|8015881|84133002|5|3|16.0000000000|1|
+557|8015881|84133002|5|3|0|740|
+558|8015881|84133002|5|1|MARCA: T&J, ID: 12115|
+551|8015881|84133002|6||BOMBA DE AGUA|142.90000|1429|1429|75.00|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|6|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|6|MA||||
+556|8015881|84133002|6|3|16.0000000000|1|
+557|8015881|84133002|6|3|0|230|
+558|8015881|84133002|6|1|MARCA: T&J, ID: 13126|
+551|8015881|84133002|7||BOMBA DE AGUA|180.40000|2706|2706|142.05|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|7|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|7|MA||||
+556|8015881|84133002|7|3|16.0000000000|1|
+557|8015881|84133002|7|3|0|437|
+558|8015881|84133002|7|1|MARCA: T&J, ID: 13165|
+551|8015881|84133002|8||BOMBA DE AGUA|135.45000|5418|5418|284.40|40.000|6|40.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|8|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|8|MA||||
+556|8015881|84133002|8|3|16.0000000000|1|
+557|8015881|84133002|8|3|0|874|
+558|8015881|84133002|8|1|MARCA: T&J, ID: 16206|
+551|8015881|84133002|9||BOMBA DE AGUA|133.35000|5334|5334|280.00|40.000|6|40.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|9|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|9|MA||||
+556|8015881|84133002|9|3|16.0000000000|1|
+557|8015881|84133002|9|3|0|860|
+558|8015881|84133002|9|1|MARCA: T&J, ID: 16214|
+551|8015881|84133002|10||BOMBA DE AGUA|157.18000|7859|7859|412.50|50.000|6|50.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|10|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|10|MA||||
+556|8015881|84133002|10|3|16.0000000000|1|
+557|8015881|84133002|10|3|0|1267|
+558|8015881|84133002|10|1|MARCA: T&J, ID: 16503|
+551|8015881|84133002|11||BOMBA DE AGUA|152.40000|4572|4572|240.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|11|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|11|MA||||
+556|8015881|84133002|11|3|16.0000000000|1|
+557|8015881|84133002|11|3|0|737|
+558|8015881|84133002|11|1|MARCA: T&J, ID: 18377|
+551|8015881|84133002|12||BOMBA DE AGUA|249.40000|4988|4988|261.80|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|12|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|12|MA||||
+556|8015881|84133002|12|3|16.0000000000|1|
+557|8015881|84133002|12|3|0|804|
+558|8015881|84133002|12|1|MARCA: T&J, ID: 22093|
+551|8015881|84133002|13||BOMBA DE AGUA|166.66667|2500|2500|131.25|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|13|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|13|MA||||
+556|8015881|84133002|13|3|16.0000000000|1|
+557|8015881|84133002|13|3|0|403|
+558|8015881|84133002|13|1|MARCA: T&J, ID: 23300|
+551|8015881|84133002|14||BOMBA DE AGUA|129.36667|3881|3881|203.70|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|14|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|14|MA||||
+556|8015881|84133002|14|3|16.0000000000|1|
+557|8015881|84133002|14|3|0|626|
+558|8015881|84133002|14|1|MARCA: T&J, ID: 28065|
+551|8015881|84133002|15||BOMBA DE AGUA|389.58824|13246|13246|695.30|34.000|6|34.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|15|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|15|MA||||
+556|8015881|84133002|15|3|16.0000000000|1|
+557|8015881|84133002|15|3|0|2136|
+558|8015881|84133002|15|1|MARCA: T&J, ID: 31010|
+551|8015881|84133002|16||BOMBA DE AGUA|233.40000|3501|3501|183.75|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|16|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|16|MA||||
+556|8015881|84133002|16|3|16.0000000000|1|
+557|8015881|84133002|16|3|0|565|
+558|8015881|84133002|16|1|MARCA: T&J, ID: 32066|
+551|8015881|84133002|17||BOMBA DE AGUA|266.70000|8001|8001|420.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|17|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|17|MA||||
+556|8015881|84133002|17|3|16.0000000000|1|
+557|8015881|84133002|17|3|0|1290|
+558|8015881|84133002|17|1|MARCA: T&J, ID: 32102|
+551|8015881|84133002|18||BOMBA DE AGUA|325.76667|9773|9773|513.00|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|18|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|18|MA||||
+556|8015881|84133002|18|3|16.0000000000|1|
+557|8015881|84133002|18|3|0|1576|
+558|8015881|84133002|18|1|MARCA: T&J, ID: 41077|
+551|8015881|84133002|19||BOMBA DE AGUA|303.85000|6077|6077|319.00|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|19|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|19|MA||||
+556|8015881|84133002|19|3|16.0000000000|1|
+557|8015881|84133002|19|3|0|980|
+558|8015881|84133002|19|1|MARCA: T&J, ID: 42095|
+551|8015881|84133002|20||BOMBA DE AGUA|360.05000|7201|7201|378.00|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|20|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|20|MA||||
+556|8015881|84133002|20|3|16.0000000000|1|
+557|8015881|84133002|20|3|0|1161|
+558|8015881|84133002|20|1|MARCA: T&J, ID: 42108|
+551|8015881|84133002|21||BOMBA DE AGUA|321.00000|9630|9630|505.50|30.000|6|30.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|21|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|21|MA||||
+556|8015881|84133002|21|3|16.0000000000|1|
+557|8015881|84133002|21|3|0|1553|
+558|8015881|84133002|21|1|MARCA: T&J, ID: 43163|
+551|8015881|84133002|22||BOMBA DE AGUA|152.40000|3048|3048|160.00|20.000|6|20.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|22|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|22|MA||||
+556|8015881|84133002|22|3|16.0000000000|1|
+557|8015881|84133002|22|3|0|492|
+558|8015881|84133002|22|1|MARCA: T&J, ID: 11001|
+551|8015881|84133002|23||BOMBA DE AGUA|144.60000|1446|1446|75.90|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|23|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|23|MA||||
+556|8015881|84133002|23|3|16.0000000000|1|
+557|8015881|84133002|23|3|0|233|
+558|8015881|84133002|23|1|MARCA: T&J, ID: 11033|
+551|8015881|84133002|24||BOMBA DE AGUA|121.53333|1823|1823|95.70|15.000|6|15.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|24|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|24|MA||||
+556|8015881|84133002|24|3|16.0000000000|1|
+557|8015881|84133002|24|3|0|294|
+558|8015881|84133002|24|1|MARCA: T&J, ID: 11057|
+551|8015881|84133002|25||BOMBA DE AGUA|171.50000|1715|1715|90.00|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|25|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|25|MA||||
+556|8015881|84133002|25|3|16.0000000000|1|
+557|8015881|84133002|25|3|0|277|
+558|8015881|84133002|25|1|MARCA: T&J, ID: 26800|
+551|8015881|84133002|26||BOMBA DE AGUA|846.10000|8461|8461|444.10|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|26|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|26|MA||||
+556|8015881|84133002|26|3|16.0000000000|1|
+557|8015881|84133002|26|3|0|1365|
+558|8015881|84133002|26|1|MARCA: T&J, ID: 71616|
+551|8015881|84133002|27||BOMBA DE AGUA|923.00000|9230|9230|484.50|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|27|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|27|MA||||
+556|8015881|84133002|27|3|16.0000000000|1|
+557|8015881|84133002|27|3|0|1489|
+558|8015881|84133002|27|1|MARCA: T&J, ID: 71617|
+551|8015881|84133002|28||BOMBA DE AGUA|147.50000|1475|1475|77.40|10.000|6|10.00000|6||0|1||||CHN|USA|||||
+554|8015881|84133002|28|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|84133002|28|MA||||
+556|8015881|84133002|28|3|16.0000000000|1|
+557|8015881|84133002|28|3|0|238|
+558|8015881|84133002|28|1|MARCA: T&J, ID: 82001|
+551|8015881|49111099|29||CATALOGOS|19.06000|953|953|50.00|50.000|6|12.50000|1||0|1||||CHN|USA|||||
+554|8015881|49111099|29|MA||||
+556|8015881|49111099|29|3|16.0000000000|1|
+556|8015881|49111099|29|6|15.0000000000|1|
+557|8015881|49111099|29|3|0|177|
+557|8015881|49111099|29|6|0|143|
+558|8015881|49111099|29|1|MARCA: T&J, ID: TJ-CWP02|
+551|8015881|48211001|30||ETIQUETAS|4.76000|238|238|12.50|50.000|6|50.00000|1||0|1||||CHN|USA|||||
+554|8015881|48211001|30|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|48211001|30|MA||||
+556|8015881|48211001|30|3|16.0000000000|1|
+557|8015881|48211001|30|3|0|38|
+558|8015881|48211001|30|1|MARCA: T&J, ID: TJ-SR01|
+551|8015881|49119199|31||POSTER|9.50000|95|95|5.00|10.000|6|0.50000|1||0|1||||CHN|USA|||||
+554|8015881|49119199|31|EN|VIII|NOM-050-SCFI-2004||
+554|8015881|49119199|31|MA||||
+556|8015881|49119199|31|3|16.0000000000|1|
+556|8015881|49119199|31|6|15.0000000000|1|
+557|8015881|49119199|31|3|0|18|
+557|8015881|49119199|31|6|0|14|
+558|8015881|49119199|31|1|MARCA: T&J, ID: TJ-CWP04|
+800|8015881|1|ITpVy/oo8quhd9LbXLHh+XXw1615VFZ9BH20k4l+whJeWsiieHmDsqmhGcCoAN82Relm1GazjOhNREeu7qkp27AKT/VQxl3RqoHZfhXGlB/Wob2pqCAqzXXSKMzcNhIxawoViRGwPcxncLhWjP/xZsiUvvFgT9afYVDEtGsaxA0MubY+/w5feBm8Ny3Nj50LfXkeNiZlBshsuCUy7XDAktm3aguSFeCUDipmLp0XHMWPDns14WaHsUYqYw8bOAk0KNxl9C7jyd5UJAZpfruzC4sPnI/r0LKMBw46sdE//1t2rSxUjbn7/Z10sTwRtz+HbqT3h2b1hKKmuPebgVcryg==|00001000000517049032|
+801|m3726414.262|1|210|010|
diff --git a/uploads/expedientes/pedimento_5/68f96d9554188_m3726428.262 b/uploads/expedientes/pedimento_5/68f96d9554188_m3726428.262
new file mode 100644
index 0000000..78f52c7
--- /dev/null
+++ b/uploads/expedientes/pedimento_5/68f96d9554188_m3726428.262
@@ -0,0 +1,19 @@
+500|1|3726|8015737|071||
+501|3726|8015737|071|1|A1|071||MMT110415BT6|NUAJ680527HCHXLS05|19.26800|0|0|3112|0||21313|7|7|7|9|MANSOUR MINING TECHNOLOGIES DE MEXICO S.A. DE C.V.|RUDYARD KIPLING||11311|31136|CHIHUAHUA||MEX|CAI040913544|0|0|0|0|0|
+505|8015737|11092018|COVE257QJTYU2|DAP|USD|36934.50|36934.50|USA||74-1871394|OBRIEN WIRE PRODUCTS|ALDINE WESTFIELD RD.||12800-A|77039|HOUSTON|
+506|8015737|1|13092018|
+506|8015737|2|13092018|
+509|8015737|15|240.00000|2|
+509|8015737|21|20.00000|2|
+510|8015737|15|0|240|
+511|8015737|1|SIN PRECINTO FISCAL POR|
+511|8015737|2|SE ANEXA FACTURA CON CONCEPTO DE INCREMENTABLES CON NUMERO: 182801|
+551|8015737|73143101|1||SECCIONES DE MALLA GALVANIZADA DE 6 PIES (183 cm) DE ANCHO POR 10 PIES (305 cm) DE LARGO CADA SECCION|33.39061|714766|711654|36934.50|21313.000|1|21313.00000|1||0|1||||USA|USA|||||
+553|8015737|73143101|1|C1||0814C118119732|36934.50|21313.00000|
+554|8015737|73143101|1|TL|USA|||
+554|8015737|73143101|1|PO|714766|OBRIEN WIRE PRODUCTS|44398|
+554|8015737|73143101|1|MA||||
+556|8015737|73143101|1|3|16.0000000000|1|
+557|8015737|73143101|1|3|0|114363|
+800|8015737|1|dq6wyhhSOukJ5bPyqbGqjxGUvArga/mUPXUzrjWM43XKrOJlNE3z2r3WKMviyxbMmZgQc1WkbKXdCB07mSAeA31xSSAXgZKzCD79OOW7eyvyH6dqsqUOL+ZTj4h5sJOjdQr9gmN53OkNtsvY3/lCGRqCvWpN+fc+B/bjoELIEt9pj/2kNSbfGWMq/uxkdFNWL00P+dTgDUmCy8POe59g23cTOYvXAs4M6SZEsL2Y/5r3Prw3Ypon1lYEjwQeY5RvjRLeEM/gp1A6SL+V16hkftAS/WUPtxvZ7BB5yd2BJdm3mN/sSEGCLfU9IfHxLeli8gjdUDOWNgsvVz53wNyuXg==|00001000000517049032|
+801|m3726428.262|1|18|010|
diff --git a/uploads/expedientes/pedimento_5/68f96d9554612_m3726435.267 b/uploads/expedientes/pedimento_5/68f96d9554612_m3726435.267
new file mode 100644
index 0000000..fa329e6
--- /dev/null
+++ b/uploads/expedientes/pedimento_5/68f96d9554612_m3726435.267
@@ -0,0 +1,65 @@
+500|1|3726|8015877|070||
+501|3726|8015877|070|1|A1|070||MMI150217CCA|NUAJ680527HCHXLS05|17.78100|0|0|0|0||0|7|7|7|7|MULTISERVICIOS MIKZA S. DE R.L. DE C.V|PEDRO ROSALES DE LEON|A|7361|32500|JUAREZ||MEX|CAI040913544|0|0|0|0|0|
+505|8015877|07092018|COVE257R06QR7|DAP|USD|6685.20|6685.20|USA||03-0591335|GLOBAL GLOVE & SAFETY MANUFACTURING, INC.|RADIUM ST NW STE A||13915|55303|RAMSEY|
+506|8015877|1|14092017|
+506|8015877|2|14092017|
+509|8015877|1|8.00000|7|
+509|8015877|15|210.00000|2|
+509|8015877|21|20.00000|2|
+510|8015877|1|0|951|
+510|8015877|15|0|210|
+510|8015877|21|0|57|
+551|8015877|90049099|1||LENTES DE SEGURIDAD No BH2254AF|32.89583|4737|4737|266.40|144.000|6|144.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|1|MA||||
+551|8015877|90049099|2||LENTES DE SEGURIDAD No BH22108AF|48.01042|13827|13827|777.60|288.000|6|288.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|2|MA||||
+551|8015877|90049099|3||LENTES DE SEGURIDAD No BH2213AF|48.01042|13827|13827|777.60|288.000|6|288.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|3|MA||||
+551|8015877|90049099|4||LENTES DE SEGURIDAD No BH2253AF|31.82639|9166|9166|515.52|288.000|6|288.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|4|MA||||
+551|8015877|90049099|5||LENTES DE SEGURIDAD No BH2143AF|26.66667|1920|1920|108.00|72.000|6|72.00000|6||0|1||||CHN|USA|||||
+554|8015877|90049099|5|MA||||
+551|8015877|90049099|6||LENTES DE SEGURIDAD No BH578|15.11458|4353|4353|244.80|288.000|6|288.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|6|MA||||
+551|8015877|90049099|7||LENTES DE SEGURIDAD No BH584|15.11111|2176|2176|122.40|144.000|6|144.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|7|MA||||
+551|8015877|90049099|8||LENTES DE SEGURIDAD No BH5410|20.44792|5889|5889|331.20|288.000|6|288.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|8|MA||||
+551|8015877|90049099|9||LENTES DE SEGURIDAD No BH543AF|16.88889|2432|2432|136.80|144.000|6|144.00000|6||0|1||||CHN|USA|||||
+554|8015877|90049099|9|MA||||
+551|8015877|90049099|10||LENTES DE SEGURIDAD No BH516|19.56250|2817|2817|158.40|144.000|6|144.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|10|MA||||
+551|8015877|90049099|11||LENTES DE SEGURIDAD No BH2333AF|24.36111|7016|7016|394.56|288.000|6|288.00000|6||0|1||||TWN|USA|||||
+554|8015877|90049099|11|MA||||
+551|8015877|61161099|12||GUANTES DE NAILON( CON REFUERZO DE NITRILO) ESTILO 510MFV No 510MFV-08 510MFV-M TALLA (8-M) MEDIANO|348.50000|8364|8364|470.40|24.000|19|288.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|12|MA||||
+554|8015877|61161099|12|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|13||GUANTES DE NAILON( CON REFUERZO DE NITRILO) ESTILO 510MFV No 510MFV-09 510MFV-L TALLA (9-L) GRANDE|348.50000|16728|16728|940.80|48.000|19|576.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|13|MA||||
+554|8015877|61161099|13|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|14||GUANTES DE NAILON( CON REFUERZO DE NITRILO) No 508XFT TALLA (9-L) GRANDE|302.29167|7255|7255|408.00|24.000|19|288.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|14|MA||||
+554|8015877|61161099|14|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|15||GUANTES DE POLIESTER( CON REFUERZO DE NITRILO) No 550XFT TALLA (9-L) GRANDE|153.62500|3687|3687|207.36|24.000|19|288.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|15|MA||||
+554|8015877|61161099|15|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|16||GUANTES DE NAILON( CON REFUERZO DE NITRILO) No 508XFT TALLA (8-M) MEDIANO|302.25000|3627|3627|204.00|12.000|19|144.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|16|MA||||
+554|8015877|61161099|16|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|17||GUANTES DE POLIESTER( CON REFUERZO DE NITRILO) No 550XFT TALLA (8-M) MEDIANO|153.66667|1844|1844|103.68|12.000|19|144.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|17|MA||||
+554|8015877|61161099|17|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|18||GUANTES DE NAILON( CON REFUERZO DE NITRILO) No 508XFT TALLA (7-S) PEQUEO|302.25000|3627|3627|204.00|12.000|19|144.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|18|MA||||
+554|8015877|61161099|18|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|61161099|19||GUANTES DE POLIESTER( CON REFUERZO DE NITRILO) No 550XFT TALLA (7-S) PEQUEO|153.66667|1844|1844|103.68|12.000|19|144.00000|9||0|1||||CHN|USA|||||
+554|8015877|61161099|19|MA||||
+554|8015877|61161099|19|EN|VIII|NOM-004-SCFI-2006||
+551|8015877|40151999|20||GUANTES DE NITRILO No 705PFE TALLA (M) MEDIANO (DE USO INDUSTRIAL, PRESENTACION CAJA DE 100 PZS)|53.35000|1067|1067|60.00|20.000|20|8.80000|1||0|1||||THA|USA|||||
+554|8015877|40151999|20|MA||||
+554|8015877|40151999|20|EN|VIII|NOM-050-SCFI-2004||
+551|8015877|40151999|21||GUANTES DE NITRILO No 705PFE TALLA (L) GRANDE (DE USO INDUSTRIAL, PRESENTACION CAJA DE 100 PZS)|53.34000|2667|2667|150.00|50.000|20|21.00000|1||0|1||||THA|USA|||||
+554|8015877|40151999|21|MA||||
+554|8015877|40151999|21|EN|VIII|NOM-050-SCFI-2004||
+800|8015877|1|HW4moEojOoyqQoVasray4Vk9WkJR9vqBcvMo+x1lfNUdLA95lcn5c8z/Ctm1F7qXZNVO2gYDK7v8TbMP3rcnQ1Y5GC/8eJZoYsn4LmOAjpy2K8gfut6kvxrIxO8/SVCp7bJrrss8Df2nHCbLqbr6ZaFPgIlbOvAFq9kRWjQVO4qEUBNYuijN9WH8L/WMtbvjJ+J68bOlOsLRwUPtlyqYldrNqSYEXv5g0tV4l8CuGVEjwiaACfBBXihsswyn3ava3kCfLgXL3TxRM5liT5HJ5lBN8RwxID4QCGbD2eNpv0vLGXcDTb7w8fBwvZX+LJRQMBqVLe/aEKt51JWYXy8MIQ==|00001000000517049032|
+801|m3726435.267|1|64|010|
diff --git a/uploads/expedientes/pedimento_5/68f96d9554ea3_m3726898.260 b/uploads/expedientes/pedimento_5/68f96d9554ea3_m3726898.260
new file mode 100644
index 0000000..3191d33
--- /dev/null
+++ b/uploads/expedientes/pedimento_5/68f96d9554ea3_m3726898.260
@@ -0,0 +1,335 @@
+500|1|3726|1024136|071||
+501|3726|1024136|071|1|A1|071||CCI8111293TA|NUAJ680527HCHXLS05|20.78230|10575|0|0|0||57.32|7|7|7|9|COMPAIA COMERCIAL CIMACO, S.A. DE C.V.|AVENIDA HIDALGO PTE||399|27000|TORREON||MEX|CAI040913544|0|0|0|0|0|
+505|1024136|19112021|2246799|CPT|USD|78.00|78.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|21122021|122121|CPT|USD|6.06|6.06|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|19112021|2246820|CPT|USD|78.00|78.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|19112021|2246800|CPT|USD|78.00|78.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|19112021|2246822|CPT|USD|39.00|39.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|19112021|2246798|CPT|USD|39.00|39.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247867|CPT|USD|55.00|55.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247863|CPT|USD|60.00|60.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247865|CPT|USD|30.00|30.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247868|CPT|USD|174.00|174.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247869|CPT|USD|174.00|174.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247870|CPT|USD|126.00|126.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247872|CPT|USD|174.00|174.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247873|CPT|USD|174.00|174.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247862|CPT|USD|55.00|55.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247866|CPT|USD|30.00|30.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247871|CPT|USD|87.00|87.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|02122021|2247864|CPT|USD|55.00|55.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+505|1024136|19112021|2246821|CPT|USD|78.00|78.00|USA||113268564|PPI APPAREL GROUP|FIFTH AVENUE 2ND. FLOOR||320|10001|NEW YORK|
+506|1024136|1|23122021|
+506|1024136|2|23122021|
+509|1024136|1|352.00000|4|
+509|1024136|15|240.00000|2|
+509|1024136|23|16.00000|1|
+510|1024136|1|0|352|
+510|1024136|15|0|240|
+510|1024136|23|0|38|
+551|1024136|62121007|1|92|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS|135.08333|2140|1621|78.00|12.000|12|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|1|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|1|EX|31|||
+556|1024136|62121007|1|3|16.0000000000|1|
+556|1024136|62121007|1|6|25.0000000000|1|
+557|1024136|62121007|1|3|0|430|
+557|1024136|62121007|1|6|0|535|
+558|1024136|62121007|1|1|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS 82% NAILON 18% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|62121007|1|2|2PKBRA2429 TEJIDO DE NO PUNTO|
+551|1024136|39269099|2|99|GANCHOS|0.41270|69|52|2.52|126.000|6|1.26000|1||0|1||||CHN|USA|||||
+553|1024136|39269099|2|N3||NOM-050-SCFI-2004|0.00||
+554|1024136|39269099|2|XP|A1|U||
+554|1024136|39269099|2|XP|S1|U||
+554|1024136|39269099|2|XP|S3|U||
+556|1024136|39269099|2|3|16.0000000000|1|
+557|1024136|39269099|2|3|0|13|
+558|1024136|39269099|2|1|GANCHOS PLASTICO SON 126 PIEZAS MARCA(S): NANETTE LEPORE|
+551|1024136|39269099|3|99|GANCHOS|0.41808|97|74|3.54|177.000|6|1.77000|1||0|1||||CHN|USA|||||
+553|1024136|39269099|3|N3||NOM-050-SCFI-2004|0.00||
+554|1024136|39269099|3|XP|A1|U||
+554|1024136|39269099|3|XP|S1|U||
+554|1024136|39269099|3|XP|S3|U||
+556|1024136|39269099|3|3|16.0000000000|1|
+557|1024136|39269099|3|3|0|17|
+558|1024136|39269099|3|1|GANCHOS PLASTICO SON 177 PIEZAS MARCA(S): BEBE|
+551|1024136|62121007|4|92|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS|135.08333|2140|1621|78.00|12.000|12|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|4|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|4|EX|31|||
+556|1024136|62121007|4|3|16.0000000000|1|
+556|1024136|62121007|4|6|25.0000000000|1|
+557|1024136|62121007|4|3|0|430|
+557|1024136|62121007|4|6|0|535|
+558|1024136|62121007|4|1|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS 82% NAILON 18% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|62121007|4|2|2PKBRA2429 TEJIDO DE NO PUNTO|
+551|1024136|62121007|5|92|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS|135.08333|2140|1621|78.00|12.000|12|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|5|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|5|EX|31|||
+556|1024136|62121007|5|3|16.0000000000|1|
+556|1024136|62121007|5|6|25.0000000000|1|
+557|1024136|62121007|5|3|0|430|
+557|1024136|62121007|5|6|0|535|
+558|1024136|62121007|5|1|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS 82% NAILON 18% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|62121007|5|2|2PKBRA2429 TEJIDO DE NO PUNTO|
+551|1024136|62121007|6|92|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS|135.16667|1070|811|39.00|6.000|12|12.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|6|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|6|EX|31|||
+556|1024136|62121007|6|3|16.0000000000|1|
+556|1024136|62121007|6|6|25.0000000000|1|
+557|1024136|62121007|6|3|0|216|
+557|1024136|62121007|6|6|0|267|
+558|1024136|62121007|6|1|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS 82% NAILON 18% ELASTANO SON 6 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|62121007|6|2|2PKBRA2429 TEJIDO DE NO PUNTO|
+551|1024136|62121007|7|92|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS|135.16667|1070|811|39.00|6.000|12|12.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|7|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|7|EX|31|||
+556|1024136|62121007|7|3|16.0000000000|1|
+556|1024136|62121007|7|6|25.0000000000|1|
+557|1024136|62121007|7|3|0|216|
+557|1024136|62121007|7|6|0|267|
+558|1024136|62121007|7|1|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS 82% NAILON 18% ELASTANO SON 6 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|62121007|7|2|2PKBRA2429 TEJIDO DE NO PUNTO|
+551|1024136|61082203|8|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|103.90000|1372|1039|50.00|10.000|12|30.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|8|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|8|EX|31|||
+554|1024136|61082203|8|MC|4|1||
+556|1024136|61082203|8|3|16.0000000000|1|
+556|1024136|61082203|8|6|25.0000000000|1|
+557|1024136|61082203|8|3|0|276|
+557|1024136|61082203|8|6|0|343|
+558|1024136|61082203|8|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 94% NAILON 6% ELASTANO SON 10 JUEGOS MARCA(S): BEBE MODELO(S): 3PKBL1464 T|
+558|1024136|61082203|8|2|EJIDO DE PUNTO|
+551|1024136|61082203|9|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|137|104|5.00|1.000|12|3.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|9|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|9|EX|31|||
+554|1024136|61082203|9|MC|4|1||
+556|1024136|61082203|9|3|16.0000000000|1|
+556|1024136|61082203|9|6|25.0000000000|1|
+557|1024136|61082203|9|3|0|29|
+557|1024136|61082203|9|6|0|34|
+558|1024136|61082203|9|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 56% NAILON 35% POLIESTER 9% ELASTANO SON 1 JUEGO MARCA(S): BEBE MODELO(S):|
+558|1024136|61082203|9|2|3PKBL1464 TEJIDO DE PUNTO|
+551|1024136|61082203|10|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|103.90909|1509|1143|55.00|11.000|12|33.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|10|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|10|EX|31|||
+554|1024136|61082203|10|MC|4|1||
+556|1024136|61082203|10|3|16.0000000000|1|
+556|1024136|61082203|10|6|25.0000000000|1|
+557|1024136|61082203|10|3|0|303|
+557|1024136|61082203|10|6|0|377|
+558|1024136|61082203|10|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 94% NAILON 6% ELASTANO SON 11 JUEGOS MARCA(S): BEBE MODELO(S): 3PKBL1464 T|
+558|1024136|61082203|10|2|EJIDO DE PUNTO|
+551|1024136|61082203|11|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|137|104|5.00|1.000|12|3.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|11|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|11|EX|31|||
+554|1024136|61082203|11|MC|4|1||
+556|1024136|61082203|11|3|16.0000000000|1|
+556|1024136|61082203|11|6|25.0000000000|1|
+557|1024136|61082203|11|3|0|29|
+557|1024136|61082203|11|6|0|34|
+558|1024136|61082203|11|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 56% NAILON 35% POLIESTER 9% ELASTANO SON 1 JUEGO MARCA(S): BEBE MODELO(S):|
+558|1024136|61082203|11|2|3PKBL1464 TEJIDO DE PUNTO|
+551|1024136|61082203|12|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|686|520|25.00|5.000|12|15.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|12|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|12|EX|31|||
+554|1024136|61082203|12|MC|4|1||
+556|1024136|61082203|12|3|16.0000000000|1|
+556|1024136|61082203|12|6|25.0000000000|1|
+557|1024136|61082203|12|3|0|139|
+557|1024136|61082203|12|6|0|171|
+558|1024136|61082203|12|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 94% NAILON 6% ELASTANO SON 5 JUEGOS MARCA(S): BEBE MODELO(S): 3PKBL1464 TE|
+558|1024136|61082203|12|2|JIDO DE PUNTO|
+551|1024136|61082203|13|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|137|104|5.00|1.000|12|3.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|13|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|13|EX|31|||
+554|1024136|61082203|13|MC|4|1||
+556|1024136|61082203|13|3|16.0000000000|1|
+556|1024136|61082203|13|6|25.0000000000|1|
+557|1024136|61082203|13|3|0|29|
+557|1024136|61082203|13|6|0|34|
+558|1024136|61082203|13|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 56% NAILON 35% POLIESTER 9% ELASTANO SON 1 JUEGO MARCA(S): BEBE MODELO(S):|
+558|1024136|61082203|13|2|3PKBL1464 TEJIDO DE PUNTO|
+551|1024136|62121007|14|02|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE|83.12500|2634|1995|96.00|24.000|6|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|14|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|14|EX|31|||
+556|1024136|62121007|14|3|16.0000000000|1|
+556|1024136|62121007|14|6|25.0000000000|1|
+557|1024136|62121007|14|3|0|528|
+557|1024136|62121007|14|6|0|658|
+558|1024136|62121007|14|1|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE 90% NAILON 10% ELASTANO SON 24 PIEZAS MARCA(S): BEBE MODELO(S): BRA3578 TEJID|
+558|1024136|62121007|14|2|O DE NO PUNTO|
+551|1024136|61082203|15|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS|135.08333|2140|1621|78.00|12.000|12|60.00000|6||0|1||NANETTE LEPORE||CHN|USA|||||
+553|1024136|61082203|15|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|15|EX|31|||
+554|1024136|61082203|15|MC|4|1||
+556|1024136|61082203|15|3|16.0000000000|1|
+556|1024136|61082203|15|6|25.0000000000|1|
+557|1024136|61082203|15|3|0|430|
+557|1024136|61082203|15|6|0|535|
+558|1024136|61082203|15|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS 86% NAILON 14% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|61082203|15|2|5PKHP827 TEJIDO DE PUNTO|
+551|1024136|61082203|16|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS|135.08333|2140|1621|78.00|12.000|12|60.00000|6||0|1||NANETTE LEPORE||CHN|USA|||||
+553|1024136|61082203|16|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|16|EX|31|||
+554|1024136|61082203|16|MC|4|1||
+556|1024136|61082203|16|3|16.0000000000|1|
+556|1024136|61082203|16|6|25.0000000000|1|
+557|1024136|61082203|16|3|0|430|
+557|1024136|61082203|16|6|0|535|
+558|1024136|61082203|16|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS 86% NAILON 14% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|61082203|16|2|5PKHP827 TEJIDO DE PUNTO|
+551|1024136|62121007|17|02|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE|83.12500|2634|1995|96.00|24.000|6|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|17|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|17|EX|31|||
+556|1024136|62121007|17|3|16.0000000000|1|
+556|1024136|62121007|17|6|25.0000000000|1|
+557|1024136|62121007|17|3|0|528|
+557|1024136|62121007|17|6|0|658|
+558|1024136|62121007|17|1|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE 90% NAILON 10% ELASTANO SON 24 PIEZAS MARCA(S): BEBE MODELO(S): BRA3578 TEJID|
+558|1024136|62121007|17|2|O DE NO PUNTO|
+551|1024136|61082203|18|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS|135.08333|2140|1621|78.00|12.000|12|60.00000|6||0|1||NANETTE LEPORE||CHN|USA|||||
+553|1024136|61082203|18|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|18|EX|31|||
+554|1024136|61082203|18|MC|4|1||
+556|1024136|61082203|18|3|16.0000000000|1|
+556|1024136|61082203|18|6|25.0000000000|1|
+557|1024136|61082203|18|3|0|430|
+557|1024136|61082203|18|6|0|535|
+558|1024136|61082203|18|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS 86% NAILON 14% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|61082203|18|2|5PKHP827 TEJIDO DE PUNTO|
+551|1024136|62121007|19|02|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE|83.16667|1317|998|48.00|12.000|6|12.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|19|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|19|EX|31|||
+556|1024136|62121007|19|3|16.0000000000|1|
+556|1024136|62121007|19|6|25.0000000000|1|
+557|1024136|62121007|19|3|0|265|
+557|1024136|62121007|19|6|0|329|
+558|1024136|62121007|19|1|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE 90% NAILON 10% ELASTANO SON 12 PIEZAS MARCA(S): BEBE MODELO(S): BRA3578 TEJID|
+558|1024136|62121007|19|2|O DE NO PUNTO|
+551|1024136|62121007|20|02|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE|83.12500|2634|1995|96.00|24.000|6|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|20|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|20|EX|31|||
+556|1024136|62121007|20|3|16.0000000000|1|
+556|1024136|62121007|20|6|25.0000000000|1|
+557|1024136|62121007|20|3|0|528|
+557|1024136|62121007|20|6|0|658|
+558|1024136|62121007|20|1|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE 90% NAILON 10% ELASTANO SON 24 PIEZAS MARCA(S): BEBE MODELO(S): BRA3578 TEJID|
+558|1024136|62121007|20|2|O DE NO PUNTO|
+551|1024136|61082203|21|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS|135.08333|2140|1621|78.00|12.000|12|60.00000|6||0|1||NANETTE LEPORE||CHN|USA|||||
+553|1024136|61082203|21|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|21|EX|31|||
+554|1024136|61082203|21|MC|4|1||
+556|1024136|61082203|21|3|16.0000000000|1|
+556|1024136|61082203|21|6|25.0000000000|1|
+557|1024136|61082203|21|3|0|430|
+557|1024136|61082203|21|6|0|535|
+558|1024136|61082203|21|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS 86% NAILON 14% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|61082203|21|2|5PKHP827 TEJIDO DE PUNTO|
+551|1024136|62121007|22|02|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE|83.12500|2634|1995|96.00|24.000|6|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|22|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|22|EX|31|||
+556|1024136|62121007|22|3|16.0000000000|1|
+556|1024136|62121007|22|6|25.0000000000|1|
+557|1024136|62121007|22|3|0|528|
+557|1024136|62121007|22|6|0|658|
+558|1024136|62121007|22|1|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE 90% NAILON 10% ELASTANO SON 24 PIEZAS MARCA(S): BEBE MODELO(S): BRA3578 TEJID|
+558|1024136|62121007|22|2|O DE NO PUNTO|
+551|1024136|61082203|23|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS|135.08333|2140|1621|78.00|12.000|12|60.00000|6||0|1||NANETTE LEPORE||CHN|USA|||||
+553|1024136|61082203|23|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|23|EX|31|||
+554|1024136|61082203|23|MC|4|1||
+556|1024136|61082203|23|3|16.0000000000|1|
+556|1024136|61082203|23|6|25.0000000000|1|
+557|1024136|61082203|23|3|0|430|
+557|1024136|61082203|23|6|0|535|
+558|1024136|61082203|23|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS 86% NAILON 14% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|61082203|23|2|5PKHP827 TEJIDO DE PUNTO|
+551|1024136|61082203|24|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|103.90000|1372|1039|50.00|10.000|12|30.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|24|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|24|EX|31|||
+554|1024136|61082203|24|MC|4|1||
+556|1024136|61082203|24|3|16.0000000000|1|
+556|1024136|61082203|24|6|25.0000000000|1|
+557|1024136|61082203|24|3|0|276|
+557|1024136|61082203|24|6|0|343|
+558|1024136|61082203|24|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 94% NAILON 6% ELSTANO SON 10 JUEGOS MARCA(S): BEBE MODELO(S): 3PKBL1464 TE|
+558|1024136|61082203|24|2|JIDO DE PUNTO|
+551|1024136|61082203|25|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|137|104|5.00|1.000|12|3.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|25|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|25|EX|31|||
+554|1024136|61082203|25|MC|4|1||
+556|1024136|61082203|25|3|16.0000000000|1|
+556|1024136|61082203|25|6|25.0000000000|1|
+557|1024136|61082203|25|3|0|29|
+557|1024136|61082203|25|6|0|34|
+558|1024136|61082203|25|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 56% NAILON 35% POLIESTER 9% ELASTANO SON 1 JUEGO MARCA(S): BEBE MODELO(S):|
+558|1024136|61082203|25|2|3PKBL1464 TEJIDO DE PUNTO|
+551|1024136|61082203|26|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|686|520|25.00|5.000|12|15.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|26|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|26|EX|31|||
+554|1024136|61082203|26|MC|4|1||
+556|1024136|61082203|26|3|16.0000000000|1|
+556|1024136|61082203|26|6|25.0000000000|1|
+557|1024136|61082203|26|3|0|139|
+557|1024136|61082203|26|6|0|171|
+558|1024136|61082203|26|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 94% NAILON 6% ELASTANO SON 5 JUEGOS MARCA(S): BEBE MODELO(S): 3PKBL1464 TE|
+558|1024136|61082203|26|2|JIDO DE PUNTO|
+551|1024136|61082203|27|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|137|104|5.00|1.000|12|3.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|27|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|27|EX|31|||
+554|1024136|61082203|27|MC|4|1||
+556|1024136|61082203|27|3|16.0000000000|1|
+556|1024136|61082203|27|6|25.0000000000|1|
+557|1024136|61082203|27|3|0|29|
+557|1024136|61082203|27|6|0|34|
+558|1024136|61082203|27|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 56% NAILON 35% POLIESTER 9% ELASTANO SON 1 JUEGO MARCA(S): BEBE MODELO(S):|
+558|1024136|61082203|27|2|3PKBL1464 TEJIDO DE PUNTO|
+551|1024136|62121007|28|01|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE|83.16667|1317|998|48.00|12.000|6|12.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|28|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|28|EX|31|||
+556|1024136|62121007|28|3|16.0000000000|1|
+556|1024136|62121007|28|6|25.0000000000|1|
+557|1024136|62121007|28|3|0|265|
+557|1024136|62121007|28|6|0|329|
+558|1024136|62121007|28|1|ROPA INTERIOR PARA DAMA BRASIER CON ENCAJE 90% NAILON 10% ELASTANO SON 12 PIEZAS MARCA(S): BEBE MODELO(S): BRA3578 TEJID|
+558|1024136|62121007|28|2|O DE NO PUNTO|
+551|1024136|61082203|29|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS|135.16667|1070|811|39.00|6.000|12|30.00000|6||0|1||NANETTE LEPORE||CHN|USA|||||
+553|1024136|61082203|29|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|29|EX|31|||
+554|1024136|61082203|29|MC|4|1||
+556|1024136|61082203|29|3|16.0000000000|1|
+556|1024136|61082203|29|6|25.0000000000|1|
+557|1024136|61082203|29|3|0|216|
+557|1024136|61082203|29|6|0|267|
+558|1024136|61082203|29|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 5 PIEZAS 86% NAILON 14% ELASTANO SON 6 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S): 5|
+558|1024136|61082203|29|2|PKHP827 TEJIDO DE PUNTO|
+551|1024136|61082203|30|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|103.90000|1372|1039|50.00|10.000|12|30.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|30|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|30|EX|31|||
+554|1024136|61082203|30|MC|4|1||
+556|1024136|61082203|30|3|16.0000000000|1|
+556|1024136|61082203|30|6|25.0000000000|1|
+557|1024136|61082203|30|3|0|276|
+557|1024136|61082203|30|6|0|343|
+558|1024136|61082203|30|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 94% NAILON 6% ELASTANO SON 10 JUEGOS MARCA(S): BEBE MODELO(S): 3PKBL1464 T|
+558|1024136|61082203|30|2|EJIDO DE PUNTO|
+551|1024136|61082203|31|01|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS|104.00000|137|104|5.00|1.000|12|3.00000|6||0|1||BEBE||CHN|USA|||||
+553|1024136|61082203|31|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|61082203|31|EX|31|||
+554|1024136|61082203|31|MC|4|1||
+556|1024136|61082203|31|3|16.0000000000|1|
+556|1024136|61082203|31|6|25.0000000000|1|
+557|1024136|61082203|31|3|0|29|
+557|1024136|61082203|31|6|0|34|
+558|1024136|61082203|31|1|ROPA INTERIOR PARA DAMA CALZON JUEGO 3 PIEZAS 56% NAILON 35% POLIESTER 9% ELASTANO SON 1 JUEGO MARCA(S): BEBE MODELO(S):|
+558|1024136|61082203|31|2|3PKBL1464 TEJIDO DE PUNTO|
+551|1024136|62121007|32|92|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS|135.08333|2140|1621|78.00|12.000|12|24.00000|6||0|1||||CHN|USA|||||
+553|1024136|62121007|32|N3||NOM-004-SCFI-2006|0.00||
+554|1024136|62121007|32|EX|31|||
+556|1024136|62121007|32|3|16.0000000000|1|
+556|1024136|62121007|32|6|25.0000000000|1|
+557|1024136|62121007|32|3|0|430|
+557|1024136|62121007|32|6|0|535|
+558|1024136|62121007|32|1|ROPA INTERIOR PARA DAMA BRASIER JUEGO 2 PIEZAS 82% NAILON 18% ELASTANO SON 12 JUEGOS MARCA(S): NANETTE LEPORE MODELO(S):|
+558|1024136|62121007|32|2|2PKBRA2429 TEJIDO DE NO PUNTO|
+800|1024136|1|dkkw0EaMPAdiagXpjWqm6L/kqGSZKvXh7V6OJv22snG1YyrU5AmqQ5Qgx2KToJwNU1Cwl6Z3PBV+7TGxMYROizihPSMfP3vBnlk4OXpv0Q86npjdUv7BUXAUU0e34S7uHNaLSK+VX46LiuccAVdRwzo5M31m1UDYXbANJpPRqnVCTZ5By1SKiV7KfgXbpBapnLtogq5k6r7oeJNzXu6Rejzir23w/AFCFtKfqEvcTId61zqsd0mU+0iNGlQ3OUk99NuBsbqVJpZOXOw5Iyh3n7xwSHJvfOHFF3dtASuo0gEr7MlFTQ9gID0vqxHwx16oT5hrlFWTrk7uzgMgfmL6ng==|00001000000517049032|
+801|m3726898.260|1|334|010|
diff --git a/uploads/expedientes/pedimento_5/68f96d9e6f012_reporte_tickets_1_.xlsx b/uploads/expedientes/pedimento_5/68f96d9e6f012_reporte_tickets_1_.xlsx
new file mode 100644
index 0000000..0e82bf5
Binary files /dev/null and b/uploads/expedientes/pedimento_5/68f96d9e6f012_reporte_tickets_1_.xlsx differ
diff --git a/uploads/expedientes/pedimento_5/Acuse Manifestacion de Valor_1761172066.pdf b/uploads/expedientes/pedimento_5/Acuse Manifestacion de Valor_1761172066.pdf
new file mode 100644
index 0000000..c5434ad
Binary files /dev/null and b/uploads/expedientes/pedimento_5/Acuse Manifestacion de Valor_1761172066.pdf differ
diff --git a/uploads/expedientes/pedimento_5/Acuse Manifestacion de Valor_1761172889.pdf b/uploads/expedientes/pedimento_5/Acuse Manifestacion de Valor_1761172889.pdf
new file mode 100644
index 0000000..9456948
Binary files /dev/null and b/uploads/expedientes/pedimento_5/Acuse Manifestacion de Valor_1761172889.pdf differ
diff --git a/uploads/expedientes/pedimento_5/Detalle Manifestacion de Valor_1761172066.pdf b/uploads/expedientes/pedimento_5/Detalle Manifestacion de Valor_1761172066.pdf
new file mode 100644
index 0000000..1203f23
Binary files /dev/null and b/uploads/expedientes/pedimento_5/Detalle Manifestacion de Valor_1761172066.pdf differ
diff --git a/uploads/expedientes/pedimento_5/Detalle Manifestacion de Valor_1761172889.pdf b/uploads/expedientes/pedimento_5/Detalle Manifestacion de Valor_1761172889.pdf
new file mode 100644
index 0000000..a1dcafb
Binary files /dev/null and b/uploads/expedientes/pedimento_5/Detalle Manifestacion de Valor_1761172889.pdf differ
diff --git a/vendor/dompdf/dompdf/lib/fonts/Courier.afm.json b/vendor/dompdf/dompdf/lib/fonts/Courier.afm.json
new file mode 100644
index 0000000..b507841
--- /dev/null
+++ b/vendor/dompdf/dompdf/lib/fonts/Courier.afm.json
@@ -0,0 +1,569 @@
+{
+ "codeToName": {
+ "32": "space",
+ "160": "space",
+ "33": "exclam",
+ "34": "quotedbl",
+ "35": "numbersign",
+ "36": "dollar",
+ "37": "percent",
+ "38": "ampersand",
+ "146": "quoteright",
+ "40": "parenleft",
+ "41": "parenright",
+ "42": "asterisk",
+ "43": "plus",
+ "44": "comma",
+ "45": "hyphen",
+ "173": "hyphen",
+ "46": "period",
+ "47": "slash",
+ "48": "zero",
+ "49": "one",
+ "50": "two",
+ "51": "three",
+ "52": "four",
+ "53": "five",
+ "54": "six",
+ "55": "seven",
+ "56": "eight",
+ "57": "nine",
+ "58": "colon",
+ "59": "semicolon",
+ "60": "less",
+ "61": "equal",
+ "62": "greater",
+ "63": "question",
+ "64": "at",
+ "65": "A",
+ "66": "B",
+ "67": "C",
+ "68": "D",
+ "69": "E",
+ "70": "F",
+ "71": "G",
+ "72": "H",
+ "73": "I",
+ "74": "J",
+ "75": "K",
+ "76": "L",
+ "77": "M",
+ "78": "N",
+ "79": "O",
+ "80": "P",
+ "81": "Q",
+ "82": "R",
+ "83": "S",
+ "84": "T",
+ "85": "U",
+ "86": "V",
+ "87": "W",
+ "88": "X",
+ "89": "Y",
+ "90": "Z",
+ "91": "bracketleft",
+ "92": "backslash",
+ "93": "bracketright",
+ "94": "asciicircum",
+ "95": "underscore",
+ "145": "quoteleft",
+ "97": "a",
+ "98": "b",
+ "99": "c",
+ "100": "d",
+ "101": "e",
+ "102": "f",
+ "103": "g",
+ "104": "h",
+ "105": "i",
+ "106": "j",
+ "107": "k",
+ "108": "l",
+ "109": "m",
+ "110": "n",
+ "111": "o",
+ "112": "p",
+ "113": "q",
+ "114": "r",
+ "115": "s",
+ "116": "t",
+ "117": "u",
+ "118": "v",
+ "119": "w",
+ "120": "x",
+ "121": "y",
+ "122": "z",
+ "123": "braceleft",
+ "124": "bar",
+ "125": "braceright",
+ "126": "asciitilde",
+ "161": "exclamdown",
+ "162": "cent",
+ "163": "sterling",
+ "165": "yen",
+ "131": "florin",
+ "167": "section",
+ "164": "currency",
+ "39": "quotesingle",
+ "147": "quotedblleft",
+ "171": "guillemotleft",
+ "139": "guilsinglleft",
+ "155": "guilsinglright",
+ "150": "endash",
+ "134": "dagger",
+ "135": "daggerdbl",
+ "183": "periodcentered",
+ "182": "paragraph",
+ "149": "bullet",
+ "130": "quotesinglbase",
+ "132": "quotedblbase",
+ "148": "quotedblright",
+ "187": "guillemotright",
+ "133": "ellipsis",
+ "137": "perthousand",
+ "191": "questiondown",
+ "96": "grave",
+ "180": "acute",
+ "136": "circumflex",
+ "152": "tilde",
+ "175": "macron",
+ "168": "dieresis",
+ "184": "cedilla",
+ "151": "emdash",
+ "198": "AE",
+ "170": "ordfeminine",
+ "216": "Oslash",
+ "140": "OE",
+ "186": "ordmasculine",
+ "230": "ae",
+ "248": "oslash",
+ "156": "oe",
+ "223": "germandbls",
+ "207": "Idieresis",
+ "233": "eacute",
+ "159": "Ydieresis",
+ "247": "divide",
+ "221": "Yacute",
+ "194": "Acircumflex",
+ "225": "aacute",
+ "219": "Ucircumflex",
+ "253": "yacute",
+ "234": "ecircumflex",
+ "220": "Udieresis",
+ "218": "Uacute",
+ "203": "Edieresis",
+ "169": "copyright",
+ "229": "aring",
+ "224": "agrave",
+ "227": "atilde",
+ "154": "scaron",
+ "237": "iacute",
+ "251": "ucircumflex",
+ "226": "acircumflex",
+ "231": "ccedilla",
+ "222": "Thorn",
+ "179": "threesuperior",
+ "210": "Ograve",
+ "192": "Agrave",
+ "215": "multiply",
+ "250": "uacute",
+ "255": "ydieresis",
+ "238": "icircumflex",
+ "202": "Ecircumflex",
+ "228": "adieresis",
+ "235": "edieresis",
+ "205": "Iacute",
+ "177": "plusminus",
+ "166": "brokenbar",
+ "174": "registered",
+ "200": "Egrave",
+ "142": "Zcaron",
+ "208": "Eth",
+ "199": "Ccedilla",
+ "193": "Aacute",
+ "196": "Adieresis",
+ "232": "egrave",
+ "211": "Oacute",
+ "243": "oacute",
+ "239": "idieresis",
+ "212": "Ocircumflex",
+ "217": "Ugrave",
+ "254": "thorn",
+ "178": "twosuperior",
+ "214": "Odieresis",
+ "181": "mu",
+ "236": "igrave",
+ "190": "threequarters",
+ "153": "trademark",
+ "204": "Igrave",
+ "189": "onehalf",
+ "244": "ocircumflex",
+ "241": "ntilde",
+ "201": "Eacute",
+ "188": "onequarter",
+ "138": "Scaron",
+ "176": "degree",
+ "242": "ograve",
+ "249": "ugrave",
+ "209": "Ntilde",
+ "245": "otilde",
+ "195": "Atilde",
+ "197": "Aring",
+ "213": "Otilde",
+ "206": "Icircumflex",
+ "172": "logicalnot",
+ "246": "odieresis",
+ "252": "udieresis",
+ "240": "eth",
+ "158": "zcaron",
+ "185": "onesuperior",
+ "128": "Euro"
+ },
+ "isUnicode": false,
+ "FontName": "Courier",
+ "FullName": "Courier",
+ "FamilyName": "Courier",
+ "Weight": "Medium",
+ "ItalicAngle": "0",
+ "IsFixedPitch": "true",
+ "CharacterSet": "ExtendedRoman",
+ "FontBBox": [
+ "-23",
+ "-250",
+ "715",
+ "805"
+ ],
+ "UnderlinePosition": "-100",
+ "UnderlineThickness": "50",
+ "Version": "003.000",
+ "EncodingScheme": "WinAnsiEncoding",
+ "CapHeight": "562",
+ "XHeight": "426",
+ "Ascender": "629",
+ "Descender": "-157",
+ "StdHW": "51",
+ "StdVW": "51",
+ "StartCharMetrics": "317",
+ "C": {
+ "32": 600,
+ "160": 600,
+ "33": 600,
+ "34": 600,
+ "35": 600,
+ "36": 600,
+ "37": 600,
+ "38": 600,
+ "146": 600,
+ "40": 600,
+ "41": 600,
+ "42": 600,
+ "43": 600,
+ "44": 600,
+ "45": 600,
+ "173": 600,
+ "46": 600,
+ "47": 600,
+ "48": 600,
+ "49": 600,
+ "50": 600,
+ "51": 600,
+ "52": 600,
+ "53": 600,
+ "54": 600,
+ "55": 600,
+ "56": 600,
+ "57": 600,
+ "58": 600,
+ "59": 600,
+ "60": 600,
+ "61": 600,
+ "62": 600,
+ "63": 600,
+ "64": 600,
+ "65": 600,
+ "66": 600,
+ "67": 600,
+ "68": 600,
+ "69": 600,
+ "70": 600,
+ "71": 600,
+ "72": 600,
+ "73": 600,
+ "74": 600,
+ "75": 600,
+ "76": 600,
+ "77": 600,
+ "78": 600,
+ "79": 600,
+ "80": 600,
+ "81": 600,
+ "82": 600,
+ "83": 600,
+ "84": 600,
+ "85": 600,
+ "86": 600,
+ "87": 600,
+ "88": 600,
+ "89": 600,
+ "90": 600,
+ "91": 600,
+ "92": 600,
+ "93": 600,
+ "94": 600,
+ "95": 600,
+ "145": 600,
+ "97": 600,
+ "98": 600,
+ "99": 600,
+ "100": 600,
+ "101": 600,
+ "102": 600,
+ "103": 600,
+ "104": 600,
+ "105": 600,
+ "106": 600,
+ "107": 600,
+ "108": 600,
+ "109": 600,
+ "110": 600,
+ "111": 600,
+ "112": 600,
+ "113": 600,
+ "114": 600,
+ "115": 600,
+ "116": 600,
+ "117": 600,
+ "118": 600,
+ "119": 600,
+ "120": 600,
+ "121": 600,
+ "122": 600,
+ "123": 600,
+ "124": 600,
+ "125": 600,
+ "126": 600,
+ "161": 600,
+ "162": 600,
+ "163": 600,
+ "fraction": 600,
+ "165": 600,
+ "131": 600,
+ "167": 600,
+ "164": 600,
+ "39": 600,
+ "147": 600,
+ "171": 600,
+ "139": 600,
+ "155": 600,
+ "fi": 600,
+ "fl": 600,
+ "150": 600,
+ "134": 600,
+ "135": 600,
+ "183": 600,
+ "182": 600,
+ "149": 600,
+ "130": 600,
+ "132": 600,
+ "148": 600,
+ "187": 600,
+ "133": 600,
+ "137": 600,
+ "191": 600,
+ "96": 600,
+ "180": 600,
+ "136": 600,
+ "152": 600,
+ "175": 600,
+ "breve": 600,
+ "dotaccent": 600,
+ "168": 600,
+ "ring": 600,
+ "184": 600,
+ "hungarumlaut": 600,
+ "ogonek": 600,
+ "caron": 600,
+ "151": 600,
+ "198": 600,
+ "170": 600,
+ "Lslash": 600,
+ "216": 600,
+ "140": 600,
+ "186": 600,
+ "230": 600,
+ "dotlessi": 600,
+ "lslash": 600,
+ "248": 600,
+ "156": 600,
+ "223": 600,
+ "207": 600,
+ "233": 600,
+ "abreve": 600,
+ "uhungarumlaut": 600,
+ "ecaron": 600,
+ "159": 600,
+ "247": 600,
+ "221": 600,
+ "194": 600,
+ "225": 600,
+ "219": 600,
+ "253": 600,
+ "scommaaccent": 600,
+ "234": 600,
+ "Uring": 600,
+ "220": 600,
+ "aogonek": 600,
+ "218": 600,
+ "uogonek": 600,
+ "203": 600,
+ "Dcroat": 600,
+ "commaaccent": 600,
+ "169": 600,
+ "Emacron": 600,
+ "ccaron": 600,
+ "229": 600,
+ "Ncommaaccent": 600,
+ "lacute": 600,
+ "224": 600,
+ "Tcommaaccent": 600,
+ "Cacute": 600,
+ "227": 600,
+ "Edotaccent": 600,
+ "154": 600,
+ "scedilla": 600,
+ "237": 600,
+ "lozenge": 600,
+ "Rcaron": 600,
+ "Gcommaaccent": 600,
+ "251": 600,
+ "226": 600,
+ "Amacron": 600,
+ "rcaron": 600,
+ "231": 600,
+ "Zdotaccent": 600,
+ "222": 600,
+ "Omacron": 600,
+ "Racute": 600,
+ "Sacute": 600,
+ "dcaron": 600,
+ "Umacron": 600,
+ "uring": 600,
+ "179": 600,
+ "210": 600,
+ "192": 600,
+ "Abreve": 600,
+ "215": 600,
+ "250": 600,
+ "Tcaron": 600,
+ "partialdiff": 600,
+ "255": 600,
+ "Nacute": 600,
+ "238": 600,
+ "202": 600,
+ "228": 600,
+ "235": 600,
+ "cacute": 600,
+ "nacute": 600,
+ "umacron": 600,
+ "Ncaron": 600,
+ "205": 600,
+ "177": 600,
+ "166": 600,
+ "174": 600,
+ "Gbreve": 600,
+ "Idotaccent": 600,
+ "summation": 600,
+ "200": 600,
+ "racute": 600,
+ "omacron": 600,
+ "Zacute": 600,
+ "142": 600,
+ "greaterequal": 600,
+ "208": 600,
+ "199": 600,
+ "lcommaaccent": 600,
+ "tcaron": 600,
+ "eogonek": 600,
+ "Uogonek": 600,
+ "193": 600,
+ "196": 600,
+ "232": 600,
+ "zacute": 600,
+ "iogonek": 600,
+ "211": 600,
+ "243": 600,
+ "amacron": 600,
+ "sacute": 600,
+ "239": 600,
+ "212": 600,
+ "217": 600,
+ "Delta": 600,
+ "254": 600,
+ "178": 600,
+ "214": 600,
+ "181": 600,
+ "236": 600,
+ "ohungarumlaut": 600,
+ "Eogonek": 600,
+ "dcroat": 600,
+ "190": 600,
+ "Scedilla": 600,
+ "lcaron": 600,
+ "Kcommaaccent": 600,
+ "Lacute": 600,
+ "153": 600,
+ "edotaccent": 600,
+ "204": 600,
+ "Imacron": 600,
+ "Lcaron": 600,
+ "189": 600,
+ "lessequal": 600,
+ "244": 600,
+ "241": 600,
+ "Uhungarumlaut": 600,
+ "201": 600,
+ "emacron": 600,
+ "gbreve": 600,
+ "188": 600,
+ "138": 600,
+ "Scommaaccent": 600,
+ "Ohungarumlaut": 600,
+ "176": 600,
+ "242": 600,
+ "Ccaron": 600,
+ "249": 600,
+ "radical": 600,
+ "Dcaron": 600,
+ "rcommaaccent": 600,
+ "209": 600,
+ "245": 600,
+ "Rcommaaccent": 600,
+ "Lcommaaccent": 600,
+ "195": 600,
+ "Aogonek": 600,
+ "197": 600,
+ "213": 600,
+ "zdotaccent": 600,
+ "Ecaron": 600,
+ "Iogonek": 600,
+ "kcommaaccent": 600,
+ "minus": 600,
+ "206": 600,
+ "ncaron": 600,
+ "tcommaaccent": 600,
+ "172": 600,
+ "246": 600,
+ "252": 600,
+ "notequal": 600,
+ "gcommaaccent": 600,
+ "240": 600,
+ "158": 600,
+ "ncommaaccent": 600,
+ "185": 600,
+ "imacron": 600,
+ "128": 600
+ },
+ "CIDtoGID_Compressed": true,
+ "CIDtoGID": "eJwDAAAAAAE=",
+ "_version_": 6
+}
\ No newline at end of file
diff --git a/views/catalogo_pedimentos/crear.php b/views/catalogo_pedimentos/crear.php
index f327239..a2766f2 100644
--- a/views/catalogo_pedimentos/crear.php
+++ b/views/catalogo_pedimentos/crear.php
@@ -27,36 +27,190 @@ if (empty($claves_pedimentos)) {
- 📋 Nuevo Pedimento de Importación
+ Nuevo Pedimento de Importación
-
-
-
+
+
-
-
-
-
📋 Catálogo de Pedimentos
-
-
-
-
-
-
-
-
Lista de Pedimentos
-
Visualizar y gestionar todos los pedimentos registrados
-
-
-
-
-
-
- Ver Lista
-
+
+
+
+
+
+
+
+
+
+
+
Lista de Pedimentos
+
Visualiza y gestiona todos los pedimentos registrados en el sistema con herramientas de búsqueda y filtrado avanzado.
+
+ Ver Lista
+
+
-
-
-
-
-
-
Nuevo Pedimento
-
Registrar un nuevo pedimento en el sistema
-
-
-
-
-
-
- Crear Nuevo
-
+
+
+
+
+
Nuevo Pedimento
+
Registra un nuevo pedimento con toda la información requerida y documentación necesaria para el proceso de importación.
+
+ Crear Nuevo
+
+
-
-
-
-
-
-
Reportes
-
Generar reportes y estadísticas de pedimentos
-
-
-
-
-
-
- Ver Reportes
+
+
+
+
+
+
Importar Archivo
+
Carga masiva de pedimentos desde archivo de texto con formato específico del sistema aduanero.
+
+ Importar Datos
+
+
+
+
+ Ver Existentes
+
+
+ Limpiar BD
+
+
+
+
+
+
+
Reportes
+
Genera reportes detallados y estadísticas de pedimentos para análisis y seguimiento de operaciones.
+
+ Ver Reportes
+
+
+
+
-
-
-
-
-
-
- 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
-
+
+
+
+
+ El catálogo de pedimentos te permite gestionar de manera eficiente todos los pedimentos
+ de importación. Desde aquí puedes realizar las siguientes acciones:
+
+
+
+
+ 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 y análisis
+
+
+
+ Mantener un histórico completo de operaciones
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Formato del archivo:
+
El sistema reconoce archivos con los siguientes códigos:
+
+ 501: Datos del pedimento (número, RFC, fechas)
+ 505: Información de facturas
+ 551: Partidas de mercancías
+
+
+
+ Archivos julianos: Se aceptan extensiones de día del año (.001 a .366)
+
+
+
+
+
+
-
-
-
+
diff --git a/views/catalogo_pedimentos/lista.php b/views/catalogo_pedimentos/lista.php
index cfd7c05..1498fea 100644
--- a/views/catalogo_pedimentos/lista.php
+++ b/views/catalogo_pedimentos/lista.php
@@ -4,80 +4,316 @@
-
📋 Catálogo de Pedimentos
+
Lista de Pedimentos
-
-
-
-
+
+
-
-
+
-
-
-
📋 Lista de Pedimentos
-
-
- Nuevo Pedimento
+
+
+
-
-
-
+
+
+
+
ID
@@ -97,16 +333,152 @@
-
+
+
+
+
+
+
+
+
+
+
Formato del archivo:
+
El sistema reconoce archivos con los siguientes códigos:
+
+ 501: Datos del pedimento (número, RFC, fechas)
+ 505: Información de facturas
+ 551: Partidas de mercancías
+
+
+
+ Archivos julianos: Se aceptan extensiones de día del año (.001 a .366)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Facturas
+
+
+ Partidas
+
+
+
+
+
+
+
+
+ #
+ Número
+ Fecha
+ Proveedor
+ Moneda
+ Total
+
+
+
+
+
+
+
+
+
+
+
+ #
+ Fracción
+ Descripción
+ Cantidad
+ UM
+ Valor Aduana
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
diff --git a/views/expediente/index.php b/views/expediente/index.php
index 131d8ee..c0a17e7 100644
--- a/views/expediente/index.php
+++ b/views/expediente/index.php
@@ -9,92 +9,142 @@
-
-
-
-
-
📁 Expedientes Electrónicos
-
-
-
-
-
- Pedimento
- Fecha Factura
- Aduana
- Proveedor
- Archivos
- Tamaño Total
- Acciones
-
-
-
-
-
- = htmlspecialchars($exp['numero_pedimento']) ?>
- = is_a($exp['fecha_factura'], 'DateTime') ? $exp['fecha_factura']->format('Y-m-d') : htmlspecialchars($exp['fecha_factura']) ?>
+
- = htmlspecialchars($exp['aduana']) ?>
- = htmlspecialchars($exp['proveedor_clave']) ?>
- = $exp['total_archivos'] ?> archivos
- = number_format($exp['total_tamano'], 2) ?> KB
-
- 📂 Ver
- ⬆ Subir
-
-
-
-
-
+
+
+
+
📁 Expediente electrónico
+
Consulta y organiza los documentos por pedimento
+
+
+
+
+ Todos
+ Con archivos
+ Sin archivos
+
+
+
+
+
+
Pedimentos
+
= (int)$totalPed ?>
+
+
+
+
+
Archivos
+
= (int)$totalArch ?>
+
+
+
+
+
+
Tamaño total
+
= number_format($totalSize, 2) ?> KB
+
+
Incluye todos los archivos subidos a los pedimentos
+
+
+
+
+
+
+
Aún no hay pedimentos listados.
+
Cuando importes pedimentos, podrás cargar y consultar documentos desde aquí.
+
+
+
+ format('Y-m-d'); }
+ else if (is_array($ff) && isset($ff['date'])) { $fecha = substr($ff['date'],0,10); }
+ elseif ($ff) { $fecha = htmlspecialchars((string)$ff); }
+ $archCount = (int)($exp['total_archivos'] ?? 0);
+ $hasFiles = $archCount > 0;
+ ?>
+
+
+
+
= htmlspecialchars($exp['pedimento_display'] ?? ($exp['numero_pedimento'] ?? '')) ?>
+
+ = $archCount ?> archivos
+
+
+
+ = htmlspecialchars($exp['proveedor'] ?? '-') ?>
+ = $fecha ?>
+ = htmlspecialchars($exp['aduana'] ?? '-') ?>
+ = htmlspecialchars($exp['patente'] ?? '-') ?>
+
+
Tamaño: = number_format((float)($exp['total_tamano'] ?? 0), 2) ?> KB
+
+
+
+
+
+
-
+
+
+
\ No newline at end of file
diff --git a/views/expediente/subir.php b/views/expediente/subir.php
index 47a0c31..9ee01bb 100644
--- a/views/expediente/subir.php
+++ b/views/expediente/subir.php
@@ -8,64 +8,67 @@
-
-
-
-
📤 Subir Archivos al Expediente
-
+
+