Files
MVE/views/seguridad/ventanilla_unica.php
2025-10-21 11:41:30 -06:00

349 lines
20 KiB
PHP

<?php include __DIR__ . '/../partials/sidebar_configuracion.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>🔐 Configuración Ventanilla Única</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 rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<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; }
@media (min-width: 768px) { .content { margin-left: 250px; } }
@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; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); }
.btn-animated { transition: all 0.3s ease; }
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
.form-floating { position: relative; }
.form-floating > .form-control:focus ~ label { color: #0d6efd; }
.security-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.status-indicator { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); }
.path-input { font-family: 'Courier New', monospace; font-size: 0.9em; }
.config-section { border-left: 4px solid #0d6efd; padding-left: 20px; margin-bottom: 30px; }
</style>
</head>
<body>
<div class="content">
<!-- Header -->
<div class="security-header text-white p-4 rounded-3 mb-4">
<div class="d-flex align-items-center justify-content-between">
<div>
<h4 class="mb-1"><i class="fas fa-university me-2"></i>Configuración Ventanilla Única</h4>
<p class="mb-0 opacity-75">Configuración para transmisiones de Manifestación de Valor Electrónica</p>
</div>
<div class="text-end">
<a href="/IMPORTADORES/seguridad/index" class="btn btn-light btn-sm">
<i class="fas fa-arrow-left me-1"></i>Regresar a Seguridad
</a>
</div>
</div>
</div>
<!-- Mensajes de éxito/error -->
<?php if (isset($_SESSION['config_success'])): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle me-2"></i>
<?= htmlspecialchars($_SESSION['config_success']) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php unset($_SESSION['config_success']); ?>
<?php endif; ?>
<?php if (isset($_SESSION['config_error'])): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-triangle me-2"></i>
<?= htmlspecialchars($_SESSION['config_error']) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php unset($_SESSION['config_error']); ?>
<?php endif; ?>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="fas fa-cogs me-2"></i>Configuración de Ventanilla Única</h5>
</div>
<div class="card-body">
<form action="/IMPORTADORES/seguridad/guardarConfiguracionVU" method="POST" id="configForm" enctype="multipart/form-data">
<!-- Sección 1: Certificados FIEL -->
<div class="config-section">
<h6 class="text-success mb-3">
<i class="fas fa-certificate me-2"></i>Certificados FIEL
</h6>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="archivo_key" class="form-label">
<i class="fas fa-key me-1"></i>Archivo KEY *
</label>
<input type="file"
class="form-control"
id="archivo_key"
name="archivo_key"
accept=".key"
<?= empty($configuracion_vu['ruta_archivo_key']) ? 'required' : '' ?>>
<?php if (!empty($configuracion_vu['ruta_archivo_key'])): ?>
<div class="mt-2 p-2 bg-light rounded">
<small class="text-success">
<i class="fas fa-check me-1"></i>
Archivo actual: <?= basename($configuracion_vu['ruta_archivo_key']) ?>
</small>
<input type="hidden" name="ruta_archivo_key_actual" value="<?= htmlspecialchars($configuracion_vu['ruta_archivo_key']) ?>">
</div>
<?php endif; ?>
<small class="text-muted d-block mt-1">
Solo archivos .key permitidos
</small>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="archivo_cer" class="form-label">
<i class="fas fa-certificate me-1"></i>Archivo CER *
</label>
<input type="file"
class="form-control"
id="archivo_cer"
name="archivo_cer"
accept=".cer"
<?= empty($configuracion_vu['ruta_archivo_cer']) ? 'required' : '' ?>>
<?php if (!empty($configuracion_vu['ruta_archivo_cer'])): ?>
<div class="mt-2 p-2 bg-light rounded">
<small class="text-success">
<i class="fas fa-check me-1"></i>
Archivo actual: <?= basename($configuracion_vu['ruta_archivo_cer']) ?>
</small>
<input type="hidden" name="ruta_archivo_cer_actual" value="<?= htmlspecialchars($configuracion_vu['ruta_archivo_cer']) ?>">
</div>
<?php endif; ?>
<small class="text-muted d-block mt-1">
Solo archivos .cer permitidos
</small>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-floating mb-3">
<input type="password"
class="form-control"
id="clave_fiel"
name="clave_fiel"
value="<?= htmlspecialchars($configuracion_vu['clave_fiel']) ?>"
placeholder="Contraseña FIEL"
required>
<label for="clave_fiel">
<i class="fas fa-lock me-1"></i>Clave de Acceso FIEL *
</label>
<button type="button"
class="btn btn-outline-secondary position-absolute end-0 top-50 translate-middle-y me-3"
style="z-index: 10;"
onclick="togglePassword('clave_fiel')">
<i class="fas fa-eye" id="clave_fiel_icon"></i>
</button>
</div>
<small class="text-muted">
<i class="fas fa-shield-alt me-1"></i>
Esta contraseña se almacena de forma encriptada
</small>
</div>
</div>
</div>
<!-- Sección 2: Acceso Ventanilla Única -->
<div class="config-section">
<h6 class="text-warning mb-3">
<i class="fas fa-user-cog me-2"></i>Acceso a Ventanilla Única
</h6>
<div class="row">
<div class="col-md-6">
<div class="form-floating mb-3">
<input type="text"
class="form-control"
id="rfc_usuario_vu"
name="rfc_usuario_vu"
value="<?= htmlspecialchars($configuracion_vu['rfc_usuario_vu']) ?>"
placeholder="RFC12345678901"
maxlength="13"
style="text-transform: uppercase;"
required>
<label for="rfc_usuario_vu">
<i class="fas fa-id-card me-1"></i>RFC Usuario VU *
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-floating mb-3">
<input type="password"
class="form-control"
id="clave_webservice"
name="clave_webservice"
value="<?= htmlspecialchars($configuracion_vu['clave_webservice']) ?>"
placeholder="Contraseña Web Service">
<label for="clave_webservice">
<i class="fas fa-globe me-1"></i>Clave de Acceso Web Service (Opcional)
</label>
<button type="button"
class="btn btn-outline-secondary position-absolute end-0 top-50 translate-middle-y me-3"
style="z-index: 10;"
onclick="togglePassword('clave_webservice')">
<i class="fas fa-eye" id="clave_webservice_icon"></i>
</button>
</div>
</div>
</div>
<small class="text-muted">
<i class="fas fa-info-circle me-1"></i>
Las contraseñas se almacenan de forma encriptada por seguridad
</small>
</div>
<!-- Información adicional -->
<?php if ($configuracion_vu['fecha_creacion'] || $configuracion_vu['fecha_actualizacion']): ?>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
<strong>Información de configuración:</strong><br>
<?php if ($configuracion_vu['fecha_creacion']): ?>
Creada: <?= $configuracion_vu['fecha_creacion']->format('d/m/Y H:i') ?><br>
<?php endif; ?>
<?php if ($configuracion_vu['fecha_actualizacion']): ?>
Última actualización: <?= $configuracion_vu['fecha_actualizacion']->format('d/m/Y H:i') ?>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Botones de acción -->
<div class="d-flex justify-content-between align-items-center">
<button type="button"
class="btn btn-outline-info btn-animated"
onclick="probarConfiguracion()">
<i class="fas fa-vial me-2"></i>Probar Configuración
</button>
<div>
<button type="button"
class="btn btn-outline-secondary me-2"
onclick="limpiarFormulario()">
<i class="fas fa-eraser me-1"></i>Limpiar
</button>
<button type="submit"
class="btn btn-primary btn-animated">
<i class="fas fa-save me-2"></i>Guardar Configuración
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
// Función para mostrar/ocultar contraseñas
function togglePassword(fieldId) {
const field = document.getElementById(fieldId);
const icon = document.getElementById(fieldId + '_icon');
if (field.type === 'password') {
field.type = 'text';
icon.classList.remove('fa-eye');
icon.classList.add('fa-eye-slash');
} else {
field.type = 'password';
icon.classList.remove('fa-eye-slash');
icon.classList.add('fa-eye');
}
}
// Función para limpiar el formulario
function limpiarFormulario() {
if (confirm('¿Estás seguro de que deseas limpiar todos los campos?')) {
document.getElementById('configForm').reset();
}
}
// Función para probar la configuración
function probarConfiguracion() {
const btn = event.target;
const originalHtml = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Probando...';
btn.disabled = true;
fetch('/IMPORTADORES/seguridad/probarConexionVU', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Configuración Válida',
text: data.message,
confirmButtonColor: '#28a745'
});
} else {
Swal.fire({
icon: 'error',
title: 'Error en Configuración',
text: data.message,
confirmButtonColor: '#dc3545'
});
}
})
.catch(error => {
Swal.fire({
icon: 'error',
title: 'Error de Conexión',
text: 'No se pudo probar la configuración. Verifica tu conexión.',
confirmButtonColor: '#dc3545'
});
})
.finally(() => {
btn.innerHTML = originalHtml;
btn.disabled = false;
});
}
// Validación en tiempo real de rutas de archivos
document.addEventListener('DOMContentLoaded', function() {
const pathInputs = document.querySelectorAll('.path-input');
pathInputs.forEach(input => {
input.addEventListener('blur', function() {
const statusId = this.id.replace('ruta_', '') + '-status';
const statusElement = document.getElementById(statusId);
if (this.value.trim()) {
// Aquí podrías agregar validación adicional
statusElement.innerHTML = '<i class="fas fa-check text-success"></i>';
} else {
statusElement.innerHTML = '';
}
});
});
// Convertir RFC a mayúsculas automáticamente
document.getElementById('rfc_usuario_vu').addEventListener('input', function() {
this.value = this.value.toUpperCase();
});
});
</script>
</body>
</html>