diff --git a/app/controllers/agentes.php b/app/controllers/agentes.php
index 2fd4388..d9a9eb5 100644
--- a/app/controllers/agentes.php
+++ b/app/controllers/agentes.php
@@ -165,6 +165,39 @@ function desvincularAgente()
throw new Exception('Error al desactivar la relación: ' . print_r(sqlsrv_errors(), true));
}
+ // NUEVO: Verificar si el importador desvinculado tenía esta agencia como activa
+ $sqlVerificarAgenciaActiva = "
+ SELECT id_agencia_en_uso
+ FROM usuarios_sistema
+ WHERE id_usuario = ? AND id_agencia_en_uso = ?
+ ";
+ $stmtVerificarActiva = sqlsrv_query($conn, $sqlVerificarAgenciaActiva,
+ [$relacion['id_importador'], $relacion['id_agencia']]);
+
+ if ($stmtVerificarActiva === false) {
+ throw new Exception('Error al verificar agencia activa: ' . print_r(sqlsrv_errors(), true));
+ }
+
+ if ($stmtVerificarActiva && sqlsrv_fetch_array($stmtVerificarActiva, SQLSRV_FETCH_ASSOC)) {
+ // Si tenía esta agencia como activa, quitársela
+ $sqlQuitarAgenciaActiva = "
+ UPDATE usuarios_sistema
+ SET id_agencia_en_uso = NULL
+ WHERE id_usuario = ?
+ ";
+ $stmtQuitarActiva = sqlsrv_query($conn, $sqlQuitarAgenciaActiva, [$relacion['id_importador']]);
+
+ if ($stmtQuitarActiva === false) {
+ throw new Exception('Error al actualizar la agencia activa del importador: ' . print_r(sqlsrv_errors(), true));
+ }
+ }
+
+ // Limpiar statements
+ sqlsrv_free_stmt($stmtVerificarActiva);
+ if (isset($stmtQuitarActiva)) {
+ sqlsrv_free_stmt($stmtQuitarActiva);
+ }
+
// Confirmar transacción
sqlsrv_commit($conn);
diff --git a/app/controllers/bitacoras.php b/app/controllers/bitacoras.php
index 18d22a9..671e3c9 100644
--- a/app/controllers/bitacoras.php
+++ b/app/controllers/bitacoras.php
@@ -102,7 +102,7 @@ function sistemaAgencia()
include __DIR__ . '/../../views/bitacoras/sistema_agencia.php';
}
-function usuarios()
+function cambios()
{
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
header('Location: /IMPORTADORES/login');
@@ -122,6 +122,32 @@ function usuarios()
$registros[] = $row;
}
+ include __DIR__ . '/../../views/bitacoras/bitacora_cambios.php';
+}
+
+function usuarios()
+{
+ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
+ header('Location: /IMPORTADORES/login');
+ exit;
+ }
+
+ $conn = getConnection();
+ $sql = "SELECT u.*, creador.nombre AS nombre_creador
+ FROM usuarios_sistema u
+ LEFT JOIN usuarios_sistema creador ON u.creado_por = creador.id_usuario
+ ORDER BY creado_en DESC";
+ $stmt = sqlsrv_query($conn, $sql);
+
+ if ($stmt === false) {
+ die(print_r(sqlsrv_errors(), true));
+ }
+
+ $usuarios = [];
+ while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
+ $usuarios[] = $row;
+ }
+
include __DIR__ . '/../../views/bitacoras/bitacora_usuarios.php';
}
diff --git a/app/controllers/importadores.php b/app/controllers/importadores.php
index 5481345..0051f3a 100644
--- a/app/controllers/importadores.php
+++ b/app/controllers/importadores.php
@@ -184,9 +184,26 @@ function desvincularUsuario()
throw new Exception('No se pudo actualizar la relación');
}
+ // 3. Actualizar el campo id_agencia_en_uso del usuario si es necesario
+ if ($_SESSION['id_agencia_en_uso'] == $relacion['id_agencia']) {
+ $sqlActualizarAgencia = "
+ UPDATE usuarios_sistema
+ SET id_agencia_en_uso = NULL
+ WHERE id_usuario = ?
+ ";
+ $stmtActualizarAgencia = sqlsrv_query($conn, $sqlActualizarAgencia, [$_SESSION['usuario_id']]);
+
+ if ($stmtActualizarAgencia === false) {
+ $errors = sqlsrv_errors();
+ error_log("Error al actualizar agencia en uso: " . print_r($errors, true));
+ throw new Exception('Error al actualizar la agencia en uso');
+ }
+ }
+
// Limpiar statements
sqlsrv_free_stmt($stmtVerificar);
sqlsrv_free_stmt($stmtDesactivar);
+ sqlsrv_free_stmt($stmtActualizarAgencia);
// Confirmar transacción
sqlsrv_commit($conn);
diff --git a/app/controllers/reset.php b/app/controllers/reset.php
new file mode 100644
index 0000000..bf704af
--- /dev/null
+++ b/app/controllers/reset.php
@@ -0,0 +1,505 @@
+ false, 'message' => '❌ Sesión no válida. Inicia sesión nuevamente.']);
+ exit;
+ }
+
+ $conn = getConnection();
+ if (!$conn) {
+ echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']);
+ exit;
+ }
+
+ $id_usuario = $_SESSION['usuario_id'];
+ $email = $_SESSION['usuario_email'];
+ $emailEncrypted = encrypt($email);
+
+ // Verificar que la cuenta esté activa
+ $sql = "SELECT activo FROM usuarios_sistema WHERE id_usuario = ?";
+ $stmt = sqlsrv_query($conn, $sql, [$id_usuario]);
+
+ if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) {
+ echo json_encode(['success' => false, 'message' => '❌ Usuario no encontrado.']);
+ exit;
+ }
+
+ if ($row['activo'] != 1) {
+ echo json_encode(['success' => false, 'message' => '❌ Tu cuenta está inactiva.']);
+ exit;
+ }
+
+ // Verificar si ya existe un código activo
+ $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);
+
+ if ($checkRow['total'] > 0) {
+ echo json_encode(['success' => false, 'message' => '⚠️ Ya tienes un código activo. Revisa tu correo o espera 10 minutos.']);
+ exit;
+ }
+
+ // Generar nuevo código
+ $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 (?, ?, ?, ?)";
+ $params = [$emailEncrypted, $codigo, $expira, $estatus];
+ $result = sqlsrv_query($conn, $insert, $params);
+
+ if (!$result) {
+ echo json_encode(['success' => false, 'message' => '❌ Error al generar el código de verificación.']);
+ exit;
+ }
+
+ // Establecer variables de sesión para el cambio interno
+ $_SESSION['cambio_interno'] = true;
+ $_SESSION['codigo_timestamp'] = time();
+
+ // Agregar estos logs:
+ error_log("DEBUG enviarCodigoInterno - SESSION después de establecer variables: " . print_r($_SESSION, true));
+ error_log("DEBUG - cambio_interno establecido: " . ($_SESSION['cambio_interno'] ? 'TRUE' : 'FALSE'));
+
+ // Enviar código por correo
+ 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->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
+ $mail->Port = 587;
+
+ $mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
+ $mail->addAddress($email);
+ $mail->CharSet = 'UTF-8';
+ $mail->isHTML(true);
+ $mail->Subject = 'Código para cambio de contraseña';
+
+ $mail->Body = "
+
+
+
+
Cambio de contraseña
+
+
+
Has solicitado cambiar tu contraseña desde tu cuenta.
+
+
Tu código de verificación es:
+
$codigo
+
+
Este código expirará en 10 minutos.
+
Si no solicitaste este cambio, ignora este correo.
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+
+ // Redirigir directamente desde PHP
+ header("Location: /IMPORTADORES/reset/verificarCodigoInternoView");
+ exit;
+
+ } catch (Exception $e) {
+ error_log("Error al enviar correo de cambio interno: {$mail->ErrorInfo}");
+
+ // Solo en caso de error, devolver JSON
+ echo json_encode(['success' => false, 'message' => '❌ Error al enviar el correo. Intenta más tarde.']);
+ exit;
+ }
+}
+
+function verificarCodigoInternoView()
+{
+ // Verificar si el usuario ya está autenticado
+ if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) || !isset($_SESSION['cambio_interno'])) {
+ header("Location: /IMPORTADORES/login");
+ exit;
+ }
+
+ // Verificar si el código ya fue verificado
+ if (isset($_SESSION['codigo_verificado_interno']) && $_SESSION['codigo_verificado_interno'] === true) {
+ header("Location: /IMPORTADORES/reset/cambiarPasswordInternoView");
+ exit;
+ }
+
+ // Mostrar la vista de verificación de código interno
+ include __DIR__ . '/../../views/reset/verificar_codigo.php';
+}
+
+function verificarCodigoInterno()
+{
+ header('Content-Type: application/json');
+
+ $conn = getConnection();
+
+ $email = $_SESSION['usuario_email'];
+ $emailEncrypted = encrypt($email); // aplica aquí también
+
+ try {
+ // Verificar conexión
+ if (!isset($conn) || $conn === false) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Error de conexión a la base de datos.',
+ 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0))
+ ]);
+ exit;
+ }
+
+ $codigo = trim($_POST['codigo'] ?? '');
+
+ if (empty($codigo)) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Código requerido.',
+ 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0))
+ ]);
+ exit;
+ }
+
+ if (!preg_match('/^\d{6}$/', $codigo)) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ El código debe tener 6 dígitos numéricos.',
+ 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0))
+ ]);
+ exit;
+ }
+
+ $intentosActuales = $_SESSION['intentos_codigo_interno'] ?? 0;
+
+ if ($intentosActuales >= 3) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Demasiados intentos fallidos. Solicita un nuevo código.',
+ 'blocked' => true,
+ 'redirect' => '/IMPORTADORES/seguridad/index',
+ 'intentos_restantes' => 0
+ ]);
+ exit;
+ }
+
+ if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email'])) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Sesión inválida. Intenta nuevamente.',
+ 'blocked' => true,
+ 'redirect' => '/IMPORTADORES/seguridad/index'
+ ]);
+ exit;
+ }
+
+ // Consulta principal para verificar el código
+ $sql = "SELECT id, codigo, expiracion
+ FROM recuperacion_password
+ WHERE email = ? AND estatus = 0 AND expiracion > GETDATE()
+ ORDER BY expiracion DESC
+ ";
+
+ $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]);
+
+ if (!$stmt) {
+ throw new Exception("Error en la consulta a la base de datos");
+ }
+
+ $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
+ sqlsrv_free_stmt($stmt);
+
+ if (!$row) {
+ $_SESSION['intentos_codigo_interno'] = $intentosActuales + 1;
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Código inválido o expirado.',
+ 'intentos_restantes' => max(0, 3 - $_SESSION['intentos_codigo_interno'])
+ ]);
+ exit;
+ }
+
+ if (!isset($row['codigo'], $row['id'], $row['expiracion'])) {
+ throw new Exception("Faltan campos requeridos en la respuesta de la base de datos.");
+ }
+
+ if ($codigo !== $row['codigo']) {
+ $_SESSION['intentos_codigo_interno'] = $intentosActuales + 1;
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Código incorrecto.',
+ 'intentos_restantes' => max(0, 3 - $_SESSION['intentos_codigo_interno'])
+ ]);
+ exit;
+ }
+
+ $expiracion = $row['expiracion'];
+ $ahora = new DateTime();
+
+ if ($expiracion instanceof DateTime) {
+ $expiracionStr = $expiracion->format('Y-m-d H:i:s');
+
+ if ($expiracion <= $ahora) {
+ $_SESSION['intentos_codigo_interno'] = $intentosActuales + 1;
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ El código ha expirado.',
+ 'intentos_restantes' => max(0, 3 - $_SESSION['intentos_codigo_interno'])
+ ]);
+ exit;
+ }
+ }
+
+ // Marcar el código como usado
+ $sqlUpdate = "UPDATE recuperacion_password SET estatus = 1 WHERE id = ?";
+ $stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$row['id']]);
+
+ if (!$stmtUpdate) {
+ throw new Exception("Error al actualizar el estado del código");
+ }
+
+ sqlsrv_free_stmt($stmtUpdate);
+
+ // Marcar como verificado y limpiar intentos
+ $_SESSION['codigo_verificado_interno'] = true;
+ unset($_SESSION['intentos_codigo_interno']);
+
+ echo json_encode([
+ 'success' => true,
+ 'message' => '✅ Código verificado correctamente.',
+ 'redirect' => '/IMPORTADORES/reset/cambiarPasswordInternoView'
+ ]);
+
+ } catch (Exception $e) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => '❌ Error interno del servidor. Intenta nuevamente.',
+ 'intentos_restantes' => max(0, 3 - ($_SESSION['intentos_codigo_interno'] ?? 0))
+ ]);
+ exit;
+ } finally {
+ // Cerrar conexión si existe
+ if (isset($conn) && $conn !== false) {
+ sqlsrv_close($conn);
+ }
+ }
+}
+
+function cambiarPasswordInternoView()
+{
+ // Verificar si el usuario ya está autenticado y el código verificado
+ if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) ||
+ !isset($_SESSION['cambio_interno']) || !isset($_SESSION['codigo_verificado_interno'])) {
+ header("Location: /IMPORTADORES/login");
+ exit;
+ }
+
+ // Mostrar la vista de cambio de contraseña interno
+ include __DIR__ . '/../../views/reset/change_password.php';
+}
+
+function cambiarPasswordInterno()
+{
+ header('Content-Type: application/json'); // ⬅️ AGREGAR ESTA LÍNEA
+
+ // Verificar autorización completa
+ if (!isset($_SESSION['usuario_id']) || !isset($_SESSION['usuario_email']) ||
+ !isset($_SESSION['cambio_interno']) || !isset($_SESSION['codigo_verificado_interno'])) {
+ echo json_encode(['success' => false, 'message' => '❌ No tienes autorización para cambiar la contraseña.']);
+ exit;
+ }
+
+ $conn = getConnection();
+ if (!$conn) {
+ echo json_encode(['success' => false, 'message' => '❌ Error de conexión con la base de datos.']);
+ exit;
+ }
+
+ $passwordActual = $_POST['password_actual'] ?? '';
+ $passwordNueva = $_POST['password_nueva'] ?? '';
+ $confirmarPassword = $_POST['confirmar_password'] ?? '';
+
+ // Validaciones
+ if (empty($passwordActual)) {
+ echo json_encode(['success' => false, 'message' => '❌ La contraseña actual es requerida.']);
+ exit;
+ }
+
+ if (strlen($passwordNueva) < 6) {
+ echo json_encode(['success' => false, 'message' => '❌ La nueva contraseña debe tener al menos 6 caracteres.']);
+ exit;
+ }
+
+ if ($passwordNueva !== $confirmarPassword) {
+ echo json_encode(['success' => false, 'message' => '❌ Las contraseñas nuevas no coinciden.']);
+ exit;
+ }
+
+ if ($passwordActual === $passwordNueva) {
+ echo json_encode(['success' => false, 'message' => '❌ La nueva contraseña debe ser diferente a la actual.']);
+ exit;
+ }
+
+ $id_usuario = $_SESSION['usuario_id'];
+ $email = $_SESSION['usuario_email'];
+ $emailEncrypted = encrypt($email);
+
+ // Verificar contraseña actual
+ $sql = "SELECT password_hash FROM usuarios_sistema WHERE id_usuario = ?";
+ $stmt = sqlsrv_query($conn, $sql, [$id_usuario]);
+
+ if (!$stmt || !($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))) {
+ echo json_encode(['success' => false, 'message' => '❌ Error al verificar la contraseña actual.']);
+ exit;
+ }
+
+ if (!password_verify($passwordActual, $row['password_hash'])) {
+ echo json_encode(['success' => false, 'message' => '❌ La contraseña actual es incorrecta.']);
+ exit;
+ }
+
+ // Actualizar contraseña
+ $hashNueva = password_hash($passwordNueva, PASSWORD_BCRYPT);
+ $sqlUpdate = "UPDATE usuarios_sistema SET password_hash = ? WHERE id_usuario = ?";
+ $stmtUpdate = sqlsrv_prepare($conn, $sqlUpdate, [$hashNueva, $id_usuario]);
+
+ if (!$stmtUpdate || !sqlsrv_execute($stmtUpdate)) {
+ echo json_encode(['success' => false, 'message' => '❌ Error al actualizar la contraseña.']);
+ exit;
+ }
+
+ // Registrar en bitácora
+ $ip = $_SERVER['REMOTE_ADDR'] ?? 'N/A';
+ registrarBitacora($conn, $id_usuario, $email, $ip, 1, 'Cambio de contraseña interno');
+
+ // Enviar correo de confirmación
+ 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->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
+ $mail->Port = 587;
+
+ $mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | AduanaSoft');
+ $mail->addAddress($email);
+ $mail->CharSet = 'UTF-8';
+ $mail->isHTML(true);
+ $mail->Subject = 'Contraseña actualizada exitosamente';
+
+ $fechaHora = date('d/m/Y H:i:s');
+ $mail->Body = "
+
+
+
+
Contraseña actualizada
+
+
+
Hola,
+
Te confirmamos que tu contraseña ha sido cambiada exitosamente desde tu cuenta.
+
Fecha y hora: {$fechaHora}
+
IP: {$ip}
+
+
⚠️ Importante: Si no realizaste este cambio, contacta inmediatamente al área de soporte.
+
+
+
+ © " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
+
+
+
";
+
+ $mail->send();
+ } catch (Exception $e) {
+ error_log("Error al enviar correo de confirmación interno: {$mail->ErrorInfo}");
+ // No fallar el proceso por error de email, solo registrar el error
+ }
+
+ // Limpiar variables de sesión del proceso
+ unset($_SESSION['cambio_interno']);
+ unset($_SESSION['codigo_verificado_interno']);
+ unset($_SESSION['codigo_timestamp']);
+
+ echo json_encode([
+ 'success' => true,
+ 'message' => '✅ Contraseña actualizada exitosamente.',
+ 'redirect' => '/IMPORTADORES/login' // Redirigir a la página de seguridad
+ ]);
+ exit;
+}
+
+function cancelarCambioInterno()
+{
+ header('Content-Type: application/json');
+
+ if (isset($_SESSION['cambio_interno'])) {
+ $conn = getConnection();
+
+ if ($conn && isset($_SESSION['usuario_email'])) {
+ // Invalidar códigos activos
+ $emailEncrypted = encrypt($_SESSION['usuario_email']);
+ $sql = "UPDATE recuperacion_password SET estatus = 1 WHERE email = ? AND estatus = 0";
+ $stmt = sqlsrv_query($conn, $sql, [$emailEncrypted]);
+ if ($stmt) sqlsrv_free_stmt($stmt);
+ }
+
+ // Limpiar sesión
+ unset($_SESSION['cambio_interno']);
+ unset($_SESSION['codigo_verificado_interno']);
+ unset($_SESSION['intentos_codigo_interno']);
+ unset($_SESSION['codigo_timestamp']);
+ }
+
+ echo json_encode(['success' => true, 'message' => 'Proceso cancelado.']);
+}
+
+// Función para obtener el estado actual (para mostrar en la vista)
+function obtenerEstadoDosFactores()
+{
+ $conn = getConnection();
+
+ // CORRIGIDO: Cambiar id_usuario por usuario_id
+ $id_usuario = $_SESSION['usuario_id'] ?? null;
+ if (!$id_usuario) {
+ return 0; // valor por defecto si no hay sesión
+ }
+
+ $sql_dos_factores = "SELECT dos_factores FROM usuarios_sistema WHERE id_usuario = ?";
+ $params = [$id_usuario];
+ $stmt_dos_factores = sqlsrv_prepare($conn, $sql_dos_factores, $params);
+
+ $dos_factores_estado = 0; // valor por defecto
+
+ if ($stmt_dos_factores && sqlsrv_execute($stmt_dos_factores)) {
+ if ($row = sqlsrv_fetch_array($stmt_dos_factores, SQLSRV_FETCH_ASSOC)) {
+ $dos_factores_estado = (int)$row['dos_factores'];
+ }
+ }
+
+ sqlsrv_free_stmt($stmt_dos_factores);
+ sqlsrv_close($conn);
+
+ return $dos_factores_estado;
+}
\ No newline at end of file
diff --git a/app/controllers/transportistas.php b/app/controllers/transportistas.php
index 67ca8f6..9ef011e 100644
--- a/app/controllers/transportistas.php
+++ b/app/controllers/transportistas.php
@@ -439,15 +439,15 @@ function actualizar()
// 3) Ejecutar UPDATE
$sqlUpd = "UPDATE dbo.transportistas SET
clave_identificador = ?,
- nombre = ?,
- rfc = ?,
- curp = ?,
- telefono = ?,
- caat = ?,
- pais = ?,
- entidad_federativa = ?,
- ciudad = ?,
- domicilio = ?
+ nombre = ?,
+ rfc = ?,
+ curp = ?,
+ telefono = ?,
+ caat = ?,
+ pais = ?,
+ entidad_federativa = ?,
+ ciudad = ?,
+ domicilio = ?
WHERE id_transportista = ?";
$params = [
$clave, $nombre, $rfc, $curp, $tel,
diff --git a/app/controllers/vinculaciones.php b/app/controllers/vinculaciones.php
index 857f1c2..de1c608 100644
--- a/app/controllers/vinculaciones.php
+++ b/app/controllers/vinculaciones.php
@@ -298,6 +298,32 @@ function desvincularAgencia()
throw new Exception('Error al desactivar la relación de ' . $tipo);
}
+ // NUEVO: Verificar si el usuario desvinculado tenía esta agencia como activa
+ if ($tipo === 'importador') {
+ // Verificar si el importador tenía esta agencia como activa
+ $sqlVerificarAgenciaActiva = "
+ SELECT id_agencia_en_uso
+ FROM usuarios_sistema
+ WHERE id_usuario = ? AND id_agencia_en_uso = ?
+ ";
+ $stmtVerificarActiva = sqlsrv_query($conn, $sqlVerificarAgenciaActiva,
+ [$relacion['id_importador'], $relacion['id_agencia']]);
+
+ if ($stmtVerificarActiva && sqlsrv_fetch_array($stmtVerificarActiva, SQLSRV_FETCH_ASSOC)) {
+ // Si tenía esta agencia como activa, quitársela
+ $sqlQuitarAgenciaActiva = "
+ UPDATE usuarios_sistema
+ SET id_agencia_en_uso = NULL
+ WHERE id_usuario = ?
+ ";
+ $stmtQuitarActiva = sqlsrv_query($conn, $sqlQuitarAgenciaActiva, [$relacion['id_importador']]);
+
+ if (!$stmtQuitarActiva) {
+ throw new Exception('Error al actualizar la agencia activa del importador');
+ }
+ }
+ }
+
// Confirmar transacción
sqlsrv_commit($conn);
diff --git a/app/helpers/session.php b/app/helpers/session.php
index b5bc658..3a676ba 100644
--- a/app/helpers/session.php
+++ b/app/helpers/session.php
@@ -1,4 +1,10 @@
+
+
+
+
+
+ 🔄 Cambios de Usuario
+
+
+
+
+
+
+
+
+
+
+
+
🔄 Cambios de Usuario
+
+
+
+
+
+
+ #
+ ID Usuario
+ Acción
+ Descripción
+ Fecha
+
+
+
+
+
+ = $r['id_bitacora'] ?>
+ = $r['usuario_id'] ?>
+ = htmlspecialchars($r['accion']) ?>
+ = nl2br(htmlspecialchars($r['descripcion'])) ?>
+ = $r['fecha'] instanceof DateTime ? $r['fecha']->format('Y-m-d H:i') : htmlspecialchars($r['fecha']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/views/bitacoras/bitacora_usuarios.php b/views/bitacoras/bitacora_usuarios.php
index 2e0f83c..1162c46 100644
--- a/views/bitacoras/bitacora_usuarios.php
+++ b/views/bitacoras/bitacora_usuarios.php
@@ -4,7 +4,7 @@
- 🛠️ Cambios de Usuario
+ 👥 Registro de Usuarios
@@ -14,7 +14,7 @@
-
🛠️ Cambios de Usuario
+
👥 Registro de Usuarios
-
+
- #
- ID Usuario
- Acción
- Descripción
+ ID
+ Nombre
+ Correo
+ Tipo
Fecha
+ Estatus
+ Aprobado por
-
-
- = $r['id_bitacora'] ?>
- = $r['usuario_id'] ?>
- = htmlspecialchars($r['accion']) ?>
- = nl2br(htmlspecialchars($r['descripcion'])) ?>
- = $r['fecha'] instanceof DateTime ? $r['fecha']->format('Y-m-d H:i') : htmlspecialchars($r['fecha']) ?>
+
+
+ = htmlspecialchars($u['id_usuario'] ?? '') ?>
+ = htmlspecialchars(decrypt($u['nombre'] ?? '')) ?>
+ = htmlspecialchars(decrypt($u['email'] ?? '')) ?>
+ = htmlspecialchars($u['tipo_usuario'] ?? '') ?>
+ = htmlspecialchars($u['creado_en'] ? $u['creado_en']->format('Y-m-d H:i:s') : '') ?>
+
+
+ Activo
+
+ Inactivo
+
+
+ = htmlspecialchars(decrypt($u['nombre_creador'] ?? '')) ?>
@@ -67,7 +77,7 @@
-
+
\ No newline at end of file
diff --git a/views/bitacoras/dashboard_bitacoras.php b/views/bitacoras/dashboard_bitacoras.php
index e3971b0..2a11fd9 100644
--- a/views/bitacoras/dashboard_bitacoras.php
+++ b/views/bitacoras/dashboard_bitacoras.php
@@ -26,6 +26,9 @@
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
+ .btn-indigo { background-color: #6610f2; color: white; }
+ .btn-indigo:hover { background-color: #520dc2; color: white; }
+ .text-indigo { color: #520dc2; }
@@ -47,20 +50,30 @@
-
Registro de usuarios
+
Cambios de usuarios
+
Ver cambios realizados por los usuarios.
+
+ Ver cambios
+
+
+
+
diff --git a/views/importadores/dashboard_importador.php b/views/importadores/dashboard_importador.php
index da53d5f..2ac5af0 100644
--- a/views/importadores/dashboard_importador.php
+++ b/views/importadores/dashboard_importador.php
@@ -16,15 +16,15 @@
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
- .btn-indigo { background-color: #6610f2; color: white;}
- .btn-indigo:hover { background-color: #520dc2; color: white;}
- .text-indigo { color: #520dc2;}
- .btn-orange { background-color: orangeRed; color: white;}
- .btn-orange:hover { background-color: #ff3600; color: white;}
- .text-orange { color: orangeRed;}
+ .btn-indigo { background-color: #6610f2; color: white; }
+ .btn-indigo:hover { background-color: #520dc2; color: white; }
+ .text-indigo { color: #520dc2; }
+ .btn-orange { background-color: orangeRed; color: white; }
+ .btn-orange:hover { background-color: #ff3600; color: white; }
+ .text-orange { color: orangeRed; }
.btn-teal { background-color: #20c997; color: white; }
.btn-teal:hover { background-color: #4dd4ac; color: black; }
- .text-teal { color: #20c997; }
+ .text-teal { color: #20c997; }
/* 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 */
diff --git a/views/login/cambiar_password.php b/views/login/cambiar_password.php
index 78afd23..d93fd5a 100644
--- a/views/login/cambiar_password.php
+++ b/views/login/cambiar_password.php
@@ -107,7 +107,7 @@ if (!isset($_SESSION['recuperacion_autorizada'])) {
+
+
+
+
+
+
+
+
+
+
+
+
Cambiar contraseña
+
+
+
+
+
+
+
👮 Opciones de Seguridad
+
+
+
+
+
+
Autenticación de dos factores
+
Al activar esta funcionalidad, blindas el acceso a tu cuenta, recibiras un código de acceso a tu correo electrónico para confirmar identidad.
+
+
+
+
+
+
+
+
Cambiar contraseña
+
Al actualizar tu contraseña, refuerzas la seguridad de tu cuenta. Te recomendamos usar una combinación de letras, números y símbolos para mayor seguridad.
+
Cambiar contraseña
+
+
+
+
+
+
+
Recibe notificaciones
+
Agrega un correo adicional para recibir notificaciones.
+
+
= htmlspecialchars($correos['correo_extra']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
Correo de respaldo
+
Agrega un correo de respaldo para reuperación de tu cuenta.
+
+
= htmlspecialchars($correos['correo_respaldo']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+