Atajos de catálogos personalizables
This commit is contained in:
@@ -106,9 +106,9 @@ function aprobar_usuario()
|
||||
$email_encrypt = encrypt($email);
|
||||
|
||||
// Insertar en usuarios_sistema y obtener ID en la misma consulta
|
||||
$sqlInsert = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por)
|
||||
$sqlInsert = "INSERT INTO usuarios_sistema (nombre, email, password_hash, tipo_usuario, activo, creado_en, dos_factores, creado_por, preferencias_catalogos)
|
||||
OUTPUT INSERTED.id_usuario
|
||||
VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?)";
|
||||
VALUES (?, ?, ?, ?, 1, GETDATE(), 0, ?, 1)";
|
||||
|
||||
$stmtInsert = sqlsrv_query($conn, $sqlInsert, [
|
||||
$nombre_encrypt, $email_encrypt, $password_hash, $tipo, $_SESSION['usuario_id']
|
||||
@@ -140,6 +140,17 @@ function aprobar_usuario()
|
||||
throw new Exception("Error al insertar información general: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// Insertar en preferencias de catalogos
|
||||
$sqlPref = "INSERT INTO preferencias_catalogos_usuario
|
||||
(id_usuario, locaciones, vinculacion, transportistas, transportes, choferes, proveedores,
|
||||
productos_frecuentes, solicitudes_importacion, expediente_electronico, configuracion, cerrar_sesion)
|
||||
VALUES (?, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)";
|
||||
$stmtPref = sqlsrv_query($conn, $sqlPref, [$id_usuario]);
|
||||
|
||||
if (!$stmtPref) {
|
||||
throw new Exception("Error al insertar preferencias de catalogos: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// Actualizar solicitud
|
||||
$sqlUpdate = "UPDATE solicitudes_importadores
|
||||
SET request_status = 'approved', approval_date = GETDATE(), approved_by = ?
|
||||
@@ -283,6 +294,7 @@ function guardar_usuario()
|
||||
|
||||
// 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);
|
||||
@@ -293,12 +305,31 @@ function guardar_usuario()
|
||||
}
|
||||
|
||||
// 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);
|
||||
$idUsuarioRow = sqlsrv_fetch_array($stmtInsert, SQLSRV_FETCH_ASSOC);
|
||||
$id_usuario = $idUsuarioRow['id_usuario'] ?? null;
|
||||
|
||||
// 6. Enviar correo de bienvenida
|
||||
// 6. Insertar en informacion_general
|
||||
$sqlInfo = "INSERT INTO informacion_general
|
||||
(id_usuario, nombre, correo)
|
||||
VALUES (?, ?, ?)";
|
||||
$stmtInfo = sqlsrv_query($conn, $sqlInfo, [$id_usuario, $nombre, $email]);
|
||||
|
||||
if (!$stmtInfo) {
|
||||
throw new Exception("Error al insertar información general: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// 7. Insertar en preferencias de catalogos
|
||||
$sqlPref = "INSERT INTO preferencias_catalogos_usuario
|
||||
(id_usuario, locaciones, vinculacion, transportistas, transportes, choferes, proveedores,
|
||||
productos_frecuentes, solicitudes_importacion, expediente_electronico, configuracion, cerrar_sesion)
|
||||
VALUES (?, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)";
|
||||
$stmtPref = sqlsrv_query($conn, $sqlPref, [$id_usuario]);
|
||||
|
||||
if (!$stmtPref) {
|
||||
throw new Exception("Error al insertar preferencias de catalogos: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// 8. Enviar correo de bienvenida
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->isSMTP();
|
||||
|
||||
@@ -3,14 +3,165 @@ require_once __DIR__ . '/../helpers/session.php';
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../helpers/crypto.php';
|
||||
|
||||
// Función para obtener catálogos visibles del usuario
|
||||
function obtenerCatalogosVisibles($idUsuario) {
|
||||
$conn = getConnection();
|
||||
|
||||
// Obtener configuración general y tipo de usuario
|
||||
$query = "SELECT preferencias_catalogos, tipo_usuario FROM usuarios_sistema WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
sqlsrv_close($conn);
|
||||
return ['catalogos_activos' => false, 'catalogos' => []];
|
||||
}
|
||||
|
||||
$usuario = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
if (!$usuario) {
|
||||
sqlsrv_close($conn);
|
||||
return ['catalogos_activos' => false, 'catalogos' => []];
|
||||
}
|
||||
|
||||
$catalogos_general = $usuario['preferencias_catalogos'] ?? 0;
|
||||
$tipoUsuario = $usuario['tipo_usuario'] ?? 'importador';
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
// Si los catálogos están desactivados, solo mostrar obligatorios
|
||||
if (!$catalogos_general) {
|
||||
// Obtener solo catálogos obligatorios
|
||||
$query = "SELECT nombre, descripcion, color, ruta, accion
|
||||
FROM tipos_catalogos
|
||||
WHERE tipo_usuario = ? AND nombre IN ('Configuración', 'Cerrar sesión')
|
||||
ORDER BY id";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$tipoUsuario]);
|
||||
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
sqlsrv_close($conn);
|
||||
return ['catalogos_activos' => false, 'catalogos' => []];
|
||||
}
|
||||
|
||||
$catalogos = [];
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$catalogos[] = [
|
||||
'nombre' => $row['nombre'],
|
||||
'descripcion' => $row['descripcion'],
|
||||
'color' => $row['color'],
|
||||
'ruta' => $row['ruta'],
|
||||
'accion' => $row['accion'],
|
||||
'visible' => true,
|
||||
'obligatorio' => true
|
||||
];
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
|
||||
return ['catalogos_activos' => false, 'catalogos' => $catalogos];
|
||||
}
|
||||
|
||||
// Obtener todos los catálogos para este tipo de usuario
|
||||
$query = "SELECT nombre, descripcion, color, ruta, accion
|
||||
FROM tipos_catalogos
|
||||
WHERE tipo_usuario = ?
|
||||
ORDER BY id";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$tipoUsuario]);
|
||||
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
sqlsrv_close($conn);
|
||||
return ['catalogos_activos' => false, 'catalogos' => []];
|
||||
}
|
||||
|
||||
// Crear array de catálogos disponibles
|
||||
$catalogos_disponibles = [];
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$catalogos_disponibles[] = [
|
||||
'nombre' => $row['nombre'],
|
||||
'descripcion' => $row['descripcion'],
|
||||
'color' => $row['color'],
|
||||
'ruta' => $row['ruta'],
|
||||
'accion' => $row['accion'],
|
||||
'campo_bd' => strtolower(str_replace([' ', 'ó', 'ú', 'á', 'é', 'í'], ['_', 'o', 'u', 'a', 'e', 'i'], $row['nombre']))
|
||||
];
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
// Obtener preferencias específicas del usuario
|
||||
$preferencias = [];
|
||||
switch ($tipoUsuario) {
|
||||
case 'importador':
|
||||
$query = "SELECT * FROM preferencias_catalogos_usuario WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
$preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
if ($preferenciasRow) {
|
||||
$preferencias = $preferenciasRow;
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
}
|
||||
break;
|
||||
// Aquí agregarías otros casos cuando implementes otros tipos de usuario
|
||||
}
|
||||
|
||||
// Determinar qué catálogos mostrar
|
||||
$catalogos_visibles = [];
|
||||
foreach ($catalogos_disponibles as $catalogo) {
|
||||
$campo = $catalogo['campo_bd'];
|
||||
$esObligatorio = in_array($catalogo['nombre'], ['Configuración', 'Cerrar sesión']);
|
||||
|
||||
if ($esObligatorio) {
|
||||
// Catálogos obligatorios siempre visibles
|
||||
$catalogo['visible'] = true;
|
||||
$catalogo['obligatorio'] = true;
|
||||
} else {
|
||||
// Verificar si está activado en preferencias
|
||||
$catalogo['visible'] = isset($preferencias[$campo]) && $preferencias[$campo] == 1;
|
||||
$catalogo['obligatorio'] = false;
|
||||
}
|
||||
|
||||
if ($catalogo['visible']) {
|
||||
$catalogos_visibles[] = $catalogo;
|
||||
}
|
||||
}
|
||||
|
||||
sqlsrv_close($conn);
|
||||
|
||||
return [
|
||||
'catalogos_activos' => true,
|
||||
'catalogos' => $catalogos_visibles,
|
||||
'tipo_usuario' => $tipoUsuario
|
||||
];
|
||||
}
|
||||
|
||||
// Función para obtener icono según el nombre del catálogo
|
||||
function obtenerIconoCatalogo($nombre) {
|
||||
$iconos = [
|
||||
'Locaciones' => '📍',
|
||||
'Vinculación' => '🔗',
|
||||
'Transportistas' => '🚚',
|
||||
'Transportes' => '🚛',
|
||||
'Choferes' => '👨✈️',
|
||||
'Proveedores' => '🏭',
|
||||
'Productos frecuentes' => '⭐',
|
||||
'Solicitudes importación' => '📄',
|
||||
'Expediente electrónico' => '📁',
|
||||
'Configuración' => '⚙️',
|
||||
'Cerrar sesión' => '🚪'
|
||||
];
|
||||
|
||||
return $iconos[$nombre] ?? '📁';
|
||||
}
|
||||
|
||||
// Función para el dashboard del importador
|
||||
function dashboard()
|
||||
{
|
||||
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador') {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
$idUsuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$idUsuario) {
|
||||
header("Location: /IMPORTADORES/login");
|
||||
exit;
|
||||
}
|
||||
|
||||
$nombreImportador = $_SESSION['usuario_nombre'];
|
||||
// Obtener catálogos visibles
|
||||
$catalogosData = obtenerCatalogosVisibles($idUsuario);
|
||||
|
||||
include __DIR__ . '/../../views/importadores/dashboard_importador.php';
|
||||
}
|
||||
|
||||
@@ -540,4 +540,297 @@ function esDiaResumen($config_dias)
|
||||
return in_array($dia_letra, array_map('trim', $dias_activos));
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
function catalogos()
|
||||
{
|
||||
$conn = getConnection();
|
||||
$idUsuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$idUsuario) {
|
||||
header("Location: /IMPORTADORES/login");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener configuración general de catalogos y tipo de usuario
|
||||
$query = "SELECT preferencias_catalogos, tipo_usuario FROM usuarios_sistema WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
die("Error al obtener configuración: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
$usuario = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
if (!$usuario) {
|
||||
die("Usuario no encontrado");
|
||||
}
|
||||
|
||||
$catalogos = $usuario['preferencias_catalogos'] ?? 0;
|
||||
$tipoUsuario = $usuario['tipo_usuario'] ?? 'importador';
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
// Obtener preferencias específicas según el tipo de usuario
|
||||
switch ($tipoUsuario) {
|
||||
case 'importador':
|
||||
$query = "SELECT * FROM preferencias_catalogos_usuario WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
$preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
sqlsrv_free_stmt($stmt);
|
||||
} else {
|
||||
$preferenciasRow = false;
|
||||
}
|
||||
|
||||
// Si no existe registro, crear valores por defecto para importador
|
||||
if (!$preferenciasRow) {
|
||||
$preferencias = [
|
||||
'locaciones' => 0,
|
||||
'vinculacion' => 0,
|
||||
'transportistas' => 0,
|
||||
'transportes' => 0,
|
||||
'choferes' => 0,
|
||||
'proveedores' => 0,
|
||||
'productos_frecuentes' => 0,
|
||||
'solicitudes_importacion' => 0,
|
||||
'expediente_electronico' => 0,
|
||||
'configuracion' => 0,
|
||||
'cerrar_sesion' => 0
|
||||
];
|
||||
} else {
|
||||
$preferencias = $preferenciasRow;
|
||||
}
|
||||
break;
|
||||
|
||||
// case 'agente_aduanal':
|
||||
// $query = "SELECT * FROM preferencias_catalogos_agente WHERE id_usuario = ?";
|
||||
// $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
// if ($stmt && sqlsrv_execute($stmt)) {
|
||||
// $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
// sqlsrv_free_stmt($stmt);
|
||||
// } else {
|
||||
// $preferenciasRow = false;
|
||||
// }
|
||||
|
||||
// Si no existe registro, crear valores por defecto para agente aduanal
|
||||
// if (!$preferenciasRow) {
|
||||
// $preferencias = [
|
||||
// Aquí se definirán los campos específicos para agente aduanal
|
||||
// cuando se creen las tablas correspondientes
|
||||
// 'configuracion' => 0,
|
||||
// 'cerrar_sesion' => 0
|
||||
// ];
|
||||
// } else {
|
||||
// $preferencias = $preferenciasRow;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case 'admin_agencia':
|
||||
// $query = "SELECT * FROM preferencias_catalogos_agencia WHERE id_usuario = ?";
|
||||
// $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
// if ($stmt && sqlsrv_execute($stmt)) {
|
||||
// $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
// sqlsrv_free_stmt($stmt);
|
||||
// } else {
|
||||
// $preferenciasRow = false;
|
||||
// }
|
||||
|
||||
// Si no existe registro, crear valores por defecto para admin agencia
|
||||
// if (!$preferenciasRow) {
|
||||
// $preferencias = [
|
||||
// Aquí se definirán los campos específicos para admin agencia
|
||||
// cuando se creen las tablas correspondientes
|
||||
// 'configuracion' => 0,
|
||||
// 'cerrar_sesion' => 0
|
||||
// ];
|
||||
// } else {
|
||||
// $preferencias = $preferenciasRow;
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case 'super_admin':
|
||||
// $query = "SELECT * FROM preferencias_catalogos_admin WHERE id_usuario = ?";
|
||||
// $stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
// if ($stmt && sqlsrv_execute($stmt)) {
|
||||
// $preferenciasRow = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
// sqlsrv_free_stmt($stmt);
|
||||
// } else {
|
||||
// $preferenciasRow = false;
|
||||
// }
|
||||
|
||||
// Si no existe registro, crear valores por defecto para super admin
|
||||
// if (!$preferenciasRow) {
|
||||
// $preferencias = [
|
||||
// Aquí se definirán los campos específicos para super admin
|
||||
// cuando se creen las tablas correspondientes
|
||||
// 'configuracion' => 0,
|
||||
// 'cerrar_sesion' => 0
|
||||
// ];
|
||||
// } else {
|
||||
// $preferencias = $preferenciasRow;
|
||||
// }
|
||||
// break;
|
||||
|
||||
default:
|
||||
// Tipo de usuario no reconocido, usar valores por defecto mínimos
|
||||
$preferencias = [
|
||||
'configuracion' => 0,
|
||||
'cerrar_sesion' => 0
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
// Obtener tipos de catalogos disponibles según el tipo de usuario
|
||||
$query = "SELECT nombre, descripcion, color FROM tipos_catalogos WHERE tipo_usuario = ? ORDER BY id";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$tipoUsuario]);
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
die("Error al obtener tipos: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// Crear array asociativo para la vista
|
||||
$tipos = [];
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$tipos[$row['nombre']] = [
|
||||
'descripcion' => $row['descripcion'],
|
||||
'color' => $row['color']
|
||||
];
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
|
||||
include __DIR__ . '/../../views/preferencias/catalogos.php';
|
||||
}
|
||||
|
||||
function guardarCatalogosAjax()
|
||||
{
|
||||
// Verificar que sea una petición AJAX
|
||||
if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) ||
|
||||
$_SERVER['HTTP_X_REQUESTED_WITH'] !== 'XMLHttpRequest') {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Petición no válida']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener datos JSON del cuerpo de la petición
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (!$input || !isset($input['tipo'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'Datos no válidos']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$conn = getConnection();
|
||||
$idUsuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
if (!$idUsuario) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Obtener tipo de usuario
|
||||
$query = "SELECT tipo_usuario FROM usuarios_sistema WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'message' => 'Error al obtener información del usuario']);
|
||||
exit;
|
||||
}
|
||||
$usuario = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
$tipoUsuario = $usuario['tipo_usuario'] ?? 'importador';
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
try {
|
||||
$tipo = $input['tipo'];
|
||||
|
||||
switch ($tipo) {
|
||||
case 'catalogos_general':
|
||||
// Actualizar preferencias generales de catálogos
|
||||
$valor = isset($input['valor']) && $input['valor'] ? 1 : 0;
|
||||
|
||||
$query = "UPDATE usuarios_sistema SET preferencias_catalogos = ? WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$valor, $idUsuario]);
|
||||
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
throw new Exception('Error al actualizar preferencias generales');
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
break;
|
||||
|
||||
case 'tipo_catalogo':
|
||||
// Actualizar preferencia específica de catálogo
|
||||
if (!isset($input['nombre']) || !isset($input['valor'])) {
|
||||
throw new Exception('Datos incompletos para tipo de catálogo');
|
||||
}
|
||||
|
||||
$nombre = $input['nombre'];
|
||||
$valor = $input['valor'] ? 1 : 0;
|
||||
|
||||
// Determinar la tabla según el tipo de usuario
|
||||
$tabla = '';
|
||||
switch ($tipoUsuario) {
|
||||
case 'importador':
|
||||
$tabla = 'preferencias_catalogos_usuario';
|
||||
break;
|
||||
case 'agente_aduanal':
|
||||
$tabla = 'preferencias_catalogos_agente';
|
||||
break;
|
||||
case 'admin_agencia':
|
||||
$tabla = 'preferencias_catalogos_agencia';
|
||||
break;
|
||||
case 'super_admin':
|
||||
$tabla = 'preferencias_catalogos_admin';
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Tipo de usuario no válido');
|
||||
}
|
||||
|
||||
// Verificar si existe un registro para este usuario
|
||||
$query = "SELECT id_preferencia FROM $tabla WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario]);
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
throw new Exception('Error al verificar preferencias existentes');
|
||||
}
|
||||
|
||||
$existe = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
if ($existe) {
|
||||
// Actualizar registro existente
|
||||
$query = "UPDATE $tabla SET [$nombre] = ? WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$valor, $idUsuario]);
|
||||
} else {
|
||||
// Crear nuevo registro
|
||||
$query = "INSERT INTO $tabla (id_usuario, [$nombre]) VALUES (?, ?)";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$idUsuario, $valor]);
|
||||
}
|
||||
|
||||
if (!$stmt || !sqlsrv_execute($stmt)) {
|
||||
throw new Exception('Error al actualizar preferencia de catálogo');
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Tipo de operación no válido');
|
||||
}
|
||||
|
||||
// Confirmar transacción
|
||||
sqlsrv_commit($conn);
|
||||
|
||||
// Respuesta exitosa
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Preferencias actualizadas correctamente'
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Revertir transacción en caso de error
|
||||
sqlsrv_rollback($conn);
|
||||
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
} finally {
|
||||
sqlsrv_close($conn);
|
||||
}
|
||||
}
|
||||
61
catalogos.txt
Normal file
61
catalogos.txt
Normal file
@@ -0,0 +1,61 @@
|
||||
CREATE TABLE preferencias_catalogos_usuario (
|
||||
id_preferencia INT IDENTITY(1,1) NOT NULL,
|
||||
id_usuario INT NOT NULL,
|
||||
locaciones BIT DEFAULT 0,
|
||||
vinculacion BIT DEFAULT 0,
|
||||
transportistas BIT DEFAULT 0,
|
||||
transportes BIT DEFAULT 0,
|
||||
choferes BIT DEFAULT 0,
|
||||
proveedores BIT DEFAULT 0,
|
||||
productos_frecuentes BIT DEFAULT 0,
|
||||
solicitudes_importacion BIT DEFAULT 0,
|
||||
expediente_electronico BIT DEFAULT 0,
|
||||
configuracion BIT DEFAULT 0,
|
||||
cerrar_sesion BIT DEFAULT 0,
|
||||
FOREIGN KEY (id_usuario) REFERENCES usuarios_sistema(id_usuario)
|
||||
);
|
||||
|
||||
ALTER TABLE usuarios_sistema
|
||||
ADD [preferencias_catalogos] BIT DEFAULT 1;
|
||||
|
||||
CREATE TABLE tipos_catalogos (
|
||||
id INT PRIMARY KEY IDENTITY,
|
||||
tipo_usuario VARCHAR(20) NOT NULL,
|
||||
nombre VARCHAR(255) NOT NULL,
|
||||
descripcion VARCHAR(500) NULL,
|
||||
color VARCHAR(20) NOT NULL,
|
||||
ruta VARCHAR(100) NOT NULL,
|
||||
accion VARCAHR(50) NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO tipos_catalogos (tipo_usuario, nombre, descripcion, color, ruta, accion) VALUES
|
||||
('importador', 'Locaciones', 'Visualiza las locaciones registradas.', 'lime', '/IMPORTADORES/importadores/lista', 'Ver locaciones'),
|
||||
('importador', 'Vinculación', 'Visualiza o establece nuevas vinculaciones con agencias aduanales.', 'teal', '/IMPORTADORES/viculaciones/vinculacionesUsuario', 'Ver vinculaciones'),
|
||||
('importador', 'Transportistas', 'Agrega o consulta los choferes que colaboran contigo.', 'success', '/IMPORTADORES/transportistas/lista', 'Ver transportistas'),
|
||||
('importador', 'Transportes', 'Gestiona y carga tus unidades de transporte.', 'info', '/IMPORTADORES/transportes/lista', 'Ver transportes'),
|
||||
('importador', 'Choferes', 'Gestiona y carga a tus choferes.', 'cyan', '/IMPORTADORES/choferes/lista', 'Ver choferes'),
|
||||
('importador', 'Proveedores', 'Agrega tus proveedores.', 'primary', '/IMPORTADORES/proveedores/crear', 'Nuevo proveedor'),
|
||||
('importador', 'Productos frecuentes', 'Agrega productos frecuentes de tu interez.', 'violet', '/IMPORTADORES/productos_frecuentes/alta', 'Nuevo producto'),
|
||||
('importador', 'Solicitudes importación', 'Inicia nuevas solicitudes de pedimentos.', 'indigo', '/IMPORTADORES/solicitud_importacion/crear', 'Nueva solicitud'),
|
||||
('importador', 'Expediente electrónico', 'Revisa el expediente electrónico para tus solicitudes.', 'orange', '/IMPORTADORES/expediente/index', 'Ver expediente'),
|
||||
('importador', 'Configuración', 'Administra los datos de tu empresa y preferencias.', 'warning', '/IMPORTADORES/configuracion', 'Ir a configuración'),
|
||||
('importador', 'Cerrar sesión', 'Salir del sistema de forma segura.', 'danger', '/IMPORTADORES/sistemas/logout', 'Cerrar sesión');
|
||||
|
||||
|
||||
|
||||
UPDATE usuarios_sistema
|
||||
SET preferencias_catalogos = 1
|
||||
WHERE preferencias_catalogos IS NULL OR preferencias_catalogos = 0;
|
||||
|
||||
-- 2. Insertar en preferencias_catalogos_usuario solo para los que aún no tienen registro
|
||||
INSERT INTO preferencias_catalogos_usuario (
|
||||
id_usuario, locaciones, vinculacion, transportistas, transportes, choferes, proveedores,
|
||||
productos_frecuentes, solicitudes_importacion, expediente_electronico, configuracion, cerrar_sesion
|
||||
)
|
||||
SELECT u.id_usuario, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
FROM usuarios_sistema u
|
||||
WHERE u.tipo_usuario = 'importador'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM preferencias_catalogos_usuario p
|
||||
WHERE p.id_usuario = u.id_usuario
|
||||
);
|
||||
@@ -25,6 +25,15 @@
|
||||
.btn-teal { background-color: #20c997; color: white; }
|
||||
.btn-teal:hover { background-color: #4dd4ac; color: black; }
|
||||
.text-teal { color: #20c997; }
|
||||
.btn-lime { background-color: #84cc16; color: white; }
|
||||
.text-lime { color: #84cc16; }
|
||||
.btn-lime:hover { background-color: #65a30d; color: white; }
|
||||
.btn-cyan { background-color: #06b6d4; color: white; }
|
||||
.text-cyan { color: #06b6d4; }
|
||||
.btn-cyan:hover { background-color: #0891b2; color: white; }
|
||||
.btn-violet { background-color: #8b5cf6; color: white; }
|
||||
.text-violet { color: #8b5cf6; }
|
||||
.btn-violet:hover { background-color: #7c3aed; color: white; }
|
||||
/* 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 */
|
||||
@@ -42,92 +51,73 @@
|
||||
<div class="content">
|
||||
<h4 class="mb-4">📦 Panel del Importador</h4>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-primary">Transportes</h5>
|
||||
<p>Gestiona y carga tus unidades de transporte.</p>
|
||||
<a href="/IMPORTADORES/transportes/lista"
|
||||
class="btn btn-primary btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/transportes/lista' ? 'active' : '' ?>">
|
||||
Ver transportes
|
||||
</a>
|
||||
</div>
|
||||
<?php if ($catalogosData['catalogos_activos']): ?>
|
||||
<div class="row g-4">
|
||||
<?php foreach ($catalogosData['catalogos'] as $catalogo): ?>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3 <?= $catalogo['obligatorio'] ? 'border-warning' : '' ?>">
|
||||
<h5 class="text-<?= $catalogo['color'] ?>">
|
||||
<?= obtenerIconoCatalogo($catalogo['nombre']) ?> <?= $catalogo['nombre'] ?>
|
||||
</h5>
|
||||
<p class="text-muted small"><?= $catalogo['descripcion'] ?></p>
|
||||
<a href="<?= $catalogo['ruta'] ?>"
|
||||
class="btn btn-<?= $catalogo['color'] ?> btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === $catalogo['ruta'] ? 'active' : '' ?>">
|
||||
<?= $catalogo['accion'] ?>
|
||||
</a>
|
||||
<?php if ($catalogo['obligatorio']): ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Transportistas</h5>
|
||||
<p>Agrega o consulta los choferes que colaboran contigo.</p>
|
||||
<a href="/IMPORTADORES/transportistas/lista"
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/transportistas/lista' ? 'active' : '' ?>">
|
||||
Ver transportistas
|
||||
</a>
|
||||
<?php if (count($catalogosData['catalogos']) === 2): // Solo obligatorios ?>
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<h6>💡 Consejo</h6>
|
||||
<p class="mb-2">Parece que no tienes catálogos activados. Puedes activar los que necesites desde tus preferencias.</p>
|
||||
<a href="/IMPORTADORES/preferencias/catalogos" class="btn btn-primary btn-sm">
|
||||
Configurar Catálogos
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-info">Solicitudes de Importación</h5>
|
||||
<p>Inicia nuevas solicitudes de pedimentos.</p>
|
||||
<a href="/IMPORTADORES/solicitud_importacion/crear"
|
||||
class="btn btn-info btn-sm mt-2 <?= str_contains($_SERVER['REQUEST_URI'], '/solicitud_importacion/crear') ? 'active' : '' ?>">
|
||||
Nueva solicitud
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<!-- Si los catálogos están completamente desactivados -->
|
||||
<div class="row g-4">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning">
|
||||
<h5>🔒 Catálogos Desactivados</h5>
|
||||
<p>Los catálogos están desactivados en tus preferencias. Solo tienes acceso a las funciones básicas del sistema.</p>
|
||||
<a href="/IMPORTADORES/preferencias/catalogos" class="btn btn-primary btn-sm">
|
||||
Activar Catálogos
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-indigo">Proveedores</h5>
|
||||
<p>Agrega tus proveedores.</p>
|
||||
<a href="/IMPORTADORES/proveedores/crear"
|
||||
class="btn btn-indigo btn-sm mt-2 <?= str_contains($_SERVER['REQUEST_URI'], '/proveedores/crear') ? 'active' : '' ?>">
|
||||
Nuevo proveedor
|
||||
</a>
|
||||
</div>
|
||||
<!-- Mostrar solo catálogos obligatorios -->
|
||||
<?php foreach ($catalogosData['catalogos'] as $catalogo): ?>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3 border-warning">
|
||||
<h5 class="text-<?= $catalogo['color'] ?>">
|
||||
<?= obtenerIconoCatalogo($catalogo['nombre']) ?> <?= $catalogo['nombre'] ?>
|
||||
</h5>
|
||||
<p class="text-muted small"><?= $catalogo['descripcion'] ?></p>
|
||||
<a href="<?= $catalogo['ruta'] ?>"
|
||||
class="btn btn-<?= $catalogo['color'] ?> btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === $catalogo['ruta'] ? 'active' : '' ?>">
|
||||
<?= $catalogo['accion'] ?>
|
||||
</a>
|
||||
<small class="text-warning mt-1">
|
||||
<i class="fas fa-lock"></i> Función básica
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-warning">Configuración</h5>
|
||||
<p>Administra los datos de tu empresa y preferencias.</p>
|
||||
<a href="/IMPORTADORES/configuracion"
|
||||
class="btn btn-warning btn-sm mt-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion') ? 'active' : '' ?>">
|
||||
Configurar
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-orange">Locaciones</h5>
|
||||
<p>Visualiza las locaciones registradas.</p>
|
||||
<a href="/IMPORTADORES/importadores/lista"
|
||||
class="btn btn-orange btn-sm mt-2 <?= str_contains($_SERVER['REQUEST_URI'], '/importadores/lista') ? 'active' : '' ?>">
|
||||
Ver locaciones
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-teal">Vinculaciones</h5>
|
||||
<p>Visualiza o establece nuevas vinculaciones con agencias aduanales.</p>
|
||||
<a href="/IMPORTADORES/vinculaciones/vinculacionesUsuario"
|
||||
class="btn btn-teal btn-sm mt-2 <?= str_contains($_SERVER['REQUEST_URI'], '/importadores/vinculaciones') ? 'active' : '' ?>">
|
||||
Ver vinculaciones
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-danger">Cerrar sesión</h5>
|
||||
<p>Salir del sistema de forma segura.</p>
|
||||
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-danger btn-sm mt-2">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -233,7 +233,7 @@ function obtenerUrlPermiso($permiso) {
|
||||
role="button" aria-expanded="true" aria-controls="submenuPreferencias"
|
||||
onclick="<? $enDashboardPreferencias ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/preferencias/index\';' ?>">
|
||||
✅ Preferencias
|
||||
<span class="badge bg-secondary">1</span>
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<div class="collapse show" id="submenuPreferencias">
|
||||
<nav class="nav flex-column ms-3">
|
||||
@@ -241,13 +241,17 @@ function obtenerUrlPermiso($permiso) {
|
||||
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/notificaciones' ? 'active' : '' ?>">
|
||||
• Gestión de Notificaciones
|
||||
</a>
|
||||
<a href="/IMPORTADORES/preferencias/catalogos"
|
||||
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/catalogos' ? 'active' : '' ?>">
|
||||
• Visualización de Catálogos
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaSeguridad || $esVistaBitacoras || $esVistaReset): ?>
|
||||
<a href="/IMPORTADORES/preferencias/index"
|
||||
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
|
||||
✅ Preferencias
|
||||
<span class="badge bg-secondary">1</span>
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
@@ -377,7 +381,7 @@ function obtenerUrlPermiso($permiso) {
|
||||
role="button" aria-expanded="true" aria-controls="submenuPreferencias"
|
||||
onclick="<? $enDashboardPreferencias ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/preferencias/index\';' ?>">
|
||||
✅ Preferencias
|
||||
<span class="badge bg-secondary">1</span>
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<div class="collapse show" id="submenuPreferencias">
|
||||
<nav class="nav flex-column ms-3">
|
||||
@@ -385,13 +389,17 @@ function obtenerUrlPermiso($permiso) {
|
||||
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/notificaciones' ? 'active' : '' ?>">
|
||||
• Gestión de Notificaciones
|
||||
</a>
|
||||
<a href="/IMPORTADORES/preferencias/catalogos"
|
||||
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/catalogos' ? 'active' : '' ?>">
|
||||
• Visualización de Catálogos
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaSeguridad || $esVistaBitacoras || $esVistaReset): ?>
|
||||
<a href="/IMPORTADORES/preferencias/index"
|
||||
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
|
||||
✅ Preferencias
|
||||
<span class="badge bg-secondary">1</span>
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportistas') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse" href="#submenuTransportistas" role="button" aria-expanded="false">
|
||||
👨✈️ Transportistas
|
||||
🚚 Transportistas
|
||||
<span class="badge bg-secondary">3</span>
|
||||
</a>
|
||||
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportistas') ? 'show' : '' ?>" id="submenuTransportistas">
|
||||
@@ -94,7 +94,7 @@
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportes') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse" href="#submenuTransportes" role="button" aria-expanded="false">
|
||||
🚚 Transportes
|
||||
🚛 Transportes
|
||||
<span class="badge bg-secondary">3</span>
|
||||
</a>
|
||||
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportes') ? 'show' : '' ?>" id="submenuTransportes">
|
||||
@@ -118,7 +118,7 @@
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/choferes') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse" href="#submenuChoferes" role="button" aria-expanded="false">
|
||||
🚛 Choferes
|
||||
👨✈️ Choferes
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/choferes') ? 'show' : '' ?>" id="submenuChoferes">
|
||||
@@ -266,7 +266,7 @@
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportistas') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse" href="#submenuTransportistas" role="button" aria-expanded="false">
|
||||
👨✈️ Transportistas
|
||||
🚚 Transportistas
|
||||
<span class="badge bg-secondary">3</span>
|
||||
</a>
|
||||
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportistas') ? 'show' : '' ?>" id="submenuTransportistas">
|
||||
@@ -290,7 +290,7 @@
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportes') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse" href="#submenuTransportes" role="button" aria-expanded="false">
|
||||
🚚 Transportes
|
||||
🚛 Transportes
|
||||
<span class="badge bg-secondary">3</span>
|
||||
</a>
|
||||
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/transportes') ? 'show' : '' ?>" id="submenuTransportes">
|
||||
@@ -314,7 +314,7 @@
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/choferes') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse" href="#submenuChoferes" role="button" aria-expanded="false">
|
||||
🚛 Choferes
|
||||
👨✈️ Choferes
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/choferes') ? 'show' : '' ?>" id="submenuChoferes">
|
||||
|
||||
348
views/preferencias/catalogos.php
Normal file
348
views/preferencias/catalogos.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php include __DIR__ . '/../partials/sidebar_configuracion.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>📊 Visualización de Catálogos</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
|
||||
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
|
||||
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
|
||||
.sidebar .nav-link:hover,
|
||||
.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-teal { background-color: #20c997; color: white; }
|
||||
.btn-teal:hover { background-color: #4dd4ac; color: black; }
|
||||
.text-teal { color: #20c997; }
|
||||
.btn-lime { background-color: #84cc16; color: white; }
|
||||
.text-lime { color: #84cc16; }
|
||||
.btn-lime:hover { background-color: #65a30d; color: white; }
|
||||
.btn-cyan { background-color: #06b6d4; color: white; }
|
||||
.text-cyan { color: #06b6d4; }
|
||||
.btn-cyan:hover { background-color: #0891b2; color: white; }
|
||||
.btn-violet { background-color: #8b5cf6; color: white; }
|
||||
.text-violet { color: #8b5cf6; }
|
||||
.btn-violet:hover { background-color: #7c3aed; color: white; }
|
||||
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
|
||||
@media (min-width: 768px) { .content { margin-left: 250px; } }
|
||||
/* En móviles, sin margen lateral */
|
||||
@media (max-width: 767.98px) {
|
||||
.content { margin-left: 0; }
|
||||
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
|
||||
.sidebar .nav-link:hover,
|
||||
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
|
||||
}
|
||||
.card { border-radius: 12px; }
|
||||
.fade-transition { transition: all 0.3s ease-in-out; }
|
||||
.section-divider { border-bottom: 1px solid #e9ecef; padding-bottom: 1.5rem; margin-bottom: 1.5rem; }
|
||||
.section-divider:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
|
||||
/* Indicador de guardado */
|
||||
.save-indicator { position: fixed; top: 20px; right: 20px; padding: 12px 20px; border-radius: 8px; font-weight: 500; font-size: 14px; z-index: 9999;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); transition: all 0.3s ease; display: flex; align-items: center; }
|
||||
.save-indicator.saving { background-color: #ffc107; color: #856404; border: 1px solid #ffeaa7; }
|
||||
.save-indicator.saved { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
||||
.save-indicator.error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
||||
/* Transiciones suaves para los switches */
|
||||
.form-check-input:disabled { opacity: 0.6; cursor: not-allowed; }
|
||||
.fade-transition { transition: opacity 0.3s ease; }
|
||||
/* Mejorar la apariencia de los switches de catálogos */
|
||||
.tipo-catalogo { margin-right: 10px; }
|
||||
.form-check-label { cursor: pointer; }
|
||||
.form-check-label .form-text { margin-top: 4px; font-size: 0.875rem; }
|
||||
/* Animación para el spinner */
|
||||
@keyframes spinner-border { to { transform: rotate(360deg); } }
|
||||
.spinner-border { display: inline-block; width: 1rem; height: 1rem; vertical-align: text-bottom; border: 0.125em solid currentColor; border-right-color: transparent;
|
||||
border-radius: 50%; animation: spinner-border 0.75s linear infinite; }
|
||||
.spinner-border-sm { width: 0.875rem; height: 0.875rem; border-width: 0.125em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<h4 class="mb-4">📊 Visualización de Catálogos</h4>
|
||||
|
||||
<!-- Mensajes de éxito o error iniciales -->
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<div class="success-message">
|
||||
✅ Las preferencias de catálogos se han guardado correctamente.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_GET['error'])): ?>
|
||||
<div class="error-message">
|
||||
❌ Error: <?= htmlspecialchars($_GET['error']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card shadow-sm p-4 mb-4 bg-white">
|
||||
<!-- Switch general de notificaciones -->
|
||||
<div class="section-divider">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="preferencias-catalogos"
|
||||
data-tipo="catalogos_general"
|
||||
<?= !empty($catalogos) ? 'checked' : '' ?>>
|
||||
<label class="form-check-label fw-bold" for="preferencias-catalogos">
|
||||
Catálogos
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tipos de catalogos -->
|
||||
<div id="tipos-catalogos" class="fade-transition" style="opacity:1;">
|
||||
<div class="section-divider">
|
||||
<h6 class="mb-3">📋 Preferencias de Catálogos</h6>
|
||||
<div class="row">
|
||||
<?php if (!empty($tipos)): ?>
|
||||
<?php foreach ($tipos as $nombre => $info): ?>
|
||||
<?php
|
||||
// Convertir el nombre a formato de campo (minúsculas y guiones bajos)
|
||||
$nombreCampo = strtolower(str_replace([' ', 'ó', 'ú', 'á', 'é', 'í'], ['_', 'o', 'u', 'a', 'e', 'i'], $nombre));
|
||||
$nombreCampo = str_replace(['ñ'], ['n'], $nombreCampo);
|
||||
|
||||
// Crear ID único para cada checkbox
|
||||
$idCampo = 'catalogo_' . $nombreCampo;
|
||||
|
||||
// Verificar si el campo existe en preferencias
|
||||
$checked = isset($preferencias[$nombreCampo]) && !empty($preferencias[$nombreCampo]);
|
||||
?>
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input tipo-catalogo" type="checkbox"
|
||||
name="<?= $nombreCampo ?>" id="<?= $idCampo ?>"
|
||||
data-tipo="tipo-catalogo" data-nombre="<?= $nombreCampo ?>"
|
||||
<?= $checked ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="<?= $idCampo ?>">
|
||||
<strong><?= htmlspecialchars($nombre) ?></strong>
|
||||
<div class="form-text text-<?= htmlspecialchars($info['color']) ?>">
|
||||
<?= htmlspecialchars($info['descripcion']) ?>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
No hay catálogos disponibles para tu tipo de usuario.
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Indicador de guardado -->
|
||||
<div id="save-indicator" class="save-indicator" style="display: none;">
|
||||
<span class="indicator-text">Guardando...</span>
|
||||
<div class="spinner-border spinner-border-sm ms-2" style="display: none;"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Estado global para controlar las peticiones
|
||||
let isAutoSaving = false;
|
||||
let saveTimeout = null;
|
||||
|
||||
// Referencias a elementos
|
||||
const saveIndicator = document.getElementById('save-indicator');
|
||||
const indicatorText = saveIndicator.querySelector('.indicator-text');
|
||||
const spinner = saveIndicator.querySelector('.spinner-border');
|
||||
|
||||
// Función para mostrar indicador de guardado
|
||||
function showSaveIndicator(type, message) {
|
||||
// Limpiar clases anteriores
|
||||
saveIndicator.className = 'save-indicator';
|
||||
|
||||
// Agregar clase según el tipo
|
||||
saveIndicator.classList.add(type);
|
||||
indicatorText.textContent = message;
|
||||
|
||||
// Mostrar/ocultar spinner
|
||||
if (type === 'saving') {
|
||||
spinner.style.display = 'inline-block';
|
||||
} else {
|
||||
spinner.style.display = 'none';
|
||||
}
|
||||
|
||||
saveIndicator.style.display = 'block';
|
||||
|
||||
// Auto-ocultar después de unos segundos (excepto cuando está guardando)
|
||||
if (type !== 'saving') {
|
||||
setTimeout(() => {
|
||||
saveIndicator.style.display = 'none';
|
||||
}, type === 'error' ? 5000 : 3000);
|
||||
}
|
||||
}
|
||||
|
||||
// Función para realizar guardado automático
|
||||
async function autoSave(tipo, data) {
|
||||
if (isAutoSaving) return;
|
||||
|
||||
isAutoSaving = true;
|
||||
showSaveIndicator('saving', 'Guardando cambios...');
|
||||
|
||||
try {
|
||||
const response = await fetch('/IMPORTADORES/preferencias/guardarCatalogosAjax', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
tipo: tipo,
|
||||
...data
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showSaveIndicator('saved', '✓ Cambios guardados');
|
||||
} else {
|
||||
throw new Error(result.message || 'Error desconocido');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error al guardar:', error);
|
||||
showSaveIndicator('error', '✗ Error: ' + error.message);
|
||||
|
||||
// En caso de error, podríamos revertir el estado del switch
|
||||
// pero por ahora solo mostramos el error
|
||||
} finally {
|
||||
isAutoSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Función para mostrar/ocultar secciones con animación
|
||||
function toggleSection(checkbox, targetId) {
|
||||
const target = document.getElementById(targetId);
|
||||
const isChecked = checkbox.checked;
|
||||
|
||||
if (isChecked) {
|
||||
target.style.display = 'block';
|
||||
setTimeout(() => {
|
||||
target.style.opacity = '1';
|
||||
}, 10);
|
||||
} else {
|
||||
target.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
target.style.display = 'none';
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// Función para debounce (evitar múltiples guardados rápidos)
|
||||
function debounce(func, wait) {
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(saveTimeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(saveTimeout);
|
||||
saveTimeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// === FUNCIONALIDAD DE CATÁLOGOS ===
|
||||
|
||||
// Event listener para switch general de catálogos
|
||||
document.getElementById('preferencias-catalogos').addEventListener('change', function() {
|
||||
const isChecked = this.checked;
|
||||
|
||||
// Deshabilitar temporalmente otros switches para evitar conflictos
|
||||
const allSwitches = document.querySelectorAll('.form-check-input');
|
||||
allSwitches.forEach(sw => sw.disabled = true);
|
||||
|
||||
// Guardar cambio
|
||||
autoSave('catalogos_general', {
|
||||
valor: isChecked
|
||||
}).finally(() => {
|
||||
// Rehabilitar switches
|
||||
allSwitches.forEach(sw => sw.disabled = false);
|
||||
});
|
||||
|
||||
// Mostrar/ocultar sección de tipos
|
||||
toggleSection(this, 'tipos-catalogos');
|
||||
|
||||
// Si se desactivan los catálogos, también desactivar todos los tipos
|
||||
if (!isChecked) {
|
||||
// Desmarcar todos los tipos de catálogo
|
||||
document.querySelectorAll('.tipo-catalogo').forEach(checkbox => {
|
||||
checkbox.checked = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Event listeners para tipos específicos de catálogo
|
||||
document.querySelectorAll('.tipo-catalogo').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', function() {
|
||||
const isChecked = this.checked;
|
||||
const tipoNombre = this.dataset.nombre;
|
||||
|
||||
// Verificar que los catálogos generales estén activados
|
||||
const catalogosGenerales = document.getElementById('preferencias-catalogos').checked;
|
||||
if (!catalogosGenerales) {
|
||||
showSaveIndicator('error', 'Primero debes activar las preferencias de catálogos');
|
||||
this.checked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Deshabilitar switch temporalmente
|
||||
this.disabled = true;
|
||||
|
||||
// Guardar cambio
|
||||
autoSave('tipo_catalogo', {
|
||||
nombre: tipoNombre,
|
||||
valor: isChecked
|
||||
}).finally(() => {
|
||||
this.disabled = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// === FIN FUNCIONALIDAD DE CATÁLOGOS ===
|
||||
|
||||
// Prevenir envío accidental del formulario
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter' && e.target.type !== 'submit') {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// Mensaje de confirmación antes de salir si hay guardado en progreso
|
||||
window.addEventListener('beforeunload', function(e) {
|
||||
if (isAutoSaving) {
|
||||
e.preventDefault();
|
||||
e.returnValue = 'Hay cambios pendientes de guardar. ¿Estás seguro de que quieres salir?';
|
||||
return e.returnValue;
|
||||
}
|
||||
});
|
||||
|
||||
// Inicialización al cargar la página
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Verificar estado inicial del switch general
|
||||
const catalogosGenerales = document.getElementById('preferencias-catalogos');
|
||||
if (catalogosGenerales && !catalogosGenerales.checked) {
|
||||
const tiposCatalogos = document.getElementById('tipos-catalogos');
|
||||
if (tiposCatalogos) {
|
||||
tiposCatalogos.style.opacity = '0';
|
||||
tiposCatalogos.style.display = 'none';
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -45,6 +45,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Catalogos</h5>
|
||||
<p>Personaliza la visualización de tus catalogos.</p>
|
||||
<a href="/IMPORTADORES/preferencias/catalogos"
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/catalogos' ? 'active' : '' ?>">
|
||||
Personalizar Catálogos
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,7 @@
|
||||
<!-- 📄 CONTENIDO -->
|
||||
<div class="content">
|
||||
<h4 class="mb-4">🔗 Mis vinculaciones</h4>
|
||||
<a href="/IMPORTADORES/vinculaciones/nuevaVinculacion" class="btn btn-success mb-3">➕ Nueva Vinculación</a>
|
||||
<!-- TABLA DE VINCULACIÓN USUARIO -->
|
||||
<div class="card p-3 shadow-sm">
|
||||
<h5 class="mb-3">🏪 Agencia Vinculadas</h5>
|
||||
|
||||
Reference in New Issue
Block a user