diff --git a/agencias.txt b/agencias.txt
index a655797..d695f0a 100644
--- a/agencias.txt
+++ b/agencias.txt
@@ -1,4 +1,33 @@
--- 1. Tabla de Agencias Aduanales
+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,
@@ -15,15 +44,33 @@ CREATE TABLE [dbo].[agencias_aduanales](
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,
--- 2. Actualizar tipos de usuario válidos
+ 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:
@@ -34,11 +81,10 @@ FOREIGN KEY ([id_administrador]) REFERENCES [dbo].[usuarios_sistema]([id_usuario
-- Campos de auditoría para usuarios_sistema
ALTER TABLE [dbo].[usuarios_sistema]
-ADD [actualizado_en] [datetime] NULL,
- [creado_por] [int] NULL;
+ADD [creado_por] [int] NULL;
--- 3. Tabla de relación importador-agencia (many-to-many)
+-- Tabla de relación importador-agencia (many-to-many)
CREATE TABLE [dbo].[importador_agencia](
[id_relacion] [int] IDENTITY(1,1) NOT NULL,
@@ -68,7 +114,7 @@ ON [dbo].[importador_agencia] ([id_importador], [id_agencia])
WHERE [activo] = 1;
--- 4. Tabla de relación agente-agencia
+-- Tabla de relación agente-agencia
CREATE TABLE [dbo].[agente_agencia](
[id_relacion] INT IDENTITY(1,1) NOT NULL,
@@ -81,11 +127,15 @@ CREATE TABLE [dbo].[agente_agencia](
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]),
- CONSTRAINT [UQ_agente_activo]
- UNIQUE ([id_agente]) WHERE [activo] = 1 -- evita duplicados activos
+ 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]
@@ -93,7 +143,7 @@ ON [dbo].[agente_agencia] ([id_agente], [id_agencia])
WHERE [activo] = 1;
--- 5. Tabla para solicitudes de vinculación de importadores
+-- Tabla para solicitudes de vinculación de importadores
CREATE TABLE [dbo].[solicitudes_vinculacion](
[id_solicitud] [int] IDENTITY(1,1) NOT NULL,
@@ -115,25 +165,32 @@ CREATE TABLE [dbo].[solicitudes_vinculacion](
);
--- 6. Tabla para auditoría de cambios de agencia
+-- Tabla para auditoría de cambios de agencia
-CREATE TABLE [dbo].[historial_agencia](
- [id_historial] [int] IDENTITY(1,1) NOT NULL,
- [id_importador] [int] NULL,
- [id_agente] [int] NULL,
- [id_agencia_anterior] [int] NULL,
- [id_agencia_nueva] [int] NULL,
- [accion] [varchar](50) NOT NULL, -- 'VINCULACION', 'DESVINCULACION'
- [motivo] [nvarchar](500) NULL,
+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_cambio] [datetime] NOT NULL DEFAULT GETDATE(),
- [datos_adicionales] [nvarchar](max) NULL, -- JSON con información adicional
- CONSTRAINT [PK_historial_agencia_cambios] PRIMARY KEY CLUSTERED ([id_historial] ASC)
+ [fecha] [datetime] NOT NULL DEFAULT GETDATE(),
+ CONSTRAINT [PK_bitacora_agenciaS] PRIMARY KEY CLUSTERED ([id_bitacora] ASC)
);
--- Índices adicionales para mejorar rendimiento
+ALTER TABLE [dbo].[bitacora_agencias]
+ADD CONSTRAINT [FK_bitacora_agencias_agencia]
+FOREIGN KEY ([id_agencia]) REFERENCES [dbo].[agencias_aduanales]([id_agencia]);
-CREATE INDEX [IX_usuarios_tipo_agencia] ON [dbo].[usuarios_sistema] ([tipo_usuario], [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]);
diff --git a/app/controllers/administrador.php b/app/controllers/administrador.php
new file mode 100644
index 0000000..629cf58
--- /dev/null
+++ b/app/controllers/administrador.php
@@ -0,0 +1,1057 @@
+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 = 'Tu acceso a la plataforma SIIH ha sido autorizado';
+
+ $mail->Body = "
+
+
+
+
¡Bienvenido a SIIH!
+
+
+
Tu registro como importador ha sido aprobado. Aquí tienes tus credenciales de acceso:
+
Correo: $email
+
Contraseña: $password_plain
+
📌 Te recomendamos cambiar tu contraseña una vez que ingreses al sistema.
+
Ir al sistema
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+ } catch (Exception $e) {
+ error_log("Error al enviar correo: {$mail->ErrorInfo}");
+ }
+
+ header("Location: /IMPORTADORES/administrador/aprobarUsuarios?success=approved");
+ exit;
+}
+
+function altaUsuarios()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $sql = "SELECT * FROM usuarios_sistema WHERE activo = 1 ORDER BY creado_en DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ $usuarios = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $usuarios[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/alta_usuarios.php';
+}
+
+function guardar_usuario()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=unauthorized");
+ exit;
+ }
+
+ $conn = getConnection();
+
+ // 1. Capturar y validar datos
+ $nombre = trim($_POST['nombre'] ?? '');
+ $email = trim($_POST['email'] ?? '');
+ $password = $_POST['password'] ?? '';
+ $tipo = $_POST['tipo_usuario'] ?? '';
+
+ if (empty($nombre) || empty($email) || empty($password) || empty($tipo)) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=invalid_data");
+ exit;
+ }
+
+ if (!in_array($tipo, ['importador', 'super_admin'])) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=invalid_user_type");
+ exit;
+ }
+
+ // 2. Encriptar datos sensibles
+ $nombre_encrypted = encrypt($nombre);
+ $email_encrypted = encrypt($email);
+ $password_hash = password_hash($password, PASSWORD_DEFAULT);
+
+ // 3. Validar duplicado por email encriptado
+ $sqlCheck = "SELECT COUNT(*) AS total FROM usuarios_sistema WHERE email = ?";
+ $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$email_encrypted]);
+ $rowCheck = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
+ if ($rowCheck['total'] > 0) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=email_exists");
+ exit;
+ }
+
+ // 4. Insertar usuario
+ $sqlInsert = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
+ VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)";
+ $params = [$nombre_encrypted, $email_encrypted, $password_hash, $tipo, $_SESSION['usuario_id']];
+
+ $stmtInsert = sqlsrv_query($conn, $sqlInsert, $params);
+
+ if ($stmtInsert === false) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=save_failed");
+ exit;
+ }
+
+ // 5. Obtener ID del nuevo usuario (para posibles tablas relacionadas)
+ $sqlGetId = "SELECT SCOPE_IDENTITY() AS id_usuario";
+ $stmtGetId = sqlsrv_query($conn, $sqlGetId);
+ $idUsuarioRow = sqlsrv_fetch_array($stmtGetId, SQLSRV_FETCH_ASSOC);
+ $id_usuario = $idUsuarioRow['id_usuario'] ?? null;
+
+ // 6. Enviar correo de bienvenida
+ $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); // Email sin encriptar para el envío
+ $mail->CharSet = 'UTF-8';
+ $mail->isHTML(true);
+ $mail->Subject = 'Tu acceso a la plataforma SIIH ha sido creado';
+
+ // Determinar el tipo de usuario para el mensaje
+ $tipoUsuarioTexto = match($tipo) {
+ 'importador' => 'importador',
+ 'super_admin' => 'administrador'
+ };
+
+ $mail->Body = "
+
+
+
+
¡Bienvenido a SIIH!
+
+
+
Hola $nombre,
+
Se ha creado tu cuenta en la plataforma SIIH con el rol de $tipoUsuarioTexto.
+
Aquí tienes tus credenciales de acceso:
+
+
Correo: $email
+
Contraseña: $password
+
+
📌 Importante: Te recomendamos cambiar tu contraseña una vez que ingreses al sistema por primera vez.
+
+
+ Acceder al Sistema
+
+
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+
+ // Log de éxito (opcional)
+ error_log("Correo de bienvenida enviado exitosamente a: $email");
+
+ } catch (Exception $e) {
+ // Log del error pero no detener el proceso
+ error_log("Error al enviar correo de bienvenida a $email: {$mail->ErrorInfo}");
+
+ // Opcional: Puedes mostrar una advertencia al usuario
+ $_SESSION['mensaje_advertencia'] = "Usuario creado exitosamente, pero no se pudo enviar el correo de bienvenida.";
+ }
+
+ // 7. Redirigir con mensaje de éxito
+ $_SESSION['mensaje_exito'] = "Usuario creado exitosamente. Se ha enviado un correo con las credenciales de acceso.";
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?success=created");
+ exit;
+}
+
+function usuariosInactivos()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT * FROM usuarios_sistema WHERE activo = 0 ORDER BY creado_en DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ $usuarios = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $usuarios[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/usuarios_inactivos.php';
+}
+
+/** AGENCIAS **/
+function aprobarAgencias()
+{
+ if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $sql = "SELECT request_id, agencia_name, rfc, email, phone, request_date, opinion_file
+ FROM solicitudes_agencias
+ WHERE request_status = 'pending'
+ ORDER BY request_date DESC";
+
+ $stmt = sqlsrv_query($conn, $sql);
+ $solicitudes = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $solicitudes[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/aprobar_agencias.php';
+}
+
+function aprobar_agencia()
+{
+ $conn = getConnection();
+ $id = $_GET['id'] ?? null;
+ $usuario_id = $_SESSION['usuario_id'];
+
+ if (!$id || !is_numeric($id)) {
+ die("❌ ID inválido.");
+ }
+
+ // 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) {
+ die("❌ Solicitud no encontrada.");
+ }
+
+ // Validar que no haya sido aprobada ya
+ if ($solicitud['request_status'] === 'approved') {
+ die("⚠️ Esta solicitud ya fue aprobada.");
+ }
+
+ // Preparar datos
+ $nombre = decrypt($solicitud['agencia_name']);
+ $email = $solicitud['email'];
+ $rfc = decrypt($solicitud['rfc']);
+ $phone = $solicitud['phone'];
+ $direccion = $solicitud['direccion'];
+
+ // Preparar datos de administrador de agencia
+ $admin_name = decrypt($solicitud['admin_name']);
+ $admin_email = $solicitud['admin_email'];
+ $tipo = 'admin_agencia';
+
+ // Generar contraseña aleatoria
+ $password_plain = bin2hex(random_bytes(5));
+ $password_hash = password_hash($password_plain, PASSWORD_DEFAULT);
+
+ // Encriptar datos sensibles
+ $nombre_encrypt = encrypt($nombre);
+ $email_encrypt = encrypt($email);
+ $admin_name_encrypt = encrypt($admin_name);
+ $admin_email_encrypt = encrypt($admin_email);
+
+ // Insertar en agencias_aduanales
+ $sqlInsert = "INSERT INTO agencias_aduanales (nombre_agencia, rfc_agencia, direccion, telefono, email, creado_en, creado_por)
+ VALUES (?, ?, ?, ?, ?, GETDATE()), ?";
+ $stmtInsert = sqlsrv_query($conn, $sqlInsert, [
+ $nombre_encrypt, $rfc, $direccion, $phone, $email_encrypt, $usuario_id
+ ]);
+
+ if (!$stmtInsert) {
+ die("❌ Error al crear agencia: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Obtener ID de la agencia recién creada
+ $sqlGetAgenciaId = "SELECT SCOPE_IDENTITY() AS id_agencia";
+ $stmtGetAgenciaId = sqlsrv_query($conn, $sqlGetAgenciaId);
+ $agenciaIdRow = sqlsrv_fetch_array($stmtGetAgenciaId, SQLSRV_FETCH_ASSOC);
+ $id_agencia = $idUsuarioRow['id_agencia'] ?? null;
+
+ if (!$id_agencia) {
+ die("❌ No se pudo obtener el ID de la agencia recién creada.");
+ }
+
+ // Insertar en usuarios_sistema
+ $sqlInsert2 = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos factores, creado_por)
+ VALUES (?, ?, ?, ?, 1, GETDATE()), 0, ?";
+ $stmtInsert2 = sqlsrv_query($conn, $sqlInsert, [
+ $admin_name_encrypt, $admin_email_encrypt, $password_hash, $tipo, $usuario_id
+ ]);
+
+ if (!$stmtInsert2) {
+ die("❌ Error al crear usuario administrador: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Obtener ID del nuevo usuario
+ $sqlGetId = "SELECT SCOPE_IDENTITY() AS id_usuario";
+ $stmtGetId = sqlsrv_query($conn, $sqlGetId);
+ $idUsuarioRow = sqlsrv_fetch_array($stmtGetId, SQLSRV_FETCH_ASSOC);
+ $id_usuario = $idUsuarioRow['id_usuario'] ?? null;
+
+ if (!$id_usuario) {
+ die("❌ No se pudo obtener el ID del usuario recién creado.");
+ }
+
+ // Actualizar agencia con el ID del administrador
+ $sqlUpdateAgencia = "UPDATE agencias_aduanales SET id_administrador = ? WHERE id_agencia = ?";
+ $stmtUpdateAgencia = sqlsrv_query($conn, $sqlUpdateAgencia, [$id_usuario, $id_agencia]);
+
+ if (!$stmtUpdateAgencia) {
+ die("❌ Error al actualizar agencia con administrador: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Insertar en informacion_general
+ $sqlInfo = "INSERT INTO informacion_general
+ (id_usuario, nombre, correo)
+ VALUES (?, ?, ?)";
+ $stmtInfo = sqlsrv_query($conn, $sqlInfo, [
+ $id_usuario, $admin_name, $admin_email
+ ]);
+
+ if (!$stmtInfo) {
+ die("❌ Error al insertar información general: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Actualizar solicitud
+ $sqlUpdate = "UPDATE solicitudes_agencias
+ SET request_status = 'approved', approval_date = GETDATE(), approved_by = ?
+ WHERE request_id = ?";
+ $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$usuario_id, $id]);
+
+ if (!$stmtUpdate) {
+ die("❌ Error al actualizar solicitud: " . print_r(sqlsrv_errors(), true));
+ }
+
+ // Enviar correo a la agencia
+ $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 = 'Te asignaron como administrador de agencia en SIIH';
+
+ $mail->Body = "
+
+
+
+
¡Bienvenido a SIIH!
+
+
+
Te asignaron como administrador de la agencia $nombre
+
Correo: $admin_email
+
Contraseña: $password_plain
+
📌 Te recomendamos cambiar tu contraseña una vez que ingreses al sistema.
+
Ir al sistema
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+
+ } catch (Exception $e) {
+ error_log("Error al enviar correo: {$mail->ErrorInfo}");
+ }
+
+ header("Location: /IMPORTADORES/administrador/agenciasActivas");
+ exit;
+}
+
+function altaAgencias()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT * FROM agencias_aduanales ORDER BY creado_en DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ $agencias = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $agencias[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/alta_agencias.php';
+}
+
+function guardar_agencia()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header("Location: /IMPORTADORES/administrador/altaAgencias?error=unauthorized");
+ exit;
+ }
+
+ $conn = getConnection();
+
+ try {
+ if (!sqlsrv_begin_transaction($conn)) {
+ error_log("ERROR: No se pudo iniciar la transacción");
+ throw new Exception("Error al iniciar transacción");
+ }
+
+ error_log("Transacción iniciada correctamente");
+
+ // 1️⃣ Captura y validación de datos
+ $nombre_agencia = trim($_POST['nombre_agencia'] ?? '');
+ $rfc_agencia = trim($_POST['rfc_agencia'] ?? '');
+ $correo_agencia = trim($_POST['correo'] ?? '');
+ $telefono = trim($_POST['telefono'] ?? '');
+ $direccion = trim($_POST['direccion'] ?? '');
+ $nombre_admin = trim($_POST['nombre_admin'] ?? '');
+ $correo_admin = trim($_POST['correo_admin'] ?? '');
+
+ error_log("Datos recibidos:");
+ error_log("- Nombre agencia: " . $nombre_agencia);
+ error_log("- RFC: " . $rfc_agencia);
+ error_log("- Correo agencia: " . $correo_agencia);
+
+ if (empty($nombre_agencia) || empty($rfc_agencia) || empty($correo_agencia) ||
+ empty($telefono) || empty($direccion) || empty($nombre_admin) || empty($correo_admin)) {
+ error_log("ERROR: Datos incompletos");
+ throw new Exception("Datos incompletos");
+ }
+
+ // 2️⃣ Verificar función de encriptación
+ if (!function_exists('encrypt')) {
+ error_log("ERROR: Función encrypt no existe");
+ throw new Exception("Función de encriptación no disponible");
+ }
+
+ // Encriptar datos
+ $nombre_agencia_enc = encrypt($nombre_agencia);
+ $correo_agencia_enc = encrypt($correo_agencia);
+ $nombre_admin_enc = encrypt($nombre_admin);
+ $correo_admin_enc = encrypt($correo_admin);
+
+ error_log("Datos encriptados correctamente");
+
+ // 3️⃣ CREAR USUARIO ADMINISTRADOR Y OBTENER SU ID EN UNA SOLA CONSULTA
+ $password_plain = bin2hex(random_bytes(5));
+ $password_hash = password_hash($password_plain, PASSWORD_DEFAULT);
+
+ error_log("Password generado: " . $password_plain);
+
+ // ✅ SOLUCIÓN: INSERT con OUTPUT para obtener el ID inmediatamente
+ $sqlInsertAdmin = "
+ INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
+ OUTPUT INSERTED.id_usuario
+ VALUES (?, ?, ?, 'admin_agencia', 1, GETDATE(), 0, ?);
+ ";
+
+ $paramsAdmin = [$nombre_admin_enc, $correo_admin_enc, $password_hash, $_SESSION['usuario_id']];
+ $stmtAdmin = sqlsrv_query($conn, $sqlInsertAdmin, $paramsAdmin);
+
+ if (!$stmtAdmin) {
+ $errors = sqlsrv_errors();
+ error_log("ERROR SQL Admin: " . print_r($errors, true));
+ throw new Exception("Error al crear administrador: " . print_r($errors, true));
+ }
+
+ // Obtener el ID directamente del resultado del OUTPUT
+ $rowAdmin = sqlsrv_fetch_array($stmtAdmin, SQLSRV_FETCH_ASSOC);
+ $id_admin = $rowAdmin['id_usuario'] ?? null;
+
+ if (!$id_admin) {
+ error_log("ERROR: ID de administrador es null");
+ throw new Exception("No se pudo obtener ID de administrador");
+ }
+
+ error_log("Usuario administrador creado exitosamente con ID: " . $id_admin);
+
+ // 4️⃣ CREAR AGENCIA Y OBTENER SU ID
+ $sqlInsertAgencia = "
+ INSERT INTO agencias_aduanales (nombre_agencia, rfc_agencia, direccion, telefono, email, id_administrador, activo, creado_en, creado_por)
+ OUTPUT INSERTED.id_agencia
+ VALUES (?, ?, ?, ?, ?, ?, 1, GETDATE(), ?)
+ ";
+ $paramsAgencia = [$nombre_agencia_enc, $rfc_agencia, $direccion, $telefono, $correo_agencia_enc, $id_admin, $_SESSION['usuario_id']];
+
+ error_log("Ejecutando SQL Agencia con ID admin: " . $id_admin);
+ $stmtAgencia = sqlsrv_query($conn, $sqlInsertAgencia, $paramsAgencia);
+
+ if (!$stmtAgencia) {
+ $errors = sqlsrv_errors();
+ error_log("ERROR SQL Agencia: " . print_r($errors, true));
+ throw new Exception("Error al crear agencia: " . print_r($errors, true));
+ }
+
+ // Obtener el ID de la agencia directamente
+ $rowAgencia = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC);
+ $id_agencia = $rowAgencia['id_agencia'] ?? null;
+
+ if (!$id_agencia) {
+ error_log("ERROR: ID de agencia es null");
+ throw new Exception("No se pudo obtener ID de agencia");
+ }
+
+ error_log("Agencia creada exitosamente con ID: " . $id_agencia);
+
+ // 5️⃣ CREAR RELACIÓN AGENTE-AGENCIA
+ $sqlInsertRelacion = "INSERT INTO agente_agencia (id_agente, id_agencia, fecha_asignacion, activo, asignado_por)
+ VALUES (?, ?, GETDATE(), 1, ?)";
+ $paramsRelacion = [$id_admin, $id_agencia, $_SESSION['usuario_id']];
+
+ error_log("Creando relación agente-agencia");
+ $stmtRelacion = sqlsrv_query($conn, $sqlInsertRelacion, $paramsRelacion);
+
+ if (!$stmtRelacion) {
+ $errors = sqlsrv_errors();
+ error_log("ERROR SQL Relación: " . print_r($errors, true));
+ throw new Exception("Error al crear relación agente-agencia: " . print_r($errors, true));
+ }
+
+ error_log("Relación agente-agencia creada exitosamente");
+
+ // 6️⃣ CONFIRMAR TRANSACCIÓN ✅
+ if (!sqlsrv_commit($conn)) {
+ error_log("ERROR: No se pudo confirmar la transacción");
+ throw new Exception("Error al confirmar transacción");
+ }
+
+ error_log("Transacción confirmada exitosamente");
+
+ // 7️⃣ Enviar correo (DESPUÉS de confirmar transacción)
+ if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
+ $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($correo_admin);
+ $mail->CharSet = 'UTF-8';
+ $mail->isHTML(true);
+ $mail->Subject = 'Te asignaron como administrador de una nueva agencia en SIIH';
+
+ $mail->Body = "
+
+
+
+
¡Bienvenido a SIIH!
+
+
+
Has sido registrado como Administrador de la agencia {$nombre_agencia}.
+
Correo de acceso: {$correo_admin}
+
Contraseña temporal: {$password_plain}
+
📌 Te recomendamos cambiar tu contraseña al primer inicio de sesión.
+
Ir al sistema
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+ error_log("Correo enviado exitosamente a: " . $correo_admin);
+
+ } catch (Exception $e) {
+ error_log("Error al enviar correo: " . $e->getMessage());
+ // No es crítico, continúa
+ }
+ }
+
+ // 8️⃣ Redirigir con éxito
+ error_log("=== FIN EXITOSO guardar_agencia ===");
+ header("Location: /IMPORTADORES/administrador/altaAgencias?success=created");
+ exit;
+
+ } catch (Exception $e) {
+ error_log("ERROR CAPTURADO: " . $e->getMessage());
+ if (!sqlsrv_rollback($conn)) {
+ error_log("ERROR: No se pudo revertir la transacción");
+ } else {
+ error_log("Transacción revertida exitosamente");
+ }
+
+ error_log("=== FIN CON ERROR guardar_agencia ===");
+ header("Location: /IMPORTADORES/administrador/altaAgencias?error=save_failed");
+ exit;
+ } finally {
+ if ($conn) {
+ sqlsrv_close($conn);
+ error_log("Conexión cerrada");
+ }
+ }
+}
+
+function agenciasActivas()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT * FROM agencias_aduanales ORDER BY creado_en DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ $agencias = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $agencias[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/agencias_activas.php';
+}
+
+
+function suspender()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=unauthorized");
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $id = $_GET['id'] ?? null;
+
+ if (!$id || !is_numeric($id)) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=invalid_id");
+ exit;
+ }
+
+ // Obtener el estado actual
+ $sqlEstado = "SELECT activo FROM usuarios_sistema WHERE id_usuario = ?";
+ $stmtEstado = sqlsrv_query($conn, $sqlEstado, [$id]);
+
+ if (!$stmtEstado || !($row = sqlsrv_fetch_array($stmtEstado, SQLSRV_FETCH_ASSOC))) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=user_not_found");
+ exit;
+ }
+
+ $nuevoEstado = $row['activo'] ? 0 : 1;
+
+ // Actualizar estado
+ $sqlUpdate = "UPDATE usuarios_sistema SET activo = ? WHERE id_usuario = ?";
+ $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$nuevoEstado, $id]);
+
+ if (!$stmtUpdate) {
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?error=update_failed");
+ exit;
+ }
+
+ // Determinar el tipo de cambio para el mensaje
+ $accion = $nuevoEstado ? 'activated' : 'deactivated';
+
+ header("Location: /IMPORTADORES/administrador/altaUsuarios?success=status_$accion");
+ exit;
+}
+
+function activar()
+{
+ if (!($_SESSION['tipo_usuario'] ?? false)) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=unauthorized");
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $id = $_GET['id'] ?? null;
+
+ if (!$id || !is_numeric($id)) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=invalid_id");
+ exit;
+ }
+
+ // Obtener el estado actual
+ $sqlEstado = "SELECT activo FROM usuarios_sistema WHERE id_usuario = ?";
+ $stmtEstado = sqlsrv_query($conn, $sqlEstado, [$id]);
+
+ if (!$stmtEstado || !($row = sqlsrv_fetch_array($stmtEstado, SQLSRV_FETCH_ASSOC))) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=user_not_found");
+ exit;
+ }
+
+ $nuevoEstado = $row['activo'] ? 0 : 1;
+
+ // Actualizar estado
+ $sqlUpdate = "UPDATE usuarios_sistema SET activo = ? WHERE id_usuario = ?";
+ $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$nuevoEstado, $id]);
+
+ if (!$stmtUpdate) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=update_failed");
+ exit;
+ }
+
+ // Determinar el tipo de cambio para el mensaje
+ $accion = $nuevoEstado ? 'activated' : 'deactivated';
+
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?success=status_$accion");
+ exit;
+}
+
+function reset_password()
+{
+ if (!($_SESSION['tipo_usuario'] ?? false)) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=unauthorized");
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $id = $_GET['id'] ?? null;
+
+ if (!$id || !is_numeric($id)) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=invalid_id");
+ exit;
+ }
+
+ // 🔐 Generar contraseña aleatoria de 10 caracteres
+ $randomPassword = bin2hex(random_bytes(5)); // genera algo como 'a8c4f1b92d'
+ $passwordHash = password_hash($randomPassword, PASSWORD_DEFAULT);
+
+ $sqlEmail = "SELECT email FROM usuarios_sistema WHERE id_usuario = ?";
+ $stmtEmail = sqlsrv_query($conn, $sqlEmail, [$id]);
+ $row = sqlsrv_fetch_array($stmtEmail, SQLSRV_FETCH_ASSOC);
+
+ $sql = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?";
+ $stmt = sqlsrv_query($conn, $sql, [$passwordHash, $id]);
+
+ if (!$stmt) {
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?error=update_failed");
+ exit;
+ }
+
+ enviar_password_directamente($row['email'], $randomPassword);
+
+ // 🔁 Redirigir pasando la contraseña como parámetro temporal (solo visible para el admin)
+ header("Location: /IMPORTADORES/administrador/usuariosInactivos?success=update_success");
+ exit;
+}
+
+function enviar_password_directamente($email_encrypted, $pass) {
+ $email = decrypt($email_encrypted);
+
+ $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 | AduanaSoft');
+ $mail->addAddress($email);
+
+ $mail->isHTML(true);
+ $mail->Subject = 'Nueva Contraseña de Acceso Temporal';
+ $mail->CharSet = 'UTF-8';
+ $logoURL = 'http://siih.aduanasoft.com/IMPORTADORES/public/assets/img/logo_siih.png';
+ $mail->Body = "
+
+
+
+

+
Contraseña restablecida
+
+
+
Tu contraseña de acceso al SIIH ha sido restablecida por el administrador.
+
+ Nueva contraseña:
+ $pass
+
+
Por favor, cambia esta contraseña una vez que inicies sesión.
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+ } catch (Exception $e) {
+ error_log("Error al enviar correo: {$mail->ErrorInfo}");
+ }
+}
+
+function suspenderAgencia()
+{
+ if (!($_SESSION['usuario_id'] ?? false)) {
+ header("Location: /IMPORTADORES/administrador/agenciasActivas?error=unauthorized");
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $id = $_GET['id'] ?? null;
+
+ if (!$id || !is_numeric($id)) {
+ header("Location: /IMPORTADORES/administrador/agenciasActivas?error=invalid_id");
+ exit;
+ }
+
+ // Obtener el estado actual
+ $sqlEstado = "SELECT activo FROM agencias_aduanles WHERE id_usuario = ?";
+ $stmtEstado = sqlsrv_query($conn, $sqlEstado, [$id]);
+
+ if (!$stmtEstado || !($row = sqlsrv_fetch_array($stmtEstado, SQLSRV_FETCH_ASSOC))) {
+ header("Location: /IMPORTADORES/administrador/agenciasActivas?error=agencia_not_found");
+ exit;
+ }
+
+ $nuevoEstado = $row['activo'] ? 0 : 1;
+
+ // Actualizar estado
+ $sqlUpdate = "UPDATE agencias_aduanles SET activo = ? WHERE id_usuario = ?";
+ $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$nuevoEstado, $id]);
+
+ if (!$stmtUpdate) {
+ header("Location: /IMPORTADORES/administrador/agenciasActivas?error=update_failed");
+ exit;
+ }
+
+ // Determinar el tipo de cambio para el mensaje
+ $accion = $nuevoEstado ? 'activated' : 'deactivated';
+
+ header("Location: /IMPORTADORES/administrador/agenciasActivas?success=status_$accion");
+ exit;
+}
+
+
+function bitacoraLogin()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT * FROM bitacora_login ORDER BY fecha DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ $registros = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $registros[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/bitacora_login.php';
+}
+
+function bitacoraUsuarios()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT * FROM bitacora_usuarios ORDER BY fecha DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ $registros = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $registros[] = $row;
+ }
+
+ include __DIR__ . '/../../views/admin/bitacora_usuarios.php';
+}
+
+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';
+}
\ No newline at end of file
diff --git a/app/controllers/agencias.php b/app/controllers/agencias.php
index 7072f0b..42a4c98 100644
--- a/app/controllers/agencias.php
+++ b/app/controllers/agencias.php
@@ -14,32 +14,206 @@ loadEnv();
function dashboard()
{
- if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
header("Location: /IMPORTADORES/login");
exit;
}
- $nombreAgencia = $_SESSION['nombre_agencia'];
-
include __DIR__ . '/../../views/agencias/dashboard_agencias.php';
}
+function solicitudesVinculacion()
+{
+ include __DIR__ . '/../../views/agencias/solicitudes_vinculacion.php';
+}
+
function alta()
{
- include __DIR__ . '/../../views/agencias/.php';
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ include __DIR__ . '/../../views/agencias/alta_agentes.php';
}
function guardarAgente()
{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
+ header("Location: /IMPORTADORES/agencias/alta?error=unauthorized");
+ exit;
+ }
-}
+ $conn = getConnection();
-function activos()
-{
- include __DIR__ . '/../../views/agencias/usuarios_activos.php';
-}
+ try {
+ if (!sqlsrv_begin_transaction($conn)) {
+ error_log("ERROR: No se pudo iniciar la transacción");
+ throw new Exception("Error al iniciar transacción");
+ }
+
+ error_log("Transacción iniciada correctamente");
-function bitacora()
-{
- include __DIR__ . '/../../views/agencias/dashboard_agencias.php';
+ // 1. Capturar y validar datos
+ $nombre = trim($_POST['nombre'] ?? '');
+ $email = trim($_POST['email'] ?? '');
+ $password = $_POST['password'] ?? '';
+ $tipo = $_POST['tipo_usuario'] ?? '';
+
+ if (empty($nombre) || empty($email) || empty($password) || empty($tipo)) {
+ header("Location: /IMPORTADORES/agencias/alta?error=invalid_data");
+ exit;
+ }
+
+ if ($tipo !== 'agente_aduanal') {
+ error_log("DEBUG 5: Tipo de usuario inválido: $tipo");
+ header("Location: /IMPORTADORES/agencias/alta?error=invalid_user_type");
+ exit;
+ }
+
+ // 2. Encriptar datos sensibles
+ $nombre_encrypted = encrypt($nombre);
+ $email_encrypted = encrypt($email);
+ $password_hash = password_hash($password, PASSWORD_DEFAULT);
+
+ // 3. Validar duplicado por email encriptado
+ $sqlCheck = "SELECT COUNT(*) AS total FROM usuarios_sistema WHERE email = ?";
+ $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$email_encrypted]);
+ $rowCheck = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
+ if ($rowCheck['total'] > 0) {
+ header("Location: /IMPORTADORES/agencias/alta?error=email_exists");
+ exit;
+ }
+
+ // 4. Insertar usuario
+ $sqlInsert = "
+ INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
+ OUTPUT INSERTED.id_usuario
+ VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)";
+ $params = [$nombre_encrypted, $email_encrypted, $password_hash, $tipo, $_SESSION['usuario_id']];
+ $stmtInsert = sqlsrv_query($conn, $sqlInsert, $params);
+
+ if ($stmtInsert === false) {
+ error_log("ERROR: Fallo al insertar usuario");
+ error_log(print_r(sqlsrv_errors(), true));
+ throw new Exception("Error al insertar usuario");
+ }
+
+ $idUsuarioRow = sqlsrv_fetch_array($stmtInsert, SQLSRV_FETCH_ASSOC);
+ $id_usuario = $idUsuarioRow['id_usuario'] ?? null;
+
+ if (!$id_usuario) {
+ error_log("ERROR: No se obtuvo id_usuario tras el insert");
+ throw new Exception("Error al obtener ID del nuevo usuario");
+ }
+
+ // 6. Obtener la agencia del administrador actual
+ $sqlAgencia = "SELECT id_agencia FROM agencias_aduanales WHERE id_administrador = ?";
+ $stmtAgencia = sqlsrv_query($conn, $sqlAgencia, [$_SESSION['usuario_id']]);
+ $agenciaRow = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC);
+ $id_agencia = $agenciaRow['id_agencia'] ?? null;
+
+ if (!$id_agencia) {
+ error_log("ERROR: No se encontró agencia para el admin_agencia con id_usuario=" . $_SESSION['usuario_id']);
+ throw new Exception("No se encontró agencia asociada al administrador");
+ }
+
+ // 7. Crear la relación agente-agencia
+ $sqlRelacion = "INSERT INTO agente_agencia (id_agente, id_agencia, fecha_asignacion, activo, asignado_por)
+ VALUES (?, ?, GETDATE(), 1, ?)";
+ $paramsRelacion = [$id_usuario, $id_agencia, $_SESSION['usuario_id']];
+ $stmtRelacion = sqlsrv_query($conn, $sqlRelacion, $paramsRelacion);
+
+ if ($stmtRelacion === false) {
+ error_log("ERROR: No se pudo insertar la relación agente-agencia");
+ error_log(print_r(sqlsrv_errors(), true));
+ throw new Exception("Error al guardar relación agente-agencia");
+ }
+
+ // 8. CONFIRMAR TRANSACCIÓN ✅
+ if (!sqlsrv_commit($conn)) {
+ error_log("ERROR: No se pudo confirmar la transacción");
+ throw new Exception("Error al confirmar transacción");
+ }
+
+ // 9. Enviar correo de bienvenida
+ if (class_exists('PHPMailer\PHPMailer\PHPMailer')) {
+ $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); // Email sin encriptar para el envío
+ $mail->CharSet = 'UTF-8';
+ $mail->isHTML(true);
+ $mail->Subject = 'Tu acceso a la plataforma SIIH ha sido creado';
+
+ // Determinar el tipo de usuario para el mensaje
+ $tipoUsuarioTexto = match($tipo) {
+ 'agente_aduanal' => 'agente aduanal',
+ default => 'usuario'
+ };
+
+ $mail->Body = "
+
+
+
+
¡Bienvenido a SIIH!
+
+
+
Hola $nombre,
+
Se ha creado tu cuenta en la plataforma SIIH con el rol de $tipoUsuarioTexto.
+
Aquí tienes tus credenciales de acceso:
+
+
Correo: $email
+
Contraseña: $password
+
+
📌 Importante: Te recomendamos cambiar tu contraseña una vez que ingreses al sistema por primera vez.
+
+
+ Acceder al Sistema
+
+
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+
+ } catch (Exception $e) {
+ error_log("Error al enviar correo: " . $e->getMessage());
+ }
+ }
+
+ // 10. Redirigir con mensaje de éxito
+ header("Location: /IMPORTADORES/agencias/alta?success=created");
+ exit;
+
+ } catch (Exception $e) {
+ error_log("ERROR CAPTURADO: " . $e->getMessage());
+ if (!sqlsrv_rollback($conn)) {
+ error_log("ERROR: No se pudo revertir la transacción");
+ } else {
+ error_log("Transacción revertida exitosamente");
+ }
+
+ error_log("=== FIN CON ERROR guardar_agencia ===");
+ header("Location: /IMPORTADORES/agencias/alta?error=save_failed");
+ exit;
+ } finally {
+ if ($conn) {
+ sqlsrv_close($conn);
+ error_log("Conexión cerrada");
+ }
+ }
}
\ No newline at end of file
diff --git a/app/controllers/agentes.php b/app/controllers/agentes.php
index 53c77cb..17da4fa 100644
--- a/app/controllers/agentes.php
+++ b/app/controllers/agentes.php
@@ -60,7 +60,6 @@ function solicitudes_pendientes() {
WHERE request_status = 'pending'
ORDER BY request_date DESC";
-
$stmt = sqlsrv_query($conn, $sql);
$solicitudes = [];
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
diff --git a/app/controllers/bitacoras.php b/app/controllers/bitacoras.php
index ada0963..d46b819 100644
--- a/app/controllers/bitacoras.php
+++ b/app/controllers/bitacoras.php
@@ -1,47 +1,45 @@
isSMTP();
- $mail->Host = 'secure.emailsrvr.com';
- $mail->SMTPAuth = true;
- $mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS'];
+ $mail->Host = 'secure.emailsrvr.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = 'noreply@aduanasoft.com.mx';
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
- $mail->Port = 587;
+ $mail->Port = 587;
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
$mail->addAddress($email);
@@ -219,9 +198,9 @@ function confirmarAcceso()
}
$codigoIngresado = trim($_POST['codigo'] ?? '');
- $usuarioId = $_SESSION['usuario_id'] ?? null;
- $email = $_SESSION['usuario_email'] ?? '';
- $ip = $_SERVER['REMOTE_ADDR'] ?? 'N/A';
+ $usuarioId = $_SESSION['usuario_id'] ?? null;
+ $email = $_SESSION['usuario_email'] ?? '';
+ $ip = $_SERVER['REMOTE_ADDR'] ?? 'N/A';
// Verificar que el usuario tenga una sesión válida y pendiente de confirmación
if (!$usuarioId || !$codigoIngresado || !($_SESSION['pendiente_confirmacion'] ?? false)) {
@@ -234,9 +213,9 @@ function confirmarAcceso()
exit;
}
- $sql = "SELECT codigo, expiracion FROM verificaciones
- WHERE id_usuario = ? AND codigo = ?
- ORDER BY id DESC";
+ $sql = "SELECT codigo, expiracion FROM verificaciones
+ WHERE id_usuario = ? AND codigo = ?
+ ORDER BY id DESC";
$stmt = sqlsrv_query($conn, $sql, [$usuarioId, $codigoIngresado]);
if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) {
@@ -262,7 +241,7 @@ function confirmarAcceso()
registrarBitacora($conn, $usuarioId, $email, $ip, 1, 'Confirmación 2FA exitosa - Login completado');
$_SESSION['pendiente_confirmacion'] = false;
- $_SESSION['codigo_exito'] = '✅ Verificación de dos factores completada correctamente.';
+ $_SESSION['codigo_exito'] = '✅ Verificación de dos factores completada correctamente.';
// Obtener el tipo de usuario para redirección
$tipoUsuario = $_SESSION['tipo_usuario'] ?? 'importador';
@@ -306,7 +285,7 @@ function enviarCodigo()
$emailEncrypted = encrypt($email);
- $sql = "SELECT id_usuario, activo FROM usuarios_sistema WHERE email = ?";
+ $sql = "SELECT id_usuario, activo FROM usuarios_sistema WHERE email = ?";
$stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]);
if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) {
@@ -314,7 +293,7 @@ function enviarCodigo()
exit;
}
$id_usuario = $row['id_usuario'];
- $activo = $row['activo'];
+ $activo = $row['activo'];
// Validación del estado de la cuenta
if ($activo != 1) {
@@ -322,19 +301,19 @@ function enviarCodigo()
exit;
}
- $now = (new DateTime())->format('Y-m-d H:i:s');
+ $now = (new DateTime())->format('Y-m-d H:i:s');
$sqlCheck = "SELECT COUNT(*) AS total FROM recuperacion_password
WHERE email = ? AND estatus = 0 AND expiracion > ?";
$checkStmt = sqlsrv_query($conn, $sqlCheck, [$emailEncrypted, $now]);
- $checkRow = sqlsrv_fetch_array($checkStmt, SQLSRV_FETCH_ASSOC);
+ $checkRow = sqlsrv_fetch_array($checkStmt, SQLSRV_FETCH_ASSOC);
if ($checkRow['total'] > 0) {
echo json_encode(['success' => false, 'message' => '⚠️ Ya tienes un código activo. Revisa tu correo o espera 10 minutos.']);
exit;
}
- $codigo = strval(random_int(100000, 999999));
- $expira = (new DateTime('+10 minutes'))->format('Y-m-d H:i:s');
+ $codigo = strval(random_int(100000, 999999));
+ $expira = (new DateTime('+10 minutes'))->format('Y-m-d H:i:s');
$estatus = 0;
$insert = "INSERT INTO recuperacion_password (email, codigo, expiracion, estatus) VALUES (?, ?, ?, ?)";
@@ -353,10 +332,10 @@ function enviarCodigo()
try {
$mail = new PHPMailer(true);
$mail->isSMTP();
- $mail->Host = 'secure.emailsrvr.com';
- $mail->SMTPAuth = true;
- $mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS'];
+ $mail->Host = 'secure.emailsrvr.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = 'noreply@aduanasoft.com.mx';
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
@@ -398,7 +377,7 @@ function enviarCodigo()
function enviarCorreoRespaldo($conn, $id_usuario, $codigo)
{
// Obtener correo de respaldo
- $sql = "SELECT TOP 1 correo FROM correo_respaldo WHERE id_usuario = ?";
+ $sql = "SELECT TOP 1 correo FROM correo_respaldo WHERE id_usuario = ?";
$stmt = sqlsrv_query($conn, $sql, [$id_usuario]);
if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) {
@@ -412,10 +391,10 @@ function enviarCorreoRespaldo($conn, $id_usuario, $codigo)
$mail = new PHPMailer(true);
// ConfigEuración de servidor SMTP
$mail->isSMTP();
- $mail->Host = 'secure.emailsrvr.com';
- $mail->SMTPAuth = true;
- $mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS'];
+ $mail->Host = 'secure.emailsrvr.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = 'noreply@aduanasoft.com.mx';
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
@@ -472,7 +451,7 @@ function reenviarCodigo()
exit;
}
- $id_usuario = $_SESSION['id_usuario'];
+ $id_usuario = $_SESSION['id_usuario'];
$emailEncrypted = encrypt($_SESSION['email_recuperacion']);
// Obtener el último código activo de recuperación
@@ -512,7 +491,7 @@ function verificarCodigo()
// Validar existencia de conexión, código y email en sesión
$codigo = isset($_POST['codigo']) ? trim($_POST['codigo']) : '';
- $email = $_SESSION['email_recuperacion'] ?? '';
+ $email = $_SESSION['email_recuperacion'] ?? '';
if (!$conn) {
echo json_encode(['success' => false, 'message' => '❌ Error de conexión a la base de datos.']);
@@ -539,8 +518,8 @@ function verificarCodigo()
$emailEncrypted = encrypt($email);
// Consulta el último código válido para ese email
- $sql = "SELECT TOP 1 id, codigo, expiracion FROM recuperacion_password
- WHERE email = ? AND estatus = 0 ORDER BY id DESC";
+ $sql = "SELECT TOP 1 id, codigo, expiracion FROM recuperacion_password
+ WHERE email = ? AND estatus = 0 ORDER BY id DESC";
$stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]);
if ($stmt === false) {
@@ -555,9 +534,9 @@ function verificarCodigo()
if (!$row) {
echo json_encode([
- 'success' => false,
- 'message' => '🚫 Has excedido el número de intentos permitidos. Tu cuenta ha sido bloqueada por seguridad. Contacta a tu agente aduanal.',
- 'blocked' => true,
+ 'success' => false,
+ 'message' => '🚫 Has excedido el número de intentos permitidos. Tu cuenta ha sido bloqueada por seguridad. Contacta a tu agente aduanal.',
+ 'blocked' => true,
'redirect' => '/IMPORTADORES/login'
]);
exit;
@@ -607,7 +586,7 @@ function verificarCodigo()
}
// Validar expiración - puede venir como DateTime o string
- $expiracion = $row['expiracion'];
+ $expiracion = $row['expiracion'];
$expiracionTimestamp = null;
if ($expiracion instanceof DateTime) {
@@ -630,7 +609,7 @@ function verificarCodigo()
}
// Código correcto: actualizar estado y permitir cambio de contraseña
- $sqlSuccess = "UPDATE recuperacion_password SET estatus = 1 WHERE id = ?";
+ $sqlSuccess = "UPDATE recuperacion_password SET estatus = 1 WHERE id = ?";
$stmtSuccess = sqlsrv_query($conn, $sqlSuccess, [$row['id']]);
if ($stmtSuccess) {
@@ -682,7 +661,7 @@ function enviarNotificacionIntentosExcedidos($email)
}
// 🔐 Desencriptar datos sensibles
- $usuario['email'] = decrypt($usuario['email']);
+ $usuario['email'] = decrypt($usuario['email']);
$usuario['nombre'] = decrypt($usuario['nombre']);
// Verificar si el usuario tiene habilitadas las notificaciones de seguridad
@@ -693,10 +672,10 @@ function enviarNotificacionIntentosExcedidos($email)
// Preparar datos para la notificación
$datosNotificacion = [
- 'email' => $usuario['email'],
- 'nombre' => $usuario['nombre'],
+ 'email' => $usuario['email'],
+ 'nombre' => $usuario['nombre'],
'fecha_hora' => date('Y-m-d H:i:s'),
- 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida',
+ 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Desconocido'
];
@@ -743,12 +722,12 @@ function enviarNotificacionSeguridadIntentos($emailDestino, $nombreUsuario, $dat
// Configuración de servidor SMTP
$mail->isSMTP();
- $mail->Host = 'secure.emailsrvr.com';
- $mail->SMTPAuth = true;
- $mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS'];
+ $mail->Host = 'secure.emailsrvr.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = 'noreply@aduanasoft.com.mx';
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
- $mail->Port = 587;
+ $mail->Port = 587;
// Configuración del correo
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
@@ -868,10 +847,10 @@ function enviarNotificacionCuentaBloqueada($email)
// Preparar datos para la notificación
$datosNotificacion = [
- 'email' => $usuario['email'],
- 'nombre' => $usuario['nombre'],
+ 'email' => $usuario['email'],
+ 'nombre' => $usuario['nombre'],
'fecha_hora' => date('Y-m-d H:i:s'),
- 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida',
+ 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'Desconocida',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Desconocido'
];
@@ -915,12 +894,12 @@ function enviarEmailCuentaBloqueada($emailDestino, $nombreUsuario, $datos, $esCo
// Configuración de servidor SMTP
$mail->isSMTP();
- $mail->Host = 'secure.emailsrvr.com';
- $mail->SMTPAuth = true;
- $mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS'];
+ $mail->Host = 'secure.emailsrvr.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = 'noreply@aduanasoft.com.mx';
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
- $mail->Port = 587;
+ $mail->Port = 587;
// Configuración del correo
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
@@ -1028,8 +1007,8 @@ function cambiarPassword()
return;
}
- $conn = getConnection();
- $password = $_POST['password'] ?? '';
+ $conn = getConnection();
+ $password = $_POST['password'] ?? '';
$confirmar = $_POST['confirmar'] ?? '';
// Validaciones
@@ -1047,10 +1026,10 @@ function cambiarPassword()
// 🔐 Usa encrypt() en vez de hash() para coincidir con lo que hay en la base de datos
$emailEncrypted = encrypt($email);
- $hash = password_hash($password, PASSWORD_BCRYPT);
+ $hash = password_hash($password, PASSWORD_BCRYPT);
// Actualizar contraseña
- $sql = "UPDATE usuarios_sistema SET password_hash = ? WHERE email = ?";
+ $sql = "UPDATE usuarios_sistema SET password_hash = ? WHERE email = ?";
$stmt = sqlsrv_prepare($conn, $sql, [$hash, $emailEncrypted]);
if (!$stmt || !sqlsrv_execute($stmt)) {
@@ -1059,10 +1038,10 @@ function cambiarPassword()
}
// Obtener ID de usuario para registrar en bitácora
- $sqlUsuario = "SELECT id_usuario FROM usuarios_sistema WHERE email = ?";
+ $sqlUsuario = "SELECT id_usuario FROM usuarios_sistema WHERE email = ?";
$stmtUsuario = sqlsrv_query($conn, $sqlUsuario, [$emailEncrypted]);
- $usuario = sqlsrv_fetch_array($stmtUsuario, SQLSRV_FETCH_ASSOC);
- $idUsuario = $usuario['id_usuario'] ?? null;
+ $usuario = sqlsrv_fetch_array($stmtUsuario, SQLSRV_FETCH_ASSOC);
+ $idUsuario = $usuario['id_usuario'] ?? null;
// Registrar en bitácora
$ip = $_SERVER['REMOTE_ADDR'] ?? 'N/A';
@@ -1074,12 +1053,12 @@ function cambiarPassword()
// Configuración de servidor SMTP
$mail->isSMTP();
- $mail->Host = 'secure.emailsrvr.com';
- $mail->SMTPAuth = true;
- $mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS'];
+ $mail->Host = 'secure.emailsrvr.com';
+ $mail->SMTPAuth = true;
+ $mail->Username = 'noreply@aduanasoft.com.mx';
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
- $mail->Port = 587;
+ $mail->Port = 587;
// Configuración del correo
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
diff --git a/app/controllers/registro.php b/app/controllers/registro.php
index 48dfc44..e07e2f6 100644
--- a/app/controllers/registro.php
+++ b/app/controllers/registro.php
@@ -1,32 +1,32 @@
$secretKey,
+ 'secret' => $secretKey,
'response' => $captchaResponse
];
@@ -39,58 +39,98 @@ function enviar() {
];
$context = stream_context_create($options);
- $result = file_get_contents($verifyUrl, false, $context);
+ $result = file_get_contents($verifyUrl, false, $context);
$response = json_decode($result);
if (!$response->success) {
die("❌ Error de verificación reCAPTCHA.");
}
+ return true;
+}
- $conn = getConnection();
-
- $empresa = encrypt(trim($_POST['company_name'] ?? ''));
- $rfc = strtoupper(encrypt(trim($_POST['rfc'] ?? '')));
- $email = trim($_POST['email'] ?? '');
- $telefono = trim($_POST['phone'] ?? '');
- $archivo = $_FILES['opinion_file'];
-
- // Validar RFC (12 o 13 caracteres con formato correcto)
- if (!preg_match('/^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/', strtoupper($_POST['rfc'] ?? ''))) {
+// Función auxiliar para validaciones
+function validarDatos($rfc, $email, $telefono)
+{
+ // Validar RFC
+ if (!preg_match('/^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/', strtoupper($rfc))) {
die("❌ El RFC no tiene un formato válido.");
}
- // Validar email (solo minúsculas, sin caracteres especiales fuera del estándar)
- if (!preg_match('/^[a-z0-9._+-]+@[a-z0-9.-]+\.[a-z]{2,}$/', $email)) {
+ // Validar email
+ if (!preg_match('/^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', strtolower($email))) {
die("❌ No es una dirección de correo válida.");
}
- // Validar teléfono (formato nacional: 3 dígitos + espacio + 7 dígitos)
+ // Validar teléfono
if (!preg_match('/^\d{3}\s\d{7}$/', $telefono)) {
die("❌ El número de teléfono no tiene un formato válido. Ejemplo: 123 4567890");
}
+}
- // Validar archivo
- if ($archivo['error'] !== 0 || pathinfo($archivo['name'], PATHINFO_EXTENSION) !== 'pdf') {
- die("❌ Archivo inválido. Solo se permiten PDFs.");
+// Función auxiliar para manejar archivos
+function procesarArchivo($archivo)
+{
+ if ($archivo['error'] !== UPLOAD_ERR_OK) {
+ die("❌ Error al subir el archivo.");
+ }
+
+ // Validar tipo MIME real del archivo
+ $finfo = finfo_open(FILEINFO_MIME_TYPE);
+ $mimeType = finfo_file($finfo, $archivo['tmp_name']);
+ finfo_close($finfo);
+
+ if ($mimeType !== 'application/pdf') {
+ die("❌ El archivo debe ser un PDF válido.");
+ }
+
+ // Validar extensión
+ if (pathinfo($archivo['name'], PATHINFO_EXTENSION) !== 'pdf') {
+ die("❌ Solo se permiten archivos PDF.");
+ }
+
+ // Validar tamaño (5MB máximo)
+ if ($archivo['size'] > 5 * 1024 * 1024) {
+ die("❌ El archivo no debe exceder 5MB.");
}
- // Guardar archivo
+ // Guardar archivo con nombre único
$nombreArchivo = uniqid() . '_' . basename($archivo['name']);
- $rutaDestino = __DIR__ . '/../../storage/opiniones/' . $nombreArchivo;
- move_uploaded_file($archivo['tmp_name'], $rutaDestino);
+ $rutaDestino = __DIR__ . '/../../storage/opiniones/' . $nombreArchivo;
+
+ if (!move_uploaded_file($archivo['tmp_name'], $rutaDestino)) {
+ die("❌ Error al guardar el archivo.");
+ }
+
+ return $nombreArchivo;
+}
- // Insertar en la base de datos
- $sql = "INSERT INTO solicitudes_importadores
- (company_name, rfc, email, phone, opinion_file, request_status, request_date)
- VALUES (?, ?, ?, ?, ?, 'pending', GETDATE())";
-
- $params = [$empresa, $rfc, $email, $telefono, $nombreArchivo];
- $stmt = sqlsrv_query($conn, $sql, $params);
-
- if ($stmt === false) {
- die(print_r(sqlsrv_errors(), true));
- }
+// Función auxiliar para obtener configuración
+function obtenerConfiguracion($conn)
+{
+ $sqlConf = "SELECT TOP 1 * FROM configuracion_sistema";
+ $stmtConf = sqlsrv_query($conn, $sqlConf);
+
+ if ($stmtConf === false) {
+ error_log("Error al obtener configuración: " . print_r(sqlsrv_errors(), true));
+ return [
+ 'nombre_plataforma' => 'Sistema Integral para Importadores de Hidrocarburos',
+ 'siglas' => 'SIIH',
+ 'logo_url' => 'assets/img/logo_siih.png',
+ 'colores_primarios' => '#003366,#0055A5'
+ ];
+ }
+
+ return sqlsrv_fetch_array($stmtConf, SQLSRV_FETCH_ASSOC) ?: [
+ 'nombre_plataforma' => 'Sistema Integral para Importadores de Hidrocarburos',
+ 'siglas' => 'SIIH',
+ 'logo_url' => 'assets/img/logo_siih.png',
+ 'colores_primarios' => '#003366,#0055A5'
+ ];
+}
+// Función auxiliar para enviar email
+function enviarEmailConfirmacion($destinatario, $datosEmpresa, $esAgencia = false)
+{
$mail = new PHPMailer(true);
try {
@@ -99,31 +139,31 @@ function enviar() {
$mail->Host = 'secure.emailsrvr.com';
$mail->SMTPAuth = true;
$mail->Username = 'noreply@aduanasoft.com.mx';
- $mail->Password = $_ENV['SMTP_PASS']; // desde el .env
+ $mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
- // Correo remitente y destinatario
+ // Configurar remitente y destinatario
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
- $mail->addAddress($email); // destinatario principal
+ $mail->addAddress($destinatario);
- // Formato y contenido
+ // Obtener configuración
+ $conn = getConnection();
+ $conf = obtenerConfiguracion($conn);
+
+ $nombrePlataforma = $conf['nombre_plataforma'];
+ $siglas = $conf['siglas'];
+ $logoUrl = $conf['logo_url'];
+ $color2 = explode(',', $conf['colores_primarios'])[1];
+
+ // Contenido del email
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
$mail->Subject = 'Confirmación de solicitud de registro | SIIH';
$fechaRegistro = date('d/m/Y H:i');
-
- // Consulta configuración institucional
- $sqlConf = "SELECT TOP 1 * FROM configuracion_sistema";
- $stmtConf = sqlsrv_query($conn, $sqlConf);
- $conf = sqlsrv_fetch_array($stmtConf, SQLSRV_FETCH_ASSOC);
-
- $nombrePlataforma = $conf['nombre_plataforma'] ?? 'Sistema Integral para Importadores de Hidrocarburos';
- $siglas = $conf['siglas'] ?? 'SIIH';
- $logoUrl = $conf['logo_url'] ?? 'assets/img/logo_siih.png';
- $color1 = explode(',', $conf['colores_primarios'] ?? '#003366,#0055A5')[0];
- $color2 = explode(',', $conf['colores_primarios'] ?? '#003366,#0055A5')[1];
+ $tipoRegistro = $esAgencia ? 'Agencia' : 'Empresa';
+ $nombreEntidad = $esAgencia ? $datosEmpresa['agencia'] : $datosEmpresa['empresa'];
$mail->Body = "
@@ -138,28 +178,141 @@ function enviar() {
-
📋 Empresa: " . htmlspecialchars($_POST['company_name']) . "
-
📞 Teléfono: " . htmlspecialchars($telefono) . "
+
📋 $tipoRegistro: " . htmlspecialchars($nombreEntidad) . "
+
📞 Teléfono: " . htmlspecialchars($datosEmpresa['telefono']) . "
🕓 Fecha de registro: $fechaRegistro
-
Un agente aduanal revisará tu información y te notificará por este medio cuando tu solicitud sea aprobada.
+
Un administrador revisará tu información y te notificará por este medio cuando tu solicitud sea aprobada.
Por favor, mantente atento a tu correo (y revisa también tu carpeta de spam o promociones).
Este es un mensaje automático enviado por el sistema de registro de importadores.
- © " . date('Y') . " $siglas · Desarrollado por AduanaSoft
+ © " . date('Y') . " $siglas · $nombrePlataforma
-
- ";
+ ";
$mail->send();
+ return true;
} catch (Exception $e) {
error_log("Error al enviar correo: {$mail->ErrorInfo}");
+ return false;
}
+}
- include __DIR__ . '/../../views/registro/gracias.php';
-}
\ No newline at end of file
+function enviarSoliImportador()
+{
+ try {
+ // Validar reCAPTCHA
+ validarRecaptcha($_POST['g-recaptcha-response'] ?? '');
+
+ $conn = getConnection();
+
+ // Sanitizar y obtener datos
+ $empresa = trim($_POST['company_name'] ?? '');
+ $rfc = trim($_POST['rfc'] ?? '');
+ $email = trim($_POST['email'] ?? '');
+ $telefono = trim($_POST['phone'] ?? '');
+
+ // Validar datos
+ validarDatos($rfc, $email, $telefono);
+
+ // Procesar archivo
+ $nombreArchivo = procesarArchivo($_FILES['opinion_file']);
+
+ // Encriptar datos sensibles
+ $empresaEncriptada = encrypt($empresa);
+ $rfcEncriptado = encrypt(strtoupper($rfc));
+
+ // Insertar en base de datos
+ $sql = "INSERT INTO solicitudes_importadores
+ (company_name, rfc, email, phone, opinion_file, request_status, request_date)
+ VALUES (?, ?, ?, ?, ?, 'pending', GETDATE())";
+
+ $params = [$empresaEncriptada, $rfcEncriptado, $email, $telefono, $nombreArchivo];
+ $stmt = sqlsrv_query($conn, $sql, $params);
+
+ if ($stmt === false) {
+ error_log("Error en BD: " . print_r(sqlsrv_errors(), true));
+ die("❌ Error al procesar la solicitud.");
+ }
+
+ // Enviar email de confirmación
+ $datosEmpresa = [
+ 'empresa' => $empresa,
+ 'telefono' => $telefono
+ ];
+ enviarEmailConfirmacion($email, $datosEmpresa, false);
+
+ include __DIR__ . '/../../views/registro/gracias.php';
+
+ } catch (Exception $e) {
+ error_log("Error en enviarSoliImportador: " . $e->getMessage());
+ die("❌ Error interno del servidor.");
+ }
+}
+
+function enviarSoliAgencia()
+{
+ try {
+ // Validar reCAPTCHA
+ validarRecaptcha($_POST['g-recaptcha-response'] ?? '');
+
+ $conn = getConnection();
+
+ // Sanitizar y obtener datos
+ $agencia = trim($_POST['nombre_agencia'] ?? '');
+ $rfc = trim($_POST['rfc'] ?? '');
+ $correo = trim($_POST['correo'] ?? '');
+ $telefono = trim($_POST['telefono'] ?? '');
+ $direccion = trim($_POST['direccion'] ?? '');
+ $admin = trim($_POST['nombre_admin'] ?? '');
+ $admin_correo = trim($_POST['correo_admin'] ?? '');
+
+ // Validar datos principales
+ validarDatos($rfc, $correo, $telefono);
+
+ // Validar correo del administrador
+ if (!preg_match('/^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', strtolower($admin_correo))) {
+ die("❌ El correo del administrador no es válido.");
+ }
+
+ // Procesar archivo
+ $nombreArchivo = procesarArchivo($_FILES['opinion_file']);
+
+ // Encriptar datos sensibles
+ $agenciaEncriptada = encrypt($agencia);
+ $rfcEncriptado = encrypt(strtoupper($rfc));
+ $adminEncriptado = encrypt($admin);
+
+ // Insertar en base de datos
+ $sql = "INSERT INTO solicitudes_agencias
+ (agencia_name, rfc, email, phone, direccion, opinion_file, admin_name, admin_email, request_status, request_date)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', GETDATE())";
+
+ $params = [$agenciaEncriptada, $rfcEncriptado, $correo, $telefono, $direccion, $nombreArchivo, $adminEncriptado, $admin_correo];
+ $stmt = sqlsrv_query($conn, $sql, $params);
+
+ if ($stmt === false) {
+ error_log("Error en BD: " . print_r(sqlsrv_errors(), true));
+ die("❌ Error al procesar la solicitud.");
+ }
+
+ // Enviar email de confirmación
+ $datosAgencia = [
+ 'agencia' => $agencia,
+ 'telefono' => $telefono
+ ];
+ enviarEmailConfirmacion($correo, $datosAgencia, true);
+
+ include __DIR__ . '/../../views/registro/gracias.php';
+
+ } catch (Exception $e) {
+ error_log("Error en enviarSoliAgencia: " . $e->getMessage());
+ die("❌ Error interno del servidor.");
+ }
+}
+?>
\ No newline at end of file
diff --git a/app/controllers/sistemas.php b/app/controllers/sistemas.php
index 5252620..74b4552 100644
--- a/app/controllers/sistemas.php
+++ b/app/controllers/sistemas.php
@@ -2,286 +2,15 @@
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/env.php';
require_once __DIR__ . '/../helpers/crypto.php';
-
-use PHPMailer\PHPMailer\PHPMailer;
-use PHPMailer\PHPMailer\Exception;
+require_once __DIR__ . '/../helpers/session.php';
loadEnv();
-session_start();
-
-function index() {
- header("Location: /IMPORTADORES/sistemas/login");
- exit;
-}
-
-function login() {
- // Si es GET, mostrar el formulario
- if ($_SERVER['REQUEST_METHOD'] === 'GET') {
- include __DIR__ . '/../../views/admin/login_sistemas.php';
- return;
- }
-
- // Si es POST, procesar login
- $email = $_POST['email'] ?? '';
- $clave = $_POST['clave'] ?? '';
-
- if ($email === 'sistemas@aduanasoft.com.mx' && $clave === 'rootSecure2025!') {
- $_SESSION['usuario_sistemas'] = true;
- header("Location: /IMPORTADORES/sistemas/alta_usuarios");
- } else {
- echo "❌ Acceso denegado.";
- }
-}
-
-function alta_usuarios() {
- if (!($_SESSION['usuario_sistemas'] ?? false)) {
- die("⚠️ No autorizado.");
- }
-
- $conn = getConnection();
- $sql = "SELECT * FROM usuarios_sistema ORDER BY creado_en DESC";
- $stmt = sqlsrv_query($conn, $sql);
-
- $usuarios = [];
- while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
- $usuarios[] = $row;
- }
-
- include __DIR__ . '/../../views/admin/alta_usuarios.php';
-}
-
-function guardar_usuario()
+function logout()
{
- if (!($_SESSION['usuario_sistemas'] ?? false)) {
- die("⚠️ No autorizado.");
- }
-
-
- $conn = getConnection();
-
- // 1. Capturar y validar datos
- $nombre = trim($_POST['nombre'] ?? '');
- $email = trim($_POST['email'] ?? '');
- $password = $_POST['password'] ?? '';
- $tipo = $_POST['tipo_usuario'] ?? '';
-
- if (empty($nombre) || empty($email) || empty($password) || empty($tipo)) {
- die("❌ Todos los campos son obligatorios.");
- }
-
- if (!in_array($tipo, ['importador', 'agente_aduanal'])) {
- die("❌ Tipo de usuario inválido.");
- }
-
- // 2. Encriptar datos sensibles
- $nombre_encrypted = encrypt($nombre);
- $email_encrypted = encrypt($email);
- $password_hash = password_hash($password, PASSWORD_DEFAULT);
-
- // 3. Validar duplicado por email encriptado
- $sqlCheck = "SELECT COUNT(*) AS total FROM usuarios_sistema WHERE email = ?";
- $stmtCheck = sqlsrv_query($conn, $sqlCheck, [$email_encrypted]);
- $rowCheck = sqlsrv_fetch_array($stmtCheck, SQLSRV_FETCH_ASSOC);
- if ($rowCheck['total'] > 0) {
- die("❌ Este correo ya está registrado.");
- }
-
- // 4. Insertar usuario
- $sqlInsert = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en)
- VALUES (?, ?, ?, ?, 1, GETDATE())";
- $params = [$nombre_encrypted, $email_encrypted, $password_hash, $tipo];
-
- $stmtInsert = sqlsrv_query($conn, $sqlInsert, $params);
-
- if ($stmtInsert === false) {
- die("❌ Error al guardar: " . print_r(sqlsrv_errors(), true));
- }
-
- // 5. Redirigir
- header("Location: /IMPORTADORES/sistemas/alta_usuarios");
- exit;
-}
-
-function agencias_activas()
-{
-
-}
-
-function logout() {
- session_start();
session_unset(); // Limpia variables de sesión
session_destroy(); // Destruye la sesión
header("Location: /IMPORTADORES/login");
exit;
-}
-
-function toggle_estado() {
- session_start();
-
- if (!($_SESSION['usuario_sistemas'] ?? false)) {
- die("⚠️ No autorizado.");
- }
-
- $conn = getConnection();
-
- $id = $_GET['id'] ?? null;
-
- if (!$id || !is_numeric($id)) {
- die("❌ ID inválido.");
- }
-
- // Obtener el estado actual
- $sqlEstado = "SELECT activo FROM usuarios_sistema WHERE id_usuario = ?";
- $stmtEstado = sqlsrv_query($conn, $sqlEstado, [$id]);
-
- if (!$stmtEstado || !($row = sqlsrv_fetch_array($stmtEstado, SQLSRV_FETCH_ASSOC))) {
- die("❌ Usuario no encontrado.");
- }
-
- $nuevoEstado = $row['activo'] ? 0 : 1;
-
- // Actualizar estado
- $sqlUpdate = "UPDATE usuarios_sistema SET activo = ? WHERE id_usuario = ?";
- $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$nuevoEstado, $id]);
-
- if (!$stmtUpdate) {
- die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true));
- }
-
- header("Location: /IMPORTADORES/sistemas/alta_usuarios");
- exit;
-}
-
-function reset_password() {
- session_start();
-
- if (!($_SESSION['usuario_sistemas'] ?? false)) {
- die("⚠️ No autorizado.");
- }
-
- $conn = getConnection();
-
- $id = $_GET['id'] ?? null;
-
- if (!$id || !is_numeric($id)) {
- die("❌ ID inválido.");
- }
-
- // 🔐 Generar contraseña aleatoria de 10 caracteres
- $randomPassword = bin2hex(random_bytes(5)); // genera algo como 'a8c4f1b92d'
- $passwordHash = password_hash($randomPassword, PASSWORD_DEFAULT);
-
- $sqlEmail = "SELECT email FROM usuarios_sistema WHERE id_usuario = ?";
- $stmtEmail = sqlsrv_query($conn, $sqlEmail, [$id]);
- $row = sqlsrv_fetch_array($stmtEmail, SQLSRV_FETCH_ASSOC);
-
- $sql = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?";
- $stmt = sqlsrv_query($conn, $sql, [$passwordHash, $id]);
-
- if (!$stmt) {
- die("❌ Error al actualizar: " . print_r(sqlsrv_errors(), true));
- }
-
- // 🔁 Redirigir pasando la contraseña como parámetro temporal (solo visible para el admin)
- header("Location: /IMPORTADORES/sistemas/alta_usuarios?reset=ok&pass=" . urlencode($randomPassword) . "&email=" . urlencode(decrypt($row['email'])));
-
- exit;
-}
-
-function enviar_password() {
- $email = $_GET['email'] ?? '';
- $pass = $_GET['pass'] ?? '';
-
- if (!$email || !$pass) {
- http_response_code(400);
- echo "Datos incompletos.";
- return;
- }
-
- require_once __DIR__ . '/../../vendor/autoload.php';
-
- $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 | AduanaSoft');
- $mail->addAddress($email);
-
- $mail->isHTML(true);
- $mail->Subject = 'Nueva contraseña de acceso';
- $mail->CharSet = 'UTF-8';
- $logoURL='http://siih.aduanasoft.com/IMPORTADORES/public/assets/img/logo_siih.png';
- $mail->Body = "
-
-
-
-

-
Contraseña restablecida
-
-
-
Tu contraseña de acceso al $nombreSistema ha sido restablecida por el administrador.
-
- Nueva contraseña:
- $pass
-
-
Por favor, cambia esta contraseña una vez que inicies sesión.
-
-
Este es un mensaje automático generado por el sistema. Si no solicitaste esta acción, contacta al administrador.
-
-
- © " . date('Y') . " $siglas · Sistema Integral para Importadores de Hidrocarburos
-
-
-
- ";
-
- $mail->send();
- echo "Correo enviado";
- } catch (Exception $e) {
- http_response_code(500);
- echo "Error al enviar correo: {$mail->ErrorInfo}";
- }
-}
-
-function bitacora_login() {
- if (!($_SESSION['usuario_sistemas'] ?? false)) {
- die("⚠️ No autorizado.");
- }
-
- $conn = getConnection();
- $sql = "SELECT * FROM bitacora_login ORDER BY fecha DESC";
- $stmt = sqlsrv_query($conn, $sql);
-
- $registros = [];
- while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
- $registros[] = $row;
- }
-
- include __DIR__ . '/../../views/admin/bitacora_login.php';
-}
-
-function bitacora_usuarios() {
- if (!($_SESSION['usuario_sistemas'] ?? false)) {
- die("⚠️ No autorizado.");
- }
-
- $conn = getConnection();
- $sql = "SELECT * FROM bitacora_usuarios ORDER BY fecha DESC";
- $stmt = sqlsrv_query($conn, $sql);
-
- $registros = [];
- while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
- $registros[] = $row;
- }
-
- include __DIR__ . '/../../views/admin/bitacora_usuarios.php';
}
\ No newline at end of file
diff --git a/app/controllers/vinculaciones.php b/app/controllers/vinculaciones.php
new file mode 100644
index 0000000..7a2b28e
--- /dev/null
+++ b/app/controllers/vinculaciones.php
@@ -0,0 +1,648 @@
+ 0) {
+ header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?error=pending_request');
+ exit;
+ }
+ }
+
+ // Insertar la nueva solicitud
+ $sql = "INSERT INTO solicitudes_vinculacion (id_importador, id_agencia, mensaje, estado, fecha_solicitud) VALUES (?, ?, 'Solicitud de vinculación', 'PENDIENTE', GETDATE())";
+ $params = [$id_importador, $id_agencia];
+ $stmt = sqlsrv_prepare($conn, $sql, $params);
+
+ if ($stmt && sqlsrv_execute($stmt)) {
+ header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=sended_request');
+ exit;
+ } else {
+ header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?error=failed_request');
+ exit;
+ }
+}
+
+function desvincular()
+{
+ // ✅ CORREGIR: Debe ser admin_agencia, no importador
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ // Verificar que se recibió el ID de la relación
+ $id_relacion = $_GET['id'] ?? null;
+ if (!$id_relacion || !is_numeric($id_relacion)) {
+ header('Location: /IMPORTADORES/vinculaciones/usuariosVinculados?error=invalid_id');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ try {
+ // Iniciar transacción
+ sqlsrv_begin_transaction($conn);
+
+ // 1. Verificar que la relación existe y pertenece a la agencia del admin
+ $sqlVerificar = "
+ SELECT
+ ia.*,
+ aa.id_administrador,
+ u.nombre as importador_nombre
+ FROM importador_agencia ia
+ INNER JOIN agencias_aduanales aa ON ia.id_agencia = aa.id_agencia
+ INNER JOIN usuarios_sistema u ON ia.id_importador = u.id_usuario
+ WHERE ia.id_relacion = ? AND aa.id_administrador = ?
+ ";
+ $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$id_relacion, $_SESSION['usuario_id']]);
+ $relacion = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC);
+
+ if (!$relacion) {
+ throw new Exception('Relación no encontrada o no tienes permisos para desvincularla');
+ }
+
+ if ($relacion['activo'] == 0) {
+ throw new Exception('Esta relación ya está inactiva');
+ }
+
+ // 2. Desactivar la relación (no eliminar, mantener historial)
+ $sqlDesactivar = "
+ UPDATE importador_agencia
+ SET activo = 0,
+ fecha_desvinculacion = GETDATE(),
+ estado = 'DESVINCULADO'
+ WHERE id_relacion = ?
+ ";
+ $stmtDesactivar = sqlsrv_query($conn, $sqlDesactivar, [$id_relacion]);
+
+ if (!$stmtDesactivar) {
+ throw new Exception('Error al desactivar la relación');
+ }
+
+ // Confirmar transacción
+ sqlsrv_commit($conn);
+
+ header('Location: /IMPORTADORES/vinculaciones/usuariosVinculados?success=unlinked');
+ exit;
+
+ } catch (Exception $e) {
+ // Revertir transacción en caso de error
+ sqlsrv_rollback($conn);
+ header('Location: /IMPORTADORES/vinculaciones/usuariosVinculados?error=unlinked_failed');
+ exit;
+ }
+}
+
+function cancelar()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ $id_importador = $_SESSION['usuario_id'];
+ $id_agencia = (int) $_GET['id'];
+
+ $sql = "UPDATE solicitudes_vinculacion
+ SET estado = 'CANCELADA', fecha_respuesta = GETDATE()
+ WHERE id_importador = ? AND id_agencia = ? AND estado = 'PENDIENTE'";
+
+ $params = [$id_importador, $id_agencia];
+ $stmt = sqlsrv_prepare($conn, $sql, $params);
+
+ if ($stmt && sqlsrv_execute($stmt)) {
+ header('Location: /IMPORTADORES/vinculaciones/nuevaVinculacion?success=cancelled');
+ exit;
+ }
+}
+
+function solicitudesVinculacion()
+{
+ if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ // Obtener agencia...
+ $sqlAgencia = "SELECT id_agencia FROM agencias_aduanales WHERE id_administrador = ?";
+ $params = [$_SESSION['usuario_id']];
+ $stmtAgencia = sqlsrv_query($conn, $sqlAgencia, $params);
+ $rowAgencia = sqlsrv_fetch_array($stmtAgencia, SQLSRV_FETCH_ASSOC);
+
+ if (!$rowAgencia) {
+ $solicitudes = [];
+ include __DIR__ . '/../../views/agencias/solicitudes_vinculacion.php';
+ return;
+ }
+
+ $id_agencia = $rowAgencia['id_agencia'];
+
+ // Verificar solicitudes básicas
+ $debugSql = "SELECT COUNT(*) as total FROM solicitudes_vinculacion WHERE id_agencia = ?";
+ $debugStmt = sqlsrv_query($conn, $debugSql, [$id_agencia]);
+ $debugRow = sqlsrv_fetch_array($debugStmt, SQLSRV_FETCH_ASSOC);
+
+ // Verificar pendientes
+ $debugSql2 = "SELECT COUNT(*) as total FROM solicitudes_vinculacion WHERE estado = 'PENDIENTE' AND id_agencia = ?";
+ $debugStmt2 = sqlsrv_query($conn, $debugSql2, [$id_agencia]);
+ $debugRow2 = sqlsrv_fetch_array($debugStmt2, SQLSRV_FETCH_ASSOC);
+
+ // Consulta principal
+ $sql = "
+ SELECT
+ sv.id_solicitud,
+ u.nombre AS importador_nombre,
+ ig.rfc,
+ sv.mensaje,
+ sv.fecha_solicitud,
+ si.opinion_file
+ FROM solicitudes_vinculacion sv
+ INNER JOIN usuarios_sistema u ON sv.id_importador = u.id_usuario
+ LEFT JOIN informacion_general ig ON u.id_usuario = ig.id_usuario
+ LEFT JOIN solicitudes_importadores si ON LTRIM(RTRIM(LOWER(si.company_name))) = LTRIM(RTRIM(LOWER(u.nombre)))
+ WHERE sv.estado = 'PENDIENTE' AND sv.id_agencia = ?
+ ORDER BY sv.fecha_solicitud DESC
+ ";
+ $params = [$id_agencia];
+ $stmt = sqlsrv_query($conn, $sql, $params);
+
+ // ✅ INICIALIZAR EL ARRAY DE SOLICITUDES
+ $solicitudes = [];
+
+ // ✅ VERIFICAR SI LA CONSULTA FUNCIONÓ
+ if ($stmt === false) {
+ // Usar consulta simplificada como backup
+ $sqlSimple = "
+ SELECT
+ sv.id_solicitud,
+ u.nombre AS importador_nombre,
+ sv.mensaje,
+ sv.fecha_solicitud
+ FROM solicitudes_vinculacion sv
+ INNER JOIN usuarios_sistema u ON sv.id_importador = u.id_usuario
+ WHERE sv.estado = 'PENDIENTE' AND sv.id_agencia = ?
+ ORDER BY sv.fecha_solicitud DESC
+ ";
+ $stmt = sqlsrv_query($conn, $sqlSimple, $params);
+ }
+
+ // ✅ PROCESAR LOS RESULTADOS Y LLENAR EL ARRAY
+ if ($stmt !== false) {
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $solicitudes[] = $row;
+ }
+ }
+
+ include __DIR__ . '/../../views/agencias/solicitudes_vinculacion.php';
+}
+
+function aprobarVinculacion()
+{
+ // Verificar autenticación y permisos
+ if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ // Verificar que se recibió el ID de la solicitud
+ $id_solicitud = $_GET['id'] ?? null;
+ if (!$id_solicitud || !is_numeric($id_solicitud)) {
+ header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?error=request_id_invalid');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ try {
+ // Iniciar transacción
+ sqlsrv_begin_transaction($conn);
+
+ // 1. Obtener datos de la solicitud y verificar que pertenece a la agencia del admin
+ $sqlSolicitud = "
+ SELECT
+ sv.id_solicitud,
+ sv.id_importador,
+ sv.id_agencia,
+ sv.estado,
+ aa.id_administrador
+ FROM solicitudes_vinculacion sv
+ INNER JOIN agencias_aduanales aa ON sv.id_agencia = aa.id_agencia
+ WHERE sv.id_solicitud = ? AND aa.id_administrador = ?
+ ";
+ $stmtSolicitud = sqlsrv_query($conn, $sqlSolicitud, [$id_solicitud, $_SESSION['usuario_id']]);
+ $solicitud = sqlsrv_fetch_array($stmtSolicitud, SQLSRV_FETCH_ASSOC);
+
+ if (!$solicitud) {
+ throw new Exception('Solicitud no encontrada o no tienes permisos para aprobarla');
+ }
+
+ if ($solicitud['estado'] !== 'PENDIENTE') {
+ throw new Exception('Esta solicitud ya ha sido procesada');
+ }
+
+ // 2. Verificar si ya existe una relación activa entre importador y agencia
+ $sqlVerificar = "
+ SELECT id_relacion
+ FROM importador_agencia
+ WHERE id_importador = ? AND id_agencia = ? AND activo = 1
+ ";
+ $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$solicitud['id_importador'], $solicitud['id_agencia']]);
+ $relacionExistente = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC);
+
+ if ($relacionExistente) {
+ throw new Exception('Ya existe una vinculación activa entre este importador y la agencia');
+ }
+
+ // 3. Actualizar el estado de la solicitud a APROBADO
+ $sqlActualizar = "
+ UPDATE solicitudes_vinculacion
+ SET estado = 'APROBADO',
+ fecha_respuesta = GETDATE(),
+ respondido_por = ?,
+ comentarios_respuesta = 'Vinculación aprobada'
+ WHERE id_solicitud = ?
+ ";
+ $stmtActualizar = sqlsrv_query($conn, $sqlActualizar, [$_SESSION['usuario_id'], $id_solicitud]);
+
+ if (!$stmtActualizar) {
+ throw new Exception('Error al actualizar la solicitud');
+ }
+
+ // 4. Crear la relación en importador_agencia
+ $sqlRelacion = "
+ INSERT INTO importador_agencia (
+ id_importador,
+ id_agencia,
+ activo,
+ fecha_vinculacion,
+ creado_por,
+ aprobado_por,
+ estado
+ ) VALUES (?, ?, 1, GETDATE(), ?, ?, 'APROBADO')
+ ";
+ $stmtRelacion = sqlsrv_query($conn, $sqlRelacion, [
+ $solicitud['id_importador'],
+ $solicitud['id_agencia'],
+ $solicitud['id_importador'], // creado_por (el importador que solicitó)
+ $_SESSION['usuario_id'] // aprobado_por (el admin de agencia)
+ ]);
+
+ if (!$stmtRelacion) {
+ throw new Exception('Error al crear la relación importador-agencia');
+ }
+
+ // Confirmar transacción
+ sqlsrv_commit($conn);
+
+ header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?success=approved');
+ exit;
+
+ } catch (Exception $e) {
+ // Revertir transacción en caso de error
+ sqlsrv_rollback($conn);
+ header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?error=denied');
+ exit;
+ }
+}
+
+function denegarVinculacion()
+{
+ // Verificar autenticación y permisos
+ if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'admin_agencia') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ // Verificar que se recibió el ID de la solicitud
+ $id_solicitud = $_GET['id'] ?? null;
+ if (!$id_solicitud || !is_numeric($id_solicitud)) {
+ header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?error=request_id_invalid');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ try {
+ // Iniciar transacción
+ sqlsrv_begin_transaction($conn);
+
+ // 1. Obtener datos de la solicitud y verificar que pertenece a la agencia del admin
+ $sqlSolicitud = "
+ SELECT
+ sv.id_solicitud,
+ sv.id_importador,
+ sv.id_agencia,
+ sv.estado,
+ aa.id_administrador
+ FROM solicitudes_vinculacion sv
+ INNER JOIN agencias_aduanales aa ON sv.id_agencia = aa.id_agencia
+ WHERE sv.id_solicitud = ? AND aa.id_administrador = ?
+ ";
+ $stmtSolicitud = sqlsrv_query($conn, $sqlSolicitud, [$id_solicitud, $_SESSION['usuario_id']]);
+ $solicitud = sqlsrv_fetch_array($stmtSolicitud, SQLSRV_FETCH_ASSOC);
+
+ if (!$solicitud) {
+ throw new Exception('Solicitud no encontrada o no tienes permisos para denegarla');
+ }
+
+ if ($solicitud['estado'] !== 'PENDIENTE') {
+ throw new Exception('Esta solicitud ya ha sido procesada');
+ }
+
+ // 2. Actualizar el estado de la solicitud a DENEGADO
+ $sqlActualizar = "
+ UPDATE solicitudes_vinculacion
+ SET estado = 'DENEGADO',
+ fecha_respuesta = GETDATE(),
+ respondido_por = ?
+ WHERE id_solicitud = ?
+ ";
+ $stmtActualizar = sqlsrv_query($conn, $sqlActualizar, [$_SESSION['usuario_id'], $id_solicitud]);
+
+ if (!$stmtActualizar) {
+ throw new Exception('Error al actualizar la solicitud');
+ }
+
+ if (!$stmtRelacion) {
+ throw new Exception('Error al registrar el rechazo en el historial');
+ }
+
+ // Confirmar transacción
+ sqlsrv_commit($conn);
+
+ header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?success=denied');
+ exit;
+
+ } catch (Exception $e) {
+ // Revertir transacción en caso de error
+ sqlsrv_rollback($conn);
+ header('Location: /IMPORTADORES/vinculaciones/solicitudesVinculacion?error=denied_error');
+ exit;
+ }
+}
+
+function desvincularUsuario()
+{
+ // ✅ CORREGIR: Debe ser admin_agencia, no importador
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ // Verificar que se recibió el ID de la relación
+ $id_relacion = $_GET['id'] ?? null;
+ if (!$id_relacion || !is_numeric($id_relacion)) {
+ header('Location: /IMPORTADORES/vinculaciones/vinculacionesUsuario?error=invalid_id');
+ exit;
+ }
+
+ $conn = getConnection();
+
+ try {
+ // 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
+ FROM importador_agencia ia
+ INNER JOIN usuarios_sistema u ON ia.id_importador = u.id_usuario
+ INNER JOIN agencias_aduanales aa ON ia.id_agencia = aa.id_agencia
+ WHERE ia.id_relacion = ? AND ia.id_importador = ?
+ ";
+ $stmtVerificar = sqlsrv_query($conn, $sqlVerificar, [$id_relacion, $_SESSION['usuario_id']]);
+
+ // Verificar si la consulta fue exitosa
+ if ($stmtVerificar === false) {
+ $errors = sqlsrv_errors();
+ error_log("Error en consulta verificar: " . print_r($errors, true));
+ throw new Exception('Error en la consulta de verificación');
+ }
+
+ $relacion = sqlsrv_fetch_array($stmtVerificar, SQLSRV_FETCH_ASSOC);
+
+ if (!$relacion) {
+ throw new Exception('Relación no encontrada o no tienes permisos para desvincularla');
+ }
+
+ if ($relacion['activo'] == 0) {
+ throw new Exception('Esta relación ya está inactiva');
+ }
+
+ // 2. Desactivar la relación (no eliminar, mantener historial)
+ $sqlDesactivar = "
+ UPDATE importador_agencia
+ SET activo = 0,
+ fecha_desvinculacion = GETDATE(),
+ estado = 'DESVINCULADO'
+ WHERE id_relacion = ? AND id_importador = ?
+ ";
+
+ $stmtDesactivar = sqlsrv_query($conn, $sqlDesactivar, [$id_relacion, $_SESSION['usuario_id']]);
+
+ if ($stmtDesactivar === false) {
+ $errors = sqlsrv_errors();
+ error_log("Error en actualización: " . print_r($errors, true));
+ throw new Exception('Error al desactivar la relación');
+ }
+
+ // Verificar que se actualizó al menos una fila
+ $filasAfectadas = sqlsrv_rows_affected($stmtDesactivar);
+ if ($filasAfectadas === 0) {
+ throw new Exception('No se pudo actualizar la relación');
+ }
+
+ // Limpiar statements
+ sqlsrv_free_stmt($stmtVerificar);
+ sqlsrv_free_stmt($stmtDesactivar);
+
+ // Confirmar transacción
+ sqlsrv_commit($conn);
+ sqlsrv_close($conn);
+
+ header('Location: /IMPORTADORES/vinculaciones/vinculacionesUsuario?success=unlinked');
+ exit;
+
+ } catch (Exception $e) {
+ // Revertir transacción en caso de error
+ sqlsrv_rollback($conn);
+ sqlsrv_close($conn);
+
+ header('Location: /IMPORTADORES/vinculaciones/vinculacionesUsuario?error=unlinked_failed&msg=' . urlencode($e->getMessage()));
+ exit;
+ }
+}
\ No newline at end of file
diff --git a/app/helpers/bitacoras.php b/app/helpers/bitacoras.php
index 8fc5f78..38f70a2 100644
--- a/app/helpers/bitacoras.php
+++ b/app/helpers/bitacoras.php
@@ -17,4 +17,12 @@ function registrar_bitacora_usuario($usuarioId, $accion, $descripcion) {
sqlsrv_query($conn, $sql, $params);
}
+function registrar_bitacora_agencia($agenciaId, $nombreAgencia, $accion, $idAdmin) {
+ $conn = getConnection();
+ $sql = "INSERT INTO bitacora_agencias (id_agencia, nombre, accion, realizado_por)
+ VALUES (?, ?, ?, ?)";
+ $params = [$usuarioId, $nombre, $accion, $idAdmin];
+
+ sqlsrv_query($conn, $sql, $params);
+}
diff --git a/uploads/expedientes/53/685414da683db_Reporte-de-movimiento-de-cuentas-por-cobrar-768x447.png b/uploads/expedientes/53/685414da683db_Reporte-de-movimiento-de-cuentas-por-cobrar-768x447.png
new file mode 100644
index 0000000..ab00d4c
Binary files /dev/null and b/uploads/expedientes/53/685414da683db_Reporte-de-movimiento-de-cuentas-por-cobrar-768x447.png differ
diff --git a/uploads/expedientes/53/685414da6b0a7_IMG-20250520-WA0001.jpg b/uploads/expedientes/53/685414da6b0a7_IMG-20250520-WA0001.jpg
new file mode 100644
index 0000000..0e4436b
Binary files /dev/null and b/uploads/expedientes/53/685414da6b0a7_IMG-20250520-WA0001.jpg differ
diff --git a/uploads/expedientes/53/685414da6c671_Screenshot_20250520_130018_com.mercadopago.wallet.jpg b/uploads/expedientes/53/685414da6c671_Screenshot_20250520_130018_com.mercadopago.wallet.jpg
new file mode 100644
index 0000000..7cfbe1a
Binary files /dev/null and b/uploads/expedientes/53/685414da6c671_Screenshot_20250520_130018_com.mercadopago.wallet.jpg differ
diff --git a/uploads/expedientes/53/685414da6ce58_IMG_20250520_125855.jpg b/uploads/expedientes/53/685414da6ce58_IMG_20250520_125855.jpg
new file mode 100644
index 0000000..143d4a9
Binary files /dev/null and b/uploads/expedientes/53/685414da6ce58_IMG_20250520_125855.jpg differ
diff --git a/uploads/expedientes/53/685414da6e0db_Ismael_Camarillo_Molina.pdf b/uploads/expedientes/53/685414da6e0db_Ismael_Camarillo_Molina.pdf
new file mode 100644
index 0000000..4612dc4
Binary files /dev/null and b/uploads/expedientes/53/685414da6e0db_Ismael_Camarillo_Molina.pdf differ
diff --git a/views/admin/agencias_activas.php b/views/admin/agencias_activas.php
index fc85ff9..096816f 100644
--- a/views/admin/agencias_activas.php
+++ b/views/admin/agencias_activas.php
@@ -1,11 +1,17 @@
-
+
-
+
+
- Dashboard | Agencia Aduanal
+
+ Dashboard | Administrador
+
+
+
+
-
-
✅ Agencias Activas
+
✅ Agencias Activas
+
+
+
+
+
+
+ | # |
+ Nombre |
+ RFC |
+ Correo |
+ Teléfono |
+ Dirección |
+ Fecha |
+ Administrador |
+ Acciones |
+
+
+
+
+
+
+ | = $ag['id_agencia'] ?> |
+ = htmlspecialchars(decrypt($ag['nombre_agencia'])) ?> |
+ = htmlspecialchars($ag['rfc_agencia']) ?> |
+ = htmlspecialchars(decrypt($ag['email'])) ?> |
+ = htmlspecialchars($ag['telefono']) ?> |
+ = htmlspecialchars($ag['direccion']) ?> |
+ = $ag['creado_en'] ? $ag['creado_en']->format('Y-m-d H:i') : '' ?> |
+ = htmlspecialchars($ag['id_administrador']) ?> |
+
+
+ Suspender
+
+ |
+
+
+
+
+ | No hay agencias registradas aún. |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/views/admin/alta_agencias.php b/views/admin/alta_agencias.php
new file mode 100644
index 0000000..c1a119e
--- /dev/null
+++ b/views/admin/alta_agencias.php
@@ -0,0 +1,202 @@
+
+
+
+
+
+
+ Dashboard | Administrador
+
+
+
+
+
+
+
+
+
+
+
🏪 Alta de Agencias Aduanales
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/views/admin/alta_usuarios.php b/views/admin/alta_usuarios.php
index 9502b1a..35b6047 100644
--- a/views/admin/alta_usuarios.php
+++ b/views/admin/alta_usuarios.php
@@ -1,128 +1,153 @@
-
+
-
Panel de Administración - Usuarios
+
Dashboard | Administrador
+
+
+
+
+
+
+
-
-
Administración de Usuarios
-
+