Compare commits
10 Commits
1960a52c36
...
feature/mo
| Author | SHA1 | Date | |
|---|---|---|---|
| d0af739ce2 | |||
| b1b9e4a77c | |||
| ed2ef4e01b | |||
| b18c05d52a | |||
| 8bb0f84fd1 | |||
| 597ab73d4a | |||
| c376ddbcdf | |||
| 90e9eea12b | |||
| 37dcfffd7b | |||
| 1900091b99 |
4
.env
4
.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
|
||||
|
||||
8
.env.example
Normal file
8
.env.example
Normal file
@@ -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
|
||||
266
agencias.txt
266
agencias.txt
@@ -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]);
|
||||
303
app/controllers/ImportadorPedimentos.php
Normal file
303
app/controllers/ImportadorPedimentos.php
Normal file
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
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, $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');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -237,6 +237,154 @@ function aprobar_usuario()
|
||||
exit;
|
||||
}
|
||||
|
||||
function denegar_usuario()
|
||||
{
|
||||
$conn = getConnection();
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
$motivo = trim($_POST['motivo'] ?? '');
|
||||
|
||||
// Definir motivo por defecto si no se ingresó uno
|
||||
if ($motivo === '') {
|
||||
$motivo = 'La solicitud ha sido rechazada por no cumplir con los requisitos establecidos.';
|
||||
}
|
||||
|
||||
// Validar parámetros
|
||||
if (!$id || !is_numeric($id)) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=invalid_id");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$motivo || trim($motivo) === '') {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=motivo_required");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verificar sesión del usuario administrador
|
||||
if (!isset($_SESSION['usuario_id']) || empty($_SESSION['usuario_id'])) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=session_error");
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// Obtener la solicitud
|
||||
$sql = "SELECT * FROM solicitudes_importadores WHERE request_id = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id]);
|
||||
|
||||
if (!$stmt) {
|
||||
throw new Exception("Error en consulta de solicitud: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$solicitud = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$solicitud) {
|
||||
throw new Exception("Solicitud no encontrada");
|
||||
}
|
||||
|
||||
// Validar que no haya sido procesada ya
|
||||
if ($solicitud['request_status'] === 'denied') {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=already_denied");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($solicitud['request_status'] === 'approved') {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=already_approved");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Preparar datos para el correo
|
||||
$nombre = !empty($solicitud['company_name']) ? decrypt($solicitud['company_name']) : 'Usuario';
|
||||
$email = $solicitud['email'] ?? null;
|
||||
|
||||
if (empty($email)) {
|
||||
throw new Exception("Email no disponible en la solicitud");
|
||||
}
|
||||
|
||||
// Actualizar solicitud como denegada
|
||||
$sqlUpdate = "UPDATE solicitudes_importadores
|
||||
SET request_status = 'denied',
|
||||
approval_date = GETDATE(),
|
||||
approved_by = ?
|
||||
WHERE request_id = ?
|
||||
";
|
||||
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$_SESSION['usuario_id'], $id]);
|
||||
|
||||
if (!$stmtUpdate) {
|
||||
throw new Exception("Error al actualizar solicitud: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// Enviar correo de notificación de denegación
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->isSMTP();
|
||||
$mail->Host = 'secure.emailsrvr.com';
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = 'noreply@aduanasoft.com.mx';
|
||||
$mail->Password = $_ENV['SMTP_PASS'] ?? '';
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mail->Port = 587;
|
||||
|
||||
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
|
||||
$mail->addAddress($email);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = 'Solicitud de registro denegada - SIIH';
|
||||
|
||||
$mail->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
|
||||
<div style='background: linear-gradient(to right, #dc3545, #c82333); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white;'>Solicitud Denegada</h2>
|
||||
</div>
|
||||
<div style='padding: 30px; color: #333; font-size: 16px;'>
|
||||
<p>Estimado(a) <strong>$nombre</strong>,</p>
|
||||
<p>Lamentamos informarte que tu solicitud de registro como importador en el sistema SIIH ha sido denegada.</p>
|
||||
|
||||
<div style='background: #f8f9fa; padding: 15px; border-left: 4px solid #dc3545; margin: 20px 0;'>
|
||||
<p style='margin: 0; font-weight: bold; color: #dc3545;'>Motivo de la denegación:</p>
|
||||
<p style='margin: 10px 0 0 0;'>$motivo</p>
|
||||
</div>
|
||||
|
||||
<p>Si consideras que esta decisión es incorrecta o deseas obtener más información, puedes contactarnos para revisar tu caso.</p>
|
||||
|
||||
<p>Agradecemos tu interés en formar parte del Sistema Integral para Importadores de Hidrocarburos.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
|
||||
</div>
|
||||
</div>
|
||||
</div>";
|
||||
|
||||
$mail->send();
|
||||
|
||||
// Éxito completo (solicitud denegada y correo enviado)
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?success=denied");
|
||||
|
||||
} catch (Exception $mailException) {
|
||||
// Error en el correo, pero la solicitud fue denegada exitosamente
|
||||
error_log("Error al enviar correo de denegación: " . $mailException->getMessage());
|
||||
|
||||
// Redirigir con mensaje de éxito parcial
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?success=denied&warning=email_failed");
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Log del error para debugging
|
||||
error_log("Error al denegar usuario: " . $e->getMessage());
|
||||
|
||||
// Redirigir con error específico basado en el tipo de error
|
||||
if (strpos($e->getMessage(), 'Solicitud no encontrada') !== false) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=invalid_request");
|
||||
} elseif (strpos($e->getMessage(), 'Email no disponible') !== false) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=email_unavailable");
|
||||
} else {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=process_failed");
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
function altaUsuarios()
|
||||
{
|
||||
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
|
||||
@@ -270,6 +418,7 @@ function guardar_usuario()
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
// 1. Capturar y validar datos
|
||||
@@ -649,6 +798,123 @@ function aprobar_agencia()
|
||||
exit;
|
||||
}
|
||||
|
||||
function denegar_agencia()
|
||||
{
|
||||
$conn = getConnection();
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
$motivo = trim($_POST['motivo'] ?? '');
|
||||
$usuario_id = $_SESSION['usuario_id'];
|
||||
|
||||
// Definir motivo por defecto si no se ingresó uno
|
||||
if ($motivo === '') {
|
||||
$motivo = 'La solicitud ha sido rechazada por no cumplir con los requisitos establecidos.';
|
||||
}
|
||||
|
||||
// Validar parámetros
|
||||
if (!$id || !is_numeric($id)) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=invalid_id");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$motivo || trim($motivo) === '') {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=motivo_required");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener la solicitud
|
||||
$sql = "SELECT * FROM solicitudes_agencias WHERE request_id = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id]);
|
||||
$solicitud = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$solicitud) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=invalid_request");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Validar que no haya sido procesada ya
|
||||
if ($solicitud['request_status'] === 'denied') {
|
||||
die("⚠️ Esta solicitud ya fue denegada.");
|
||||
}
|
||||
|
||||
if ($solicitud['request_status'] === 'approved') {
|
||||
die("⚠️ Esta solicitud ya fue aprobada y no se puede denegar.");
|
||||
}
|
||||
|
||||
// Preparar datos para el correo
|
||||
$nombre = decrypt($solicitud['agencia_name']);
|
||||
$admin_name = decrypt($solicitud['admin_name']);
|
||||
$admin_email = $solicitud['admin_email'];
|
||||
|
||||
// Actualizar solicitud como denegada
|
||||
$sqlUpdate = "UPDATE solicitudes_agencias
|
||||
SET request_status = 'denied',
|
||||
approval_date = GETDATE(),
|
||||
approved_by = ?
|
||||
WHERE request_id = ?
|
||||
";
|
||||
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$usuario_id, $id]);
|
||||
|
||||
if (!$stmtUpdate) {
|
||||
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=update_request_failed");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Enviar correo de notificación de denegación
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->isSMTP();
|
||||
$mail->Host = 'secure.emailsrvr.com';
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = 'noreply@aduanasoft.com.mx';
|
||||
$mail->Password = $_ENV['SMTP_PASS'];
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mail->Port = 587;
|
||||
|
||||
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
|
||||
$mail->addAddress($admin_email);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = 'Solicitud de agencia denegada - SIIH';
|
||||
|
||||
$mail->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
|
||||
<div style='background: linear-gradient(to right, #dc3545, #c82333); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white;'>Solicitud Denegada</h2>
|
||||
</div>
|
||||
<div style='padding: 30px; color: #333; font-size: 16px;'>
|
||||
<p>Estimado(a) <strong>$admin_name</strong>,</p>
|
||||
<p>Lamentamos informarte que tu solicitud para registrar la agencia <strong>$nombre</strong> en el sistema SIIH ha sido denegada.</p>
|
||||
|
||||
<div style='background: #f8f9fa; padding: 15px; border-left: 4px solid #dc3545; margin: 20px 0;'>
|
||||
<p style='margin: 0; font-weight: bold; color: #dc3545;'>Motivo de la denegación:</p>
|
||||
<p style='margin: 10px 0 0 0;'>$motivo</p>
|
||||
</div>
|
||||
|
||||
<p>Si consideras que esta decisión es incorrecta o deseas obtener más información, puedes contactarnos para revisar tu caso.</p>
|
||||
|
||||
<p>Agradecemos tu interés en formar parte del Sistema Integral para Importadores de Hidrocarburos.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
|
||||
</div>
|
||||
</div>
|
||||
</div>";
|
||||
|
||||
$mail->send();
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Error al enviar correo de denegación: {$mail->ErrorInfo}");
|
||||
}
|
||||
|
||||
// Registrar en bitácora (opcional - crear función específica para denegaciones)
|
||||
registrar_bitacora_agencia($id, $nombre, 'DENEGACION', $usuario_id);
|
||||
|
||||
header("Location: /IMPORTADORES/administrador/aprobarAgencias?success=denied");
|
||||
exit;
|
||||
}
|
||||
|
||||
function altaAgencias()
|
||||
{
|
||||
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
|
||||
@@ -1125,27 +1391,4 @@ function suspenderAgencia()
|
||||
|
||||
header("Location: /IMPORTADORES/administrador/agenciasActivas?success=status_$accion");
|
||||
exit;
|
||||
}
|
||||
|
||||
function configuracion()
|
||||
{
|
||||
$conn = getConnection();
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$id_usuario) {
|
||||
die("ID de usuario no disponible en la sesión.");
|
||||
}
|
||||
|
||||
$sql = "SELECT * FROM informacion_general WHERE id_usuario = ?";
|
||||
$params = [$id_usuario];
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$datos = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
include __DIR__ . '/../../views/configuracion/dashboard_configuracion.php';
|
||||
}
|
||||
@@ -18,6 +18,8 @@ function dashboard()
|
||||
exit;
|
||||
}
|
||||
|
||||
$idUsuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
include __DIR__ . '/../../views/agencias/dashboard_agencias.php';
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ function dashboard()
|
||||
exit;
|
||||
}
|
||||
|
||||
$nombreAgente = $_SESSION['usuario_nombre'];
|
||||
$idUsuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
include __DIR__ . '/../../views/agentes/dashboard_agentes.php';
|
||||
}
|
||||
|
||||
687
app/controllers/catalogo_pedimentos.php
Normal file
687
app/controllers/catalogo_pedimentos.php
Normal file
@@ -0,0 +1,687 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/crypto.php';
|
||||
|
||||
function index()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/catalogo_pedimentos/index.php';
|
||||
}
|
||||
|
||||
function lista()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/catalogo_pedimentos/lista.php';
|
||||
}
|
||||
|
||||
function crear()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
// Obtener información del importador
|
||||
$sqlImportador = "SELECT rfc, nombre, correo FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
|
||||
|
||||
if ($stmtImportador === false) {
|
||||
die("❌ Error al consultar información del importador: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
// Obtener claves de pedimentos activas del usuario
|
||||
$sqlClaves = "SELECT codigo, descripcion FROM claves_pedimentos_usuario
|
||||
WHERE id_usuario = ? AND activo = 1 AND tipo_operacion = 'importacion'
|
||||
ORDER BY codigo ASC";
|
||||
$stmtClaves = sqlsrv_query($conn, $sqlClaves, [$id_usuario]);
|
||||
|
||||
$claves_pedimentos = [];
|
||||
if ($stmtClaves !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmtClaves, SQLSRV_FETCH_ASSOC)) {
|
||||
$claves_pedimentos[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/catalogo_pedimentos/crear.php';
|
||||
}
|
||||
|
||||
function guardar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
// Obtener información del importador automáticamente
|
||||
$sqlImportador = "SELECT rfc, nombre FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
|
||||
|
||||
if ($stmtImportador === false) {
|
||||
die("❌ Error al consultar información del importador: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$importador) {
|
||||
die("❌ Error: No se encontró información del importador. Configure su información general primero.");
|
||||
}
|
||||
|
||||
// Obtener datos del formulario
|
||||
$pedimento = trim($_POST['pedimento'] ?? '');
|
||||
$clave_ped = trim($_POST['clave_ped'] ?? '');
|
||||
$tipo_operacion = $_POST['tipo_operacion'] ?? 1; // Por defecto importación
|
||||
$tipo_pedimento = $_POST['tipo_pedimento'] ?? 1; // Por defecto normal
|
||||
$regimen = trim($_POST['regimen'] ?? '');
|
||||
$destino = trim($_POST['destino'] ?? '');
|
||||
|
||||
// Fechas
|
||||
$fecha_pedimento = $_POST['fecha_pedimento'] ?? null;
|
||||
$fecha_inicio = $_POST['fecha_inicio'] ?? null;
|
||||
$fecha_final = $_POST['fecha_final'] ?? null;
|
||||
|
||||
// Información adicional
|
||||
$archivo_final_previo = trim($_POST['archivo_final_previo'] ?? '');
|
||||
$acuse_cons = trim($_POST['acuse_cons'] ?? '');
|
||||
$tipo = trim($_POST['tipo'] ?? '');
|
||||
$status = isset($_POST['status']) ? (int)$_POST['status'] : 1;
|
||||
|
||||
// Validaciones
|
||||
if (empty($pedimento)) {
|
||||
die("❌ El número de pedimento es obligatorio.");
|
||||
}
|
||||
|
||||
if (empty($clave_ped)) {
|
||||
die("❌ La clave de pedimento es obligatoria.");
|
||||
}
|
||||
|
||||
// Convertir fechas a formato YYYYMMDD si están presentes
|
||||
$fecha_pedimento_int = null;
|
||||
$fecha_inicio_int = null;
|
||||
$fecha_final_int = null;
|
||||
|
||||
if ($fecha_pedimento) {
|
||||
$fecha_pedimento_int = (int)str_replace('-', '', $fecha_pedimento);
|
||||
}
|
||||
if ($fecha_inicio) {
|
||||
$fecha_inicio_int = (int)str_replace('-', '', $fecha_inicio);
|
||||
}
|
||||
if ($fecha_final) {
|
||||
$fecha_final_int = (int)str_replace('-', '', $fecha_final);
|
||||
}
|
||||
|
||||
$sql = "INSERT INTO PREVIOS_COMPARTIDOS_WS
|
||||
(Pedimento, ClienteRFC, ClienteNombre, ClavePed, TipoOperacion, TipoPedimento,
|
||||
Regimen, Destino, FechaPedimento, FechaInicio, FechaFinal,
|
||||
ArchivoFinalPrevio, AcuseCons, Tipo, Status, Timestamp, id_usuario)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, GETDATE(), ?)";
|
||||
|
||||
$params = [
|
||||
$pedimento,
|
||||
$importador['rfc'],
|
||||
$importador['nombre'],
|
||||
$clave_ped,
|
||||
$tipo_operacion,
|
||||
$tipo_pedimento,
|
||||
$regimen,
|
||||
$destino,
|
||||
$fecha_pedimento_int,
|
||||
$fecha_inicio_int,
|
||||
$fecha_final_int,
|
||||
$archivo_final_previo,
|
||||
$acuse_cons,
|
||||
$tipo,
|
||||
$status,
|
||||
$id_usuario
|
||||
];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al guardar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/catalogo_pedimentos/lista?created=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function editar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
// Obtener información del importador
|
||||
$sqlImportador = "SELECT rfc, nombre FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
|
||||
|
||||
if ($stmtImportador === false) {
|
||||
die("❌ Error al consultar información del importador: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
// Obtener claves de pedimentos activas del usuario
|
||||
$sqlClaves = "SELECT codigo, descripcion FROM claves_pedimentos_usuario
|
||||
WHERE id_usuario = ? AND activo = 1 AND tipo_operacion = 'importacion'
|
||||
ORDER BY codigo ASC";
|
||||
$stmtClaves = sqlsrv_query($conn, $sqlClaves, [$id_usuario]);
|
||||
|
||||
$claves_pedimentos = [];
|
||||
if ($stmtClaves !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmtClaves, SQLSRV_FETCH_ASSOC)) {
|
||||
$claves_pedimentos[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener datos del pedimento
|
||||
$sql = "SELECT * FROM PREVIOS_COMPARTIDOS_WS WHERE IdPrevio = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error en consulta: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$previo = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$previo) {
|
||||
die("❌ Pedimento no encontrado.");
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/catalogo_pedimentos/editar.php';
|
||||
}
|
||||
|
||||
function actualizar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
// Obtener información del importador automáticamente
|
||||
$sqlImportador = "SELECT rfc, nombre FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
|
||||
|
||||
if ($stmtImportador === false) {
|
||||
die("❌ Error al consultar información del importador: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$importador) {
|
||||
die("❌ Error: No se encontró información del importador.");
|
||||
}
|
||||
|
||||
$id_previo = $_POST['id_previo'] ?? null;
|
||||
$pedimento = trim($_POST['pedimento'] ?? '');
|
||||
$clave_ped = trim($_POST['clave_ped'] ?? '');
|
||||
$tipo_operacion = $_POST['tipo_operacion'] ?? 1;
|
||||
$tipo_pedimento = $_POST['tipo_pedimento'] ?? 1;
|
||||
$regimen = trim($_POST['regimen'] ?? '');
|
||||
$destino = trim($_POST['destino'] ?? '');
|
||||
|
||||
// Fechas
|
||||
$fecha_pedimento = $_POST['fecha_pedimento'] ?? null;
|
||||
$fecha_inicio = $_POST['fecha_inicio'] ?? null;
|
||||
$fecha_final = $_POST['fecha_final'] ?? null;
|
||||
|
||||
// Información adicional
|
||||
$archivo_final_previo = trim($_POST['archivo_final_previo'] ?? '');
|
||||
$acuse_cons = trim($_POST['acuse_cons'] ?? '');
|
||||
$tipo = trim($_POST['tipo'] ?? '');
|
||||
$status = isset($_POST['status']) ? (int)$_POST['status'] : 1;
|
||||
|
||||
if (!$id_previo || !is_numeric($id_previo)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
// Validaciones
|
||||
if (empty($pedimento)) {
|
||||
die("❌ El número de pedimento es obligatorio.");
|
||||
}
|
||||
|
||||
if (empty($clave_ped)) {
|
||||
die("❌ La clave de pedimento es obligatoria.");
|
||||
}
|
||||
|
||||
// Convertir fechas a formato YYYYMMDD si están presentes
|
||||
$fecha_pedimento_int = null;
|
||||
$fecha_inicio_int = null;
|
||||
$fecha_final_int = null;
|
||||
|
||||
if ($fecha_pedimento) {
|
||||
$fecha_pedimento_int = (int)str_replace('-', '', $fecha_pedimento);
|
||||
}
|
||||
if ($fecha_inicio) {
|
||||
$fecha_inicio_int = (int)str_replace('-', '', $fecha_inicio);
|
||||
}
|
||||
if ($fecha_final) {
|
||||
$fecha_final_int = (int)str_replace('-', '', $fecha_final);
|
||||
}
|
||||
|
||||
$sql = "UPDATE PREVIOS_COMPARTIDOS_WS SET
|
||||
Pedimento = ?, ClienteRFC = ?, ClienteNombre = ?, ClavePed = ?,
|
||||
TipoOperacion = ?, TipoPedimento = ?, Regimen = ?, Destino = ?,
|
||||
FechaPedimento = ?, FechaInicio = ?, FechaFinal = ?,
|
||||
ArchivoFinalPrevio = ?, AcuseCons = ?, Tipo = ?, Status = ?
|
||||
WHERE IdPrevio = ?";
|
||||
|
||||
$params = [
|
||||
$pedimento,
|
||||
$importador['rfc'],
|
||||
$importador['nombre'],
|
||||
$clave_ped,
|
||||
$tipo_operacion,
|
||||
$tipo_pedimento,
|
||||
$regimen,
|
||||
$destino,
|
||||
$fecha_pedimento_int,
|
||||
$fecha_inicio_int,
|
||||
$fecha_final_int,
|
||||
$archivo_final_previo,
|
||||
$acuse_cons,
|
||||
$tipo,
|
||||
$status,
|
||||
$id_previo
|
||||
];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/catalogo_pedimentos/lista?updated=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function eliminar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
$sql = "DELETE FROM PREVIOS_COMPARTIDOS_WS WHERE IdPrevio = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al eliminar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/catalogo_pedimentos/lista?deleted=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function ajax_lista()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(403);
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$conn = getConnection();
|
||||
|
||||
// Parámetros de DataTables
|
||||
$draw = intval($_GET['draw'] ?? 0);
|
||||
$start = intval($_GET['start'] ?? 0);
|
||||
$length = intval($_GET['length'] ?? 10);
|
||||
$search = $_GET['search']['value'] ?? '';
|
||||
|
||||
// Total registros sin filtro 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,
|
||||
"recordsFiltered" => 0,
|
||||
"data" => [],
|
||||
"error" => "Error al contar registros totales"
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
$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 (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, $like, $like]);
|
||||
}
|
||||
|
||||
// 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,
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => 0,
|
||||
"data" => [],
|
||||
"error" => "Error al contar registros filtrados"
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
$rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC);
|
||||
$recordsFiltered = (int)($rowF['total'] ?? 0);
|
||||
|
||||
// Datos 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";
|
||||
$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)) {
|
||||
$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['id'],
|
||||
$r['numero_pedimento'],
|
||||
$r['rfc_importador'],
|
||||
$r['nombre_importador'] ?? '',
|
||||
$fecha,
|
||||
$estado
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => $recordsFiltered,
|
||||
"data" => $data
|
||||
];
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function buscar_pedimentos()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(403);
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$query = trim($_GET['q'] ?? '');
|
||||
$limit = intval($_GET['limit'] ?? 10); // ✅ NUEVO: Parámetro limit con valor por defecto
|
||||
|
||||
// ✅ MODIFICADO: Para el panel de referencia, si no hay query, traer los más recientes
|
||||
if (empty($query)) {
|
||||
// Si no hay query, obtener los pedimentos más recientes para el panel de referencia
|
||||
$whereCondition = "ClienteRFC = ? AND Status = 1";
|
||||
$searchParams = [];
|
||||
} else {
|
||||
// Si hay query, mantener la lógica original de búsqueda
|
||||
if (strlen($query) < 3) {
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
$whereCondition = "ClienteRFC = ? AND (Pedimento LIKE ? OR ClienteNombre LIKE ? OR ClavePed LIKE ?) AND Status = 1";
|
||||
$like = "%{$query}%";
|
||||
$searchParams = [$like, $like, $like];
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
// Obtener RFC del usuario para filtrar solo sus pedimentos
|
||||
$sqlImportador = "SELECT rfc FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
|
||||
|
||||
if ($stmtImportador === false) {
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$importador) {
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ✅ MODIFICADO: Query dinámico con límite configurable
|
||||
$sql = "SELECT TOP {$limit} IdPrevio, Pedimento, ClienteRFC, ClienteNombre, ClavePed, Timestamp
|
||||
FROM PREVIOS_COMPARTIDOS_WS
|
||||
WHERE {$whereCondition}
|
||||
ORDER BY Timestamp DESC";
|
||||
|
||||
$params = array_merge([$importador['rfc']], $searchParams);
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
$pedimentos = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$fecha_formateada = '';
|
||||
if ($row['Timestamp'] instanceof DateTime) {
|
||||
$fecha_formateada = $row['Timestamp']->format('d/m/Y');
|
||||
}
|
||||
|
||||
$pedimentos[] = [
|
||||
'IdPrevio' => $row['IdPrevio'],
|
||||
'Pedimento' => $row['Pedimento'],
|
||||
'ClienteRFC' => $row['ClienteRFC'],
|
||||
'ClienteNombre' => $row['ClienteNombre'],
|
||||
'ClavePed' => $row['ClavePed'],
|
||||
'fecha_formateada' => $fecha_formateada
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
echo json_encode($pedimentos, JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
553
app/controllers/claves_pedimentos.php
Normal file
553
app/controllers/claves_pedimentos.php
Normal file
@@ -0,0 +1,553 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/crypto.php';
|
||||
|
||||
function index()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/claves_pedimentos/index.php';
|
||||
}
|
||||
|
||||
function lista()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/claves_pedimentos/lista.php';
|
||||
}
|
||||
|
||||
function crear()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/claves_pedimentos/crear.php';
|
||||
}
|
||||
|
||||
function guardar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
$codigo = strtoupper(trim($_POST['codigo'] ?? ''));
|
||||
$descripcion = trim($_POST['descripcion'] ?? '');
|
||||
$tipo_operacion = $_POST['tipo_operacion'] ?? 'importacion';
|
||||
$activo = isset($_POST['activo']) ? 1 : 0;
|
||||
|
||||
// Validaciones
|
||||
if (empty($codigo) || empty($descripcion)) {
|
||||
die("❌ El código y descripción son obligatorios.");
|
||||
}
|
||||
|
||||
if (strlen($codigo) > 10) {
|
||||
die("❌ El código no puede tener más de 10 caracteres.");
|
||||
}
|
||||
|
||||
if (!preg_match('/^[A-Z0-9]+$/', $codigo)) {
|
||||
die("❌ El código solo puede contener letras y números.");
|
||||
}
|
||||
|
||||
// Verificar que no exista el código para este usuario
|
||||
$sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario WHERE id_usuario = ? AND codigo = ?";
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario, $codigo]);
|
||||
|
||||
if ($stmtCheck === false) {
|
||||
die("❌ Error al verificar código existente: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($result['count'] > 0) {
|
||||
die("❌ Ya existe una clave con el código '{$codigo}' para este usuario.");
|
||||
}
|
||||
|
||||
$sql = "INSERT INTO claves_pedimentos_usuario
|
||||
(id_usuario, codigo, descripcion, tipo_operacion, activo, fecha_creacion, fecha_modificacion)
|
||||
VALUES (?, ?, ?, ?, ?, GETDATE(), GETDATE())";
|
||||
|
||||
$params = [$id_usuario, $codigo, $descripcion, $tipo_operacion, $activo];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al guardar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/claves_pedimentos/lista?created=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function editar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
$sql = "SELECT * FROM claves_pedimentos_usuario WHERE id_clave_pedimento = ? AND id_usuario = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id, $id_usuario]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error en consulta: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$clave = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$clave) {
|
||||
die("❌ Clave de pedimento no encontrada.");
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/claves_pedimentos/editar.php';
|
||||
}
|
||||
|
||||
function actualizar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
$id_clave_pedimento = $_POST['id_clave_pedimento'] ?? null;
|
||||
$codigo = strtoupper(trim($_POST['codigo'] ?? ''));
|
||||
$descripcion = trim($_POST['descripcion'] ?? '');
|
||||
$tipo_operacion = $_POST['tipo_operacion'] ?? 'importacion';
|
||||
$activo = isset($_POST['activo']) ? 1 : 0;
|
||||
|
||||
if (!$id_clave_pedimento || !is_numeric($id_clave_pedimento)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
// Validaciones
|
||||
if (empty($codigo) || empty($descripcion)) {
|
||||
die("❌ El código y descripción son obligatorios.");
|
||||
}
|
||||
|
||||
if (strlen($codigo) > 10) {
|
||||
die("❌ El código no puede tener más de 10 caracteres.");
|
||||
}
|
||||
|
||||
if (!preg_match('/^[A-Z0-9]+$/', $codigo)) {
|
||||
die("❌ El código solo puede contener letras y números.");
|
||||
}
|
||||
|
||||
// Verificar que no exista otro código igual (excepto el actual)
|
||||
$sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario
|
||||
WHERE id_usuario = ? AND codigo = ? AND id_clave_pedimento != ?";
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario, $codigo, $id_clave_pedimento]);
|
||||
|
||||
if ($stmtCheck === false) {
|
||||
die("❌ Error al verificar código existente: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($result['count'] > 0) {
|
||||
die("❌ Ya existe otra clave con el código '{$codigo}' para este usuario.");
|
||||
}
|
||||
|
||||
$sql = "UPDATE claves_pedimentos_usuario SET
|
||||
codigo = ?, descripcion = ?, tipo_operacion = ?, activo = ?, fecha_modificacion = GETDATE()
|
||||
WHERE id_clave_pedimento = ? AND id_usuario = ?";
|
||||
|
||||
$params = [$codigo, $descripcion, $tipo_operacion, $activo, $id_clave_pedimento, $id_usuario];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/claves_pedimentos/lista?updated=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function eliminar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
$sql = "DELETE FROM claves_pedimentos_usuario WHERE id_clave_pedimento = ? AND id_usuario = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id, $id_usuario]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al eliminar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/claves_pedimentos/lista?deleted=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function ajax_lista()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(403);
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$conn = getConnection();
|
||||
|
||||
// Parámetros de DataTables
|
||||
$draw = intval($_GET['draw'] ?? 0);
|
||||
$start = intval($_GET['start'] ?? 0);
|
||||
$length = intval($_GET['length'] ?? 10);
|
||||
$search = $_GET['search']['value'] ?? '';
|
||||
|
||||
// Total registros sin filtro
|
||||
$sqlTotal = "SELECT COUNT(*) AS total FROM claves_pedimentos_usuario WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_query($conn, $sqlTotal, [$id_usuario]);
|
||||
|
||||
if ($stmt === false) {
|
||||
echo json_encode([
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => 0,
|
||||
"recordsFiltered" => 0,
|
||||
"data" => [],
|
||||
"error" => "Error al contar registros totales"
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
$recordsTotal = (int)($row['total'] ?? 0);
|
||||
|
||||
// Construir condiciones de filtro
|
||||
$where = "id_usuario = ?";
|
||||
$params = [$id_usuario];
|
||||
|
||||
if ($search !== '') {
|
||||
$where .= " AND (codigo LIKE ? OR descripcion LIKE ? OR tipo_operacion LIKE ?)";
|
||||
$like = "%{$search}%";
|
||||
$params = array_merge($params, [$like, $like, $like]);
|
||||
}
|
||||
|
||||
// Total registros filtrados
|
||||
$sqlFiltered = "SELECT COUNT(*) AS total FROM claves_pedimentos_usuario WHERE $where";
|
||||
$stmtF = sqlsrv_query($conn, $sqlFiltered, $params);
|
||||
|
||||
if ($stmtF === false) {
|
||||
echo json_encode([
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => 0,
|
||||
"data" => [],
|
||||
"error" => "Error al contar registros filtrados"
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC);
|
||||
$recordsFiltered = (int)($rowF['total'] ?? 0);
|
||||
|
||||
// Datos de la página
|
||||
$sqlData = "SELECT id_clave_pedimento, codigo, descripcion, tipo_operacion,
|
||||
CASE WHEN activo = 1 THEN 'Activo' ELSE 'Inactivo' END as estado,
|
||||
FORMAT(fecha_creacion, 'dd/MM/yyyy HH:mm') as fecha_creacion
|
||||
FROM claves_pedimentos_usuario
|
||||
WHERE $where
|
||||
ORDER BY codigo ASC
|
||||
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||
$params[] = $start;
|
||||
$params[] = $length;
|
||||
|
||||
$stmtD = sqlsrv_query($conn, $sqlData, $params);
|
||||
|
||||
$data = [];
|
||||
if ($stmtD !== false) {
|
||||
while ($r = sqlsrv_fetch_array($stmtD, SQLSRV_FETCH_ASSOC)) {
|
||||
$data[] = [
|
||||
$r['id_clave_pedimento'],
|
||||
$r['codigo'],
|
||||
$r['descripcion'],
|
||||
ucfirst($r['tipo_operacion']),
|
||||
$r['estado'],
|
||||
$r['fecha_creacion']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
"draw" => $draw,
|
||||
"recordsTotal" => $recordsTotal,
|
||||
"recordsFiltered" => $recordsFiltered,
|
||||
"data" => $data
|
||||
];
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function inicializar_claves_usuario()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
// Verificar si ya tiene claves configuradas
|
||||
$sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario WHERE id_usuario = ?";
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario]);
|
||||
|
||||
if ($stmtCheck === false) {
|
||||
die("❌ Error al verificar claves existentes: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($result['count'] > 0) {
|
||||
header('Location: /IMPORTADORES/claves_pedimentos/lista?info=already_initialized');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Claves de pedimentos por defecto para importación
|
||||
$claves_default = [
|
||||
['A1', 'Importación definitiva de mercancías', 'importacion'],
|
||||
['A3', 'Importación definitiva de vehículos usados', 'importacion'],
|
||||
['A4', 'Importación definitiva de vehículos nuevos', 'importacion'],
|
||||
['B1', 'Importación temporal para elaborar, transformar o reparar', 'importacion'],
|
||||
['C1', 'Importación definitiva de mercancías donadas', 'importacion'],
|
||||
['G1', 'Importación de mercancías con Programa IMMEX', 'importacion'],
|
||||
['I1', 'Importación definitiva exenta', 'importacion'],
|
||||
['J1', 'Importación temporal para reexportación en el mismo estado', 'importacion'],
|
||||
['L1', 'Importación definitiva con franquicia arancelaria con TLC', 'importacion'],
|
||||
['M1', 'Importación de menajes de casa', 'importacion'],
|
||||
['N1', 'Importación de equipaje', 'importacion'],
|
||||
['P1', 'Importación temporal de remolques y semirremolques', 'importacion'],
|
||||
['R1', 'Importación temporal de contenedores', 'importacion'],
|
||||
['S1', 'Importación temporal de vehículos', 'importacion'],
|
||||
['T1', 'Importación temporal de enseres de tripulantes', 'importacion'],
|
||||
['V1', 'Importación temporal de mercancías para exposición', 'importacion']
|
||||
];
|
||||
|
||||
$sql = "INSERT INTO claves_pedimentos_usuario
|
||||
(id_usuario, codigo, descripcion, tipo_operacion, activo, fecha_creacion, fecha_modificacion)
|
||||
VALUES (?, ?, ?, ?, 1, GETDATE(), GETDATE())";
|
||||
|
||||
$insertadas = 0;
|
||||
foreach ($claves_default as $clave) {
|
||||
$params = [$id_usuario, $clave[0], $clave[1], $clave[2]];
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt !== false) {
|
||||
$insertadas++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($insertadas > 0) {
|
||||
header('Location: /IMPORTADORES/claves_pedimentos/lista?created=initialized');
|
||||
} else {
|
||||
die("❌ Error al inicializar las claves de pedimentos.");
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
function importar_csv()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/claves_pedimentos/importar_csv.php';
|
||||
}
|
||||
|
||||
function procesar_csv()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
// Verificar que se subió un archivo
|
||||
if (!isset($_FILES['csv_file']) || $_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) {
|
||||
die("❌ Error: No se pudo cargar el archivo CSV.");
|
||||
}
|
||||
|
||||
$archivo_csv = $_FILES['csv_file']['tmp_name'];
|
||||
$nombre_archivo = $_FILES['csv_file']['name'];
|
||||
|
||||
// Validar extensión
|
||||
if (!str_ends_with(strtolower($nombre_archivo), '.csv')) {
|
||||
die("❌ Error: El archivo debe tener extensión .csv");
|
||||
}
|
||||
|
||||
// Opciones de importación
|
||||
$omitir_duplicados = isset($_POST['omitir_duplicados']);
|
||||
$activar_todas = isset($_POST['activar_todas']);
|
||||
|
||||
try {
|
||||
// Leer archivo CSV
|
||||
$archivo = fopen($archivo_csv, 'r');
|
||||
if (!$archivo) {
|
||||
die("❌ Error: No se pudo abrir el archivo CSV.");
|
||||
}
|
||||
|
||||
// Leer encabezados
|
||||
$encabezados = fgetcsv($archivo, 1000, ',');
|
||||
if (!$encabezados) {
|
||||
fclose($archivo);
|
||||
die("❌ Error: El archivo CSV está vacío o no tiene el formato correcto.");
|
||||
}
|
||||
|
||||
// Validar encabezados requeridos
|
||||
$encabezados_requeridos = ['codigo', 'descripcion', 'tipo_operacion', 'activo'];
|
||||
$encabezados_faltantes = array_diff($encabezados_requeridos, $encabezados);
|
||||
|
||||
if (!empty($encabezados_faltantes)) {
|
||||
fclose($archivo);
|
||||
die("❌ Error: Faltan las siguientes columnas: " . implode(', ', $encabezados_faltantes));
|
||||
}
|
||||
|
||||
$insertadas = 0;
|
||||
$omitidas = 0;
|
||||
$errores = [];
|
||||
$fila_numero = 1;
|
||||
|
||||
// SQL para verificar códigos existentes
|
||||
$sqlCheck = "SELECT COUNT(*) as count FROM claves_pedimentos_usuario WHERE id_usuario = ? AND codigo = ?";
|
||||
|
||||
// SQL para insertar
|
||||
$sqlInsert = "INSERT INTO claves_pedimentos_usuario
|
||||
(id_usuario, codigo, descripcion, tipo_operacion, activo, fecha_creacion, fecha_modificacion)
|
||||
VALUES (?, ?, ?, ?, ?, GETDATE(), GETDATE())";
|
||||
|
||||
// Procesar cada fila
|
||||
while (($fila = fgetcsv($archivo, 1000, ',')) !== FALSE) {
|
||||
$fila_numero++;
|
||||
|
||||
if (count($fila) < count($encabezados_requeridos)) {
|
||||
$errores[] = "Fila $fila_numero: Datos insuficientes";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Crear array asociativo
|
||||
$datos = array_combine($encabezados, $fila);
|
||||
|
||||
// Validar datos
|
||||
$codigo = strtoupper(trim($datos['codigo']));
|
||||
$descripcion = trim($datos['descripcion']);
|
||||
$tipo_operacion = trim($datos['tipo_operacion']);
|
||||
$activo = $activar_todas ? 1 : (int)($datos['activo'] ?? 1);
|
||||
|
||||
// Validaciones
|
||||
if (empty($codigo)) {
|
||||
$errores[] = "Fila $fila_numero: Código vacío";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($descripcion)) {
|
||||
$errores[] = "Fila $fila_numero: Descripción vacía";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($tipo_operacion, ['importacion', 'exportacion'])) {
|
||||
$errores[] = "Fila $fila_numero: Tipo de operación inválido ($tipo_operacion)";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen($codigo) > 10) {
|
||||
$errores[] = "Fila $fila_numero: Código muy largo (máximo 10 caracteres)";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!preg_match('/^[A-Z0-9]+$/', $codigo)) {
|
||||
$errores[] = "Fila $fila_numero: Código inválido (solo letras y números)";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verificar si ya existe
|
||||
if ($omitir_duplicados) {
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id_usuario, $codigo]);
|
||||
|
||||
if ($stmtCheck === false) {
|
||||
$errores[] = "Fila $fila_numero: Error al verificar código existente";
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($result['count'] > 0) {
|
||||
$omitidas++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Insertar registro
|
||||
$params = [$id_usuario, $codigo, $descripcion, $tipo_operacion, $activo];
|
||||
$stmt = sqlsrv_query($conn, $sqlInsert, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
$sql_errors = sqlsrv_errors();
|
||||
$errores[] = "Fila $fila_numero: Error al insertar - " . $sql_errors[0]['message'];
|
||||
} else {
|
||||
$insertadas++;
|
||||
}
|
||||
}
|
||||
|
||||
fclose($archivo);
|
||||
|
||||
// Preparar mensaje de resultado
|
||||
$mensaje = "✅ Proceso completado:";
|
||||
$mensaje .= "<br>• Registros insertados: $insertadas";
|
||||
if ($omitidas > 0) {
|
||||
$mensaje .= "<br>• Registros omitidos (duplicados): $omitidas";
|
||||
}
|
||||
if (!empty($errores)) {
|
||||
$mensaje .= "<br>• Errores encontrados: " . count($errores);
|
||||
$mensaje .= "<br><br>Detalle de errores:<br>" . implode("<br>", array_slice($errores, 0, 10));
|
||||
if (count($errores) > 10) {
|
||||
$mensaje .= "<br>... y " . (count($errores) - 10) . " errores más.";
|
||||
}
|
||||
}
|
||||
|
||||
// Redirigir con resultado
|
||||
$encoded_message = urlencode($mensaje);
|
||||
header("Location: /IMPORTADORES/claves_pedimentos/lista?imported=ok&message=" . $encoded_message);
|
||||
exit;
|
||||
|
||||
} catch (Exception $e) {
|
||||
die("❌ Error inesperado: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -124,18 +124,17 @@ function guardar()
|
||||
}
|
||||
|
||||
// Captura los datos del formulario
|
||||
$campos = [
|
||||
'clave', 'tipo_identificador', 'curp', 'calle', 'num_exterior', 'num_interior',
|
||||
'ciudad', 'colonia', 'pais', 'codigo_postal', 'municipio', 'estado', 'telefono', 'fax', 'observaciones'
|
||||
];
|
||||
|
||||
$campos = [
|
||||
'clave', 'tipo_identificador', 'curp', 'calle', 'num_exterior', 'num_interior',
|
||||
'ciudad', 'colonia', 'pais', 'codigo_postal', 'municipio', 'estado', 'telefono', 'fax', 'observaciones'
|
||||
];
|
||||
$sql_parts = [];
|
||||
$params = [];
|
||||
|
||||
foreach ($campos as $campo) {
|
||||
if (isset($_POST[$campo]) && $_POST[$campo] !== '') {
|
||||
$sql_parts[] = "$campo = ?";
|
||||
$params[] = $_POST[$campo];
|
||||
$params[] = $_POST[$campo];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +217,7 @@ function guardar()
|
||||
// Confirmar transacción
|
||||
sqlsrv_commit($conn);
|
||||
|
||||
header("Location: /IMPORTADORES/configuracion/index");
|
||||
header("Location: /IMPORTADORES/configuracion/index?updated=ok");
|
||||
exit;
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
170
app/controllers/cove.php
Normal file
170
app/controllers/cove.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
|
||||
/**
|
||||
* GET /IMPORTADORES/cove/ajax_estado_facturas?pedimento_id=123
|
||||
* Devuelve estado de COVE por factura del pedimento actual del usuario.
|
||||
*/
|
||||
function ajax_estado_facturas()
|
||||
{
|
||||
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($_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;
|
||||
}
|
||||
22
app/controllers/debug_paths.php
Normal file
22
app/controllers/debug_paths.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
// Debug para ver rutas
|
||||
echo "<h3>Información de rutas del servidor:</h3>";
|
||||
echo "<p><strong>DOCUMENT_ROOT:</strong> " . $_SERVER['DOCUMENT_ROOT'] . "</p>";
|
||||
echo "<p><strong>SCRIPT_NAME:</strong> " . $_SERVER['SCRIPT_NAME'] . "</p>";
|
||||
echo "<p><strong>REQUEST_URI:</strong> " . $_SERVER['REQUEST_URI'] . "</p>";
|
||||
echo "<p><strong>HTTP_HOST:</strong> " . $_SERVER['HTTP_HOST'] . "</p>";
|
||||
echo "<p><strong>__FILE__:</strong> " . __FILE__ . "</p>";
|
||||
echo "<p><strong>__DIR__:</strong> " . __DIR__ . "</p>";
|
||||
|
||||
// Verificar si los archivos existen
|
||||
$test_file = __DIR__ . '/test_connection.php';
|
||||
$import_file = __DIR__ . '/importar_pedimentos.php';
|
||||
|
||||
echo "<h3>Verificación de archivos:</h3>";
|
||||
echo "<p><strong>test_connection.php:</strong> " . (file_exists($test_file) ? '✅ Existe' : '❌ No existe') . "</p>";
|
||||
echo "<p><strong>importar_pedimentos.php:</strong> " . (file_exists($import_file) ? '✅ Existe' : '❌ No existe') . "</p>";
|
||||
|
||||
echo "<h3>URLs sugeridas:</h3>";
|
||||
$base_url = "http" . (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on" ? "s" : "") . "://" . $_SERVER["HTTP_HOST"];
|
||||
echo "<p><strong>Test URL:</strong> <a href='{$base_url}/IMPORTADORES/app/controllers/test_connection.php' target='_blank'>{$base_url}/IMPORTADORES/app/controllers/test_connection.php</a></p>";
|
||||
?>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/crypto.php';
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
loadEnv();
|
||||
|
||||
// Función para obtener catálogos visibles del usuario
|
||||
function obtenerCatalogosVisibles($idUsuario)
|
||||
@@ -136,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
|
||||
@@ -228,6 +236,21 @@ function vincular()
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener información del importador y la agencia para el correo
|
||||
$infoSql = "SELECT
|
||||
u.nombre AS nombre_importador, u.email AS email_importador,
|
||||
a.nombre_agencia, a.email AS email_agencia,
|
||||
admin.email AS admin_email, admin.nombre AS admin_nombre
|
||||
FROM usuarios_sistema u
|
||||
CROSS JOIN agencias_aduanales a
|
||||
LEFT JOIN usuarios_sistema admin
|
||||
ON a.id_administrador = admin.id_usuario
|
||||
WHERE u.id_usuario = ?
|
||||
AND a.id_agencia = ?
|
||||
";
|
||||
$infoStmt = sqlsrv_query($conn, $infoSql, [$id_importador, $id_agencia]);
|
||||
$info = sqlsrv_fetch_array($infoStmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
// Insertar la nueva solicitud
|
||||
$sql = "INSERT INTO solicitudes_vinculacion
|
||||
(id_importador, id_agencia, mensaje, estado, fecha_solicitud)
|
||||
@@ -237,6 +260,48 @@ function vincular()
|
||||
$stmt = sqlsrv_prepare($conn, $sql, $params);
|
||||
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
// Enviar notificación al administrador de la agencia
|
||||
if (!empty($info['admin_email'])) {
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->isSMTP();
|
||||
$mail->Host = 'secure.emailsrvr.com';
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = 'noreply@aduanasoft.com.mx';
|
||||
$mail->Password = $_ENV['SMTP_PASS'];
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mail->Port = 587;
|
||||
|
||||
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
|
||||
$mail->addAddress($info['admin_email']);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = 'Nueva solicitud de vinculación en SIIH';
|
||||
|
||||
$mail->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
|
||||
<div style='background: linear-gradient(to right, #003366, #0055A5); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white;'>¡Nueva solicitud de vinculación!</h2>
|
||||
</div>
|
||||
<div style='padding: 30px; color: #333; font-size: 16px;'>
|
||||
<p>El importador <strong>{$info['nombre_importador']}</strong> ha solicitado vincularse con su agencia <strong>{$info['nombre_agencia']}</strong>.</p>
|
||||
<p><strong>Correo del importador:</strong> {$info['email_importador']}</p>
|
||||
<p>Por favor, revise la solicitud en su panel de administración para aprobarla o rechazarla.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
";
|
||||
|
||||
$mail->send();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error al enviar correo: " . $mail->ErrorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=sended_request');
|
||||
exit;
|
||||
} else {
|
||||
@@ -257,6 +322,18 @@ function cancelarVinculacion()
|
||||
$id_importador = $_SESSION['usuario_id'];
|
||||
$id_agencia = (int) $_GET['id'];
|
||||
|
||||
// Obtener información para el correo
|
||||
$infoSql = "SELECT
|
||||
u.nombre AS nombre_importador, u.email AS email_importador,
|
||||
a.nombre_agencia
|
||||
FROM solicitudes_vinculacion sv
|
||||
JOIN usuarios_sistema u ON sv.id_importador = u.id_usuario
|
||||
JOIN agencias_aduanales a ON sv.id_agencia = a.id_agencia
|
||||
WHERE sv.id_importador = ? AND sv.id_agencia = ? AND sv.estado = 'PENDIENTE'";
|
||||
|
||||
$infoStmt = sqlsrv_query($conn, $infoSql, [$id_importador, $id_agencia]);
|
||||
$info = sqlsrv_fetch_array($infoStmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
$sql = "UPDATE solicitudes_vinculacion
|
||||
SET estado = 'CANCELADA', fecha_respuesta = GETDATE()
|
||||
WHERE id_importador = ?
|
||||
@@ -267,6 +344,48 @@ function cancelarVinculacion()
|
||||
$stmt = sqlsrv_prepare($conn, $sql, $params);
|
||||
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
// Enviar notificación al importador
|
||||
if (!empty($info['email_importador'])) {
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->isSMTP();
|
||||
$mail->Host = 'secure.emailsrvr.com';
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = 'noreply@aduanasoft.com.mx';
|
||||
$mail->Password = $_ENV['SMTP_PASS'];
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mail->Port = 587;
|
||||
|
||||
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
|
||||
$mail->addAddress($info['email_importador']);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = 'Cancelación de solicitud de vinculación en SIIH';
|
||||
|
||||
$mail->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
|
||||
<div style='background: linear-gradient(to right, #003366, #0055A5); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white;'>Solicitud cancelada</h2>
|
||||
</div>
|
||||
<div style='padding: 30px; color: #333; font-size: 16px;'>
|
||||
<p>Estimado/a <strong>{$info['nombre_importador']}</strong>,</p>
|
||||
<p>Has cancelado tu solicitud de vinculación con la agencia <strong>{$info['nombre_agencia']}</strong>.</p>
|
||||
<p>Si esto fue un error, puedes volver a solicitar la vinculación desde tu panel de importador.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
";
|
||||
|
||||
$mail->send();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error al enviar correo: " . $mail->ErrorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=cancelled');
|
||||
exit;
|
||||
}
|
||||
@@ -289,17 +408,23 @@ function desvincularUsuario()
|
||||
$conn = getConnection();
|
||||
|
||||
try {
|
||||
$stmtActualizarAgencia = null;
|
||||
|
||||
// Iniciar transacción
|
||||
sqlsrv_begin_transaction($conn);
|
||||
|
||||
// 1. Verificar que la relación existe y pertenece a la agencia del admin
|
||||
$sqlVerificar = "SELECT
|
||||
ia.*, u.id_usuario, u.nombre as importador_nombre, aa.nombre_agencia
|
||||
ia.*, u.id_usuario, u.nombre as importador_nombre, u.email as importador_email,
|
||||
aa.nombre_agencia, aa.email as agencia_email,
|
||||
admin.email as admin_email, admin.nombre as admin_nombre
|
||||
FROM importador_agencia ia
|
||||
INNER JOIN usuarios_sistema u
|
||||
ON ia.id_importador = u.id_usuario
|
||||
INNER JOIN agencias_aduanales aa
|
||||
ON ia.id_agencia = aa.id_agencia
|
||||
LEFT JOIN usuarios_sistema admin
|
||||
ON aa.id_administrador = admin.id_usuario
|
||||
WHERE ia.id_relacion = ?
|
||||
AND ia.id_importador = ?
|
||||
";
|
||||
@@ -356,10 +481,103 @@ function desvincularUsuario()
|
||||
}
|
||||
}
|
||||
|
||||
// Enviar notificaciones por correo
|
||||
if (!empty($relacion['importador_email'])) {
|
||||
// Notificación al importador
|
||||
$mailImportador = new PHPMailer(true);
|
||||
try {
|
||||
$mailImportador->isSMTP();
|
||||
$mailImportador->Host = 'secure.emailsrvr.com';
|
||||
$mailImportador->SMTPAuth = true;
|
||||
$mailImportador->Username = 'noreply@aduanasoft.com.mx';
|
||||
$mailImportador->Password = $_ENV['SMTP_PASS'];
|
||||
$mailImportador->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mailImportador->Port = 587;
|
||||
|
||||
$mailImportador->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
|
||||
$mailImportador->addAddress($relacion['importador_email']);
|
||||
$mailImportador->CharSet = 'UTF-8';
|
||||
$mailImportador->isHTML(true);
|
||||
$mailImportador->Subject = 'Confirmación de desvinculación en SIIH';
|
||||
|
||||
$mailImportador->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
|
||||
<div style='background: linear-gradient(to right, #003366, #0055A5); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white;'>Desvinculación completada</h2>
|
||||
</div>
|
||||
<div style='padding: 30px; color: #333; font-size: 16px;'>
|
||||
<p>Estimado/a <strong>{$relacion['importador_nombre']}</strong>,</p>
|
||||
<p>Has sido desvinculado de la agencia <strong>{$relacion['nombre_agencia']}</strong>.</p>
|
||||
<p><strong>Fecha de desvinculación:</strong> " . date('d/m/Y H:i:s') . "</p>
|
||||
<p>Si esto es un error, por favor contacta al administrador de la agencia.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
";
|
||||
|
||||
$mailImportador->send();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error al enviar correo a importador: " . $mailImportador->ErrorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($relacion['admin_email'])) {
|
||||
// Notificación al administrador de la agencia
|
||||
$mailAdmin = new PHPMailer(true);
|
||||
try {
|
||||
$mailAdmin->isSMTP();
|
||||
$mailAdmin->Host = 'secure.emailsrvr.com';
|
||||
$mailAdmin->SMTPAuth = true;
|
||||
$mailAdmin->Username = 'noreply@aduanasoft.com.mx';
|
||||
$mailAdmin->Password = $_ENV['SMTP_PASS'];
|
||||
$mailAdmin->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$mailAdmin->Port = 587;
|
||||
|
||||
$mailAdmin->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
|
||||
$mailAdmin->addAddress($relacion['admin_email']);
|
||||
$mailAdmin->CharSet = 'UTF-8';
|
||||
$mailAdmin->isHTML(true);
|
||||
$mailAdmin->Subject = 'Notificación de desvinculación en SIIH';
|
||||
|
||||
$mailAdmin->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
|
||||
<div style='background: linear-gradient(to right, #003366, #0055A5); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white;'>Notificación de desvinculación</h2>
|
||||
</div>
|
||||
<div style='padding: 30px; color: #333; font-size: 16px;'>
|
||||
<p>Estimado/a <strong>{$relacion['admin_nombre']}</strong>,</p>
|
||||
<p>El importador <strong>{$relacion['importador_nombre']}</strong> se ha desvinculado de su agencia <strong>{$relacion['nombre_agencia']}</strong>.</p>
|
||||
<p><strong>Correo del importador:</strong> {$relacion['importador_email']}</p>
|
||||
<p><strong>Fecha de desvinculación:</strong> " . date('d/m/Y H:i:s') . "</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
";
|
||||
|
||||
$mailAdmin->send();
|
||||
} catch (Exception $e) {
|
||||
error_log("Error al enviar correo a administrador: " . $mailAdmin->ErrorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Limpiar statements
|
||||
sqlsrv_free_stmt($stmtVerificar);
|
||||
sqlsrv_free_stmt($stmtDesactivar);
|
||||
sqlsrv_free_stmt($stmtActualizarAgencia);
|
||||
if (isset($stmtVerificar) && is_resource($stmtVerificar)) {
|
||||
sqlsrv_free_stmt($stmtVerificar);
|
||||
}
|
||||
if (isset($stmtDesactivar) && is_resource($stmtDesactivar)) {
|
||||
sqlsrv_free_stmt($stmtDesactivar);
|
||||
}
|
||||
if (isset($stmtActualizarAgencia) && is_resource($stmtActualizarAgencia)) {
|
||||
sqlsrv_free_stmt($stmtActualizarAgencia);
|
||||
}
|
||||
|
||||
// Confirmar transacción
|
||||
sqlsrv_commit($conn);
|
||||
|
||||
636
app/controllers/importar_pedimentos.php
Normal file
636
app/controllers/importar_pedimentos.php
Normal file
@@ -0,0 +1,636 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
// Headers para AJAX
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
// Log para debugging
|
||||
error_log("=== INICIO IMPORTACIÓN ===");
|
||||
error_log("Usuario ID en sesión: " . (isset($_SESSION['usuario_id']) ? $_SESSION['usuario_id'] : 'NO_USUARIO'));
|
||||
error_log("Tipo usuario: " . (isset($_SESSION['tipo_usuario']) ? $_SESSION['tipo_usuario'] : 'NO_TIPO'));
|
||||
error_log("Método: " . $_SERVER['REQUEST_METHOD']);
|
||||
error_log("Archivos recibidos: " . print_r($_FILES, true));
|
||||
|
||||
// Verificar que el usuario esté logueado
|
||||
if (!isset($_SESSION['usuario_id'])) {
|
||||
error_log("ERROR: Usuario no autenticado - no hay usuario_id en sesión");
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => 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()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
@@ -1112,4 +1112,38 @@ function cambiarPassword()
|
||||
<script>
|
||||
setTimeout(() => { window.location.href = '/IMPORTADORES/login'; }, 4000);
|
||||
</script>";
|
||||
}
|
||||
}
|
||||
|
||||
// MÉTODOS ADICIONALES CON NOMBRES DE RUTA COMPATIBLES
|
||||
|
||||
function enviar_codigo()
|
||||
{
|
||||
// Redirigir al método camelCase existente
|
||||
return enviarCodigo();
|
||||
}
|
||||
|
||||
function verificar_codigo_recuperacion()
|
||||
{
|
||||
// Redirigir al método camelCase existente
|
||||
return verificarCodigo();
|
||||
}
|
||||
|
||||
function reenviar_codigo()
|
||||
{
|
||||
// Redirigir al método camelCase existente
|
||||
return reenviarCodigo();
|
||||
}
|
||||
|
||||
function actualizar_password()
|
||||
{
|
||||
// Redirigir al método camelCase existente
|
||||
return cambiarPassword();
|
||||
}
|
||||
|
||||
function verificar_codigo()
|
||||
{
|
||||
// Mostrar vista de verificar código
|
||||
return verificarCodigoVista();
|
||||
}
|
||||
|
||||
?>
|
||||
677
app/controllers/mve.php
Normal file
677
app/controllers/mve.php
Normal file
@@ -0,0 +1,677 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
|
||||
// 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 = "<html><head><meta charset='utf-8'><style>body{font-family:sans-serif} h1{font-size:18px} .m{font-family:monospace}</style></head><body>"
|
||||
."<h1>Acuse de Manifestación de Valor</h1>"
|
||||
."<p><strong>Pedimento:</strong> <span class='m'>{$display}</span></p>"
|
||||
."<p><strong>RFC:</strong> ".htmlspecialchars($ped['rfc_importador'] ?? '-', ENT_QUOTES, 'UTF-8')."</p>"
|
||||
."<p><strong>Clave:</strong> ".htmlspecialchars($ped['clave_documento'] ?? '-', ENT_QUOTES, 'UTF-8')."</p>"
|
||||
."<p><strong>Generado:</strong> {$now}</p>"
|
||||
."<p>Documento de prueba generado automáticamente.</p>"
|
||||
."</body></html>";
|
||||
|
||||
$htmlDetalle = "<html><head><meta charset='utf-8'><style>body{font-family:sans-serif} h1{font-size:18px} .m{font-family:monospace}</style></head><body>"
|
||||
."<h1>Detalle de Manifestación de Valor</h1>"
|
||||
."<p><strong>Pedimento:</strong> <span class='m'>{$display}</span></p>"
|
||||
."<p>Este es un detalle de ejemplo para pruebas.</p>"
|
||||
."<ul><li>Sección 65/66 capturada (mock)</li><li>Precios pagados y por pagar (mock)</li><li>Compensaciones (mock)</li></ul>"
|
||||
."<p><strong>Generado:</strong> {$now}</p>"
|
||||
."</body></html>";
|
||||
|
||||
// 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';
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
$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 <= 0 || $id_pedimento <= 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
|
||||
return;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
// 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 = ?,
|
||||
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 = ?,
|
||||
|
||||
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,
|
||||
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,
|
||||
|
||||
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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
|
||||
// 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 = [
|
||||
$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,
|
||||
]
|
||||
];
|
||||
|
||||
echo json_encode(['success' => true, 'datos' => $datosEstructurados]);
|
||||
} else {
|
||||
echo json_encode(['success' => true, 'datos' => 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']);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ function lista()
|
||||
}
|
||||
|
||||
// === Consulta de productos frecuentes ===
|
||||
$sql = "SELECT
|
||||
$sql = "SELECT
|
||||
pf.id_producto_frecuente,
|
||||
pf.sinonimo,
|
||||
pf.fraccion,
|
||||
@@ -120,16 +120,16 @@ function lista()
|
||||
pf.estado_mercancia,
|
||||
pf.preferencia,
|
||||
pf.frecuencia_uso
|
||||
FROM dbo.productos_frecuentes pf
|
||||
LEFT JOIN dbo.unidades_medida_apendice7 u
|
||||
FROM dbo.productos_frecuentes pf
|
||||
LEFT JOIN dbo.unidades_medida_apendice7 u
|
||||
ON pf.umc_id = u.id
|
||||
LEFT JOIN dbo.paises por
|
||||
LEFT JOIN dbo.paises por
|
||||
ON pf.pais_origen_destino = por.nombre
|
||||
LEFT JOIN dbo.paises pc
|
||||
LEFT JOIN dbo.paises pc
|
||||
ON pf.pais_comprador_vendedor = pc.nombre
|
||||
WHERE pf.id_importador = ?
|
||||
WHERE pf.id_importador = ?
|
||||
AND pf.status = 1
|
||||
ORDER BY pf.fecha_alta DESC
|
||||
ORDER BY pf.frecuencia_uso DESC
|
||||
";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$_SESSION['usuario_id']]);
|
||||
|
||||
@@ -142,9 +142,9 @@ function lista()
|
||||
$productos = [];
|
||||
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$clave = $row['proveedor_guardado'];
|
||||
$clave = $row['proveedor_guardado'];
|
||||
$row['nombre_proveedor'] = $proveedoresApi[$clave] ?? 'N/D';
|
||||
$productos[] = $row;
|
||||
$productos[] = $row;
|
||||
}
|
||||
|
||||
// === Cargar la vista con productos y nombres de proveedor ===
|
||||
@@ -369,18 +369,20 @@ function guardar()
|
||||
}
|
||||
|
||||
// Convertir valores vacíos a NULL para campos opcionales
|
||||
if ($numero_parte === '') $numero_parte = null;
|
||||
if ($descripcion === '') $descripcion = null;
|
||||
if ($uso_mercancia === '') $uso_mercancia = null;
|
||||
if ($estado_mercancia === '') $estado_mercancia = null;
|
||||
if ($vinculacion === '') $vinculacion = null;
|
||||
if ($observaciones === '') $observaciones = null;
|
||||
if ($preferencia === '') $preferencia = null;
|
||||
if ($criterio_preferencia === '') $criterio_preferencia = null;
|
||||
if ($uso_producto === '') $uso_producto = null;
|
||||
if ($descripcion_producto === '') $descripcion_producto = null;
|
||||
if ($tipo_mercancia === '') $tipo_mercancia = null;
|
||||
if ($proveedor === '') $proveedor = null;
|
||||
if ($numero_parte === '') $numero_parte = null;
|
||||
if ($descripcion === '') $descripcion = null;
|
||||
if ($uso_mercancia === '') $uso_mercancia = null;
|
||||
if ($estado_mercancia === '') $estado_mercancia = null;
|
||||
if ($vinculacion === '') $vinculacion = null;
|
||||
if ($observaciones === '') $observaciones = null;
|
||||
if ($preferencia === '') $preferencia = null;
|
||||
if ($criterio_preferencia === '') $criterio_preferencia = null;
|
||||
if ($uso_producto === '') $uso_producto = null;
|
||||
if ($descripcion_producto === '') $descripcion_producto = null;
|
||||
if ($tipo_mercancia === '') $tipo_mercancia = null;
|
||||
if ($proveedor === '') $proveedor = null;
|
||||
if ($certificado_origen === '') $certificado_origen = null;
|
||||
if ($documento_en_original === '') $documento_en_original = null;
|
||||
|
||||
// INSERT
|
||||
$sql = "INSERT INTO dbo.productos_frecuentes
|
||||
|
||||
@@ -131,6 +131,10 @@ function obtenerConfiguracion($conn)
|
||||
// Función auxiliar para enviar email
|
||||
function enviarEmailConfirmacion($destinatario, $datosEmpresa, $esAgencia = false)
|
||||
{
|
||||
if ($datosEmpresa['status'] !== 'pending') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mail = new PHPMailer(true);
|
||||
|
||||
try {
|
||||
|
||||
@@ -342,4 +342,281 @@ function obtenerCorreos($conn, $id_usuario)
|
||||
}
|
||||
|
||||
return $correos;
|
||||
}
|
||||
|
||||
function ventanillaUnica()
|
||||
{
|
||||
$conn = getConnection();
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
// Asegúrate de que el usuario está autenticado
|
||||
if (!$id_usuario || ($_SESSION['pendiente_confirmacion'] ?? false)) {
|
||||
die("Usuario no autenticado.");
|
||||
}
|
||||
|
||||
// Obtener configuración actual de ventanilla única
|
||||
$configuracion_vu = obtenerConfiguracionVU($conn, $id_usuario);
|
||||
|
||||
include __DIR__ . '/../../views/seguridad/ventanilla_unica.php';
|
||||
}
|
||||
|
||||
function guardarConfiguracionVU()
|
||||
{
|
||||
// Solo ejecutar si es una petición POST
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
if (!$id_usuario || ($_SESSION['pendiente_confirmacion'] ?? false)) {
|
||||
die("No autorizado - Sesión inválida");
|
||||
}
|
||||
|
||||
// Obtener datos del formulario (sin ruta_ejecutable)
|
||||
$clave_fiel = trim($_POST['clave_fiel'] ?? '');
|
||||
$rfc_usuario_vu = trim($_POST['rfc_usuario_vu'] ?? '');
|
||||
$clave_webservice = trim($_POST['clave_webservice'] ?? '');
|
||||
|
||||
// Validar campos obligatorios (sin ruta_ejecutable)
|
||||
if (empty($clave_fiel) || empty($rfc_usuario_vu)) {
|
||||
$_SESSION['config_error'] = 'Los campos Clave FIEL y RFC Usuario VU son obligatorios.';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener configuración actual para conservar archivos existentes
|
||||
$configuracion_actual = obtenerConfiguracionVU($conn, $id_usuario);
|
||||
$ruta_archivo_key = $configuracion_actual['ruta_archivo_key'];
|
||||
$ruta_archivo_cer = $configuracion_actual['ruta_archivo_cer'];
|
||||
|
||||
// Directorio para archivos de certificados
|
||||
$upload_dir = __DIR__ . '/../../storage/certificados/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
}
|
||||
|
||||
// Procesar archivo KEY
|
||||
if (!empty($_FILES['archivo_key']['tmp_name']) && $_FILES['archivo_key']['error'] === UPLOAD_ERR_OK) {
|
||||
$key_extension = pathinfo($_FILES['archivo_key']['name'], PATHINFO_EXTENSION);
|
||||
|
||||
if (strtolower($key_extension) !== 'key') {
|
||||
$_SESSION['config_error'] = 'El archivo KEY debe tener extensión .key';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
$key_filename = 'key_' . $id_usuario . '_' . time() . '.key';
|
||||
$key_destination = $upload_dir . $key_filename;
|
||||
|
||||
if (move_uploaded_file($_FILES['archivo_key']['tmp_name'], $key_destination)) {
|
||||
// Eliminar archivo anterior si existe
|
||||
if ($ruta_archivo_key && file_exists($ruta_archivo_key)) {
|
||||
unlink($ruta_archivo_key);
|
||||
}
|
||||
$ruta_archivo_key = $key_destination;
|
||||
} else {
|
||||
$_SESSION['config_error'] = 'Error al subir el archivo KEY.';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Procesar archivo CER
|
||||
if (!empty($_FILES['archivo_cer']['tmp_name']) && $_FILES['archivo_cer']['error'] === UPLOAD_ERR_OK) {
|
||||
$cer_extension = pathinfo($_FILES['archivo_cer']['name'], PATHINFO_EXTENSION);
|
||||
|
||||
if (strtolower($cer_extension) !== 'cer') {
|
||||
$_SESSION['config_error'] = 'El archivo CER debe tener extensión .cer';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
$cer_filename = 'cer_' . $id_usuario . '_' . time() . '.cer';
|
||||
$cer_destination = $upload_dir . $cer_filename;
|
||||
|
||||
if (move_uploaded_file($_FILES['archivo_cer']['tmp_name'], $cer_destination)) {
|
||||
// Eliminar archivo anterior si existe
|
||||
if ($ruta_archivo_cer && file_exists($ruta_archivo_cer)) {
|
||||
unlink($ruta_archivo_cer);
|
||||
}
|
||||
$ruta_archivo_cer = $cer_destination;
|
||||
} else {
|
||||
$_SESSION['config_error'] = 'Error al subir el archivo CER.';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Validar que se hayan subido los certificados (obligatorios para nueva configuración)
|
||||
if (empty($ruta_archivo_key) || empty($ruta_archivo_cer)) {
|
||||
$_SESSION['config_error'] = 'Los archivos CER y KEY son obligatorios.';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Encriptar las contraseñas sensibles
|
||||
$clave_fiel_encrypted = encrypt($clave_fiel);
|
||||
$clave_webservice_encrypted = !empty($clave_webservice) ? encrypt($clave_webservice) : '';
|
||||
|
||||
// Verificar si ya existe configuración - CORREGIR ERROR SQL
|
||||
$sql_check = "SELECT COUNT(*) as total FROM configuracion_ventanilla_unica WHERE id_usuario = ?";
|
||||
$stmt_check = sqlsrv_query($conn, $sql_check, [$id_usuario]);
|
||||
|
||||
if ($stmt_check === false) {
|
||||
$_SESSION['config_error'] = 'Error en la consulta de configuración: ' . print_r(sqlsrv_errors(), true);
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
$row = sqlsrv_fetch_array($stmt_check, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($row['total'] > 0) {
|
||||
// Actualizar configuración existente (sin ruta_ejecutable)
|
||||
$sql = "UPDATE configuracion_ventanilla_unica SET
|
||||
ruta_archivo_key = ?,
|
||||
ruta_archivo_cer = ?,
|
||||
clave_fiel = ?,
|
||||
rfc_usuario_vu = ?,
|
||||
clave_webservice = ?,
|
||||
fecha_actualizacion = GETDATE()
|
||||
WHERE id_usuario = ?";
|
||||
$params = [
|
||||
$ruta_archivo_key,
|
||||
$ruta_archivo_cer,
|
||||
$clave_fiel_encrypted,
|
||||
$rfc_usuario_vu,
|
||||
$clave_webservice_encrypted,
|
||||
$id_usuario
|
||||
];
|
||||
} else {
|
||||
// Insertar nueva configuración (sin ruta_ejecutable)
|
||||
$sql = "INSERT INTO configuracion_ventanilla_unica
|
||||
(id_usuario, ruta_archivo_key, ruta_archivo_cer,
|
||||
clave_fiel, rfc_usuario_vu, clave_webservice, fecha_creacion)
|
||||
VALUES (?, ?, ?, ?, ?, ?, GETDATE())";
|
||||
$params = [
|
||||
$id_usuario,
|
||||
$ruta_archivo_key,
|
||||
$ruta_archivo_cer,
|
||||
$clave_fiel_encrypted,
|
||||
$rfc_usuario_vu,
|
||||
$clave_webservice_encrypted
|
||||
];
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_prepare($conn, $sql, $params);
|
||||
|
||||
if (!$stmt) {
|
||||
$_SESSION['config_error'] = "Error en la preparación: " . print_r(sqlsrv_errors(), true);
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
$result = sqlsrv_execute($stmt);
|
||||
|
||||
if ($result === false) {
|
||||
$_SESSION['config_error'] = "Error al guardar configuración: " . print_r(sqlsrv_errors(), true);
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
|
||||
$_SESSION['config_success'] = 'Configuración de Ventanilla Única guardada correctamente.';
|
||||
header('Location: /IMPORTADORES/seguridad/ventanillaUnica');
|
||||
exit;
|
||||
}
|
||||
|
||||
function probarConexionVU()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
if (!$id_usuario || ($_SESSION['pendiente_confirmacion'] ?? false)) {
|
||||
echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$configuracion = obtenerConfiguracionVU($conn, $id_usuario);
|
||||
|
||||
// Verificar que todos los campos requeridos estén configurados (sin ruta_ejecutable)
|
||||
if (empty($configuracion['rfc_usuario_vu']) || empty($configuracion['clave_fiel'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Configuración incompleta. Verifica que RFC Usuario VU y Clave FIEL estén configurados.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verificar archivos de certificados
|
||||
if (!empty($configuracion['ruta_archivo_cer']) && !file_exists($configuracion['ruta_archivo_cer'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'El archivo CER no existe en la ruta especificada.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!empty($configuracion['ruta_archivo_key']) && !file_exists($configuracion['ruta_archivo_key'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'El archivo KEY no existe en la ruta especificada.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Verificar que existan ambos archivos de certificados
|
||||
if (empty($configuracion['ruta_archivo_cer']) || empty($configuracion['ruta_archivo_key'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Los archivos CER y KEY son obligatorios para la configuración.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Si llegamos aquí, la configuración es válida
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Configuración válida. Los archivos de certificados existen y todos los campos obligatorios están completos.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
function obtenerConfiguracionVU($conn, $id_usuario)
|
||||
{
|
||||
$configuracion = [
|
||||
'ruta_archivo_key' => '',
|
||||
'ruta_archivo_cer' => '',
|
||||
'clave_fiel' => '',
|
||||
'rfc_usuario_vu' => '',
|
||||
'clave_webservice' => '',
|
||||
'fecha_creacion' => null,
|
||||
'fecha_actualizacion' => null
|
||||
];
|
||||
|
||||
$sql = "SELECT * FROM configuracion_ventanilla_unica WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $sql, [$id_usuario]);
|
||||
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
if ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$configuracion['ruta_archivo_key'] = $row['ruta_archivo_key'] ?? '';
|
||||
$configuracion['ruta_archivo_cer'] = $row['ruta_archivo_cer'] ?? '';
|
||||
$configuracion['rfc_usuario_vu'] = $row['rfc_usuario_vu'] ?? '';
|
||||
|
||||
// Desencriptar contraseñas
|
||||
$configuracion['clave_fiel'] = !empty($row['clave_fiel']) ? decrypt($row['clave_fiel']) : '';
|
||||
$configuracion['clave_webservice'] = !empty($row['clave_webservice']) ? decrypt($row['clave_webservice']) : '';
|
||||
|
||||
$configuracion['fecha_creacion'] = $row['fecha_creacion'];
|
||||
$configuracion['fecha_actualizacion'] = $row['fecha_actualizacion'];
|
||||
}
|
||||
}
|
||||
|
||||
return $configuracion;
|
||||
}
|
||||
@@ -239,6 +239,150 @@ function obtenerChoferesPorTransportista()
|
||||
}
|
||||
}
|
||||
|
||||
function buscar_productos()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// 1. Validar usuario autenticado
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'No autorizado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_importador = $_SESSION['usuario_id'];
|
||||
$query = trim($_GET['q'] ?? '');
|
||||
|
||||
// 2. Validar longitud mínima
|
||||
if (strlen($query) < 2) {
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$conn = getConnection(); // Obtener conexión
|
||||
|
||||
// 3. Búsqueda mejorada con ponderación
|
||||
$searchTerm = "%$query%";
|
||||
$sql = "SELECT TOP 10
|
||||
id_producto_frecuente,
|
||||
sinonimo,
|
||||
descripcion,
|
||||
preferencia,
|
||||
fraccion,
|
||||
nico,
|
||||
numero_parte,
|
||||
CAST(umc_id AS VARCHAR) AS umc_id,
|
||||
-- Campos para cálculo de relevancia
|
||||
CASE
|
||||
WHEN sinonimo LIKE ? THEN 100
|
||||
WHEN descripcion LIKE ? THEN 50
|
||||
ELSE 0
|
||||
END AS relevancia
|
||||
FROM dbo.productos_frecuentes
|
||||
WHERE id_importador = ?
|
||||
AND status = 1
|
||||
AND (sinonimo LIKE ? OR descripcion LIKE ? OR numero_parte LIKE ?)
|
||||
ORDER BY relevancia DESC, frecuencia_uso DESC, sinonimo";
|
||||
|
||||
$params = [
|
||||
"$query%", // Para búsqueda al inicio del sinonimo
|
||||
"$query%", // Para búsqueda al inicio de descripción
|
||||
$id_importador,
|
||||
$searchTerm,
|
||||
$searchTerm,
|
||||
$searchTerm
|
||||
];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
error_log("Error en búsqueda de productos: " . print_r(sqlsrv_errors(), true));
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$productos = [];
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$productos[] = [
|
||||
'id' => $row['id_producto_frecuente'],
|
||||
'sinonimo' => $row['sinonimo'],
|
||||
'descripcion' => $row['descripcion'] ?? '',
|
||||
'preferencia' => $row['preferencia'] ?? '',
|
||||
'fraccion' => $row['fraccion'] ?? '',
|
||||
'nico' => $row['nico'] ?? '',
|
||||
'numero_parte' => $row['numero_parte'] ?? '',
|
||||
'umc_id' => $row['umc_id'] ?? null
|
||||
];
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
echo json_encode($productos);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Excepción en buscar_productos: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Error interno']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
function incrementar_frecuencia()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// 1. Validar usuario
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'error' => 'No autorizado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_importador = $_SESSION['usuario_id'];
|
||||
$producto_id = (int)($_POST['producto_id'] ?? 0);
|
||||
|
||||
if ($producto_id <= 0) {
|
||||
echo json_encode(['success' => false, 'error' => 'ID inválido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$conn = getConnection();
|
||||
|
||||
// 2. Verificar que el producto pertenece al usuario
|
||||
$sqlValidate = "SELECT 1 FROM dbo.productos_frecuentes
|
||||
WHERE id_producto_frecuente = ? AND id_importador = ?";
|
||||
$stmtValidate = sqlsrv_query($conn, $sqlValidate, [$producto_id, $id_importador]);
|
||||
|
||||
if (!$stmtValidate || !sqlsrv_fetch_array($stmtValidate)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['success' => false, 'error' => 'Producto no válido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. Actualizar frecuencia
|
||||
$sqlUpdate = "UPDATE dbo.productos_frecuentes
|
||||
SET frecuencia_uso = frecuencia_uso + 1
|
||||
WHERE id_producto_frecuente = ?";
|
||||
|
||||
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$producto_id]);
|
||||
|
||||
if ($stmtUpdate === false) {
|
||||
error_log("Error actualizando frecuencia: " . print_r(sqlsrv_errors(), true));
|
||||
echo json_encode(['success' => false, 'error' => 'Error en actualización']);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Excepción en incrementar_frecuencia: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => 'Error interno']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/** Procesa la creación de una nueva factura y sus partidas **/
|
||||
function guardar()
|
||||
{
|
||||
@@ -266,6 +410,7 @@ function guardar()
|
||||
$aduana_seccion = $_POST['anexo22_apendice'] ?? null;
|
||||
$num_factura = trim($_POST['numero_factura'] ?? '');
|
||||
$fecha = $_POST['fecha_factura'] ?? null;
|
||||
$pedimento = trim($_POST['pedimento'] ?? ''); // ✅ NUEVO CAMPO
|
||||
$incoterm = $_POST['incoterm'] ?? null;
|
||||
$pais_proveedor = $_POST['pais_proveedor'] ?? null;
|
||||
$tipo_moneda = $_POST['tipo_moneda'] ?? null;
|
||||
@@ -278,9 +423,7 @@ function guardar()
|
||||
$patente_id = $_POST['patente'] ?? null;
|
||||
|
||||
if ($patente_id) {
|
||||
$stmtValidatePatente = sqlsrv_query($conn,
|
||||
"SELECT id_agente FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ? AND activo = 1",
|
||||
[$patente_id, $id_agencia]);
|
||||
$stmtValidatePatente = sqlsrv_query($conn, "SELECT id_agente FROM dbo.agentes_aduanales WHERE id_agente = ? AND id_agencia = ? AND activo = 1", [$patente_id, $id_agencia]);
|
||||
|
||||
if (!$stmtValidatePatente || !sqlsrv_fetch_array($stmtValidatePatente, SQLSRV_FETCH_ASSOC)) {
|
||||
die("❌ La patente seleccionada no es válida para su agencia.");
|
||||
@@ -320,15 +463,16 @@ function guardar()
|
||||
$fotoUrl,
|
||||
$status,
|
||||
$proveedor_clave,
|
||||
$patente_id ? (int)$patente_id : null
|
||||
$patente_id ? (int)$patente_id : null,
|
||||
$pedimento ?: null // ✅ CORREGIDO: Campo pedimento_vinculado al final
|
||||
];
|
||||
$sql = "INSERT INTO dbo.solicitud_importacion_factura
|
||||
(id_importador, id_agencia, aduana, anexo22_apendice, numero_factura,
|
||||
fecha_factura, numero_pedimento, incoterm, pais_proveedor, tipo_moneda,
|
||||
fecha_factura, incoterm, pais_proveedor, tipo_moneda,
|
||||
valor_factura, vinculacion, transportista_id, chofer_id,
|
||||
foto_solicitud_url, status, proveedor_clave, patente_id)
|
||||
foto_solicitud_url, status, proveedor_clave, patente_id, pedimento_vinculado)
|
||||
OUTPUT INSERTED.id_solicitud
|
||||
VALUES(?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
";
|
||||
$stmt = sqlsrv_query($conn, $sql, $params, ['Scrollable' => SQLSRV_CURSOR_KEYSET]);
|
||||
|
||||
@@ -418,9 +562,9 @@ function guardar()
|
||||
if(!empty($_POST['partidas'])&&is_array($_POST['partidas'])){
|
||||
|
||||
$sqlP = "INSERT INTO dbo.solicitud_importacion_partidas
|
||||
(id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
(id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
";
|
||||
$partidas_insertadas = 0; // ← contador
|
||||
|
||||
foreach ($_POST['partidas'] as $i => $p) {
|
||||
@@ -493,46 +637,47 @@ function enviarNotificacionNuevaSolicitud($email, $nombreUsuario, $datosSolicitu
|
||||
</div>' : '';
|
||||
|
||||
$mail->Body = "
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 30px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ccc; border-radius: 10px;'>
|
||||
<div style='background: linear-gradient(to right, #003366, #0055A5); padding: 20px; text-align: center;'>
|
||||
<h2 style='color: white; margin: 0;'>📥 Nueva Solicitud Registrada</h2>
|
||||
</div>
|
||||
<div style='padding: 20px;'>
|
||||
$tipoNotificacion
|
||||
<p>Hola <strong>" . htmlspecialchars($nombreUsuario) . "</strong>,</p>
|
||||
<p>Tu solicitud de importación ha sido registrada correctamente con los siguientes datos:</p>
|
||||
|
||||
<div style='background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 15px 0;'>
|
||||
<table style='width: 100%; border-collapse: collapse;'>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>ID Solicitud:</td>
|
||||
<td style='padding: 5px 0;'>$idSolicitud</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>Número de Factura:</td>
|
||||
<td style='padding: 5px 0;'>$numeroFactura</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>Fecha:</td>
|
||||
<td style='padding: 5px 0;'>$fechaFactura</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>Valor:</td>
|
||||
<td style='padding: 5px 0;'>$valorFactura $tipoMoneda</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 30px;'>
|
||||
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ccc; border-radius: 10px;'>
|
||||
<div style='background: linear-gradient(to right, #003366, #0055A5); padding: 20px; text-align: center;'>
|
||||
h2 style='color: white; margin: 0;'>📥 Nueva Solicitud Registrada</h2>
|
||||
</div>
|
||||
<div style='padding: 20px;'>
|
||||
$tipoNotificacion
|
||||
<p>Hola <strong>" . htmlspecialchars($nombreUsuario) . "</strong>,</p>
|
||||
<p>Tu solicitud de importación ha sido registrada correctamente con los siguientes datos:</p>
|
||||
|
||||
<div style='background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 15px 0;'>
|
||||
<table style='width: 100%; border-collapse: collapse;'>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>ID Solicitud:</td>
|
||||
<td style='padding: 5px 0;'>$idSolicitud</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>Número de Factura:</td>
|
||||
<td style='padding: 5px 0;'>$numeroFactura</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>Fecha:</td>
|
||||
<td style='padding: 5px 0;'>$fechaFactura</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style='padding: 5px 0; font-weight: bold;'>Valor:</td>
|
||||
<td style='padding: 5px 0;'>$valorFactura $tipoMoneda</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p>Puedes consultar el estado de tu solicitud accediendo a tu panel de control.</p>
|
||||
<br>
|
||||
<p style='color: #888; font-size: 14px;'>Si no realizaste esta acción, contacta al administrador del sistema.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 10px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Desarrollado por AduanaSoft
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Puedes consultar el estado de tu solicitud accediendo a tu panel de control.</p>
|
||||
<br>
|
||||
<p style='color: #888; font-size: 14px;'>Si no realizaste esta acción, contacta al administrador del sistema.</p>
|
||||
</div>
|
||||
<div style='background: #e9ecef; text-align: center; padding: 10px; font-size: 13px; color: #666;'>
|
||||
© " . date('Y') . " SIIH · Desarrollado por AduanaSoft
|
||||
</div>
|
||||
</div>
|
||||
</div>";
|
||||
";
|
||||
|
||||
$envioExitoso = $mail->send();
|
||||
|
||||
@@ -733,22 +878,22 @@ function actualizar()
|
||||
$id_agencia
|
||||
];
|
||||
$sqlU = "UPDATE dbo.solicitud_importacion_factura SET
|
||||
aduana = ?,
|
||||
anexo22_apendice = ?,
|
||||
numero_factura = ?,
|
||||
fecha_factura = ?,
|
||||
incoterm = ?,
|
||||
pais_proveedor = ?,
|
||||
tipo_moneda = ?,
|
||||
valor_factura = ?,
|
||||
vinculacion = ?,
|
||||
transportista_id = ?,
|
||||
chofer_id = ?,
|
||||
foto_solicitud_url = ?,
|
||||
status = ?,
|
||||
proveedor_clave = ?,
|
||||
patente_id = ?,
|
||||
updated_at = GETDATE()
|
||||
aduana = ?,
|
||||
anexo22_apendice = ?,
|
||||
numero_factura = ?,
|
||||
fecha_factura = ?,
|
||||
incoterm = ?,
|
||||
pais_proveedor = ?,
|
||||
tipo_moneda = ?,
|
||||
valor_factura = ?,
|
||||
vinculacion = ?,
|
||||
transportista_id = ?,
|
||||
chofer_id = ?,
|
||||
foto_solicitud_url = ?,
|
||||
status = ?,
|
||||
proveedor_clave = ?,
|
||||
patente_id = ?,
|
||||
updated_at = GETDATE()
|
||||
WHERE id_solicitud = ?
|
||||
AND id_importador = ?
|
||||
AND id_agencia = ?
|
||||
@@ -759,20 +904,17 @@ function actualizar()
|
||||
die("❌ Error ejecutando UPDATE: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// 7) Borrar partidas anteriores
|
||||
$del = sqlsrv_query($conn, "DELETE FROM dbo.solicitud_importacion_partidas WHERE id_solicitud = ?", [ $id_solicitud ]);
|
||||
|
||||
if ($del === false) {
|
||||
die("❌ Error borrando partidas previas: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// 8) Reinsertar partidas desde el formulario
|
||||
// 7) Manejo de partidas - Versión mejorada
|
||||
if (!empty($_POST['partidas']) && is_array($_POST['partidas'])) {
|
||||
$sqlP = "INSERT INTO dbo.solicitud_importacion_partidas
|
||||
(id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa,
|
||||
valor_factura, peso_bruto, unidad_comercial_id, tasa_preferencial)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
";
|
||||
// Obtener partidas existentes de la base de datos
|
||||
$partidasExistentes = [];
|
||||
$stmtPartidas = sqlsrv_query($conn, "SELECT id_partida FROM dbo.solicitud_importacion_partidas WHERE id_solicitud = ?", [$id_solicitud]);
|
||||
|
||||
while ($row = sqlsrv_fetch_array($stmtPartidas, SQLSRV_FETCH_ASSOC)) {
|
||||
$partidasExistentes[] = $row['id_partida'];
|
||||
}
|
||||
|
||||
// Procesar cada partida del formulario
|
||||
foreach ($_POST['partidas'] as $i => $p) {
|
||||
$desc = trim($p['descripcion'] ?? '');
|
||||
$cantCom = floatval($p['cantidad_comercial'] ?? 0);
|
||||
@@ -781,29 +923,63 @@ function actualizar()
|
||||
$peso = floatval($p['peso_bruto'] ?? 0);
|
||||
$umId = intval($p['unidad_comercial_id'] ?? 0) ?: null;
|
||||
$tasaPref = trim($p['tasa_preferencial'] ?? '');
|
||||
|
||||
// Sólo inserta si descripción y cantidad comercial válidos
|
||||
|
||||
// Solo procesar si tiene descripción y cantidad válida
|
||||
if ($desc !== '' && $cantCom > 0) {
|
||||
$paramsP = [
|
||||
$id_solicitud,
|
||||
$desc,
|
||||
$cantCom,
|
||||
$cantTar,
|
||||
$valPart,
|
||||
$peso,
|
||||
$umId,
|
||||
$tasaPref
|
||||
];
|
||||
$stmtP = sqlsrv_query($conn, $sqlP, $paramsP);
|
||||
|
||||
if ($stmtP === false) {
|
||||
die("❌ Error insertando partida #$i: " . print_r(sqlsrv_errors(), true));
|
||||
// Verificar si es una partida existente (tiene id_partida numérico > 0)
|
||||
if (!empty($p['id_partida']) && intval($p['id_partida']) > 0) {
|
||||
// ACTUALIZAR partida existente
|
||||
$sql = "UPDATE dbo.solicitud_importacion_partidas SET
|
||||
descripcion = ?,
|
||||
cantidad_comercial = ?,
|
||||
cantidad_tarifa = ?,
|
||||
valor_factura = ?,
|
||||
peso_bruto = ?,
|
||||
unidad_comercial_id = ?,
|
||||
tasa_preferencial = ?
|
||||
WHERE id_partida = ?
|
||||
AND id_solicitud = ?
|
||||
";
|
||||
$params = [ $desc, $cantCom, $cantTar, $valPart, $peso, $umId, $tasaPref, intval($p['id_partida']), $id_solicitud ];
|
||||
|
||||
// Eliminar de la lista de existentes
|
||||
if (($key = array_search($p['id_partida'], $partidasExistentes)) !== false) {
|
||||
unset($partidasExistentes[$key]);
|
||||
}
|
||||
} else {
|
||||
// INSERTAR nueva partida (asegurarse que no tenga id_partida o sea 0)
|
||||
$sql = "INSERT INTO dbo.solicitud_importacion_partidas
|
||||
(id_solicitud, descripcion, cantidad_comercial, cantidad_tarifa, valor_factura,
|
||||
peso_bruto, unidad_comercial_id, tasa_preferencial)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
";
|
||||
$params = [ $id_solicitud, $desc, $cantCom, $cantTar, $valPart, $peso, $umId, $tasaPref ];
|
||||
|
||||
error_log("Insertando nueva partida: " . print_r($params, true));
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
if ($stmt === false) {
|
||||
error_log("Error en consulta SQL: " . print_r(sqlsrv_errors(), true));
|
||||
die("❌ Error procesando partida #$i: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Eliminar partidas que ya no están en el formulario
|
||||
if (!empty($partidasExistentes)) {
|
||||
$ids = implode(',', $partidasExistentes);
|
||||
$sql = "DELETE FROM dbo.solicitud_importacion_partidas
|
||||
WHERE id_partida IN ($ids)
|
||||
AND id_solicitud = ?
|
||||
";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id_solicitud]);
|
||||
if ($stmt === false) {
|
||||
die("❌ Error eliminando partidas obsoletas: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 9) Redirigir
|
||||
// 8) Redirigir
|
||||
header('Location: /IMPORTADORES/solicitud_importacion/lista?updated=ok');
|
||||
exit;
|
||||
}
|
||||
@@ -1056,11 +1232,11 @@ function ajax_lista()
|
||||
|
||||
$dataList[] = [
|
||||
$clave,
|
||||
htmlspecialchars($p['Nombre'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Telefono']?? '', ENT_QUOTES),
|
||||
htmlspecialchars($direccion ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Nombre'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Telefono'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($direccion ?? '', ENT_QUOTES),
|
||||
// Acciones
|
||||
"<a href=\"/IMPORTADORES/proveedores/editar?clave=" . rawurlencode($clave) . "\" class=\"btn btn-sm btn-primary\">✏️</a>
|
||||
<button class=\"btn btn-sm btn-danger\" onclick=\"confirmDelete('{$clave}')\">🗑️</button>"
|
||||
@@ -1117,7 +1293,7 @@ function update_status()
|
||||
ON s.id_importador = u.id_usuario
|
||||
WHERE u.id_usuario = ?
|
||||
AND s.id_solicitud = ?
|
||||
";
|
||||
";
|
||||
$stmtNotif = sqlsrv_prepare($conn, $sqlNotif, [$_SESSION['usuario_id'], $id]);
|
||||
|
||||
if ($stmtNotif && sqlsrv_execute($stmtNotif)) {
|
||||
@@ -1300,27 +1476,27 @@ function update_status()
|
||||
|
||||
// 4.5) Construir el arreglo PHP con la misma estructura JSON que envías
|
||||
$payload = [
|
||||
"id_solicitud" => intval($solicitud['id_solicitud']),
|
||||
"id_importador" => intval($solicitud['id_importador']),
|
||||
"aduana" => strval($solicitud['aduana']),
|
||||
"patente" => strval($solicitud['patente']),
|
||||
"anexo22_apendice" => strval($solicitud['anexo22_apendice']),
|
||||
"numero_factura" => strval($solicitud['numero_factura']),
|
||||
"fecha_factura" => $fechaFactura,
|
||||
"numero_pedimento" => "", // La API lo rellenará
|
||||
"incoterm" => strval($solicitud['incoterm']),
|
||||
"pais_proveedor" => strval($solicitud['pais_proveedor']),
|
||||
"tipo_moneda" => strval($solicitud['tipo_moneda']),
|
||||
"valor_factura" => floatval($solicitud['valor_factura']),
|
||||
"vinculacion" => intval($solicitud['vinculacion']),
|
||||
"transportista_id" => intval($solicitud['transportista_id']),
|
||||
"created_at" => $createdAt,
|
||||
"updated_at" => $updatedAt,
|
||||
"transporte_id" => null,
|
||||
"chofer_id" => intval($solicitud['chofer_id']),
|
||||
"foto_solicitud_url"=> strval($solicitud['foto_solicitud_url']),
|
||||
"proveedor_clave" => strval($solicitud['proveedor_clave']),
|
||||
"partidas" => $partidas
|
||||
"id_solicitud" => intval($solicitud['id_solicitud']),
|
||||
"id_importador" => intval($solicitud['id_importador']),
|
||||
"aduana" => strval($solicitud['aduana']),
|
||||
"patente" => strval($solicitud['patente']),
|
||||
"anexo22_apendice" => strval($solicitud['anexo22_apendice']),
|
||||
"numero_factura" => strval($solicitud['numero_factura']),
|
||||
"fecha_factura" => $fechaFactura,
|
||||
"numero_pedimento" => "", // La API lo rellenará
|
||||
"incoterm" => strval($solicitud['incoterm']),
|
||||
"pais_proveedor" => strval($solicitud['pais_proveedor']),
|
||||
"tipo_moneda" => strval($solicitud['tipo_moneda']),
|
||||
"valor_factura" => floatval($solicitud['valor_factura']),
|
||||
"vinculacion" => intval($solicitud['vinculacion']),
|
||||
"transportista_id" => intval($solicitud['transportista_id']),
|
||||
"created_at" => $createdAt,
|
||||
"updated_at" => $updatedAt,
|
||||
"transporte_id" => null,
|
||||
"chofer_id" => intval($solicitud['chofer_id']),
|
||||
"foto_solicitud_url" => strval($solicitud['foto_solicitud_url']),
|
||||
"proveedor_clave" => strval($solicitud['proveedor_clave']),
|
||||
"partidas" => $partidas
|
||||
];
|
||||
$jsonPayload = json_encode($payload);
|
||||
|
||||
@@ -1688,7 +1864,8 @@ function pdf() {
|
||||
}
|
||||
|
||||
// NUEVA FUNCIÓN: Obtener información del proveedor por clave
|
||||
function obtenerProveedorPorClave($clave) {
|
||||
function obtenerProveedorPorClave($clave)
|
||||
{
|
||||
// Obtener token de la API
|
||||
$token = getApiToken();
|
||||
if (!$token) {
|
||||
@@ -1736,7 +1913,8 @@ function obtenerProveedorPorClave($clave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = null) {
|
||||
function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info = null)
|
||||
{
|
||||
// Formatear fecha
|
||||
$fecha_expedicion = $solicitud['fecha_factura']->format('d/m/Y');
|
||||
$fecha_vencimiento = $solicitud['fecha_factura']->modify('+30 days')->format('d/m/Y');
|
||||
@@ -1792,7 +1970,7 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info =
|
||||
$unidades = ['', 'uno', 'dos', 'tres', 'cuatro', 'cinco', 'seis', 'siete', 'ocho', 'nueve'];
|
||||
$decenas = ['', '', 'veinte', 'treinta', 'cuarenta', 'cincuenta', 'sesenta', 'setenta', 'ochenta', 'noventa'];
|
||||
$especiales = ['diez', 'once', 'doce', 'trece', 'catorce', 'quince', 'dieciséis', 'diecisiete', 'dieciocho', 'diecinueve'];
|
||||
$centenas = ['', 'ciento', 'doscientos', 'trescientos', 'cuatrocientos', 'quinientos', 'seiscientos', 'setecientos', 'ochocientos', 'novecientos'];
|
||||
$centenas = ['', 'ciento', 'doscientos', 'trescientos', 'cuatrocientos', 'quinientos', 'seiscientos', 'setecientos', 'ochocientos'];
|
||||
|
||||
if ($numero == 0) return 'cero';
|
||||
if ($numero == 100) return 'cien';
|
||||
@@ -1877,162 +2055,248 @@ function generarHTMLPDF($solicitud, $partidas, $configuracion, $proveedor_info =
|
||||
}
|
||||
|
||||
$html = '
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Solicitud de Importación</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; font-size: 9px; margin: 0; padding: 15px; line-height: 1.2; }
|
||||
/** Encabezado **/
|
||||
.header { padding-bottom: 50px; }
|
||||
.logo-section { width: 20%; text-align: left; }
|
||||
.logo { max-width: 125px; height: auto; vertical-align: top; }
|
||||
.company-info { width: 60%; text-align: center; vertical-align: top; font-size: 12px; }
|
||||
.company-name { font-weight: bold; font-size: 25px; margin-bottom: 3px; }
|
||||
.invoice-info { width: 20%; text-align: right; vertical-align: top; font-size: 12px; }
|
||||
/** Sección de Información **/
|
||||
.info-section { border: 1px solid black; border-collapse: collapse; width: 100%; table-layout: fixed; }
|
||||
.clave-section { border: 0.5px solid black; border-collapse: collapse; width: 100%; table-layout: fixed; padding-bottom: 15px; }
|
||||
/** Información del Proveedor **/
|
||||
.proveedor-info { width: 100%; }
|
||||
.provedor-info table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
||||
.p-field { width: 100px; background-color: #d0d0d0; font-weight: bold; text-align: center; font-size: 12px; }
|
||||
.field { border-bottom: 0.5px solid #000; padding: 5px; font-size: 12px; }
|
||||
/** Fechas **/
|
||||
.dates-info { width: 25%; border: 1px solid #000; }
|
||||
.dates-info table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
||||
.d-field { background-color: #d0d0d0; font-weight: bold; text-align: center; font-size: 12px; }
|
||||
.date { font-weight: bold; text-align: center; font-size: 12px; padding: 7.5px; }
|
||||
/** Partidas **/
|
||||
.products-table { border-collapse: collapse; border: 0.5px solid #000; }
|
||||
.products-table td { border: 0.5px solid #000; padding: 10px; text-align: center; font-size: 10px; }
|
||||
.products-table th { border: 0.5px solid #000; padding: 5px; background-color: #d0d0d0; font-weight: bold; text-align: center; }
|
||||
.text-center { text-align: center; }
|
||||
.text-right { text-align: right; }
|
||||
.font-bold { font-weight: bold; }
|
||||
/** Total **/
|
||||
.totals-section { float: right; width: 250px; }
|
||||
.total-row { display: flex; justify-content: space-between; margin-top: 25px; font-size: 12px; }
|
||||
/** Nota inferior **/
|
||||
.footer-info { }
|
||||
.footer-note { font-size: 10px; background-color: #d0d0d0; padding: 5px; border: 0.5px solid #000; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- ENCABEZADO -->
|
||||
<table class="header" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td class="logo-section">
|
||||
<img src="' . htmlspecialchars($configuracion['logo_url'] ?? 'assets/img/logo_siih.png') . '" alt="Logo" class="logo"><br>
|
||||
</td>
|
||||
<td class="company-info">
|
||||
<div class="company-name">' . htmlspecialchars($solicitud['importador_nombre']) . '</div>
|
||||
<div>' . htmlspecialchars($direccion_completa ?: 'Dirección no disponible') . '</div>
|
||||
<div>RFC: ' . htmlspecialchars($solicitud['importador_rfc'] ?? 'No disponible') . '</div>
|
||||
<div>Tel: ' . htmlspecialchars($solicitud['telefono'] ?? 'No disponible') . '</div>
|
||||
<div>Email: ' . htmlspecialchars($solicitud['correo'] ?? 'No disponible') . '</div>
|
||||
</td>
|
||||
<td class="invoice-info">
|
||||
<div><strong>' . htmlspecialchars($configuracion['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos') . '</strong></div><br>
|
||||
<div class="invoice-title">Solicitud de Importación</div>
|
||||
<div><strong>No. ' . htmlspecialchars($solicitud['id_solicitud']) . '</strong></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Solicitud de Importación</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; font-size: 9px; margin: 0; padding: 15px; line-height: 1.2; }
|
||||
/** Encabezado **/
|
||||
.header { padding-bottom: 50px; }
|
||||
.logo-section { width: 20%; text-align: left; }
|
||||
.logo { max-width: 125px; height: auto; vertical-align: top; }
|
||||
.company-info { width: 60%; text-align: center; vertical-align: top; font-size: 12px; }
|
||||
.company-name { font-weight: bold; font-size: 25px; margin-bottom: 3px; }
|
||||
.invoice-info { width: 20%; text-align: right; vertical-align: top; font-size: 12px; }
|
||||
/** Sección de Información **/
|
||||
.info-section { border: 1px solid black; border-collapse: collapse; width: 100%; table-layout: fixed; }
|
||||
.clave-section { border: 0.5px solid black; border-collapse: collapse; width: 100%; table-layout: fixed; padding-bottom: 15px; }
|
||||
/** Información del Proveedor **/
|
||||
.proveedor-info { width: 100%; }
|
||||
.provedor-info table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
||||
.p-field { width: 100px; background-color: #d0d0d0; font-weight: bold; text-align: center; font-size: 12px; }
|
||||
.field { border-bottom: 0.5px solid #000; padding: 5px; font-size: 12px; }
|
||||
/** Fechas **/
|
||||
.dates-info { width: 25%; border: 1px solid #000; }
|
||||
.dates-info table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
||||
.d-field { background-color: #d0d0d0; font-weight: bold; text-align: center; font-size: 12px; }
|
||||
.date { font-weight: bold; text-align: center; font-size: 12px; padding: 7.5px; }
|
||||
/** Partidas **/
|
||||
.products-table { border-collapse: collapse; border: 0.5px solid #000; }
|
||||
.products-table td { border: 0.5px solid #000; padding: 10px; text-align: center; font-size: 10px; }
|
||||
.products-table th { border: 0.5px solid #000; padding: 5px; background-color: #d0d0d0; font-weight: bold; text-align: center; }
|
||||
.text-center { text-align: center; }
|
||||
.text-right { text-align: right; }
|
||||
.font-bold { font-weight: bold; }
|
||||
/** Total **/
|
||||
.totals-section { float: right; width: 250px; }
|
||||
.total-row { display: flex; justify-content: space-between; margin-top: 25px; font-size: 12px; }
|
||||
/** Nota inferior **/
|
||||
.footer-info { }
|
||||
.footer-note { font-size: 10px; background-color: #d0d0d0; padding: 5px; border: 0.5px solid #000; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- ENCABEZADO -->
|
||||
<table class="header" cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td class="logo-section">
|
||||
<img src="' . htmlspecialchars($configuracion['logo_url'] ?? 'assets/img/logo_siih.png') . '" alt="Logo" class="logo"><br>
|
||||
</td>
|
||||
<td class="company-info">
|
||||
<div class="company-name">' . htmlspecialchars($solicitud['importador_nombre']) . '</div>
|
||||
<div>' . htmlspecialchars($direccion_completa ?: 'Dirección no disponible') . '</div>
|
||||
<div>RFC: ' . htmlspecialchars($solicitud['importador_rfc'] ?? 'No disponible') . '</div>
|
||||
<div>Tel: ' . htmlspecialchars($solicitud['telefono'] ?? 'No disponible') . '</div>
|
||||
<div>Email: ' . htmlspecialchars($solicitud['correo'] ?? 'No disponible') . '</div>
|
||||
</td>
|
||||
<td class="invoice-info">
|
||||
<div><strong>' . htmlspecialchars($configuracion['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos') . '</strong></div><br>
|
||||
<div class="invoice-title">Solicitud de Importación</div>
|
||||
<div><strong>No. ' . htmlspecialchars($solicitud['id_solicitud']) . '</strong></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- SECCIÓN DE INFORMACIÓN DEL PROVEEDOR Y FECHAS -->
|
||||
<table class="info-section" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<!-- PROVEEDOR -->
|
||||
<td>
|
||||
<table class="proveedor-info" cellspacing="0" cellpadding="0">
|
||||
<!-- SECCIÓN DE INFORMACIÓN DEL PROVEEDOR Y FECHAS -->
|
||||
<table class="info-section" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<!-- PROVEEDOR -->
|
||||
<td>
|
||||
<table class="proveedor-info" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field">RAZÓN SOCIAL:</td>
|
||||
<td class="field">' . htmlspecialchars($proveedor_nombre) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="proveedor-info" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field" style="height: 45px;">DIRECCIÓN:</td>
|
||||
<td class="field">' . htmlspecialchars($proveedor_direccion) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="proveedor-info" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field">RFC:</td>
|
||||
<td class="field" style="border-bottom: none;">' . htmlspecialchars($proveedor_rfc) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<!-- FECHAS -->
|
||||
<td class="dates-info">
|
||||
<table cellspacing="0" cellpadding="2">
|
||||
<tr><td class="d-field" style="border-left: 0.5px solid black;">FECHA DE EXPEDICIÓN</td></tr>
|
||||
<tr><td class="date" style="border-bottom: 0.5px solid black;">' . $fecha_expedicion . '</td></tr>
|
||||
<tr><td class="d-field" style="border-left: 0.5px solid black;">FECHA DE VENCIMIENTO</td></tr>
|
||||
<tr><td class="date">' . $fecha_vencimiento . '</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="clave-section" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field">CLAVE:</td>
|
||||
<td class="field" style="border-bottom: none;">' . htmlspecialchars($solicitud['proveedor_clave'] ?? 'No disponible') . '</td>
|
||||
<td class="p-field">TELÉFONO:</td>
|
||||
<td class="field" style="border-bottom: none;">' . htmlspecialchars($proveedor_telefono) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- TABLA DE PRODUCTOS/PARTIDAS -->
|
||||
<table class="products-table" cellspacing="0" cellpadding="0" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="p-field">RAZÓN SOCIAL:</td>
|
||||
<td class="field">' . htmlspecialchars($proveedor_nombre) . '</td>
|
||||
<th>Producto</th>
|
||||
<th>Unidad de Medida</th>
|
||||
<th>Precio Unitario</th>
|
||||
<th>Cantidad</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="proveedor-info" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field" style="height: 45px;">DIRECCIÓN:</td>
|
||||
<td class="field">' . htmlspecialchars($proveedor_direccion) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="proveedor-info" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field">RFC:</td>
|
||||
<td class="field" style="border-bottom: none;">' . htmlspecialchars($proveedor_rfc) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<!-- FECHAS -->
|
||||
<td class="dates-info">
|
||||
<table cellspacing="0" cellpadding="2">
|
||||
<tr><td class="d-field" style="border-left: 0.5px solid black;">FECHA DE EXPEDICIÓN</td></tr>
|
||||
<tr><td class="date" style="border-bottom: 0.5px solid black;">' . $fecha_expedicion . '</td></tr>
|
||||
<tr><td class="d-field" style="border-left: 0.5px solid black;">FECHA DE VENCIMIENTO</td></tr>
|
||||
<tr><td class="date">' . $fecha_vencimiento . '</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="clave-section" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td class="p-field">CLAVE:</td>
|
||||
<td class="field" style="border-bottom: none;">' . htmlspecialchars($solicitud['proveedor_clave'] ?? 'No disponible') . '</td>
|
||||
<td class="p-field">TELÉFONO:</td>
|
||||
<td class="field" style="border-bottom: none;">' . htmlspecialchars($proveedor_telefono) . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
<!-- TABLA DE PRODUCTOS/PARTIDAS -->
|
||||
<table class="products-table" cellspacing="0" cellpadding="0" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Producto</th>
|
||||
<th>Unidad de Medida</th>
|
||||
<th>Precio Unitario</th>
|
||||
<th>Cantidad</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
// Agregar partidas
|
||||
foreach ($partidas as $partida) {
|
||||
$precio_unitario = (float)($partida['precio_unitario'] ?? 0);
|
||||
$cantidad = (float)($partida['cantidad_comercial'] ?? 0);
|
||||
$valor_partida = (float)($partida['valor_factura'] ?? 0);
|
||||
|
||||
$html .= '
|
||||
<tr>
|
||||
<td>' . htmlspecialchars($partida['descripcion']) . '</td>
|
||||
<td>' . htmlspecialchars($partida['unidad_descripcion'] ?? 'Unidad de servicio (E48)') . '</td>
|
||||
<td>' . $moneda_codigo . ' ' . number_format($precio_unitario > 0 ? $precio_unitario : $valor_partida, 2) . '</td>
|
||||
<td>' . number_format($cantidad > 0 ? $cantidad : 1, 0) . '</td>
|
||||
<td>' . $moneda_codigo . ' ' . number_format($valor_partida, 2) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
// Agregar partidas
|
||||
foreach ($partidas as $partida) {
|
||||
$precio_unitario = (float)($partida['precio_unitario'] ?? 0);
|
||||
$cantidad = (float)($partida['cantidad_comercial'] ?? 0);
|
||||
$valor_partida = (float)($partida['valor_factura'] ?? 0);
|
||||
|
||||
$html .= '
|
||||
<tr>
|
||||
<td>' . htmlspecialchars($partida['descripcion']) . '</td>
|
||||
<td>' . htmlspecialchars($partida['unidad_descripcion'] ?? 'Unidad de servicio (E48)') . '</td>
|
||||
<td>' . $moneda_codigo . ' ' . number_format($precio_unitario > 0 ? $precio_unitario : $valor_partida, 2) . '</td>
|
||||
<td>' . number_format($cantidad > 0 ? $cantidad : 1, 0) . '</td>
|
||||
<td>' . $moneda_codigo . ' ' . number_format($valor_partida, 2) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
$html .= '
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
$html .= '
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- NOTA INFERIOR -->
|
||||
<div class="footer-info">
|
||||
<div class="footer-note">' . $total_texto . '</div>
|
||||
</div>
|
||||
|
||||
<!-- NOTA INFERIOR -->
|
||||
<div class="footer-info">
|
||||
<div class="footer-note">' . $total_texto . '</div>
|
||||
</div>
|
||||
<!-- TOTALES -->
|
||||
<div class="totals-section">
|
||||
<div class="total-row text-right">
|
||||
<span><strong>Total:</strong></span>
|
||||
<span><strong>' . $moneda_codigo . ' ' . number_format($total, 2) . '</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TOTALES -->
|
||||
<div class="totals-section">
|
||||
<div class="total-row text-right">
|
||||
<span><strong>Total:</strong></span>
|
||||
<span><strong>' . $moneda_codigo . ' ' . number_format($total, 2) . '</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>';
|
||||
</body>
|
||||
</html>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
// NUEVO ENDPOINT: Pedimentos de catálogo activos del importador para panel de referencia
|
||||
function ajax_pedimentos_catalogo()
|
||||
{
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['data' => []]);
|
||||
exit;
|
||||
}
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : 10;
|
||||
$conn = getConnection();
|
||||
// Obtener RFC del importador
|
||||
$sqlImportador = "SELECT rfc FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
|
||||
if ($stmtImportador === false) {
|
||||
echo json_encode(['data' => []]);
|
||||
exit;
|
||||
}
|
||||
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
|
||||
if (!$importador) {
|
||||
echo json_encode(['data' => []]);
|
||||
exit;
|
||||
}
|
||||
// Obtener pedimentos activos del catálogo
|
||||
$sql = "SELECT TOP {$limit} IdPrevio, Pedimento, ClienteNombre, ClavePed, Timestamp
|
||||
FROM PREVIOS_COMPARTIDOS_WS
|
||||
WHERE ClienteRFC = ? AND Status = 1
|
||||
ORDER BY Timestamp DESC";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$importador['rfc']]);
|
||||
$pedimentos = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$fecha = '';
|
||||
if ($row['Timestamp'] instanceof DateTime) {
|
||||
$fecha = $row['Timestamp']->format('d/m/Y');
|
||||
}
|
||||
$pedimentos[] = [
|
||||
'numero' => $row['Pedimento'],
|
||||
'cliente' => $row['ClienteNombre'],
|
||||
'clave' => $row['ClavePed'],
|
||||
'fecha' => $fecha
|
||||
];
|
||||
}
|
||||
}
|
||||
echo json_encode(['data' => $pedimentos]);
|
||||
exit;
|
||||
}
|
||||
|
||||
function ajax_facturas_por_pedimento() {
|
||||
header('Content-Type: application/json');
|
||||
$id_previo = isset($_GET['id_pedimento']) ? trim($_GET['id_pedimento']) : '';
|
||||
if (!$id_previo) {
|
||||
echo json_encode(['success' => false, 'error' => 'ID de pedimento no válido']);
|
||||
return;
|
||||
}
|
||||
$conn = getConnection();
|
||||
// 1. Buscar el número de pedimento real en PREVIOS_COMPARTIDOS_WS
|
||||
$stmt = sqlsrv_query($conn, "SELECT Pedimento FROM PREVIOS_COMPARTIDOS_WS WHERE IdPrevio = ?", [$id_previo]);
|
||||
if ($stmt === false || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) {
|
||||
echo json_encode(['success' => false, 'error' => 'No se encontró el pedimento en PREVIOS_COMPARTIDOS_WS']);
|
||||
return;
|
||||
}
|
||||
$numero_pedimento = $row['Pedimento'];
|
||||
|
||||
// 2. Buscar las facturas en solicitud_importacion_factura usando el número de pedimento
|
||||
// ✅ CORREGIDO: Incluir id_solicitud como id_factura
|
||||
$stmt2 = sqlsrv_query($conn, "SELECT id_solicitud, numero_factura, fecha_factura, valor_factura FROM solicitud_importacion_factura WHERE numero_pedimento = ?", [$numero_pedimento]);
|
||||
if ($stmt2 === false) {
|
||||
echo json_encode(['success' => false, 'error' => 'Error en la consulta de facturas']);
|
||||
return;
|
||||
}
|
||||
|
||||
$facturas = [];
|
||||
while ($row2 = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_ASSOC)) {
|
||||
$facturas[] = [
|
||||
'id_factura' => $row2['id_solicitud'], // ✅ AGREGADO: Usar id_solicitud como id_factura
|
||||
'numero_factura' => $row2['numero_factura'],
|
||||
'fecha' => ($row2['fecha_factura'] instanceof DateTime) ? $row2['fecha_factura']->format('Y-m-d') : $row2['fecha_factura'],
|
||||
'monto' => $row2['valor_factura']
|
||||
];
|
||||
}
|
||||
echo json_encode(['success' => true, 'facturas' => $facturas]);
|
||||
}
|
||||
913
app/controllers/templates_rapidos.php
Normal file
913
app/controllers/templates_rapidos.php
Normal file
@@ -0,0 +1,913 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
|
||||
function index()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/templates_rapidos/index.php';
|
||||
}
|
||||
|
||||
function lista()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/templates_rapidos/lista.php';
|
||||
}
|
||||
|
||||
function crear()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
// Obtener datos para los selects
|
||||
$aduanas = obtenerAduanas($conn);
|
||||
$patentes = obtenerPatentes($conn);
|
||||
$incoterms = obtenerIncoterms($conn);
|
||||
$paises = obtenerPaises($conn);
|
||||
$transportistas = obtenerTransportistas($conn);
|
||||
$choferes = obtenerChoferes($conn);
|
||||
$unidades_medida = obtenerUnidadesMedida($conn);
|
||||
|
||||
include __DIR__ . '/../../views/templates_rapidos/crear.php';
|
||||
}
|
||||
|
||||
function guardar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
// Obtener datos del formulario
|
||||
$nombre = trim($_POST['nombre'] ?? '');
|
||||
$descripcion = trim($_POST['descripcion'] ?? '');
|
||||
$icono = trim($_POST['icono'] ?? '🏢');
|
||||
|
||||
// Configuración del template
|
||||
$config = [
|
||||
'tipo_moneda' => $_POST['tipo_moneda'] ?? '',
|
||||
'incoterm' => $_POST['incoterm'] ?? '',
|
||||
'vinculacion' => $_POST['vinculacion'] ?? '',
|
||||
'pais_proveedor' => $_POST['pais_proveedor'] ?? '',
|
||||
'pais_proveedor_texto' => $_POST['pais_proveedor_texto'] ?? '',
|
||||
'anexo22_apendice' => $_POST['anexo22_apendice'] ?? '',
|
||||
'patente' => $_POST['patente'] ?? '',
|
||||
'transportista_id' => $_POST['transportista_id'] ?? '',
|
||||
'chofer_id' => $_POST['chofer_id'] ?? '',
|
||||
'tasa_preferencial' => $_POST['tasa_preferencial'] ?? '',
|
||||
'unidad_comercial_id' => $_POST['unidad_comercial_id'] ?? ''
|
||||
];
|
||||
|
||||
$config_json = json_encode($config, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// Validaciones
|
||||
if (empty($nombre)) {
|
||||
die("❌ El nombre del template es obligatorio.");
|
||||
}
|
||||
|
||||
if (strlen($nombre) > 100) {
|
||||
die("❌ El nombre del template es muy largo (máximo 100 caracteres).");
|
||||
}
|
||||
|
||||
$sql = "INSERT INTO dbo.templates_rapidos
|
||||
(nombre, descripcion, icono, config_json, tipo_moneda, incoterm,
|
||||
vinculacion, pais_proveedor, tasa_preferencial, id_agencia, id_usuario_creador)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$params = [
|
||||
$nombre,
|
||||
$descripcion,
|
||||
$icono,
|
||||
$config_json,
|
||||
$config['tipo_moneda'],
|
||||
$config['incoterm'],
|
||||
$config['vinculacion'] ?: null,
|
||||
$config['pais_proveedor'],
|
||||
$config['tasa_preferencial'],
|
||||
$id_agencia,
|
||||
$id_usuario
|
||||
];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al guardar template: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/templates_rapidos/lista?created=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function editar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
// Obtener el template
|
||||
$sql = "SELECT * FROM dbo.templates_rapidos
|
||||
WHERE id = ? AND (id_usuario_creador = ? OR id_agencia = ? OR id_agencia IS NULL)";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id, $id_usuario, $id_agencia]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error en consulta: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$template = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$template) {
|
||||
die("❌ Template no encontrado o sin permisos.");
|
||||
}
|
||||
|
||||
// Decodificar configuración JSON
|
||||
$template['config'] = json_decode($template['config_json'], true) ?: [];
|
||||
|
||||
// Obtener datos para los selects
|
||||
$conn = getConnection();
|
||||
$aduanas = obtenerAduanas($conn);
|
||||
$patentes = obtenerPatentes($conn);
|
||||
$incoterms = obtenerIncoterms($conn);
|
||||
$paises = obtenerPaises($conn);
|
||||
$transportistas = obtenerTransportistas($conn);
|
||||
$choferes = obtenerChoferes($conn);
|
||||
$unidades_medida = obtenerUnidadesMedida($conn);
|
||||
|
||||
include __DIR__ . '/../../views/templates_rapidos/editar.php';
|
||||
}
|
||||
|
||||
function actualizar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
$id = $_POST['id'] ?? null;
|
||||
$nombre = trim($_POST['nombre'] ?? '');
|
||||
$descripcion = trim($_POST['descripcion'] ?? '');
|
||||
$icono = trim($_POST['icono'] ?? '🏢');
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
// Configuración del template
|
||||
$config = [
|
||||
'tipo_moneda' => $_POST['tipo_moneda'] ?? '',
|
||||
'incoterm' => $_POST['incoterm'] ?? '',
|
||||
'vinculacion' => $_POST['vinculacion'] ?? '',
|
||||
'pais_proveedor' => $_POST['pais_proveedor'] ?? '',
|
||||
'pais_proveedor_texto' => $_POST['pais_proveedor_texto'] ?? '',
|
||||
'anexo22_apendice' => $_POST['anexo22_apendice'] ?? '',
|
||||
'patente' => $_POST['patente'] ?? '',
|
||||
'transportista_id' => $_POST['transportista_id'] ?? '',
|
||||
'chofer_id' => $_POST['chofer_id'] ?? '',
|
||||
'tasa_preferencial' => $_POST['tasa_preferencial'] ?? '',
|
||||
'unidad_comercial_id' => $_POST['unidad_comercial_id'] ?? ''
|
||||
];
|
||||
|
||||
$config_json = json_encode($config, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// Validaciones
|
||||
if (empty($nombre)) {
|
||||
die("❌ El nombre del template es obligatorio.");
|
||||
}
|
||||
|
||||
// Verificar permisos
|
||||
$sqlCheck = "SELECT id FROM dbo.templates_rapidos
|
||||
WHERE id = ? AND (id_usuario_creador = ? OR id_agencia = ?)";
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id, $id_usuario, $id_agencia]);
|
||||
$exists = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$exists) {
|
||||
die("❌ Template no encontrado o sin permisos para editarlo.");
|
||||
}
|
||||
|
||||
$sql = "UPDATE dbo.templates_rapidos SET
|
||||
nombre = ?, descripcion = ?, icono = ?, config_json = ?,
|
||||
tipo_moneda = ?, incoterm = ?, vinculacion = ?,
|
||||
pais_proveedor = ?, tasa_preferencial = ?, fecha_modificacion = GETDATE()
|
||||
WHERE id = ?";
|
||||
|
||||
$params = [
|
||||
$nombre,
|
||||
$descripcion,
|
||||
$icono,
|
||||
$config_json,
|
||||
$config['tipo_moneda'],
|
||||
$config['incoterm'],
|
||||
$config['vinculacion'] ?: null,
|
||||
$config['pais_proveedor'],
|
||||
$config['tasa_preferencial'],
|
||||
$id
|
||||
];
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al actualizar template: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/templates_rapidos/lista?updated=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function eliminar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id || !is_numeric($id)) {
|
||||
die("❌ ID inválido.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
// Verificar permisos
|
||||
$sqlCheck = "SELECT id FROM dbo.templates_rapidos
|
||||
WHERE id = ? AND (id_usuario_creador = ? OR id_agencia = ?)";
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$id, $id_usuario, $id_agencia]);
|
||||
$exists = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$exists) {
|
||||
die("❌ Template no encontrado o sin permisos para eliminarlo.");
|
||||
}
|
||||
|
||||
$sql = "UPDATE dbo.templates_rapidos SET activo = 0 WHERE id = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al eliminar template: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
header('Location: /IMPORTADORES/templates_rapidos/lista?deleted=ok');
|
||||
exit;
|
||||
}
|
||||
|
||||
function ajax_lista()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(403);
|
||||
echo json_encode([]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
$conn = getConnection();
|
||||
|
||||
// Parámetros de DataTables
|
||||
$draw = intval($_GET['draw'] ?? 0);
|
||||
$start = intval($_GET['start'] ?? 0);
|
||||
$length = intval($_GET['length'] ?? 10);
|
||||
$search = $_GET['search']['value'] ?? '';
|
||||
|
||||
// Construir condiciones de filtro
|
||||
$where = "activo = 1 AND (id_agencia IS NULL OR id_agencia = ? OR id_usuario_creador = ?)";
|
||||
$params = [$id_agencia, $id_usuario];
|
||||
|
||||
if ($search !== '') {
|
||||
$where .= " AND (nombre LIKE ? OR descripcion LIKE ?)";
|
||||
$like = "%{$search}%";
|
||||
$params = array_merge($params, [$like, $like]);
|
||||
}
|
||||
|
||||
// Total registros filtrados
|
||||
$sqlFiltered = "SELECT COUNT(*) AS total FROM dbo.templates_rapidos WHERE $where";
|
||||
$stmtF = sqlsrv_query($conn, $sqlFiltered, $params);
|
||||
$rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC);
|
||||
$recordsFiltered = (int)($rowF['total'] ?? 0);
|
||||
|
||||
// Total registros sin filtro
|
||||
$sqlTotal = "SELECT COUNT(*) AS total FROM dbo.templates_rapidos WHERE activo = 1 AND (id_agencia IS NULL OR id_agencia = ? OR id_usuario_creador = ?)";
|
||||
$stmtT = sqlsrv_query($conn, $sqlTotal, [$id_agencia, $id_usuario]);
|
||||
$rowT = sqlsrv_fetch_array($stmtT, SQLSRV_FETCH_ASSOC);
|
||||
$recordsTotal = (int)($rowT['total'] ?? 0);
|
||||
|
||||
// Consulta principal con paginación
|
||||
$sql = "SELECT t.id, t.nombre, t.descripcion, t.icono, t.tipo_moneda, t.incoterm,
|
||||
t.vinculacion, t.pais_proveedor, t.tasa_preferencial, t.fecha_creacion,
|
||||
u.nombre_usuario AS usuario_creador,
|
||||
CASE WHEN t.id_agencia IS NULL THEN 'Sistema' ELSE a.nombre END AS ambito
|
||||
FROM dbo.templates_rapidos t
|
||||
LEFT JOIN dbo.usuarios u ON t.id_usuario_creador = u.id
|
||||
LEFT JOIN dbo.agencias a ON t.id_agencia = a.id
|
||||
WHERE $where
|
||||
ORDER BY t.fecha_creacion DESC
|
||||
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||
|
||||
$paramsData = array_merge($params, [$start, $length]);
|
||||
$stmt = sqlsrv_query($conn, $sql, $paramsData);
|
||||
|
||||
$data = [];
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$fecha = $row['fecha_creacion'] instanceof DateTime
|
||||
? $row['fecha_creacion']->format('d/m/Y H:i')
|
||||
: 'N/A';
|
||||
|
||||
$data[] = [
|
||||
'id' => $row['id'],
|
||||
'icono' => htmlspecialchars($row['icono'] ?? '🏢'),
|
||||
'nombre' => htmlspecialchars($row['nombre']),
|
||||
'descripcion' => htmlspecialchars($row['descripcion'] ?? ''),
|
||||
'tipo_moneda' => htmlspecialchars($row['tipo_moneda'] ?? ''),
|
||||
'incoterm' => htmlspecialchars($row['incoterm'] ?? ''),
|
||||
'pais_proveedor' => htmlspecialchars($row['pais_proveedor'] ?? ''),
|
||||
'ambito' => htmlspecialchars($row['ambito'] ?? ''),
|
||||
'usuario_creador' => htmlspecialchars($row['usuario_creador'] ?? ''),
|
||||
'fecha_creacion' => $fecha
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'draw' => $draw,
|
||||
'recordsTotal' => $recordsTotal,
|
||||
'recordsFiltered' => $recordsFiltered,
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
function ajax_obtener_templates_debug()
|
||||
{
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
echo json_encode(['error' => 'Usuario no autenticado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
try {
|
||||
$conn = getConnection();
|
||||
|
||||
// ✅ CONSULTA SIN FILTROS para debug
|
||||
$sql = "SELECT id, nombre, descripcion, icono, config_json,
|
||||
ISNULL(veces_usado, 0) as veces_usado,
|
||||
id_usuario_creador, id_agencia, activo,
|
||||
fecha_creacion
|
||||
FROM dbo.templates_rapidos
|
||||
ORDER BY fecha_creacion DESC";
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
|
||||
if ($stmt === false) {
|
||||
$errors = sqlsrv_errors();
|
||||
echo json_encode([
|
||||
'error' => 'Error en consulta SQL',
|
||||
'message' => $errors[0]['message'] ?? 'Error desconocido',
|
||||
'sql_errors' => $errors
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$templates = [];
|
||||
$debug_info = [
|
||||
'usuario_actual' => $id_usuario,
|
||||
'agencia_actual' => $id_agencia,
|
||||
'todos_los_templates' => []
|
||||
];
|
||||
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
// Info completa para debug
|
||||
$template_debug = [
|
||||
'id' => $row['id'],
|
||||
'nombre' => $row['nombre'],
|
||||
'id_usuario_creador' => $row['id_usuario_creador'],
|
||||
'id_agencia' => $row['id_agencia'],
|
||||
'activo' => $row['activo'],
|
||||
'fecha_creacion' => $row['fecha_creacion'] instanceof DateTime
|
||||
? $row['fecha_creacion']->format('Y-m-d H:i:s')
|
||||
: $row['fecha_creacion'],
|
||||
'es_del_usuario_actual' => ($row['id_usuario_creador'] == $id_usuario),
|
||||
'es_de_la_agencia' => ($row['id_agencia'] == $id_agencia),
|
||||
'deberia_mostrarse' => (
|
||||
$row['activo'] == 1 && (
|
||||
$row['id_agencia'] === null ||
|
||||
$row['id_agencia'] == $id_agencia ||
|
||||
$row['id_usuario_creador'] == $id_usuario
|
||||
)
|
||||
)
|
||||
];
|
||||
|
||||
$debug_info['todos_los_templates'][] = $template_debug;
|
||||
|
||||
// Solo agregar a templates para mostrar si cumple condiciones
|
||||
if ($template_debug['deberia_mostrarse']) {
|
||||
$config = [];
|
||||
if (!empty($row['config_json'])) {
|
||||
$decoded = json_decode($row['config_json'], true);
|
||||
$config = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
$templates[] = [
|
||||
'id' => (int)$row['id'],
|
||||
'nombre' => $row['nombre'],
|
||||
'descripcion' => $row['descripcion'] ?? '',
|
||||
'icono' => $row['icono'] ?? '📋',
|
||||
'config' => $config,
|
||||
'veces_usado' => (int)$row['veces_usado'],
|
||||
'id_usuario_creador' => $row['id_usuario_creador'],
|
||||
'es_mio' => ($row['id_usuario_creador'] == $id_usuario)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'count' => count($templates),
|
||||
'templates' => $templates,
|
||||
'debug_info' => $debug_info
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'error' => 'Error interno del servidor',
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
function ajax_obtener_templates()
|
||||
{
|
||||
// ✅ VERSIÓN CORREGIDA: Función simplificada sin filtros complejos
|
||||
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Usuario no autenticado', 'templates' => []]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
try {
|
||||
$conn = getConnection();
|
||||
|
||||
// ✅ CONSULTA SIMPLIFICADA: Mostrar todos los templates activos del usuario o agencia
|
||||
$sql = "SELECT id, nombre, descripcion, icono, config_json,
|
||||
ISNULL(veces_usado, 0) as veces_usado,
|
||||
id_usuario_creador, id_agencia
|
||||
FROM dbo.templates_rapidos
|
||||
WHERE activo = 1
|
||||
AND (id_usuario_creador = ? OR id_agencia = ? OR id_agencia IS NULL)
|
||||
ORDER BY
|
||||
CASE WHEN id_usuario_creador = ? THEN 0 ELSE 1 END,
|
||||
veces_usado DESC,
|
||||
nombre ASC";
|
||||
|
||||
$params = [$id_usuario, $id_agencia, $id_usuario];
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
$errors = sqlsrv_errors();
|
||||
echo json_encode([
|
||||
'error' => 'Error en consulta SQL',
|
||||
'message' => $errors[0]['message'] ?? 'Error desconocido',
|
||||
'templates' => []
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$templates = [];
|
||||
$templates_personales = [];
|
||||
$templates_otros = [];
|
||||
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
// Decodificar JSON con manejo de errores
|
||||
$config = [];
|
||||
if (!empty($row['config_json'])) {
|
||||
$decoded = json_decode($row['config_json'], true);
|
||||
$config = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
$template = [
|
||||
'id' => (int)$row['id'],
|
||||
'nombre' => $row['nombre'],
|
||||
'descripcion' => $row['descripcion'] ?? '',
|
||||
'icono' => $row['icono'] ?? '📋',
|
||||
'config' => $config,
|
||||
'veces_usado' => (int)$row['veces_usado'],
|
||||
'id_usuario_creador' => $row['id_usuario_creador'],
|
||||
'id_agencia' => $row['id_agencia'],
|
||||
'es_mio' => ($row['id_usuario_creador'] == $id_usuario),
|
||||
'ambito' => ($row['id_usuario_creador'] == $id_usuario) ? 'personal' :
|
||||
(($row['id_agencia'] == $id_agencia) ? 'agencia' : 'sistema')
|
||||
];
|
||||
|
||||
// Separar templates personales de otros
|
||||
if ($template['es_mio']) {
|
||||
$templates_personales[] = $template;
|
||||
} else {
|
||||
$templates_otros[] = $template;
|
||||
}
|
||||
|
||||
$templates[] = $template;
|
||||
}
|
||||
|
||||
// Respuesta con información detallada
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'count' => count($templates),
|
||||
'count_personales' => count($templates_personales),
|
||||
'count_otros' => count($templates_otros),
|
||||
'usuario_id' => $id_usuario,
|
||||
'agencia_id' => $id_agencia,
|
||||
'templates' => $templates,
|
||||
'templates_personales' => $templates_personales,
|
||||
'templates_otros' => $templates_otros
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'error' => 'Error interno del servidor',
|
||||
'message' => $e->getMessage(),
|
||||
'templates' => []
|
||||
]);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
function ajax_lista_por_seccion()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die(json_encode(['error' => 'No autorizado']));
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
$seccion = $_GET['seccion'] ?? 'personal';
|
||||
|
||||
$data = [];
|
||||
|
||||
try {
|
||||
switch($seccion) {
|
||||
case 'personal':
|
||||
// Solo templates creados por el usuario actual
|
||||
$sql = "SELECT id, nombre, descripcion, icono, config_json,
|
||||
veces_usado, fecha_creacion, id_usuario_creador
|
||||
FROM dbo.templates_rapidos
|
||||
WHERE id_usuario_creador = ? AND estado = 1
|
||||
ORDER BY veces_usado DESC, fecha_creacion DESC";
|
||||
$params = [$id_usuario];
|
||||
break;
|
||||
|
||||
case 'agencia':
|
||||
// Templates de la agencia (excluyendo los personales ya mostrados)
|
||||
$sql = "SELECT id, nombre, descripcion, icono, config_json,
|
||||
veces_usado, fecha_creacion, id_usuario_creador
|
||||
FROM dbo.templates_rapidos
|
||||
WHERE id_agencia = ? AND id_usuario_creador != ? AND estado = 1
|
||||
ORDER BY veces_usado DESC, fecha_creacion DESC";
|
||||
$params = [$id_agencia, $id_usuario];
|
||||
break;
|
||||
|
||||
case 'global':
|
||||
// Templates globales del sistema (solo si se solicitan explícitamente)
|
||||
$sql = "SELECT id, nombre, descripcion, icono, config_json,
|
||||
veces_usado, fecha_creacion, id_usuario_creador
|
||||
FROM dbo.templates_rapidos
|
||||
WHERE id_agencia IS NULL AND id_usuario_creador IS NULL AND estado = 1
|
||||
ORDER BY veces_usado DESC, fecha_creacion DESC";
|
||||
$params = [];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Sección inválida');
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
throw new Exception('Error en consulta: ' . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
// Formatear fecha
|
||||
$fecha = $row['fecha_creacion'] instanceof DateTime
|
||||
? $row['fecha_creacion']->format('d/m/Y')
|
||||
: date('d/m/Y', strtotime($row['fecha_creacion']));
|
||||
|
||||
// Determinar acciones según el tipo de template
|
||||
$acciones = '';
|
||||
$esPropio = ($row['id_usuario_creador'] == $id_usuario);
|
||||
$esAgencia = ($seccion === 'agencia');
|
||||
$esGlobal = ($seccion === 'global');
|
||||
|
||||
if ($esPropio) {
|
||||
$acciones = '
|
||||
<div class="btn-group" role="group">
|
||||
<a href="/IMPORTADORES/templates_rapidos/editar?id=' . $row['id'] . '"
|
||||
class="btn btn-sm btn-outline-primary" title="Editar">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<button onclick="duplicarTemplate(' . $row['id'] . ')"
|
||||
class="btn btn-sm btn-outline-info" title="Duplicar">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
<button onclick="eliminarTemplate(' . $row['id'] . ')"
|
||||
class="btn btn-sm btn-outline-danger" title="Eliminar">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>';
|
||||
} elseif ($esAgencia) {
|
||||
$acciones = '
|
||||
<div class="btn-group" role="group">
|
||||
<button onclick="mostrarVistaPrevia(' . $row['id'] . ')"
|
||||
class="btn btn-sm btn-outline-info" title="Ver">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button onclick="duplicarTemplate(' . $row['id'] . ')"
|
||||
class="btn btn-sm btn-outline-success" title="Duplicar">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>';
|
||||
} else { // Global
|
||||
$acciones = '
|
||||
<button onclick="mostrarVistaPrevia(' . $row['id'] . ')"
|
||||
class="btn btn-sm btn-outline-info" title="Ver detalles">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>';
|
||||
}
|
||||
|
||||
// Construir nombre con icono
|
||||
$nombreConIcono = '<span class="d-flex align-items-center">
|
||||
<span class="me-2" style="font-size: 18px;">' . htmlspecialchars($row['icono']) . '</span>
|
||||
<div>
|
||||
<strong>' . htmlspecialchars($row['nombre']) . '</strong>';
|
||||
|
||||
// Agregar badge según el tipo
|
||||
if ($esPropio) {
|
||||
$nombreConIcono .= ' <span class="badge bg-primary scope-badge ms-2">Mío</span>';
|
||||
} elseif ($esAgencia) {
|
||||
$nombreConIcono .= ' <span class="badge bg-info scope-badge ms-2">Agencia</span>';
|
||||
} else {
|
||||
$nombreConIcono .= ' <span class="badge bg-secondary scope-badge ms-2">Global</span>';
|
||||
}
|
||||
|
||||
$nombreConIcono .= '</div></span>';
|
||||
|
||||
$data[] = [
|
||||
$row['id'],
|
||||
$nombreConIcono,
|
||||
htmlspecialchars($row['descripcion'] ?? 'Sin descripción'),
|
||||
'<span class="badge bg-success">' . ($row['veces_usado'] ?? 0) . '</span>',
|
||||
$fecha,
|
||||
$acciones
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'data' => $data,
|
||||
'count' => count($data)
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $e->getMessage(),
|
||||
'data' => []
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function duplicar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
|
||||
$template_id = $_POST['template_id'] ?? null;
|
||||
|
||||
if (!$template_id || !is_numeric($template_id)) {
|
||||
die("❌ ID de template inválido.");
|
||||
}
|
||||
|
||||
// Obtener template original
|
||||
$sql = "SELECT * FROM dbo.templates_rapidos WHERE id = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$template_id]);
|
||||
|
||||
if ($stmt === false) {
|
||||
die("❌ Error al buscar template: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$original = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if (!$original) {
|
||||
die("❌ Template no encontrado.");
|
||||
}
|
||||
|
||||
// Crear duplicado con nuevo nombre
|
||||
$nuevo_nombre = $original['nombre'] . ' (Copia)';
|
||||
|
||||
$sql_insert = "INSERT INTO dbo.templates_rapidos
|
||||
(nombre, descripcion, icono, config_json, tipo_moneda, incoterm,
|
||||
vinculacion, pais_proveedor, tasa_preferencial, id_agencia, id_usuario_creador)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$params_insert = [
|
||||
$nuevo_nombre,
|
||||
$original['descripcion'],
|
||||
$original['icono'],
|
||||
$original['config_json'],
|
||||
$original['tipo_moneda'],
|
||||
$original['incoterm'],
|
||||
$original['vinculacion'],
|
||||
$original['pais_proveedor'],
|
||||
$original['tasa_preferencial'],
|
||||
$id_agencia,
|
||||
$id_usuario
|
||||
];
|
||||
|
||||
$stmt_insert = sqlsrv_query($conn, $sql_insert, $params_insert);
|
||||
|
||||
if ($stmt_insert === false) {
|
||||
die("❌ Error al duplicar: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
echo "✅ Template duplicado correctamente como '{$nuevo_nombre}'.";
|
||||
}
|
||||
|
||||
function ajax_usar_template()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['success' => false, 'message' => 'No autorizado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_template = intval($_POST['id_template'] ?? 0);
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
|
||||
if ($id_template <= 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'ID de template inválido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
|
||||
// Incrementar contador de uso
|
||||
$sql = "UPDATE dbo.templates_rapidos
|
||||
SET veces_usado = veces_usado + 1, ultima_vez_usado = GETDATE()
|
||||
WHERE id = ? AND activo = 1";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id_template]);
|
||||
|
||||
if ($stmt === false) {
|
||||
echo json_encode(['success' => false, 'message' => 'Error al actualizar estadísticas']);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Funciones auxiliares
|
||||
function obtenerAduanas($conn) {
|
||||
$sql = "SELECT DISTINCT RIGHT(REPLICATE('0', 3) + CAST(aduana_seccion AS VARCHAR), 3) AS aduana_seccion, nombre FROM dbo.aduanas ORDER BY aduana_seccion";
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function obtenerPatentes($conn) {
|
||||
$id_agencia = $_SESSION['id_agencia_en_uso'] ?? null;
|
||||
if (!$id_agencia) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$sql = "SELECT id_agente, patente, agente_aduanal FROM dbo.agentes_aduanales WHERE id_agencia = ? AND activo = 1 ORDER BY patente";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id_agencia]);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function obtenerIncoterms($conn) {
|
||||
$sql = "SELECT INCOTERM, DESCESPANOL FROM dbo.gIncoterms ORDER BY INCOTERM";
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function obtenerPaises($conn) {
|
||||
$sql = "SELECT id_pais, nombre FROM dbo.paises ORDER BY nombre";
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function obtenerTransportistas($conn) {
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
if (!$id_usuario) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$sql = "SELECT id_transportista, clave_identificador, nombre FROM dbo.transportistas WHERE id_usuario = ? AND activo = 1 ORDER BY nombre";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id_usuario]);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function obtenerChoferes($conn) {
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
if (!$id_usuario) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$sql = "SELECT c.id_chofer, c.nombre+' '+c.apellido AS nombre, c.transportista_id
|
||||
FROM dbo.choferes c
|
||||
JOIN dbo.transportistas t ON c.transportista_id = t.id_transportista
|
||||
WHERE t.id_usuario = ? AND c.status = 1
|
||||
ORDER BY c.nombre";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id_usuario]);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function obtenerUnidadesMedida($conn) {
|
||||
$sql = "SELECT id, descripcion FROM dbo.unidades_medida_apendice7 ORDER BY id";
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
$result = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$result[] = $row;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
19
app/controllers/test_connection.php
Normal file
19
app/controllers/test_connection.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
session_start();
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// Simple test endpoint
|
||||
echo json_encode([
|
||||
'success' => 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'
|
||||
]);
|
||||
?>
|
||||
237
app/controllers/winsaai.php
Normal file
237
app/controllers/winsaai.php
Normal file
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../helpers/session.php';
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/crypto.php';
|
||||
require_once __DIR__ . '/../helpers/env.php';
|
||||
|
||||
loadEnv();
|
||||
|
||||
function save_config() {
|
||||
$conn = getConnection();
|
||||
$userId = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$userId) {
|
||||
http_response_code(401);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Sesión expirada']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Método no permitido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'JSON inválido']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$host = trim($input['host'] ?? '');
|
||||
$port = intval($input['port'] ?? 80);
|
||||
$protocol = $input['protocol'] ?? 'https';
|
||||
$usuario = trim($input['usuario'] ?? '');
|
||||
$password = $input['password'] ?? '';
|
||||
$sync_pedimentos = $input['sync_pedimentos'] ?? true;
|
||||
$sync_coves = $input['sync_coves'] ?? true;
|
||||
|
||||
// Validaciones
|
||||
if (empty($host) || empty($usuario) || empty($password)) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Todos los campos son obligatorios']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Encriptar contraseña
|
||||
$encryptedPassword = encrypt($password);
|
||||
|
||||
// Verificar si existe configuración
|
||||
$sqlCheck = "SELECT id FROM winsaai_config WHERE id_usuario = ?";
|
||||
$stmtCheck = sqlsrv_query($conn, $sqlCheck, [$userId]);
|
||||
|
||||
if ($stmtCheck === false) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Error en base de datos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$existingConfig = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
|
||||
sqlsrv_free_stmt($stmtCheck);
|
||||
|
||||
if ($existingConfig) {
|
||||
// Actualizar
|
||||
$sql = "UPDATE winsaai_config
|
||||
SET host = ?, port = ?, protocol = ?, usuario = ?, password = ?,
|
||||
sync_pedimentos = ?, sync_coves = ?, updated_at = GETDATE()
|
||||
WHERE id_usuario = ?";
|
||||
$params = [$host, $port, $protocol, $usuario, $encryptedPassword,
|
||||
$sync_pedimentos ? 1 : 0, $sync_coves ? 1 : 0, $userId];
|
||||
} else {
|
||||
// Insertar
|
||||
$sql = "INSERT INTO winsaai_config (id_usuario, host, port, protocol, usuario, password, sync_pedimentos, sync_coves)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$params = [$userId, $host, $port, $protocol, $usuario, $encryptedPassword,
|
||||
$sync_pedimentos ? 1 : 0, $sync_coves ? 1 : 0];
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
|
||||
if ($stmt === false) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Error al guardar configuración']);
|
||||
exit;
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => true, 'message' => 'Configuración guardada correctamente']);
|
||||
}
|
||||
|
||||
function get_config() {
|
||||
$conn = getConnection();
|
||||
$userId = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$userId) {
|
||||
http_response_code(401);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Sesión expirada']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$sql = "SELECT * FROM winsaai_config WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$userId]);
|
||||
|
||||
if ($stmt === false) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Error en base de datos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$config = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
if ($config) {
|
||||
// No enviar contraseña por seguridad
|
||||
unset($config['password']);
|
||||
// Convertir BIT a boolean
|
||||
$config['sync_pedimentos'] = (bool)$config['sync_pedimentos'];
|
||||
$config['sync_coves'] = (bool)$config['sync_coves'];
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => true, 'data' => $config]);
|
||||
} else {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'No hay configuración']);
|
||||
}
|
||||
}
|
||||
|
||||
function test_connection() {
|
||||
$conn = getConnection();
|
||||
$userId = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$userId) {
|
||||
http_response_code(401);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Sesión expirada']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$host = trim($input['host'] ?? '');
|
||||
$port = intval($input['port'] ?? 80);
|
||||
$protocol = $input['protocol'] ?? 'https';
|
||||
$usuario = trim($input['usuario'] ?? '');
|
||||
$password = $input['password'] ?? '';
|
||||
|
||||
if (empty($host) || empty($usuario) || empty($password)) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Faltan datos para probar conexión']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$url = "{$protocol}://{$host}:{$port}/api/test";
|
||||
|
||||
// Simular prueba de conexión (aquí pondrías la lógica real)
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => true, 'message' => "Conexión exitosa con {$protocol}://{$host}:{$port}"]);
|
||||
}
|
||||
|
||||
function sync_data() {
|
||||
$conn = getConnection();
|
||||
$userId = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$userId) {
|
||||
http_response_code(401);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Sesión expirada']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener configuración del usuario
|
||||
$sql = "SELECT * FROM winsaai_config WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$userId]);
|
||||
|
||||
if ($stmt === false) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'Error en base de datos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$config = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
if (!$config) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => false, 'message' => 'No hay configuración de WINSAAI']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$syncType = $input['sync_type'] ?? 'both';
|
||||
|
||||
// Simular sincronización
|
||||
$results = [];
|
||||
if ($syncType === 'pedimentos' || $syncType === 'both') {
|
||||
$results['pedimentos'] = ['total' => 10, 'processed' => 10];
|
||||
}
|
||||
if ($syncType === 'coves' || $syncType === 'both') {
|
||||
$results['coves'] = ['total' => 5, 'processed' => 5];
|
||||
}
|
||||
|
||||
// Actualizar última sincronización
|
||||
$sqlUpdate = "UPDATE winsaai_config SET last_sync = GETDATE() WHERE id_usuario = ?";
|
||||
sqlsrv_query($conn, $sqlUpdate, [$userId]);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['success' => true, 'message' => 'Sincronización completada', 'data' => $results]);
|
||||
}
|
||||
|
||||
function index() {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'API WINSAAI disponible',
|
||||
'endpoints' => [
|
||||
'save_config' => '/IMPORTADORES/winsaai/save_config',
|
||||
'test_connection' => '/IMPORTADORES/winsaai/test_connection',
|
||||
'sync_data' => '/IMPORTADORES/winsaai/sync_data',
|
||||
'get_config' => '/IMPORTADORES/winsaai/get_config'
|
||||
]
|
||||
]);
|
||||
}
|
||||
?>
|
||||
@@ -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
|
||||
);
|
||||
@@ -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)
|
||||
);
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -1,37 +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)
|
||||
);
|
||||
@@ -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];
|
||||
13
public/check_session.php
Normal file
13
public/check_session.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
session_start();
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
echo json_encode([
|
||||
'sesion_activa' => 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);
|
||||
?>
|
||||
26
public/debug.php
Normal file
26
public/debug.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
echo "=== DEBUG IMPORTADOR ===\n";
|
||||
echo "POST: " . print_r($_POST, true) . "\n";
|
||||
echo "FILES: " . print_r($_FILES, true) . "\n";
|
||||
echo "SESSION: " . print_r($_SESSION ?? [], true) . "\n";
|
||||
|
||||
// Test de conexión a base de datos
|
||||
try {
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
echo "Config database cargado OK\n";
|
||||
|
||||
$conn = getConnection();
|
||||
echo "Conexión exitosa\n";
|
||||
|
||||
sqlsrv_close($conn);
|
||||
echo "Conexión cerrada OK\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "ERROR: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "=== FIN DEBUG ===\n";
|
||||
?>
|
||||
152
public/debug_partidas.php
Normal file
152
public/debug_partidas.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once '../config/database.php';
|
||||
|
||||
if (!isset($_SESSION['usuario_id'])) {
|
||||
die("Error: No hay sesión activa");
|
||||
}
|
||||
|
||||
echo "<!DOCTYPE html>
|
||||
<html lang='es'>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
||||
<title>Debug - Partidas de Pedimentos</title>
|
||||
<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css' rel='stylesheet'>
|
||||
</head>
|
||||
<body>
|
||||
<div class='container mt-4'>
|
||||
<h2>Debug - Últimas Partidas Insertadas</h2>";
|
||||
|
||||
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 "<div class='table-responsive'>
|
||||
<table class='table table-striped table-hover'>
|
||||
<thead class='table-dark'>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Pedimento</th>
|
||||
<th>Secuencia</th>
|
||||
<th>Fracción</th>
|
||||
<th>Descripción</th>
|
||||
<th>Cantidad</th>
|
||||
<th>Unidad</th>
|
||||
<th>Valor Unit.</th>
|
||||
<th>Valor Total</th>
|
||||
<th>Peso Neto</th>
|
||||
<th>Peso Bruto</th>
|
||||
<th>Fecha</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>";
|
||||
|
||||
$contador = 0;
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$contador++;
|
||||
|
||||
echo "<tr>
|
||||
<td>{$row['id']}</td>
|
||||
<td><strong>{$row['numero_pedimento']}</strong></td>
|
||||
<td>{$row['secuencia']}</td>
|
||||
<td><code>{$row['fraccion_arancelaria']}</code></td>
|
||||
<td>" . (strlen($row['descripcion']) > 50 ? substr($row['descripcion'], 0, 50) . '...' : $row['descripcion']) . "</td>
|
||||
<td>" . number_format($row['cantidad'], 4) . "</td>
|
||||
<td>{$row['unidad']}</td>
|
||||
<td>" . number_format($row['valor_unitario'], 4) . "</td>
|
||||
<td>" . number_format($row['valor_total'], 4) . "</td>
|
||||
<td>" . ($row['peso_neto'] ? number_format($row['peso_neto'], 4) : 'NULL') . "</td>
|
||||
<td>" . ($row['peso_bruto'] ? number_format($row['peso_bruto'], 4) : 'NULL') . "</td>
|
||||
<td>{$row['fecha_creacion']->format('Y-m-d H:i:s')}</td>
|
||||
</tr>";
|
||||
}
|
||||
|
||||
echo "</tbody></table></div>";
|
||||
|
||||
if ($contador == 0) {
|
||||
echo "<div class='alert alert-warning'>No se encontraron partidas en la base de datos.</div>";
|
||||
} else {
|
||||
echo "<div class='alert alert-info'>Se encontraron $contador partidas.</div>";
|
||||
}
|
||||
|
||||
// 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 "<div class='row mt-4'>
|
||||
<div class='col-md-3'>
|
||||
<div class='card text-center'>
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>Total Partidas</h5>
|
||||
<p class='card-text display-6'>{$stats['total_partidas']}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-md-3'>
|
||||
<div class='card text-center'>
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>Total Pedimentos</h5>
|
||||
<p class='card-text display-6'>{$stats['total_pedimentos']}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-md-3'>
|
||||
<div class='card text-center'>
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>Promedio Cantidad</h5>
|
||||
<p class='card-text display-6'>" . number_format($stats['promedio_cantidad'], 2) . "</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-md-3'>
|
||||
<div class='card text-center'>
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>Promedio Valor Unit.</h5>
|
||||
<p class='card-text display-6'>" . number_format($stats['promedio_valor_unitario'], 2) . "</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>";
|
||||
}
|
||||
|
||||
sqlsrv_close($conn);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "<div class='alert alert-danger'>Error: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
|
||||
echo "</div>
|
||||
<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js'></script>
|
||||
</body>
|
||||
</html>";
|
||||
?>
|
||||
134
public/diagnostico_importacion.php
Normal file
134
public/diagnostico_importacion.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
session_start();
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
// Función de logging mejorada
|
||||
function logDebug($mensaje) {
|
||||
error_log("[IMPORT_DEBUG] " . $mensaje);
|
||||
}
|
||||
|
||||
try {
|
||||
logDebug("=== INICIO DIAGNÓSTICO ===");
|
||||
|
||||
// 1. Verificar sesión
|
||||
logDebug("Verificando sesión...");
|
||||
$usuario_info = "No hay sesión";
|
||||
if (isset($_SESSION['usuario_id'])) {
|
||||
$usuario_info = "Usuario ID: " . $_SESSION['usuario_id'] .
|
||||
", Tipo: " . ($_SESSION['tipo_usuario'] ?? 'sin_tipo');
|
||||
}
|
||||
logDebug("Estado sesión: " . $usuario_info);
|
||||
|
||||
// 2. Verificar método
|
||||
logDebug("Método HTTP: " . $_SERVER['REQUEST_METHOD']);
|
||||
|
||||
// 3. Verificar archivo
|
||||
$archivo_info = "No hay archivo";
|
||||
if (isset($_FILES['archivo'])) {
|
||||
$archivo_info = "Archivo: " . $_FILES['archivo']['name'] .
|
||||
", Tamaño: " . $_FILES['archivo']['size'] .
|
||||
", Error: " . $_FILES['archivo']['error'];
|
||||
}
|
||||
logDebug("Estado archivo: " . $archivo_info);
|
||||
|
||||
// 4. Verificar conexión a base de datos
|
||||
logDebug("Verificando conexión DB...");
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
$conn = getConnection();
|
||||
$db_info = $conn ? "Conexión exitosa" : "Error de conexión";
|
||||
logDebug("Estado DB: " . $db_info);
|
||||
|
||||
// 5. Verificar directorio temporal
|
||||
$temp_dir = __DIR__ . '/../storage/temp/';
|
||||
logDebug("Directorio temp: " . $temp_dir);
|
||||
logDebug("Existe directorio temp: " . (is_dir($temp_dir) ? "SÍ" : "NO"));
|
||||
logDebug("Permisos escritura temp: " . (is_writable($temp_dir) ? "SÍ" : "NO"));
|
||||
|
||||
// Respuesta de diagnóstico
|
||||
$respuesta = [
|
||||
'success' => 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);
|
||||
}
|
||||
?>
|
||||
6
public/downloads/claves_pedimentos_template.csv
Normal file
6
public/downloads/claves_pedimentos_template.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
codigo,descripcion,tipo_operacion,activo
|
||||
A1,Importación definitiva de mercancías,importacion,1
|
||||
A3,Importación definitiva de vehículos usados,importacion,1
|
||||
B1,Importación temporal para elaborar transformar o reparar,importacion,1
|
||||
C1,Importación definitiva de mercancías donadas,importacion,1
|
||||
G1,Importación de mercancías con Programa IMMEX,importacion,1
|
||||
|
89
public/importar_funcional.php
Normal file
89
public/importar_funcional.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Forzar no cache
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-cache, no-store, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: 0');
|
||||
|
||||
// Log de debug
|
||||
error_log("=== NUEVO CONTROLADOR FUNCIONAL ===");
|
||||
error_log("Método: " . $_SERVER['REQUEST_METHOD']);
|
||||
error_log("POST data: " . print_r($_POST, true));
|
||||
error_log("FILES data: " . print_r($_FILES, true));
|
||||
|
||||
try {
|
||||
// Verificar método
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
throw new Exception("Método no permitido: " . $_SERVER['REQUEST_METHOD']);
|
||||
}
|
||||
|
||||
// Verificar sesión (comentado temporalmente para test)
|
||||
// if (!isset($_SESSION['usuario_id'])) {
|
||||
// throw new Exception("Usuario no autenticado");
|
||||
// }
|
||||
|
||||
$validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
|
||||
|
||||
error_log("Validar duplicados: " . ($validar_duplicados ? 'SÍ' : 'NO'));
|
||||
|
||||
// Contar archivos recibidos
|
||||
$total_archivos = 0;
|
||||
if (isset($_FILES['archivos']) && is_array($_FILES['archivos']['name'])) {
|
||||
$total_archivos = count($_FILES['archivos']['name']);
|
||||
error_log("Archivos múltiples detectados: " . $total_archivos);
|
||||
} elseif (isset($_FILES['archivo'])) {
|
||||
$total_archivos = 1;
|
||||
error_log("Archivo individual detectado");
|
||||
}
|
||||
|
||||
error_log("Total de archivos a procesar: " . $total_archivos);
|
||||
|
||||
if ($total_archivos === 0) {
|
||||
throw new Exception("No se recibieron archivos para procesar");
|
||||
}
|
||||
|
||||
// Simulación de procesamiento (reemplazar con lógica real después)
|
||||
$estadisticas = [
|
||||
'pedimentos_procesados' => $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);
|
||||
}
|
||||
?>
|
||||
739
public/importar_pedimentos.php
Normal file
739
public/importar_pedimentos.php
Normal file
@@ -0,0 +1,739 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
// Headers para AJAX
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
// Log para debugging
|
||||
error_log("=== INICIO IMPORTACIÓN ===");
|
||||
error_log("Usuario ID en sesión: " . (isset($_SESSION['usuario_id']) ? $_SESSION['usuario_id'] : 'NO_USUARIO'));
|
||||
error_log("Tipo usuario: " . (isset($_SESSION['tipo_usuario']) ? $_SESSION['tipo_usuario'] : 'NO_TIPO'));
|
||||
error_log("Método: " . $_SERVER['REQUEST_METHOD']);
|
||||
error_log("POST recibido: " . print_r($_POST, true));
|
||||
error_log("FILES recibido: " . print_r($_FILES, true));
|
||||
error_log("Tiene archivo individual: " . (isset($_FILES['archivo']) ? 'SÍ' : 'NO'));
|
||||
error_log("Tiene archivos múltiples: " . (isset($_FILES['archivos']) ? 'SÍ' : 'NO'));
|
||||
|
||||
// Verificar que el usuario esté logueado
|
||||
if (!isset($_SESSION['usuario_id'])) {
|
||||
error_log("ERROR: Usuario no autenticado - no hay usuario_id en sesión");
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => 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()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
255
public/importar_pedimentos_simple.php
Normal file
255
public/importar_pedimentos_simple.php
Normal file
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
// Limpiar cualquier output previo
|
||||
if (ob_get_level()) {
|
||||
ob_clean();
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
|
||||
error_log("=== IMPORTACIÓN SIMPLE ===");
|
||||
error_log("POST: " . print_r($_POST, true));
|
||||
error_log("FILES: " . print_r($_FILES, true));
|
||||
error_log("Número total de archivos recibidos: " . count($_FILES));
|
||||
|
||||
if (!isset($_SESSION['usuario_id'])) {
|
||||
echo json_encode(['success' => 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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
128
public/importar_test_simple.php
Normal file
128
public/importar_test_simple.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Limpiar cualquier output previo
|
||||
if (ob_get_level()) {
|
||||
ob_clean();
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
|
||||
error_log("=== IMPORTACIÓN SIMPLE V2 ===");
|
||||
error_log("POST: " . print_r($_POST, true));
|
||||
error_log("FILES: " . print_r($_FILES, true));
|
||||
|
||||
if (!isset($_SESSION['usuario_id'])) {
|
||||
echo json_encode(['success' => 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')
|
||||
]
|
||||
]);
|
||||
}
|
||||
?>
|
||||
66
public/limpiar_pedimentos.php
Normal file
66
public/limpiar_pedimentos.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// Verificar que el usuario esté logueado
|
||||
if (!isset($_SESSION['usuario_id'])) {
|
||||
echo json_encode(['success' => 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()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
36
public/test_import.php
Normal file
36
public/test_import.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
session_start();
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type');
|
||||
|
||||
// Simple test endpoint
|
||||
$response = [
|
||||
'success' => 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);
|
||||
?>
|
||||
10
public/test_json.php
Normal file
10
public/test_json.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// Test simple para verificar respuesta JSON
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Test exitoso',
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
?>
|
||||
26
public/test_ultra_simple.php
Normal file
26
public/test_ultra_simple.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
// Ultra simple test - solo devolver JSON
|
||||
header('Content-Type: application/json');
|
||||
|
||||
try {
|
||||
echo json_encode([
|
||||
'success' => 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()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
46
public/verificar_pedimentos.php
Normal file
46
public/verificar_pedimentos.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
try {
|
||||
$conn = getConnection();
|
||||
|
||||
// Obtener todos los pedimentos existentes
|
||||
$sql = "SELECT numero_pedimento, fecha_creacion, usuario_id FROM pedimentos ORDER BY fecha_creacion DESC";
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
|
||||
$pedimentos_existentes = [];
|
||||
if ($stmt !== false) {
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$pedimentos_existentes[] = $row;
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
}
|
||||
|
||||
// Obtener estadísticas
|
||||
$sql_stats = "SELECT
|
||||
COUNT(*) as total_pedimentos,
|
||||
COUNT(DISTINCT usuario_id) as usuarios_distintos,
|
||||
MIN(fecha_creacion) as primer_pedimento,
|
||||
MAX(fecha_creacion) as ultimo_pedimento
|
||||
FROM pedimentos";
|
||||
$stmt_stats = sqlsrv_query($conn, $sql_stats);
|
||||
$stats = sqlsrv_fetch_array($stmt_stats, SQLSRV_FETCH_ASSOC);
|
||||
sqlsrv_free_stmt($stmt_stats);
|
||||
|
||||
sqlsrv_close($conn);
|
||||
|
||||
echo json_encode([
|
||||
'success' => 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()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
@@ -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');
|
||||
@@ -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;
|
||||
BIN
storage/certificados/cer_46_1760569052.cer
Normal file
BIN
storage/certificados/cer_46_1760569052.cer
Normal file
Binary file not shown.
BIN
storage/certificados/cer_46_1760569397.cer
Normal file
BIN
storage/certificados/cer_46_1760569397.cer
Normal file
Binary file not shown.
BIN
storage/certificados/key_46_1760569052.key
Normal file
BIN
storage/certificados/key_46_1760569052.key
Normal file
Binary file not shown.
BIN
storage/certificados/key_46_1760569397.key
Normal file
BIN
storage/certificados/key_46_1760569397.key
Normal file
Binary file not shown.
@@ -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)
|
||||
);
|
||||
BIN
uploads/expedientes/120/688113808bfed_REVISI__N__2-SIIH.pdf
Normal file
BIN
uploads/expedientes/120/688113808bfed_REVISI__N__2-SIIH.pdf
Normal file
Binary file not shown.
Binary file not shown.
BIN
uploads/expedientes/120/689e1c5f7f770_25-07-9999-5000100.zip
Normal file
BIN
uploads/expedientes/120/689e1c5f7f770_25-07-9999-5000100.zip
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
uploads/expedientes/120/689e1d0cb6aea_A9999001.174
Normal file
1
uploads/expedientes/120/689e1d0cb6aea_A9999001.174
Normal file
@@ -0,0 +1 @@
|
||||
40012L5000100032402OCINP10709999 5000100IMS030409FZ0 0426642147138023062025 9:32:47457APKZ87845GY74546120364879805503
|
||||
7
uploads/expedientes/120/689e1d0cbd0bc_AA_AA.txt
Normal file
7
uploads/expedientes/120/689e1d0cbd0bc_AA_AA.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Agencia Aduanal
|
||||
admiagenci.aduanal@gmail.com
|
||||
13a91ace36
|
||||
|
||||
Agente Aduanal
|
||||
jorgevergaramendiola@gmail.com
|
||||
123456789
|
||||
4
uploads/expedientes/120/689e1d33b8204_M9999003.170
Normal file
4
uploads/expedientes/120/689e1d33b8204_M9999003.170
Normal file
@@ -0,0 +1,4 @@
|
||||
500|1|9999|5000100|070||
|
||||
601|9999|5000100|070|IN|1||IMS030409FZ0|CALL740419HTSNZN00|7||
|
||||
800|5000100|1|CYd5l4voZrTBXJNXOdRjj5sZeDiKWngrY/2fB0aT43TetLDEW2xl06JT5PJN3qpIe+398SeWSiL/KipHXkkzxrW4EJYQQyxbgSBmYDa5Uwp/cP27wttIKoZ28meZMsObSbld2JK0z52zPcTjIYjWD6ZlHgdYtaiEfcAcjUQ07zd/RFQwYERKqkrqYVosOxr8JJZzj8Y4k3QvnIHnDNZIhK6RBFnDBXV3UfJEx1fBKKF4UH6kQLi820SbeF5yhzg6aMbHcFL5t18zhVnP74Gf642Vr/qm7gWeddWbeZwTsu+xc6z93ILKuyFSS95XWbh4l7kCMO1S7SyWOdeFsScEmg==|00001000000516139173|
|
||||
801|M9999003.170|1|3|010|
|
||||
1
uploads/expedientes/120/689e1d33b884b_M9999003.err
Normal file
1
uploads/expedientes/120/689e1d33b884b_M9999003.err
Normal file
@@ -0,0 +1 @@
|
||||
F5000100RXMK2128
|
||||
83
uploads/expedientes/120/689e1d33b8cb9_M9999006.174
Normal file
83
uploads/expedientes/120/689e1d33b8cb9_M9999006.174
Normal file
@@ -0,0 +1,83 @@
|
||||
500|1|9999|5000100|070||
|
||||
501|9999|5000100|070|1|IN|070||IMS030409FZ0|CALL740419HTSNZN00|19.08980|0|0|0|0||16699|7|7|7|7|INTERNATIONAL MANUFACTURING SOLUTIONS|SANTOS DUMONT||6630|32695|CD. JUAREZ, CHIH|CH|MEX||0|0|0|0|0|
|
||||
506|5000100|1|19062025|
|
||||
506|5000100|2|23062025|
|
||||
507|5000100|PC||||
|
||||
509|5000100|15|290.00000|2|
|
||||
509|5000100|23|16.00000|1|
|
||||
510|5000100|1|15|0|
|
||||
510|5000100|15|0|290|
|
||||
510|5000100|23|0|46|
|
||||
551|5000100|85444299|1|01|CABLE ELECTRICO CON CONECTOR|19.09000|11454|11454|600.00|600.000|6|57.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85444299|1|3|16.0000000000|1|
|
||||
556|5000100|85444299|1|6|5.0000000000|1|
|
||||
557|5000100|85444299|1|3|0|1929|
|
||||
557|5000100|85444299|1|6|0|573|
|
||||
551|5000100|85444299|2|01|CABLE ELECTRICO CON CONECTOR|19.09000|7636|7636|400.00|400.000|6|43.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85444299|2|3|16.0000000000|1|
|
||||
556|5000100|85444299|2|6|5.0000000000|1|
|
||||
557|5000100|85444299|2|3|0|1288|
|
||||
557|5000100|85444299|2|6|0|382|
|
||||
551|5000100|85444299|3|01|CABLE ELECTRICO CON CONECTOR|19.09000|3818|3818|200.00|200.000|6|2.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85444299|3|3|16.0000000000|1|
|
||||
556|5000100|85444299|3|6|5.0000000000|1|
|
||||
557|5000100|85444299|3|3|0|646|
|
||||
557|5000100|85444299|3|6|0|191|
|
||||
551|5000100|85437099|4|01|CONTROL REMOTO (INCLUYE BATERIAS)|19.09014|11225|11225|588.00|588.000|6|588.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85437099|4|3|16.0000000000|1|
|
||||
557|5000100|85437099|4|3|0|1801|
|
||||
551|5000100|85371099|5|01|CAJA DE CONTROL|293.69444|148022|148022|7754.00|504.000|6|121.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85371099|5|3|16.0000000000|1|
|
||||
557|5000100|85371099|5|3|0|23688|
|
||||
551|5000100|85371099|6|01|CAJA DE CONTROL|293.61905|18498|18498|969.00|63.000|6|15.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85371099|6|3|16.0000000000|1|
|
||||
557|5000100|85371099|6|3|0|2964|
|
||||
551|5000100|85013199|7|00|MOTOR ELECTRICO LINEAL|19.08730|2405|2405|126.00|126.000|6|126.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85013199|7|3|16.0000000000|1|
|
||||
556|5000100|85013199|7|6|5.0000000000|1|
|
||||
557|5000100|85013199|7|3|0|409|
|
||||
557|5000100|85013199|7|6|0|120|
|
||||
551|5000100|85013199|8|00|MOTOR ELECTRICO LINEAL|19.09091|7560|7560|396.00|396.000|6|396.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85013199|8|3|16.0000000000|1|
|
||||
556|5000100|85013199|8|6|5.0000000000|1|
|
||||
557|5000100|85013199|8|3|0|1275|
|
||||
557|5000100|85013199|8|6|0|378|
|
||||
551|5000100|85013199|9|00|MOTOR ELECTRICO LINEAL|19.08750|3054|3054|160.00|160.000|6|160.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85013199|9|3|16.0000000000|1|
|
||||
556|5000100|85013199|9|6|5.0000000000|1|
|
||||
557|5000100|85013199|9|3|0|518|
|
||||
557|5000100|85013199|9|6|0|153|
|
||||
551|5000100|85013199|10|00|MOTOR ELECTRICO LINEAL|237.84511|87527|87527|4585.00|368.000|6|368.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85013199|10|3|16.0000000000|1|
|
||||
556|5000100|85013199|10|6|5.0000000000|1|
|
||||
557|5000100|85013199|10|3|0|14709|
|
||||
557|5000100|85013199|10|6|0|4376|
|
||||
551|5000100|85444299|11|01|CABLE ELECTRICO CON CONECTOR|19.08980|9354|9354|490.00|490.000|6|108.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85444299|11|3|16.0000000000|1|
|
||||
556|5000100|85444299|11|6|5.0000000000|1|
|
||||
557|5000100|85444299|11|3|0|1576|
|
||||
557|5000100|85444299|11|6|0|468|
|
||||
551|5000100|85444299|12|01|CABLE ELECTRICO CON CONECTOR|19.08571|1336|1336|70.00|70.000|6|15.00000|1||0|6||||CHN|USA|||||
|
||||
556|5000100|85444299|12|3|16.0000000000|1|
|
||||
556|5000100|85444299|12|6|5.0000000000|1|
|
||||
557|5000100|85444299|12|3|0|229|
|
||||
557|5000100|85444299|12|6|0|67|
|
||||
551|5000100|85044099|13|00|FUENTE DE CONVERSION DE VOLTAJE|71.81349|18097|18097|948.00|252.000|6|252.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85044099|13|3|16.0000000000|1|
|
||||
556|5000100|85044099|13|6|10.0000000000|1|
|
||||
557|5000100|85044099|13|3|0|3190|
|
||||
557|5000100|85044099|13|6|0|1810|
|
||||
551|5000100|85044099|14|00|FUENTE DE CONVERSION DE VOLTAJE|19.08929|6414|6414|336.00|336.000|6|336.00000|6||0|6||||CHN|USA|||||
|
||||
556|5000100|85044099|14|3|16.0000000000|1|
|
||||
556|5000100|85044099|14|6|10.0000000000|1|
|
||||
557|5000100|85044099|14|3|0|1134|
|
||||
557|5000100|85044099|14|6|0|641|
|
||||
551|5000100|94039101|15|00|BASE DE ACERO PARA CAMA|79.02326|40776|40776|2136.00|516.000|6|10103.00000|1||0|6||||CHN|USA|||||
|
||||
553|5000100|94039101|15|T5|||2136.00|10103.00000|
|
||||
553|5000100|94039101|15|T9|||2136.00|10103.00000|
|
||||
554|5000100|94039101|15|GA||||
|
||||
556|5000100|94039101|15|3|16.0000000000|1|
|
||||
557|5000100|94039101|15|3|0|6529|
|
||||
557|5000100|94039101|15|3|15|0|
|
||||
800|5000100|1|QZe3dT6rwoxwP+fyTNK5zf+UeS1PWLXwJk9WZ7TGSo6C0xGy3ER6MF7SP6M6An4x7520QUyw++oanF3EFZa4zS+G+kaoQq2UNMj17tFP2kAgdibUWEEg4HlRcb0U5jZ2bCtMuH+4YX7WU2cfH2wI3Q+DEBIR+jV0u23o6U3+jNqUnVEcuhPg0wEZNtliPdlLEQxdNchyhPr4XsPQtocUE1Ji8IMb6Z7Y1WwVT9jQAGsCOSpKz3597iSs6M3Flh1JfhDVizWJsJ93CRM51PdMFOEETKOHSsOhhHD7rcjwigZiFoEtuSQRKIAzGaXLeh7oJ6iAQSGdbmsmTPvI79FPuw==|00001000000516139173|
|
||||
801|M9999006.174|1|82|010|
|
||||
3
uploads/expedientes/120/689e1d33b95be_M9999006.err
Normal file
3
uploads/expedientes/120/689e1d33b95be_M9999006.err
Normal file
@@ -0,0 +1,3 @@
|
||||
F5000100XYJU1KF2
|
||||
L5000100032402OCINP142664214336
|
||||
C00010023
|
||||
1
uploads/expedientes/120/689e1d428073d_E9999001.174
Normal file
1
uploads/expedientes/120/689e1d428073d_E9999001.174
Normal file
@@ -0,0 +1 @@
|
||||
40012L5000100032402OCINP10709999 5000100IMS030409FZ0 04266421471380
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
uploads/expedientes/121/688263bcb0e64_Factura_de_venta_677.pdf
Normal file
BIN
uploads/expedientes/121/688263bcb0e64_Factura_de_venta_677.pdf
Normal file
Binary file not shown.
BIN
uploads/expedientes/121/688263bcb1200_Recibo_de_compra.pdf
Normal file
BIN
uploads/expedientes/121/688263bcb1200_Recibo_de_compra.pdf
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
uploads/expedientes/121/688263bcb1cb4_PMO_-_ADUANASOFT.pdf
Normal file
BIN
uploads/expedientes/121/688263bcb1cb4_PMO_-_ADUANASOFT.pdf
Normal file
Binary file not shown.
BIN
uploads/expedientes/121/688263bcb20f8_Proyecto__1_.xlsx
Normal file
BIN
uploads/expedientes/121/688263bcb20f8_Proyecto__1_.xlsx
Normal file
Binary file not shown.
BIN
uploads/expedientes/122/6883a1ec8bdd6_Proyecto__1__1_.xlsx
Normal file
BIN
uploads/expedientes/122/6883a1ec8bdd6_Proyecto__1__1_.xlsx
Normal file
Binary file not shown.
211
uploads/expedientes/pedimento_5/68f95df6cea0d_m3726414.262
Normal file
211
uploads/expedientes/pedimento_5/68f95df6cea0d_m3726414.262
Normal file
@@ -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|
|
||||
52
uploads/expedientes/pedimento_5/68f96d9552e13_m3726413.261
Normal file
52
uploads/expedientes/pedimento_5/68f96d9552e13_m3726413.261
Normal file
@@ -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|
|
||||
211
uploads/expedientes/pedimento_5/68f96d95539d4_m3726414.262
Normal file
211
uploads/expedientes/pedimento_5/68f96d95539d4_m3726414.262
Normal file
@@ -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|
|
||||
19
uploads/expedientes/pedimento_5/68f96d9554188_m3726428.262
Normal file
19
uploads/expedientes/pedimento_5/68f96d9554188_m3726428.262
Normal file
@@ -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|
|
||||
65
uploads/expedientes/pedimento_5/68f96d9554612_m3726435.267
Normal file
65
uploads/expedientes/pedimento_5/68f96d9554612_m3726435.267
Normal file
@@ -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) PEQUE<55>O|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) PEQUE<55>O|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|
|
||||
335
uploads/expedientes/pedimento_5/68f96d9554ea3_m3726898.260
Normal file
335
uploads/expedientes/pedimento_5/68f96d9554ea3_m3726898.260
Normal file
@@ -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|COMPA<50>IA 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|
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
569
vendor/dompdf/dompdf/lib/fonts/Courier.afm.json
vendored
Normal file
569
vendor/dompdf/dompdf/lib/fonts/Courier.afm.json
vendored
Normal file
@@ -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
|
||||
}
|
||||
@@ -68,7 +68,7 @@
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">✅ Agencias Activas</h4>
|
||||
<!-- TABLA DE AGENCIAS -->
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle" id="tabla-agencias-activas">
|
||||
<thead>
|
||||
@@ -98,7 +98,7 @@
|
||||
<td><?= htmlspecialchars(decrypt($ag['nombre_admin'] ?? '')) ?></td>
|
||||
<td>
|
||||
<?php if (isset($ag['activo']) && $ag['activo'] == 1): ?>
|
||||
<a href="/IMPORTADORES/administrador/suspenderAgencia?id=<?= $ag['id_agencia'] ?>&success=1" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a>
|
||||
<a href="#" onclick="confirmSuspencion(<?= (int) ($ag['id_agencia'] ?? 0) ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -119,6 +119,21 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmSuspencion(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Solo se suspenderá el perfil del usuario.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, suspender',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/suspenderAgencia?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🏪 Alta de Agencias Aduanales</h4>
|
||||
|
||||
<!-- FORMULARIO -->
|
||||
<div class="card p-4 mb-5 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-4 mb-5 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<form action="/IMPORTADORES/administrador/guardar_agencia" method="POST" id="formAltaAgencias">
|
||||
<h5 class="mb-3">➕ Nueva Agencia Aduanal</h5>
|
||||
<div class="row g-3">
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
<div class="content">
|
||||
<h3 class="mb-4 animate__animated animate__fadeInDown title_glow">👥 Alta de Usuarios</h3>
|
||||
<!-- FORMULARIO -->
|
||||
<div class="card p-4 mb-4 shadow-sm bg-white card-hover position-relative h-auto">
|
||||
<div class="card p-4 mb-4 shadow-sm bg-white card-hover position-relative h-auto fade-in-up">
|
||||
<form action="/IMPORTADORES/administrador/guardar_usuario" method="POST" id="formAltaUsuarios">
|
||||
<h5 class="mb-3">➕ Nuevo Usuario</h5>
|
||||
<div class="row g-3">
|
||||
@@ -228,7 +228,7 @@
|
||||
<td><?= isset($u['creado_en']) && $u['creado_en'] instanceof DateTime ? $u['creado_en']->format('Y-m-d H:i') : '' ?></td>
|
||||
<td>
|
||||
<?php if (isset($u['activo']) && $u['activo'] == 1): ?>
|
||||
<a href="/IMPORTADORES/administrador/suspender?id=<?= $u['id_usuario'] ?>&success=1" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a>
|
||||
<a href="#" onclick="confirmSuspencion(<?= (int) ($u['id_usuario'] ?? 0) ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -252,7 +252,8 @@
|
||||
|
||||
// Script para manejar las animaciones de validación
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
||||
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
||||
const selects = document.querySelectorAll('select.form_select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
// Validación en tiempo real
|
||||
@@ -301,14 +302,41 @@
|
||||
e.preventDefault();
|
||||
|
||||
let isValid = true;
|
||||
const inputs = document.querySelectorAll('input.form-control, select.form-select');
|
||||
|
||||
// Validar todos los campos
|
||||
inputs.forEach(input => {
|
||||
if (!input.checkValidity()) {
|
||||
input.classList.add('shake');
|
||||
isValid = false;
|
||||
setTimeout(() => input.classList.remove('shake'), 500);
|
||||
}
|
||||
});
|
||||
|
||||
// Si todo es válido, enviar el formulario
|
||||
if (isValid) {
|
||||
this.submit(); // Esta línea faltaba en tu código original
|
||||
} else {
|
||||
// Mostrar mensaje de error si lo deseas
|
||||
Swal.fire({ title: 'Campos incompletos', text: 'Por favor complete todos los campos requeridos', icon: 'error' });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmSuspencion(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Esta acción no se puede deshacer.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, suspender',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/suspender?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">✅ Aprobación de Agencias Aduanales</h4>
|
||||
|
||||
<!-- TABLA DE AGENCIAS -->
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<h5 class="mb-3">🏪 Agencias Solicitantes</h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle" id="tabla-agencias-pendientes">
|
||||
@@ -106,7 +106,8 @@
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/IMPORTADORES/administrador/aprobar_agencia?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a>
|
||||
<a href="#" onclick="confirmAprobacion(<?= $s['request_id'] ?>)" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a>
|
||||
<a href="#" onclick="denegateRequest(<?= $s['request_id'] ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Denegar</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@@ -117,6 +118,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<script>
|
||||
<?php if ($_GET['success'] === 'denied'): ?>
|
||||
Swal.fire({ icon: 'success', title: 'Registro de Agencia denegado', text: 'La solicitud fue denegada.', confirmButtonColor: '#198754' });
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#tabla-agencias-pendientes').DataTable({
|
||||
@@ -126,6 +135,36 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmAprobacion(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Se creará el perfil y se notificará al usuario.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, aprobar',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/aprobar_agencia?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function denegateRequest(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Se denegara la solicitud de registro de la agencia.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, denegar',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/denegar_agencia?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php if (isset($_GET['error'])): ?>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">✅ Aprobación de Usuarios</h4>
|
||||
<!-- TABLA DE USUARIOS -->
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<h5 class="mb-3">👥 Usuarios Solicitantes</h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle" id="tabla-usuarios-pendientes">
|
||||
@@ -103,7 +103,8 @@
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/IMPORTADORES/administrador/aprobar_usuario?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a>
|
||||
<a href="#" onclick="confirmAprobacion(<?= $s['request_id'] ?>)" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a>
|
||||
<a href="#" onclick="denegateRequest(<?= $s['request_id'] ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Denegar</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@@ -123,14 +124,46 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmAprobacion(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Se creará el perfil y se notificará al usuario.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, aprobar',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/aprobar_usuario?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function denegateRequest(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Se denegara la solicitud de registro del usuario.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, denegar',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/denegar_usuario?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<script>
|
||||
<?php if ($_GET['success'] === 'approved'): ?>
|
||||
Swal.fire({ icon: 'success', title: 'Usuario aprobado',
|
||||
text: 'El usuario ha sido aprobado correctamente y se ha enviado un correo con las credenciales.',
|
||||
confirmButtonColor: '#198754' });
|
||||
Swal.fire({ icon: 'success', title: 'Usuario aprobado', text: 'El usuario ha sido aprobado correctamente y se ha enviado un correo con las credenciales.', confirmButtonColor: '#198754' });
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($_GET['success'] === 'denied'): ?>
|
||||
Swal.fire({ icon: 'success', title: 'Registro de Usuario denegado', text: 'La solicitud fue denegada.', confirmButtonColor: '#198754' });
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
.btn-violet { background-color: #8b5cf6; color: white; }
|
||||
.text-violet { color: #8b5cf6; }
|
||||
.btn-violet:hover { background-color: #7c3aed; color: white; }
|
||||
.btn-lila { background-color: #c4b5fd; /* violeta claro */ color: white; border: none; }
|
||||
.btn-lila:hover { background-color: #a78bfa; /* tono ligeramente más fuerte */ color: white; }
|
||||
.text-lila { color: #c4b5fd; }
|
||||
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
|
||||
/* En móviles, sin margen lateral */
|
||||
@@ -49,22 +52,39 @@
|
||||
}
|
||||
.card { border-radius: 12px; }
|
||||
/* Animaciones personalizadas */
|
||||
.card-hover { transition: all 0.3s ease; }
|
||||
.card-hover:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; }
|
||||
.card-hover { transition: all 0.3s ease; cursor: pointer; }
|
||||
.card-hover:hover { transform: translateY(-8px) saqcle(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
||||
.btn-pulse { animation: pulse 2s infinite; }
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
.fade-in-up { animation: fadeInUp 0.6s ease-out; }
|
||||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
||||
@keyframes fadeInUp {
|
||||
from { opacity: 0; transform: translateY(30px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.loading-spinner { display: none; }
|
||||
/* Botón con efecto de loading */
|
||||
.btn-loading { position: relative; color: transparent !important; pointer-events: none; }
|
||||
.btn-loading::after { content: ''; position: absolute; width: 20px; height: 20px; top: 50%; left: 50%; margin-left: -10px;
|
||||
margin-top: -10px; border: 2px solid #fff; border-radius: 50%; border-top-color: transparent; animation: spin 1s linear infinite; }
|
||||
.btn-loading .loading-spinner { display: inline-block; }
|
||||
.btn-loading .btn-text { display: none; }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
/* Responsive animations */
|
||||
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
|
||||
/* Efecto de glow para elementos activos */
|
||||
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
|
||||
/* Animación para el título */
|
||||
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
|
||||
/* Efecto para botones */
|
||||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
||||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||
.btn-animated:hover::before { left: 100%; }
|
||||
/* Animación para alertas */
|
||||
.alert-animated { animation: slideInDown 0.5s ease-out; }
|
||||
@keyframes slideInDown {
|
||||
@@ -76,7 +96,7 @@
|
||||
@keyframes borderGlow {
|
||||
from { border-color: #ffc107; box-shadow: 0 0 5px rgba(255, 193, 7, 0.5); }
|
||||
to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -87,70 +107,110 @@
|
||||
|
||||
<!-- <?php // if ($catalogosData['catalogos_activos']): ?> -->
|
||||
<div class="row g-4">
|
||||
<!-- <?php
|
||||
// $delay = 0;
|
||||
<?php
|
||||
$delay = 0;
|
||||
// foreach ($catalogosData['catalogos'] as $catalogo):
|
||||
// $delay += 0.1; // Incrementar el retraso para cada catálogo
|
||||
?> -->
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-teal">Aprobar agencias</h5>
|
||||
<p>Aprueba las agencias que solicitaron un registro.</p>
|
||||
<a href="/IMPORTADORES/administrador/aprobarAgencias"
|
||||
class="btn btn-teal btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/sistemas/aprobarAgencias' ? 'active' : '' ?>">
|
||||
Ver agencias solicitantes</a>
|
||||
$delay += 0.1; // Incrementar el retraso para cada catálogo
|
||||
?>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-teal mb-3">Aprobar agencias</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Aprueba las agencias que solicitaron un registro.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-teal btn-sm mt-2 mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/administrador/aprobarAgencias')"
|
||||
data-url="/IMPORTADORES/administrador/aprobarAgencias">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver agencias solicitantes</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-lime">Alta de agencias</h5>
|
||||
<p>Da de alta manualmente una agencia.</p>
|
||||
<a href="/IMPORTADORES/administrador/altaAgencias"
|
||||
class="btn btn-lime btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/sistemas/altaAgencias' ? 'active' : '' ?>">
|
||||
Nueva agencia
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-lime mb-3">Alta de agencias</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Da de alta manualmente una agencia.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-lime btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/administrador/altaAgencias')"
|
||||
data-url="/IMPORTADORES/administrador/altaAgencias">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Nueva agencia</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Aprobar de usuarios</h5>
|
||||
<p>Aprueba los usuarios que solicitaron un registro.</p>
|
||||
<a href="/IMPORTADORES/administrador/aprobarUsuarios"
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/sistemas/aprobarUsuarios' ? 'active' : '' ?>">
|
||||
Ver usuarios solicitantes
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-success mb-3">Aprobar usuarios</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Aprueba los usuarios que solicitaron un registro.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-success btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/administrador/aprobarUsuarios')"
|
||||
data-url="/IMPORTADORES/administrador/aprobarUsuarios">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver usuarios solicitantes</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-info">Alta de usuarios</h5>
|
||||
<p>Da de alta manualmente a un usuario.</p>
|
||||
<a href="/IMPORTADORES/administrador/altaUsuarios"
|
||||
class="btn btn-info btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/sistemas/altaUsuarios' ? 'active' : '' ?>">
|
||||
Nuevo usuario
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-info mb-3">Alta de usuarios</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Da de alta manualmente a un usuario.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-info btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/administrador/altaUsuarios')"
|
||||
data-url="/IMPORTADORES/administrador/altaUsuarios">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Nuevo usuario</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-warning">Configuración</h5>
|
||||
<p>Administra los datos de tu agencia.</p>
|
||||
<a href="/IMPORTADORES/administrador/configuracion"
|
||||
class="btn btn-warning btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/sistemas/configuracion' ? 'active' : '' ?>">
|
||||
Configurar
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-warning mb-3">Configuración</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Administra los datos de tu empresa y preferencias.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-warning btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/configuracion')"
|
||||
data-url="/IMPORTADORES/configuracion">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ir a configuración</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-danger">Cerrar sesión</h5>
|
||||
<p>Salir del sistema de forma segura.</p>
|
||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-danger btn-sm mt-2">Logout</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-danger mb-3">Cerrar sesión</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Salir del sistema de forma segura.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-danger btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/sistemas/logout')"
|
||||
data-url="/IMPORTADORES/sistemas/logout">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Cerrar sesión</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <?php // endforeach; ?> -->
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<!-- 📄 CONTENIDO -->
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🚷 Usuarios Inactivos</h4>
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="tabla-inactivos">
|
||||
<thead class="table-dark">
|
||||
@@ -95,8 +95,8 @@
|
||||
<td><?= isset($u['creado_en']) && $u['creado_en'] instanceof DateTime ? $u['creado_en']->format('Y-m-d H:i') : '' ?></td>
|
||||
<td>
|
||||
<?php if (isset($u['activo']) && $u['activo'] == 0): ?>
|
||||
<a href="/IMPORTADORES/administrador/activar?id=<?= $u['id_usuario'] ?>&success=1" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Activar</a>
|
||||
<a href="/IMPORTADORES/administrador/reset_password?id=<?= $u['id_usuario'] ?>" class="btn btn-sm btn-secondary mt-auto w-auto btn-animated">Nueva Contraseña</a>
|
||||
<a href="#" onclick="confirmActivacion(<?= (int) ($u['id_usuario'] ?? 0) ?>)" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Activar</a>
|
||||
<a href="#" onclick="changePassword(<?= (int) ($u['id_usuario'] ?? 0) ?>)" class="btn btn-sm btn-secondary mt-auto w-auto btn-animated">Restablecer</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -117,6 +117,36 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmActivacion(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Se reactivara el perfil del usuario.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, reactivar',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/activar?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changePassword(id) {
|
||||
Swal.fire({
|
||||
title: '¿Estás seguro?',
|
||||
text: 'Se restablecera la contraseña del usuario.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, restablecer',
|
||||
cancelButtonText: 'Cancelar'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = `/IMPORTADORES/administrador/reset_password?id=${id}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
<div class="content px-4">
|
||||
<h3 class="mb-4 animate__animated animate__fadeInDown title_glow">👨✈️ Administración de Agentes</h3>
|
||||
<!-- FORMULARIO -->
|
||||
<div class="card p-4 mb-4 shadow-sm bg-white card-hover position-relative h-auto">
|
||||
<div class="card p-4 mb-4 shadow-sm bg-white card-hover position-relative h-auto fade-in-up">
|
||||
<form action="/IMPORTADORES/agencias/guardarAgente" method="POST" id="formAltaAgentes">
|
||||
<h5 class="mb-3">➕ Nuevo Agente</h5>
|
||||
<div class="row g-3">
|
||||
@@ -200,8 +200,8 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h4 class="mb-4">✅ Agentes Activos</h4>
|
||||
<div class="card p-3 shadow-sm">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">✅ Agentes Activos</h4>
|
||||
<div class="card p-3 shadow-sm fade-in-up">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle" id="tabla-agentes-activos">
|
||||
<thead class="table-dark">
|
||||
@@ -227,7 +227,7 @@
|
||||
<td>
|
||||
<?php if (in_array($a['tipo_usuario_sistema'], ['agente_aduanal'])): ?>
|
||||
<a href="/IMPORTADORES/vinculaciones/desvincularAgencia?id=<?= $a['id_relacion'] ?>&tipo=<?= $a['tipo_vinculacion'] ?>"
|
||||
class="btn btn-sm btn-danger"
|
||||
class="btn btn-sm btn-danger mt-auto w-auto btn-animated"
|
||||
onclick="return confirm('¿Está seguro de que desea desvincular este usuario?')">
|
||||
Desvincular
|
||||
</a>
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
.btn-violet { background-color: #8b5cf6; color: white; }
|
||||
.text-violet { color: #8b5cf6; }
|
||||
.btn-violet:hover { background-color: #7c3aed; color: white; }
|
||||
.btn-lila { background-color: #c4b5fd; /* violeta claro */ color: white; border: none; }
|
||||
.btn-lila:hover { background-color: #a78bfa; /* tono ligeramente más fuerte */ color: white; }
|
||||
.text-lila { color: #c4b5fd; }
|
||||
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
|
||||
/* En móviles, sin margen lateral */
|
||||
@@ -49,22 +52,39 @@
|
||||
}
|
||||
.card { border-radius: 12px; }
|
||||
/* Animaciones personalizadas */
|
||||
.card-hover { transition: all 0.3s ease; }
|
||||
.card-hover:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; }
|
||||
.card-hover { transition: all 0.3s ease; cursor: pointer; }
|
||||
.card-hover:hover { transform: translateY(-8px) saqcle(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
||||
.btn-pulse { animation: pulse 2s infinite; }
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
.fade-in-up { animation: fadeInUp 0.6s ease-out; }
|
||||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
||||
@keyframes fadeInUp {
|
||||
from { opacity: 0; transform: translateY(30px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.loading-spinner { display: none; }
|
||||
/* Botón con efecto de loading */
|
||||
.btn-loading { position: relative; color: transparent !important; pointer-events: none; }
|
||||
.btn-loading::after { content: ''; position: absolute; width: 20px; height: 20px; top: 50%; left: 50%; margin-left: -10px;
|
||||
margin-top: -10px; border: 2px solid #fff; border-radius: 50%; border-top-color: transparent; animation: spin 1s linear infinite; }
|
||||
.btn-loading .loading-spinner { display: inline-block; }
|
||||
.btn-loading .btn-text { display: none; }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
/* Responsive animations */
|
||||
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
|
||||
/* Efecto de glow para elementos activos */
|
||||
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
|
||||
/* Animación para el título */
|
||||
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
|
||||
/* Efecto para botones */
|
||||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
||||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||
.btn-animated:hover::before { left: 100%; }
|
||||
/* Animación para alertas */
|
||||
.alert-animated { animation: slideInDown 0.5s ease-out; }
|
||||
@keyframes slideInDown {
|
||||
@@ -76,7 +96,7 @@
|
||||
@keyframes borderGlow {
|
||||
from { border-color: #ffc107; box-shadow: 0 0 5px rgba(255, 193, 7, 0.5); }
|
||||
to { border-color: #ffcd39; box-shadow: 0 0 20px rgba(255, 193, 7, 0.8); }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -87,82 +107,127 @@
|
||||
|
||||
<!-- <?php // if ($catalogosData['catalogos_activos']): ?> -->
|
||||
<div class="row g-4">
|
||||
<!-- <?php
|
||||
// $delay = 0;
|
||||
<?php
|
||||
$delay = 0;
|
||||
// foreach ($catalogosData['catalogos'] as $catalogo):
|
||||
// $delay += 0.1; // Incrementar el retraso para cada catálogo
|
||||
?> -->
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-teal">Solicitudes de vinculación</h5>
|
||||
<p>Aprueba las solicitudes de vinculación de los importadores.</p>
|
||||
<a href="/IMPORTADORES/vinculaciones/solicitudesVinculacion"
|
||||
class="btn btn-teal btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/vinculaciones/solicitudesVinculacion' ? 'active' : '' ?>">
|
||||
Ver solicitudes
|
||||
</a>
|
||||
$delay += 0.1; // Incrementar el retraso para cada catálogo
|
||||
?>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-teal mb-3">Solicitudes de vinculación</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Aprueba las solicitudes de vinculación de los importadores.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-teal btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/vinculaciones/solicitudesVinculacion')"
|
||||
data-url="/IMPORTADORES/vinculaciones/solicitudesVinculacion">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver solicitudes</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-lime">Usuarios vinculados</h5>
|
||||
<p>Consulta los que ya fueron autorizados.</p>
|
||||
<a href="/IMPORTADORES/vinculaciones/vinculacionesAgencia"
|
||||
class="btn btn-lime btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/vinculaciones/vinculacionesAgencia' ? 'active' : '' ?>">
|
||||
Ver usuarios
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-lime mb-3">Usuarios vinculados</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Consulta los que ya fueron autorizados.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-lime btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/vinculaciones/vinculacionesAgencia')"
|
||||
data-url="/IMPORTADORES/vinculaciones/vinculacionesAgencia">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver usuarios</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Alta de agentes</h5>
|
||||
<p>Da de alta a tus agentes aduanales.</p>
|
||||
<a href="/IMPORTADORES/agencias/alta"
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agencias/alta' ? 'active' : '' ?>">
|
||||
Nuevo agente
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-success mb-3">Patentes</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Gestiona las patentes de la agencia.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-success btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/patente/dashboard')"
|
||||
data-url="/IMPORTADORES/patente/dashboard">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver agentes</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-info">Patentes</h5>
|
||||
<p>Gestiona las patentes de la agencia.</p>
|
||||
<a href="/IMPORTADORES/patente/dashboard"
|
||||
class="btn btn-info btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/dashboard' ? 'active' : '' ?>">
|
||||
Ver agentes
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-info mb-3">Locaciones</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Gestiona la locaciones validas para nuevos registros.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-info btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/locaciones/lista')"
|
||||
data-url="/IMPORTADORES/locaciones/lista">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Gestionar locaciones</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-cyan">Locaciones</h5>
|
||||
<p>Gestiona la locaciones validas para nuevos registros.</p>
|
||||
<a href="/IMPORTADORES/locaciones/lista"
|
||||
class="btn btn-cyan btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista' ? 'active' : '' ?>">
|
||||
Gestionar locaciones
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-cyan mb-3">Alta de agentes</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Da de alta a tus agentes aduanales.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-cyan btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/agencias/alta')"
|
||||
data-url="/IMPORTADORES/agencias/alta">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Nuevo agente</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-warning">Configuración</h5>
|
||||
<p>Administra tus datos y preferencias.</p>
|
||||
<a href="/IMPORTADORES/configuracion"
|
||||
class="btn btn-warning btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agencias/configuracion' ? 'active' : '' ?>">
|
||||
Configurar
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-warning mb-3">Configuración</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Administra los datos de tu empresa y preferencias.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-warning btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/configuracion')"
|
||||
data-url="/IMPORTADORES/configuracion">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ir a configuración</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-danger">Cerrar sesión</h5>
|
||||
<p>Salir del sistema de forma segura.</p>
|
||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-danger btn-sm mt-2">Logout</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-danger mb-3">Cerrar sesión</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Salir del sistema de forma segura.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-danger btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/sistemas/logout')"
|
||||
data-url="/IMPORTADORES/sistemas/logout">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Cerrar sesión</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <?php // endforeach; ?> -->
|
||||
|
||||
@@ -41,6 +41,9 @@ include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
.btn-violet { background-color: #8b5cf6; color: white; }
|
||||
.text-violet { color: #8b5cf6; }
|
||||
.btn-violet:hover { background-color: #7c3aed; color: white; }
|
||||
.btn-lila { background-color: #c4b5fd; /* violeta claro */ color: white; border: none; }
|
||||
.btn-lila:hover { background-color: #a78bfa; /* tono ligeramente más fuerte */ color: white; }
|
||||
.text-lila { color: #c4b5fd; }
|
||||
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
|
||||
/* En móviles, sin margen lateral */
|
||||
@@ -52,22 +55,39 @@ include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
}
|
||||
.card { border-radius: 12px; }
|
||||
/* Animaciones personalizadas */
|
||||
.card-hover { transition: all 0.3s ease; }
|
||||
.card-hover:hover { transform: translateY(-5px); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; }
|
||||
.card-hover { transition: all 0.3s ease; cursor: pointer; }
|
||||
.card-hover:hover { transform: translateY(-8px) saqcle(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
||||
.btn-pulse { animation: pulse 2s infinite; }
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
.fade-in-up { animation: fadeInUp 0.6s ease-out; }
|
||||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
||||
@keyframes fadeInUp {
|
||||
from { opacity: 0; transform: translateY(30px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.loading-spinner { display: none; }
|
||||
/* Botón con efecto de loading */
|
||||
.btn-loading { position: relative; color: transparent !important; pointer-events: none; }
|
||||
.btn-loading::after { content: ''; position: absolute; width: 20px; height: 20px; top: 50%; left: 50%; margin-left: -10px;
|
||||
margin-top: -10px; border: 2px solid #fff; border-radius: 50%; border-top-color: transparent; animation: spin 1s linear infinite; }
|
||||
.btn-loading .loading-spinner { display: inline-block; }
|
||||
.btn-loading .btn-text { display: none; }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
/* Responsive animations */
|
||||
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
|
||||
/* Efecto de glow para elementos activos */
|
||||
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
|
||||
/* Animación para el título */
|
||||
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
|
||||
/* Efecto para botones */
|
||||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
||||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||
.btn-animated:hover::before { left: 100%; }
|
||||
/* Animación para alertas */
|
||||
.alert-animated { animation: slideInDown 0.5s ease-out; }
|
||||
@keyframes slideInDown {
|
||||
@@ -90,60 +110,93 @@ include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
|
||||
<!-- <?php // if ($catalogosData ['catalogos_activos']): ?> -->
|
||||
<div class="row g-4">
|
||||
<!-- <?php
|
||||
// $delay = 0;
|
||||
<?php
|
||||
$delay = 0;
|
||||
// foreach ($catalogosData['catalogos'] as $catalogo):
|
||||
// $delay += 0.1; // Incrementar el retraso para cada catálogo
|
||||
?> -->
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-teal">Importadores vinculados</h5>
|
||||
<p>Consulta los que ya fueron autorizados.</p>
|
||||
<a href="/IMPORTADORES/agentes/vinculados"
|
||||
class="btn btn-teal btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/vinculados' ? 'active' : '' ?>">
|
||||
Ver importadores
|
||||
</a>
|
||||
$delay += 0.1; // Incrementar el retraso para cada catálogo
|
||||
?>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-teal mb-3">Importadores vinculados</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Consulta los que ya fueron autorizados.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-teal btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/agentes/vinculados')"
|
||||
data-url="/IMPORTADORES/agentes/vinculados">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver importadores</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-lime">Patentes</h5>
|
||||
<p>Gestiona las patentes de la agencia.</p>
|
||||
<a href="/IMPORTADORES/patente/dashboard"
|
||||
class="btn btn-lime btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES//patente/dashboard' ? 'active' : '' ?>">
|
||||
Ver solicitudes
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-lime mb-3">Patentes</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Gestiona las patentes de la agencia.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-lime btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/patente/dashboard')"
|
||||
data-url="/IMPORTADORES/patente/dashboard">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ver patentes</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Locaciones</h5>
|
||||
<p>Gestiona la locaciones validas para nuevos registros.</p>
|
||||
<a href="/IMPORTADORES/locaciones/lista"
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista' ? 'active' : '' ?>">
|
||||
Gestionar locaciones
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-success mb-3">Locaciones</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Gestiona la locaciones validas para nuevos registros.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-success btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/locaciones/lista')"
|
||||
data-url="/IMPORTADORES/locaciones/lista">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Gestionar locaciones</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-warning">Configuración</h5>
|
||||
<p>Administra tus datos y preferencias.</p>
|
||||
<a href="/IMPORTADORES/configuracion"
|
||||
class="btn btn-warning btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/configuracion' ? 'active' : '' ?>">
|
||||
Configurar
|
||||
</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-warning mb-3">Configuración</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Administra los datos de tu empresa y preferencias.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-warning btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/configuracion')"
|
||||
data-url="/IMPORTADORES/configuracion">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Ir a configuración</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-danger">Cerrar sesión</h5>
|
||||
<p>Salir del sistema de forma segura.</p>
|
||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-danger btn-sm mt-2">Logout</a>
|
||||
<div class="col-md-4 animate__animated animate__fadeInUp" style="animation-delay: <?= $delay ?>s;">
|
||||
<div class="card shadow-sm p-3 card-hover position-relative h-100">
|
||||
<div class="card-body p-0 d-flex flex-column">
|
||||
<h5 class="text-danger mb-3">Cerrar sesión</h5>
|
||||
<p class="text-muted small flex-grow-1 mb-4">Salir del sistema de forma segura.</p>
|
||||
<div class="mt-auto">
|
||||
<button class="btn btn-danger btn-sm mt-auto w-100 btn-animated"
|
||||
onclick="navigateWithAnimation(this, '/IMPORTADORES/sistemas/logout')"
|
||||
data-url="/IMPORTADORES/sistemas/logout">
|
||||
<span class="loading-spinner spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||
<span class="btn-text">Cerrar sesión</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <?php // endforeach; ?> -->
|
||||
|
||||
@@ -61,8 +61,718 @@
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">⚙️ Automatizaciones</h4>
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title-glow">⚙️ Automatizaciones</h4>
|
||||
|
||||
<!-- Card de conexión WINSAAI -->
|
||||
<div class="row mb-4 fade-in-up">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm card-hover">
|
||||
<div class="card-header bg-primary text-white d-flex align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-plug me-2"></i>
|
||||
<h5 class="mb-0">Conexión con WINSAAI</h5>
|
||||
</div>
|
||||
<div id="connection_status_header">
|
||||
<span class="badge bg-secondary">Verificando...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Estado cuando NO hay configuración -->
|
||||
<div id="no_config_section">
|
||||
<p class="text-muted mb-3">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
Configura la conexión con el sistema WINSAAI para importar automáticamente pedimentos y COVES.
|
||||
</p>
|
||||
|
||||
<!-- Botón para conectar -->
|
||||
<button class="btn btn-success btn-animated btn-pulse" type="button"
|
||||
onclick="showConfigForm()">
|
||||
<i class="fas fa-wifi me-2"></i>
|
||||
Conectar con WINSAAI
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Estado cuando SÍ hay configuración -->
|
||||
<div id="existing_config_section" style="display: none;">
|
||||
<div class="alert alert-success border-0" role="alert">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="fas fa-check-circle me-2 text-success fs-5"></i>
|
||||
<h6 class="mb-0 fw-bold">¡Estás configurado para conectarte a WINSAAI!</h6>
|
||||
</div>
|
||||
|
||||
<!-- Información de la configuración actual -->
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-server me-2 text-primary"></i>
|
||||
<div>
|
||||
<small class="text-muted d-block">Servidor</small>
|
||||
<span id="current_server" class="fw-semibold">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-user me-2 text-info"></i>
|
||||
<div>
|
||||
<small class="text-muted d-block">Usuario</small>
|
||||
<span id="current_user" class="fw-semibold">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-shield-alt me-2 text-warning"></i>
|
||||
<div>
|
||||
<small class="text-muted d-block">Protocolo</small>
|
||||
<span id="current_protocol" class="fw-semibold">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-clock me-2 text-secondary"></i>
|
||||
<div>
|
||||
<small class="text-muted d-block">Última sincronización</small>
|
||||
<span id="last_sync_display" class="fw-semibold">Nunca</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Opciones de sincronización activas -->
|
||||
<div class="mb-3">
|
||||
<small class="text-muted d-block mb-2">Datos configurados para sincronizar:</small>
|
||||
<div class="d-flex gap-2">
|
||||
<span id="sync_pedimentos_badge" class="badge bg-primary" style="display: none;">
|
||||
<i class="fas fa-file-alt me-1"></i> Pedimentos
|
||||
</span>
|
||||
<span id="sync_coves_badge" class="badge bg-info" style="display: none;">
|
||||
<i class="fas fa-ship me-1"></i> COVES
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botones de acción -->
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<button type="button" class="btn btn-outline-primary btn-animated btn-sm"
|
||||
onclick="showConfigForm(true)">
|
||||
<i class="fas fa-edit me-2"></i>
|
||||
Editar Conexión
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-warning btn-animated btn-sm"
|
||||
onclick="toggleConfigStatus()">
|
||||
<i class="fas fa-pause me-2"></i>
|
||||
<span id="toggle_status_text">Desactivar</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-animated btn-sm"
|
||||
onclick="testExistingConnection()">
|
||||
<i class="fas fa-vial me-2"></i>
|
||||
Probar Conexión
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-success btn-animated btn-sm"
|
||||
onclick="syncData()">
|
||||
<i class="fas fa-sync-alt me-2"></i>
|
||||
Sincronizar Ahora
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-animated btn-sm"
|
||||
onclick="deleteConfig()">
|
||||
<i class="fas fa-trash me-2"></i>
|
||||
Eliminar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Formulario de configuración (inicialmente oculto) -->
|
||||
<div class="collapse mt-4" id="winsaaiConfig">
|
||||
<div class="card border-secondary">
|
||||
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-cog me-2"></i>
|
||||
<span id="form_title">Configuración de Conexión API</span>
|
||||
</h6>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary"
|
||||
onclick="hideConfigForm()">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="winsaaiForm">
|
||||
<div class="row">
|
||||
<!-- Dirección IP/DNS -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="winsaai_host" class="form-label">
|
||||
<i class="fas fa-server me-1"></i>
|
||||
Dirección IP / DNS
|
||||
</label>
|
||||
<input type="text" class="form-control" id="winsaai_host"
|
||||
placeholder="192.168.1.100 o api.winsaai.com" required>
|
||||
<div class="form-text">
|
||||
Ingresa la dirección IP o nombre de dominio del servidor WINSAAI
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Puerto -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="winsaai_port" class="form-label">
|
||||
<i class="fas fa-network-wired me-1"></i>
|
||||
Puerto
|
||||
</label>
|
||||
<input type="number" class="form-control" id="winsaai_port"
|
||||
placeholder="8080" min="1" max="65535" required>
|
||||
<div class="form-text">
|
||||
Puerto del servicio API (ejemplo: 8080, 80, 443)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Usuario -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="winsaai_usuario" class="form-label">
|
||||
<i class="fas fa-user me-1"></i>
|
||||
Usuario
|
||||
</label>
|
||||
<input type="text" class="form-control" id="winsaai_usuario"
|
||||
placeholder="Tu usuario de WINSAAI" required>
|
||||
<div class="form-text">
|
||||
Nombre de usuario proporcionado por WINSAAI
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contraseña -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="winsaai_password" class="form-label">
|
||||
<i class="fas fa-lock me-1"></i>
|
||||
Contraseña
|
||||
</label>
|
||||
<input type="password" class="form-control" id="winsaai_password"
|
||||
placeholder="Tu contraseña" required>
|
||||
<div class="form-text">
|
||||
Contraseña de acceso al sistema WINSAAI
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Protocolo -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="winsaai_protocol" class="form-label">
|
||||
<i class="fas fa-shield-alt me-1"></i>
|
||||
Protocolo
|
||||
</label>
|
||||
<select class="form-select" id="winsaai_protocol" required>
|
||||
<option value="">Seleccionar protocolo</option>
|
||||
<option value="http">HTTP</option>
|
||||
<option value="https">HTTPS (Recomendado)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Estado Actual -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">
|
||||
<i class="fas fa-info-circle me-1"></i>
|
||||
Estado Actual
|
||||
</label>
|
||||
<div id="connection_status_display" class="form-control-plaintext">
|
||||
<span class="badge bg-secondary">No configurado</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Opciones de sincronización -->
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
<label class="form-label">
|
||||
<i class="fas fa-sync me-1"></i>
|
||||
Datos a sincronizar
|
||||
</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="sync_pedimentos" checked>
|
||||
<label class="form-check-label" for="sync_pedimentos">
|
||||
<i class="fas fa-file-alt me-1 text-primary"></i>
|
||||
Pedimentos
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="sync_coves" checked>
|
||||
<label class="form-check-label" for="sync_coves">
|
||||
<i class="fas fa-ship me-1 text-info"></i>
|
||||
COVES
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Botones de acción -->
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<button type="button" class="btn btn-outline-secondary btn-animated"
|
||||
onclick="testConnection()">
|
||||
<i class="fas fa-vial me-2"></i>
|
||||
Probar Conexión
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary btn-animated">
|
||||
<i class="fas fa-save me-2"></i>
|
||||
Guardar Configuración
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning btn-animated"
|
||||
onclick="syncData()">
|
||||
<i class="fas fa-sync-alt me-2"></i>
|
||||
Sincronizar Ahora
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Estado de conexión -->
|
||||
<div id="connectionStatus" class="mt-3" style="display: none;">
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle me-2"></i>
|
||||
<span id="statusMessage">Verificando conexión...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Scripts para funcionalidad WINSAAI -->
|
||||
<script>
|
||||
let currentConfig = null;
|
||||
|
||||
// Cargar configuración al inicio
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadExistingConfig();
|
||||
});
|
||||
|
||||
// Cargar configuración existente
|
||||
async function loadExistingConfig() {
|
||||
try {
|
||||
const response = await fetch('/IMPORTADORES/winsaai/get_config');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success && result.data) {
|
||||
currentConfig = result.data;
|
||||
showExistingConfig(result.data);
|
||||
} else {
|
||||
showNoConfig();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error cargando configuración:', error);
|
||||
showNoConfig();
|
||||
}
|
||||
}
|
||||
|
||||
// Mostrar estado cuando NO hay configuración
|
||||
function showNoConfig() {
|
||||
document.getElementById('no_config_section').style.display = 'block';
|
||||
document.getElementById('existing_config_section').style.display = 'none';
|
||||
document.getElementById('connection_status_header').innerHTML = '<span class="badge bg-secondary">Sin configurar</span>';
|
||||
}
|
||||
|
||||
// Mostrar estado cuando SÍ hay configuración
|
||||
function showExistingConfig(config) {
|
||||
// Ocultar sección de "no config" y mostrar sección existente
|
||||
document.getElementById('no_config_section').style.display = 'none';
|
||||
document.getElementById('existing_config_section').style.display = 'block';
|
||||
|
||||
// Actualizar información mostrada
|
||||
document.getElementById('current_server').textContent = `${config.protocol}://${config.host}:${config.port}`;
|
||||
document.getElementById('current_user').textContent = config.usuario;
|
||||
document.getElementById('current_protocol').textContent = config.protocol.toUpperCase();
|
||||
|
||||
// Mostrar última sincronización
|
||||
if (config.last_sync) {
|
||||
const lastSyncDate = new Date(config.last_sync);
|
||||
document.getElementById('last_sync_display').textContent = lastSyncDate.toLocaleString();
|
||||
} else {
|
||||
document.getElementById('last_sync_display').textContent = 'Nunca';
|
||||
}
|
||||
|
||||
// Mostrar badges de sincronización
|
||||
const pedimentosBadge = document.getElementById('sync_pedimentos_badge');
|
||||
const covesBadge = document.getElementById('sync_coves_badge');
|
||||
|
||||
if (config.sync_pedimentos) {
|
||||
pedimentosBadge.style.display = 'inline-block';
|
||||
} else {
|
||||
pedimentosBadge.style.display = 'none';
|
||||
}
|
||||
|
||||
if (config.sync_coves) {
|
||||
covesBadge.style.display = 'inline-block';
|
||||
} else {
|
||||
covesBadge.style.display = 'none';
|
||||
}
|
||||
|
||||
// Actualizar header según estado
|
||||
updateHeaderStatus(config.status);
|
||||
|
||||
// Actualizar botón de toggle según estado
|
||||
updateToggleButton(config.status);
|
||||
|
||||
// Llenar formulario con datos existentes para edición
|
||||
document.getElementById('winsaai_host').value = config.host || '';
|
||||
document.getElementById('winsaai_port').value = config.port || '';
|
||||
document.getElementById('winsaai_protocol').value = config.protocol || '';
|
||||
document.getElementById('winsaai_usuario').value = config.usuario || '';
|
||||
document.getElementById('sync_pedimentos').checked = config.sync_pedimentos == 1;
|
||||
document.getElementById('sync_coves').checked = config.sync_coves == 1;
|
||||
}
|
||||
|
||||
// Actualizar estado en el header
|
||||
function updateHeaderStatus(status) {
|
||||
const headerStatus = document.getElementById('connection_status_header');
|
||||
let badgeHtml = '';
|
||||
|
||||
switch(status) {
|
||||
case 'activo':
|
||||
badgeHtml = '<span class="badge bg-success"><i class="fas fa-check-circle me-1"></i>Conectado</span>';
|
||||
break;
|
||||
case 'inactivo':
|
||||
badgeHtml = '<span class="badge bg-warning"><i class="fas fa-pause me-1"></i>Inactivo</span>';
|
||||
break;
|
||||
case 'error':
|
||||
badgeHtml = '<span class="badge bg-danger"><i class="fas fa-exclamation-triangle me-1"></i>Error</span>';
|
||||
break;
|
||||
default:
|
||||
badgeHtml = '<span class="badge bg-secondary">Sin configurar</span>';
|
||||
}
|
||||
|
||||
headerStatus.innerHTML = badgeHtml;
|
||||
}
|
||||
|
||||
// Actualizar botón de toggle según estado
|
||||
function updateToggleButton(status) {
|
||||
const toggleBtn = document.querySelector('button[onclick="toggleConfigStatus()"]');
|
||||
const toggleText = document.getElementById('toggle_status_text');
|
||||
const icon = toggleBtn.querySelector('i');
|
||||
|
||||
if (status === 'activo') {
|
||||
toggleText.textContent = 'Desactivar';
|
||||
icon.className = 'fas fa-pause me-2';
|
||||
toggleBtn.className = 'btn btn-outline-warning btn-animated btn-sm';
|
||||
} else {
|
||||
toggleText.textContent = 'Activar';
|
||||
icon.className = 'fas fa-play me-2';
|
||||
toggleBtn.className = 'btn btn-outline-success btn-animated btn-sm';
|
||||
}
|
||||
}
|
||||
|
||||
// Mostrar formulario de configuración
|
||||
function showConfigForm(isEdit = false) {
|
||||
const formTitle = document.getElementById('form_title');
|
||||
const configCollapse = new bootstrap.Collapse(document.getElementById('winsaaiConfig'), { show: true });
|
||||
|
||||
if (isEdit) {
|
||||
formTitle.textContent = 'Editar Configuración de WINSAAI';
|
||||
} else {
|
||||
formTitle.textContent = 'Nueva Configuración de WINSAAI';
|
||||
// Limpiar formulario para nueva configuración
|
||||
document.getElementById('winsaaiForm').reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Ocultar formulario de configuración
|
||||
function hideConfigForm() {
|
||||
const configCollapse = new bootstrap.Collapse(document.getElementById('winsaaiConfig'), { hide: true });
|
||||
}
|
||||
|
||||
// Probar conexión con configuración existente
|
||||
async function testExistingConnection() {
|
||||
if (!currentConfig) {
|
||||
showStatus('error', 'No hay configuración para probar');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus('info', 'Probando conexión con configuración actual...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/IMPORTADORES/winsaai/test_connection', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
host: currentConfig.host,
|
||||
port: currentConfig.port,
|
||||
protocol: currentConfig.protocol,
|
||||
usuario: currentConfig.usuario,
|
||||
password: 'existing_config' // Indicador para usar configuración guardada
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('success', result.message);
|
||||
updateHeaderStatus('activo');
|
||||
} else {
|
||||
showStatus('error', result.message);
|
||||
updateHeaderStatus('error');
|
||||
}
|
||||
} catch (error) {
|
||||
showStatus('error', 'Error de red: ' + error.message);
|
||||
updateHeaderStatus('error');
|
||||
}
|
||||
}
|
||||
|
||||
// Activar/Desactivar configuración
|
||||
async function toggleConfigStatus() {
|
||||
if (!currentConfig) {
|
||||
showStatus('error', 'No hay configuración para modificar');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentStatus = currentConfig.status;
|
||||
const newStatus = currentStatus === 'activo' ? 'inactivo' : 'activo';
|
||||
const action = newStatus === 'activo' ? 'activar' : 'desactivar';
|
||||
|
||||
if (confirm(`¿Estás seguro de que deseas ${action} la configuración de WINSAAI?`)) {
|
||||
showStatus('info', `${action === 'activar' ? 'Activando' : 'Desactivando'} configuración...`);
|
||||
|
||||
try {
|
||||
// Aquí harías la llamada al servidor para cambiar el estado
|
||||
// Por ahora simularemos el cambio
|
||||
currentConfig.status = newStatus;
|
||||
updateHeaderStatus(newStatus);
|
||||
updateToggleButton(newStatus);
|
||||
showStatus('success', `Configuración ${action === 'activar' ? 'activada' : 'desactivada'} correctamente`);
|
||||
} catch (error) {
|
||||
showStatus('error', `Error al ${action} configuración: ` + error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminar configuración
|
||||
async function deleteConfig() {
|
||||
if (!currentConfig) {
|
||||
showStatus('error', 'No hay configuración para eliminar');
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirm('¿Estás seguro de que deseas eliminar completamente la configuración de WINSAAI? Esta acción no se puede deshacer.')) {
|
||||
showStatus('info', 'Eliminando configuración...');
|
||||
|
||||
try {
|
||||
// Aquí harías la llamada al servidor para eliminar
|
||||
// Por ahora simularemos la eliminación
|
||||
currentConfig = null;
|
||||
showNoConfig();
|
||||
hideConfigForm();
|
||||
showStatus('success', 'Configuración eliminada correctamente');
|
||||
} catch (error) {
|
||||
showStatus('error', 'Error al eliminar configuración: ' + error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Función para probar la conexión (desde formulario)
|
||||
async function testConnection() {
|
||||
const host = document.getElementById('winsaai_host').value;
|
||||
const port = document.getElementById('winsaai_port').value;
|
||||
const protocol = document.getElementById('winsaai_protocol').value;
|
||||
const usuario = document.getElementById('winsaai_usuario').value;
|
||||
const password = document.getElementById('winsaai_password').value;
|
||||
|
||||
if (!host || !port || !protocol || !usuario || !password) {
|
||||
showStatus('error', 'Por favor completa todos los campos obligatorios');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus('info', 'Probando conexión con WINSAAI...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/IMPORTADORES/winsaai/test_connection', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
host: host,
|
||||
port: parseInt(port),
|
||||
protocol: protocol,
|
||||
usuario: usuario,
|
||||
password: password
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('success', result.message);
|
||||
} else {
|
||||
showStatus('error', result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
showStatus('error', 'Error de red: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Función para sincronizar datos
|
||||
async function syncData() {
|
||||
let pedimentos, coves;
|
||||
|
||||
if (currentConfig) {
|
||||
// Usar configuración existente
|
||||
pedimentos = currentConfig.sync_pedimentos;
|
||||
coves = currentConfig.sync_coves;
|
||||
} else {
|
||||
// Usar valores del formulario
|
||||
pedimentos = document.getElementById('sync_pedimentos').checked;
|
||||
coves = document.getElementById('sync_coves').checked;
|
||||
}
|
||||
|
||||
if (!pedimentos && !coves) {
|
||||
showStatus('warning', 'No hay datos configurados para sincronizar');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus('info', 'Iniciando sincronización de datos...');
|
||||
|
||||
let syncType = 'both';
|
||||
if (pedimentos && !coves) syncType = 'pedimentos';
|
||||
else if (!pedimentos && coves) syncType = 'coves';
|
||||
|
||||
try {
|
||||
const response = await fetch('/IMPORTADORES/winsaai/sync_data', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
sync_type: syncType
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
let message = 'Sincronización completada: ';
|
||||
if (result.data.pedimentos) {
|
||||
message += `${result.data.pedimentos.processed} pedimentos `;
|
||||
}
|
||||
if (result.data.coves) {
|
||||
message += `${result.data.coves.processed} COVES `;
|
||||
}
|
||||
showStatus('success', message);
|
||||
|
||||
// Actualizar última sincronización si hay configuración
|
||||
if (currentConfig) {
|
||||
currentConfig.last_sync = new Date().toISOString();
|
||||
document.getElementById('last_sync_display').textContent = new Date().toLocaleString();
|
||||
}
|
||||
} else {
|
||||
showStatus('error', result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
showStatus('error', 'Error de red: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Función para mostrar estado
|
||||
function showStatus(type, message) {
|
||||
const statusDiv = document.getElementById('connectionStatus');
|
||||
const statusMessage = document.getElementById('statusMessage');
|
||||
const alertDiv = statusDiv.querySelector('.alert');
|
||||
|
||||
// Remover clases anteriores
|
||||
alertDiv.className = 'alert';
|
||||
|
||||
// Agregar nueva clase según el tipo
|
||||
switch(type) {
|
||||
case 'success':
|
||||
alertDiv.classList.add('alert-success');
|
||||
statusMessage.innerHTML = `<i class="fas fa-check-circle me-2"></i>${message}`;
|
||||
break;
|
||||
case 'error':
|
||||
alertDiv.classList.add('alert-danger');
|
||||
statusMessage.innerHTML = `<i class="fas fa-exclamation-circle me-2"></i>${message}`;
|
||||
break;
|
||||
case 'warning':
|
||||
alertDiv.classList.add('alert-warning');
|
||||
statusMessage.innerHTML = `<i class="fas fa-exclamation-triangle me-2"></i>${message}`;
|
||||
break;
|
||||
default:
|
||||
alertDiv.classList.add('alert-info');
|
||||
statusMessage.innerHTML = `<i class="fas fa-info-circle me-2"></i>${message}`;
|
||||
}
|
||||
|
||||
statusDiv.style.display = 'block';
|
||||
|
||||
// Auto-ocultar después de 5 segundos para mensajes de éxito
|
||||
if (type === 'success') {
|
||||
setTimeout(() => {
|
||||
statusDiv.style.display = 'none';
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Manejar envío del formulario
|
||||
document.getElementById('winsaaiForm').addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const config = {
|
||||
host: document.getElementById('winsaai_host').value,
|
||||
port: parseInt(document.getElementById('winsaai_port').value),
|
||||
protocol: document.getElementById('winsaai_protocol').value,
|
||||
usuario: document.getElementById('winsaai_usuario').value,
|
||||
password: document.getElementById('winsaai_password').value,
|
||||
sync_pedimentos: document.getElementById('sync_pedimentos').checked,
|
||||
sync_coves: document.getElementById('sync_coves').checked
|
||||
};
|
||||
|
||||
// Validar campos obligatorios
|
||||
if (!config.host || !config.port || !config.protocol || !config.usuario || !config.password) {
|
||||
showStatus('error', 'Por favor completa todos los campos obligatorios');
|
||||
return;
|
||||
}
|
||||
|
||||
showStatus('info', 'Guardando configuración...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/IMPORTADORES/winsaai/save_config', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(config)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showStatus('success', result.message);
|
||||
// Recargar configuración para mostrar el nuevo estado
|
||||
await loadExistingConfig();
|
||||
hideConfigForm();
|
||||
} else {
|
||||
showStatus('error', result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error completo:', error);
|
||||
showStatus('error', 'Error de red: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Animación suave para el collapse
|
||||
document.getElementById('winsaaiConfig').addEventListener('show.bs.collapse', function() {
|
||||
this.style.opacity = '0';
|
||||
this.style.transform = 'translateY(-20px)';
|
||||
setTimeout(() => {
|
||||
this.style.transition = 'all 0.3s ease';
|
||||
this.style.opacity = '1';
|
||||
this.style.transform = 'translateY(0)';
|
||||
}, 50);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -67,7 +67,7 @@
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🏪 Registro de Agencias</h4>
|
||||
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="tabla-registros-agencias">
|
||||
<thead class="table-dark">
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">🔄 Cambios de Usuario</h4>
|
||||
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped align-middle" id="tabla-bitacora-usuarios">
|
||||
<thead class="table-dark">
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<div class="content">
|
||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">👥 Acceso de Usuarios</h4>
|
||||
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto">
|
||||
<div class="card p-3 shadow-sm card-hover position-relative h-auto fade-in-up">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="tabla-logins">
|
||||
<thead class="table-dark">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user