1632 lines
66 KiB
PHP
1632 lines
66 KiB
PHP
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||
|
||
<!DOCTYPE html>
|
||
<html lang="es">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>➕ Nueva Solicitud de Importación</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">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
|
||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||
<!-- Font Awesome -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||
<!-- Animate.css para animaciones adicionales -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
|
||
<style>
|
||
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
|
||
/* Contenido principal: sin solaparse con sidebar/navbar */
|
||
.content { margin-top: 0; padding: 24px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
|
||
@media (min-width: 768px) { .content { margin-left: var(--sidebar-width, 280px); } }
|
||
@media (max-width: 767.98px) { .content { margin-left: 0; } }
|
||
.card { border-radius: 12px; }
|
||
/* Animaciones personalizadas */
|
||
.card-hover { transition: all 0.3s ease; cursor: pointer; }
|
||
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
||
.btn-pulse { animation: pulse 2s infinite; }
|
||
@keyframes pulse {
|
||
0% { transform: scale(1); }
|
||
50% { transform: scale(1.05); }
|
||
100% { transform: scale(1); }
|
||
}
|
||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
||
@keyframes fadeInUp {
|
||
from { opacity: 0; transform: translateY(30px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
/* Responsive animations */
|
||
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
|
||
/* Efecto de glow para elementos activos */
|
||
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
|
||
/* Animación para el título */
|
||
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
|
||
/* Efecto para botones */
|
||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||
.btn-animated:hover::before { left: 100%; }
|
||
.hide { display: none !important; }
|
||
.alert { top: calc(var(--navbar-height, 70px) + 5px); left: calc(var(--sidebar-width, 280px) + 15px); right: 15px; position: fixed; z-index: 1050; width: calc(100% - var(--sidebar-width, 280px) - 30px); }
|
||
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||
@keyframes shake {
|
||
0%, 100% { transform: translateX(0); }
|
||
25% { transform: translateX(-5px); }
|
||
75% { transform: translateX(5px); }
|
||
}
|
||
/* Animación para los campos del formulario */
|
||
.form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; }
|
||
.form-group-animated:nth-child(1) { animation-delay: 0.1s; }
|
||
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
||
.form-group-animated:nth-child(3) { animation-delay: 0.3s; }
|
||
.form-group-animated:nth-child(4) { animation-delay: 0.4s; }
|
||
.form-group-animated:nth-child(5) { animation-delay: 0.5s; }
|
||
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
|
||
.form-group-animated:nth-child(7) { animation-delay: 0.7s; }
|
||
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
||
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||
/* Estilos para las sugerencias de autocompletado */
|
||
#global-autocomplete-suggestions { box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; border: 1px solid #dee2e6 !important; width: calc(100% - 30px) !important; /* Ajusta según el padding de tu contenedor */ }
|
||
#global-autocomplete-suggestions .autocomplete-item { transition: background-color 0.15s ease; }
|
||
#global-autocomplete-suggestions .autocomplete-item:hover,
|
||
#global-autocomplete-suggestions .autocomplete-item.active { background-color: #f8f9fa !important; }
|
||
#global-autocomplete-suggestions .autocomplete-item:last-child { border-bottom: none; }
|
||
/* Estilos para validación */
|
||
.choices.required .choices__inner { border: 1px solid #ced4da; }
|
||
.choices.is-invalid .choices__inner { border: 1px solid #dc3545; background-color: #fff5f5; }
|
||
.choices.is-valid .choices__inner { border: 1px solid #28a745; background-color: #f5fff5; }
|
||
.choices__input { opacity: 1 !important; }
|
||
|
||
/* Estilos para el panel de pedimentos de referencia */
|
||
.pedimento-item {
|
||
background: #fff;
|
||
border: 1px solid #e9ecef;
|
||
border-radius: 6px;
|
||
padding: 8px;
|
||
margin-bottom: 6px;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
font-size: 11px;
|
||
}
|
||
.pedimento-item:hover {
|
||
background-color: #e3f2fd;
|
||
border-color: #2196f3;
|
||
transform: translateX(2px);
|
||
}
|
||
.pedimento-item:active {
|
||
transform: scale(0.98);
|
||
}
|
||
.pedimento-numero {
|
||
font-weight: bold;
|
||
color: #1976d2;
|
||
font-size: 12px;
|
||
}
|
||
.pedimento-cliente {
|
||
color: #666;
|
||
font-size: 10px;
|
||
margin-top: 2px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.pedimento-meta {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: 4px;
|
||
}
|
||
.pedimento-clave {
|
||
background: #e8f5e8;
|
||
color: #2e7d32;
|
||
padding: 2px 6px;
|
||
border-radius: 3px;
|
||
font-size: 9px;
|
||
font-weight: bold;
|
||
}
|
||
.pedimento-fecha {
|
||
color: #888;
|
||
font-size: 9px;
|
||
}
|
||
.pedimento-item.copiado {
|
||
background-color: #e8f5e8 !important;
|
||
border-color: #4caf50 !important;
|
||
}
|
||
.pedimento-item.copiado .pedimento-numero::after {
|
||
content: " ✓";
|
||
color: #4caf50;
|
||
}
|
||
|
||
/* Responsive para el panel */
|
||
@media (max-width: 991.98px) {
|
||
.col-lg-3 { margin-top: 20px; }
|
||
}
|
||
|
||
/* ============ OPTIMIZACIONES DE VELOCIDAD ============ */
|
||
/* Campos enfocados */
|
||
.form-control:focus, .form-select:focus {
|
||
border-color: #0d6efd;
|
||
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
||
background-color: #fff;
|
||
}
|
||
|
||
/* Indicador de campo siguiente */
|
||
.next-field-hint {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: #6c757d;
|
||
font-size: 12px;
|
||
pointer-events: none;
|
||
transition: all 0.3s ease;
|
||
opacity: 0;
|
||
}
|
||
|
||
.form-control:focus + .next-field-hint {
|
||
opacity: 1;
|
||
right: 8px;
|
||
}
|
||
|
||
/* Autocompletado mejorado */
|
||
.quick-select-bar {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
padding: 12px;
|
||
border-radius: 8px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.quick-btn {
|
||
background: rgba(255,255,255,0.2);
|
||
border: 1px solid rgba(255,255,255,0.3);
|
||
color: white;
|
||
padding: 6px 12px;
|
||
border-radius: 20px;
|
||
font-size: 12px;
|
||
margin: 2px;
|
||
transition: all 0.2s ease;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.quick-btn:hover {
|
||
background: rgba(255,255,255,0.3);
|
||
transform: translateY(-1px);
|
||
color: white;
|
||
border-color: rgba(255,255,255,0.5);
|
||
}
|
||
|
||
.quick-btn.active {
|
||
background: rgba(255,255,255,0.9);
|
||
color: #333;
|
||
}
|
||
|
||
/* Calculadora automática */
|
||
.calc-helper {
|
||
position: absolute;
|
||
right: -35px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 4px;
|
||
padding: 4px 8px;
|
||
font-size: 11px;
|
||
color: #666;
|
||
white-space: nowrap;
|
||
opacity: 0;
|
||
transition: all 0.3s ease;
|
||
pointer-events: none;
|
||
z-index: 10;
|
||
}
|
||
|
||
.calc-helper.show {
|
||
opacity: 1;
|
||
right: -120px;
|
||
}
|
||
|
||
/* Indicador de progreso */
|
||
.progress-indicator {
|
||
position: fixed;
|
||
top: calc(var(--navbar-height, 70px) + 10px);
|
||
right: 20px;
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 10px 15px;
|
||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||
z-index: 1040;
|
||
min-width: 200px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.progress-bar-custom {
|
||
height: 4px;
|
||
background: linear-gradient(90deg, #28a745, #20c997, #17a2b8);
|
||
border-radius: 2px;
|
||
transition: width 0.3s ease;
|
||
}
|
||
|
||
/* Atajos de teclado */
|
||
.keyboard-shortcuts {
|
||
position: fixed;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
background: rgba(0,0,0,0.8);
|
||
color: white;
|
||
padding: 10px 15px;
|
||
border-radius: 8px;
|
||
font-size: 11px;
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
transition: all 0.3s ease;
|
||
z-index: 1050;
|
||
max-width: 300px;
|
||
}
|
||
|
||
.keyboard-shortcuts.show {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.shortcut-key {
|
||
background: rgba(255,255,255,0.2);
|
||
padding: 2px 6px;
|
||
border-radius: 3px;
|
||
margin: 0 2px;
|
||
font-family: monospace;
|
||
font-size: 10px;
|
||
}
|
||
|
||
/* Auto-save indicator */
|
||
.auto-save-indicator {
|
||
position: fixed;
|
||
top: calc(var(--navbar-height, 70px) + 10px);
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: #28a745;
|
||
color: white;
|
||
padding: 8px 16px;
|
||
border-radius: 20px;
|
||
font-size: 12px;
|
||
opacity: 0;
|
||
transition: all 0.3s ease;
|
||
z-index: 1050;
|
||
}
|
||
|
||
.auto-save-indicator.show {
|
||
opacity: 1;
|
||
top: calc(var(--navbar-height, 70px) + 30px);
|
||
}
|
||
|
||
/* Templates rápidos */
|
||
.template-selector {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 15px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.template-item {
|
||
background: white;
|
||
border: 1px solid #e9ecef;
|
||
border-radius: 6px;
|
||
padding: 10px;
|
||
margin: 5px 0;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.template-item:hover {
|
||
border-color: #0d6efd;
|
||
background: #f8f9ff;
|
||
transform: translateX(3px);
|
||
}
|
||
|
||
.template-name {
|
||
font-weight: bold;
|
||
color: #495057;
|
||
}
|
||
|
||
.template-desc {
|
||
color: #6c757d;
|
||
margin-top: 3px;
|
||
}
|
||
|
||
/* Drag and drop para archivos */
|
||
.file-drop-zone {
|
||
border: 2px dashed #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
text-align: center;
|
||
transition: all 0.3s ease;
|
||
background: #fafafa;
|
||
}
|
||
|
||
.file-drop-zone.dragover {
|
||
border-color: #0d6efd;
|
||
background: #f0f8ff;
|
||
}
|
||
|
||
.file-drop-zone.dragover .drop-text {
|
||
color: #0d6efd;
|
||
}
|
||
|
||
/* Validación en tiempo real */
|
||
.field-valid {
|
||
position: relative;
|
||
}
|
||
|
||
.field-valid::after {
|
||
content: "✓";
|
||
position: absolute;
|
||
right: 8px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: #28a745;
|
||
font-weight: bold;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.field-valid.is-valid::after {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Notificaciones flotantes mejoradas */
|
||
.floating-notification {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 12px 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||
transform: translateX(400px);
|
||
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||
z-index: 9999;
|
||
max-width: 350px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.floating-notification.show {
|
||
transform: translateX(0);
|
||
}
|
||
|
||
.floating-notification.success {
|
||
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
|
||
}
|
||
|
||
.floating-notification.warning {
|
||
background: linear-gradient(135deg, #ffc107 0%, #fd7e14 100%);
|
||
color: #000;
|
||
}
|
||
|
||
.floating-notification.error {
|
||
background: linear-gradient(135deg, #dc3545 0%, #e91e63 100%);
|
||
}
|
||
|
||
/* ✅ NUEVOS ESTILOS PARA EL MODAL DE ATAJOS */
|
||
.shortcut-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 8px 0;
|
||
border-bottom: 1px solid #f8f9fa;
|
||
}
|
||
|
||
.shortcut-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.shortcut-key {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 4px;
|
||
padding: 4px 8px;
|
||
font-family: 'Courier New', monospace;
|
||
font-weight: bold;
|
||
font-size: 12px;
|
||
color: #495057;
|
||
min-width: 80px;
|
||
text-align: center;
|
||
}
|
||
|
||
.shortcut-desc {
|
||
color: #6c757d;
|
||
font-size: 14px;
|
||
margin-left: 15px;
|
||
}
|
||
|
||
.feature-item {
|
||
padding: 8px 0;
|
||
}
|
||
|
||
.quick-help-item {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.quick-help-item small {
|
||
color: #6c757d;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* Estilos para el botón de atajos rápidos */
|
||
#show-shortcuts-modal {
|
||
transition: all 0.3s ease;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
#show-shortcuts-modal:hover {
|
||
transform: translateY(-1px);
|
||
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||
}
|
||
|
||
/* Mejoras para el toggle de templates */
|
||
#toggle-templates {
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
#toggle-templates:hover {
|
||
transform: translateX(2px);
|
||
}
|
||
|
||
/* Estilos para las cards del panel derecho mejoradas */
|
||
.card .card-header {
|
||
border-bottom: 2px solid rgba(255,255,255,0.1);
|
||
}
|
||
|
||
.card .card-footer {
|
||
border-top: 1px solid rgba(0,0,0,0.1);
|
||
background: rgba(0,0,0,0.02) !important;
|
||
}
|
||
|
||
/* Animaciones para los elementos reorganizados */
|
||
.quick-select-bar {
|
||
animation: slideInDown 0.8s ease-out;
|
||
}
|
||
|
||
@keyframes slideInDown {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-30px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
/* Responsive para el modal */
|
||
@media (max-width: 768px) {
|
||
.modal-dialog {
|
||
margin: 0.5rem;
|
||
}
|
||
|
||
.shortcut-item {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 5px;
|
||
}
|
||
|
||
.shortcut-desc {
|
||
margin-left: 0;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.quick-help-item {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 3px;
|
||
}
|
||
}
|
||
|
||
/* Mejoras para la barra de progreso */
|
||
.progress-indicator {
|
||
border-left: 4px solid #007bff;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.progress-indicator:hover {
|
||
transform: scale(1.02);
|
||
box-shadow: 0 6px 16px rgba(0,0,0,0.2);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<?php if (!isset($_SESSION['id_agencia_en_uso']) || !$_SESSION['id_agencia_en_uso']): ?>
|
||
<div class="container mt-4">
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<div class="alert alert-warning mt-4">
|
||
<h5>⚠️ No tienes una agencia activa vinculada.</h5>
|
||
<p>Para poder gestionar tus solicitudes de importación, primero debes <strong>vincularte a una agencia</strong>.</p>
|
||
<a href="/IMPORTADORES/vinculaciones/nuevaVinculacion" class="btn btn-primary btn-animated">Ir a Vinculaciones</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php return; ?>
|
||
<?php endif; ?>
|
||
|
||
<div class="content">
|
||
<div class="row align-items-center mb-4">
|
||
<div class="col">
|
||
<h4 class="mb-0 animate__animated animate__fadeInDown title_glow">➕ Nueva factura de Importación</h4>
|
||
</div>
|
||
<div class="col-auto">
|
||
<!-- Botón flotante de información/atajos -->
|
||
<button type="button" class="btn btn-info btn-sm rounded-pill" id="show-shortcuts-modal" data-bs-toggle="modal" data-bs-target="#shortcutsModal">
|
||
<i class="fas fa-info-circle me-1"></i>
|
||
<i class="fas fa-keyboard me-1"></i>
|
||
Atajos Rápidos
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ✅ REORGANIZADO: Barra de acceso rápido más compacta -->
|
||
<div class="quick-select-bar mb-3">
|
||
<div class="row align-items-center">
|
||
<div class="col-auto">
|
||
<small class="text-white fw-bold"><i class="fas fa-zap me-1"></i> Acceso Rápido:</small>
|
||
</div>
|
||
<div class="col">
|
||
<div class="d-flex flex-wrap gap-1">
|
||
<button type="button" class="quick-btn" data-quick-fill="fecha-hoy" title="Establecer fecha de hoy">
|
||
<i class="fas fa-calendar-day me-1"></i>Hoy
|
||
</button>
|
||
<button type="button" class="quick-btn" data-quick-fill="moneda-usd" title="Moneda USD">
|
||
<i class="fas fa-dollar-sign me-1"></i>USD
|
||
</button>
|
||
<button type="button" class="quick-btn" data-quick-fill="vinculacion-no" title="Sin vinculación">
|
||
<i class="fas fa-times me-1"></i>Sin Vinc.
|
||
</button>
|
||
<button type="button" class="quick-btn" data-quick-fill="incoterm-fob" title="INCOTERM FOB">
|
||
<i class="fas fa-ship me-1"></i>FOB
|
||
</button>
|
||
<button type="button" class="quick-btn" data-quick-fill="pais-usa" title="País Estados Unidos">
|
||
<i class="fas fa-flag-usa me-1"></i>USA
|
||
</button>
|
||
<button type="button" class="quick-btn" data-quick-fill="tasa-general" title="Tasa preferencial General">
|
||
<i class="fas fa-percentage me-1"></i>General
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ✅ NUEVO: Indicador de progreso más discreto -->
|
||
<div class="progress-indicator" id="progress-indicator" style="display: none;">
|
||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||
<small><i class="fas fa-tasks me-1"></i>Progreso</small>
|
||
<small id="progress-text">0%</small>
|
||
</div>
|
||
<div class="progress-bar-custom" id="progress-bar" style="width: 0%;"></div>
|
||
</div>
|
||
|
||
<!-- ✅ MODIFICADO: Templates personalizados del cliente (con mejor inicialización) -->
|
||
<div class="template-selector collapse" id="template-selector">
|
||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||
<h6 class="mb-0"><i class="fas fa-magic me-1"></i> Mis Templates Personalizados</h6>
|
||
<div>
|
||
<button type="button" class="btn btn-sm btn-outline-primary" id="refresh-templates" title="Actualizar templates">
|
||
<i class="fas fa-sync-alt"></i>
|
||
</button>
|
||
<a href="/IMPORTADORES/templates_rapidos/crear" class="btn btn-sm btn-success" target="_blank" title="Crear nuevo template">
|
||
<i class="fas fa-plus"></i> Crear Nuevo
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div id="templates-container">
|
||
<div class="text-center py-3" id="templates-loading">
|
||
<div class="spinner-border spinner-border-sm text-primary" role="status">
|
||
<span class="visually-hidden">Cargando...</span>
|
||
</div>
|
||
<div class="small text-muted mt-1">Cargando tus templates...</div>
|
||
</div>
|
||
<!-- Templates personalizados se cargarán aquí -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ✅ REORGANIZADO: Toggle para mostrar templates con mejor funcionalidad -->
|
||
<div class="mb-3">
|
||
<button type="button" class="btn btn-outline-secondary btn-sm" id="toggle-templates"
|
||
data-bs-toggle="collapse" data-bs-target="#template-selector"
|
||
aria-expanded="false" aria-controls="template-selector">
|
||
<i class="fas fa-eye me-1"></i>
|
||
<span id="toggle-text">Mostrar Mis Templates</span>
|
||
</button>
|
||
|
||
<!-- ✅ NUEVO: Link directo para crear templates si no hay ninguno -->
|
||
<div class="mt-2" id="templates-quick-actions" style="display: none;">
|
||
<small class="text-muted d-block mb-1">
|
||
<i class="fas fa-lightbulb me-1"></i>
|
||
Los templates te ayudan a llenar formularios más rápido
|
||
</small>
|
||
<div class="d-flex gap-2 flex-wrap">
|
||
<a href="/IMPORTADORES/templates_rapidos/crear" class="btn btn-xs btn-outline-success" target="_blank">
|
||
<i class="fas fa-plus me-1"></i>Crear Mi Primer Template
|
||
</a>
|
||
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-xs btn-outline-info" target="_blank">
|
||
<i class="fas fa-list me-1"></i>Ver Todos los Templates
|
||
</a>
|
||
<button type="button" class="btn btn-xs btn-outline-warning" onclick="mostrarEjemploTemplates()">
|
||
<i class="fas fa-question-circle me-1"></i>¿Cómo funcionan?
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Layout de dos columnas -->
|
||
<div class="row">
|
||
<!-- Formulario principal (columna izquierda) -->
|
||
<div class="col-lg-9">
|
||
<div class="card p-4 bg-white shadow-sm card-hover position-relative h-auto fade-in-up">
|
||
<form id="solicitudForm" action="/IMPORTADORES/solicitud_importacion/guardar" method="POST" enctype="multipart/form-data">
|
||
|
||
<!-- Sección principal -->
|
||
<div class="row">
|
||
<div class="col-md-4 mb-3 form-group-animated">
|
||
<label for="numero_factura" class="form-label">Número de Factura</label>
|
||
<div class="position-relative">
|
||
<input id="numero_factura" name="numero_factura" type="text" class="form-control field-valid" required data-field-name="factura">
|
||
<div class="next-field-hint">Tab → Fecha</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-md-4 mb-3 form-group-animated">
|
||
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
||
<div class="position-relative">
|
||
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control field-valid" required data-field-name="fecha">
|
||
<div class="next-field-hint">Tab → Pedimento</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="col-md-4 mb-3 form-group-animated">
|
||
<label for="pedimento" class="form-label">Pedimento <span class="text-muted">(opcional)</span></label>
|
||
<div class="position-relative">
|
||
<input id="pedimento" name="pedimento" type="text" class="form-control pedimento-input field-valid" autocomplete="off"
|
||
placeholder="Buscar pedimento..." data-field-name="pedimento">
|
||
<div class="next-field-hint">Tab → Proveedor</div>
|
||
<div id="pedimento-suggestions" class="bg-white border shadow-lg position-absolute w-100"
|
||
style="display: none; max-height: 200px; overflow-y: auto; z-index: 1050; border-radius: 4px; margin-top: 2px;">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-12 mb-3">
|
||
<label for="proveedor_id" class="form-label">Proveedor</label>
|
||
<select id="proveedor_id" name="proveedor_id" class="form-select searchable field-valid" data-required="true" required data-field-name="proveedor">
|
||
<option value="">Cargando proveedores…</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Segunda fila: Patente, Incoterm, País, Moneda -->
|
||
<div class="row">
|
||
<div class="col-md-3 mb-3">
|
||
<label for="anexo22_apendice" class="form-label">Anexo 22 – Apéndice</label>
|
||
<select id="anexo22_apendice" name="anexo22_apendice" class="form-select searchable" data-required="true" required>
|
||
<option value="">-- Selecciona Aduana --</option>
|
||
<?php foreach($aduanas as $a): ?>
|
||
<option value="<?= htmlspecialchars($a['aduana_seccion']) ?>">
|
||
<?= htmlspecialchars($a['aduana_seccion'].' – '.$a['nombre']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-3 mb-3">
|
||
<label for="patente" class="form-label">Patente Aduanal</label>
|
||
<select id="patente" name="patente" class="form-select searchable" data-required="true" required>
|
||
<option value="">-- Selecciona Patente --</option>
|
||
<?php foreach($patentes as $pt): ?>
|
||
<option value="<?= htmlspecialchars($pt['id_agente']) ?>">
|
||
<?= htmlspecialchars($pt['patente'].' - '.$pt['agente_aduanal']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-3 mb-3">
|
||
<label for="incoterm" class="form-label">INCOTERM</label>
|
||
<select id="incoterm" name="incoterm" class="form-select searchable" data-required="true" required>
|
||
<option value="">-- Selecciona Incoterm --</option>
|
||
<?php foreach($incoterms as $inc): ?>
|
||
<option value="<?= htmlspecialchars($inc['INCOTERM']) ?>">
|
||
<?= htmlspecialchars($inc['INCOTERM'].' - '.$inc['DESCESPANOL']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-3 mb-3">
|
||
<label for="pais_proveedor" class="form-label">País (Proveedor)</label>
|
||
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable" data-required="true" required>
|
||
<option value="">-- Selecciona País --</option>
|
||
<?php foreach($paises as $p): ?>
|
||
<option value="<?= htmlspecialchars($p['id_pais']) ?>"><?= htmlspecialchars($p['nombre']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-3 mb-3">
|
||
<label for="tipo_moneda" class="form-label">Moneda</label>
|
||
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable" data-required="true" required>
|
||
<?php foreach(['MXN'=>'Peso Mexicano','USD'=>'Dólar USD','EUR'=>'Euro','CNY'=>'Yuan','GBP'=>'Libra GBP','JPY'=>'Yen'] as $code=>$label): ?>
|
||
<option value="<?= $code ?>"><?= "$label ($code)" ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Valor y vinculación -->
|
||
<div class="row">
|
||
<div class="col-md-8 mb-3 form-group-animated">
|
||
<label for="valor_factura" class="form-label">Valor Factura</label>
|
||
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control" required>
|
||
</div>
|
||
|
||
<div class="col-md-4 mb-3">
|
||
<label for="vinculacion" class="form-label">Vinculación</label>
|
||
<select id="vinculacion" name="vinculacion" class="form-select searchable" data-required="true" required>
|
||
<option value="0">No existe</option>
|
||
<option value="1">Existe, no afecta</option>
|
||
<option value="2">Existe y afecta</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Transportista, Chofer, Foto Solicitud -->
|
||
<div class="row">
|
||
<div class="col-md-4 mb-3">
|
||
<label for="transportista_id" class="form-label">Transportista</label>
|
||
<select id="transportista_id" name="transportista_id" class="form-select searchable field-valid" data-required="true" required data-field-name="transportista">
|
||
<option value="">-- Selecciona --</option>
|
||
<?php foreach($transportistas as $t): ?>
|
||
<option value="<?= htmlspecialchars($t['id_transportista']) ?>">
|
||
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-4 mb-3">
|
||
<label for="chofer_id" class="form-label">Chofer</label>
|
||
<select id="chofer_id" name="chofer_id" class="form-select searchable field-valid" data-required="true" required data-field-name="chofer">
|
||
<option value="">-- Selecciona Chofer --</option>
|
||
<?php foreach($choferes as $c): ?>
|
||
<option value="<?= htmlspecialchars($c['id_chofer']) ?>">
|
||
<?= htmlspecialchars($c['nombre']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="col-md-4 mb-3 form-group-animated">
|
||
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
||
<div class="file-drop-zone" id="file-drop-zone">
|
||
<div class="drop-text">
|
||
<i class="fas fa-cloud-upload-alt fa-2x mb-2 text-muted"></i>
|
||
<div>Arrastra la imagen aquí</div>
|
||
<div class="small text-muted">o</div>
|
||
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control mt-2" accept="image/*" data-field-name="foto">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Partidas dinámicas -->
|
||
<hr>
|
||
<h5 class="form-group-animated">📦 Partidas</h5>
|
||
<div class="table-responsive">
|
||
<table class="table table-sm form-group-animated" id="tabla-partidas">
|
||
<thead>
|
||
<tr>
|
||
<th>Descripción</th>
|
||
<th>Cantidad Comercial</th>
|
||
<th>Cantidad de Tarifa</th>
|
||
<th>Unidad Comercial</th>
|
||
<th>Valor Factura</th>
|
||
<th>Peso Bruto</th>
|
||
<th>Tasa Preferencial</th>
|
||
<th class="hide">Precio Unitario</th>
|
||
<th class="hide">OMA (Factura)</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<div class="position-relative">
|
||
<input name="partidas[0][descripcion]" class="form-control w-auto descripcion-input field-valid" required autocomplete="off" data-field-name="descripcion">
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div class="position-relative">
|
||
<input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-auto cantidad-comercial field-valid" min="0" required data-field-name="cantidad">
|
||
<div class="calc-helper" id="calc-cantidad-0"></div>
|
||
</div>
|
||
</td>
|
||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-auto field-valid" min="0" required data-field-name="tarifa"></td>
|
||
<td>
|
||
<div class="mb-3">
|
||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable field-valid" data-required="true" required data-field-name="unidad">
|
||
<option value="">-- Unidad --</option>
|
||
<?php foreach($unidades_medida as $um): ?>
|
||
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div class="position-relative">
|
||
<input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-auto field-valid" min="0" required data-field-name="valor">
|
||
<div class="calc-helper" id="calc-valor-0"></div>
|
||
</div>
|
||
</td>
|
||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-auto field-valid" min="0" required data-field-name="peso"></td>
|
||
<td>
|
||
<div class="mb-3">
|
||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable field-valid" data-required="true" required data-field-name="tasa">
|
||
<option value="">-- Selecciona --</option>
|
||
<option>General</option>
|
||
<option>TLC</option>
|
||
<option>PROSEC</option>
|
||
<option>ALADI</option>
|
||
<option>COMERCIALIZADORA</option>
|
||
</select>
|
||
</div>
|
||
</td>
|
||
<td class="hide"><input name="partidas[0][precio_unitario]" type="number" class="form-control w-auto"></td>
|
||
<td class="hide"><input name="partidas[0][oma_factura]" class="form-control w-auto"></td>
|
||
<td><button type="button" class="btn btn-danger btn-sm remove-row mt-auto w-auto btn-animated">✖️</button></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="form-group-animated">
|
||
<button type="button" class="btn btn-secondary btn-sm mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
||
</div>
|
||
|
||
<!-- Activo -->
|
||
<div class="form-check mt-4">
|
||
<input id="status" name="status" type="checkbox" class="hide form-check-input" checked>
|
||
<label for="status" class="hide form-check-label">Activo</label>
|
||
</div>
|
||
|
||
<!-- Botones finales -->
|
||
<div class="text-end mt-4 form-group-animated">
|
||
<button type="submit" class="btn btn-success mt-3 mt-auto w-auto btn-animated">Guardar</button>
|
||
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary mt-3 ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Panel de referencia (columna derecha) - MEJORADO -->
|
||
<div class="col-lg-3">
|
||
<!-- Card de Pedimentos -->
|
||
<div class="card bg-light shadow-sm fade-in-up mb-3" style="animation-delay: 0.2s; position: sticky; top: calc(var(--navbar-height, 70px) + 20px);">
|
||
<div class="card-header bg-primary text-white py-2">
|
||
<h6 class="mb-0"><i class="fas fa-list-ul me-1"></i> Pedimentos Disponibles</h6>
|
||
</div>
|
||
<div class="card-body p-2" style="max-height: 300px; overflow-y: auto;">
|
||
<div id="pedimentos-referencia" class="text-center text-muted">
|
||
<div class="spinner-border spinner-border-sm" role="status">
|
||
<span class="visually-hidden">Cargando...</span>
|
||
</div>
|
||
<div class="small mt-1">Cargando pedimentos...</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-footer bg-light py-2">
|
||
<small class="text-muted">
|
||
<i class="fas fa-info-circle me-1"></i>
|
||
Clic para copiar al formulario
|
||
</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Card de Ayuda Rápida -->
|
||
<div class="card bg-light shadow-sm fade-in-up" style="animation-delay: 0.3s;">
|
||
<div class="card-header bg-success text-white py-2">
|
||
<h6 class="mb-0"><i class="fas fa-lightbulb me-1"></i> Tips Rápidos</h6>
|
||
</div>
|
||
<div class="card-body p-3">
|
||
<div class="small">
|
||
<div class="mb-2">
|
||
<i class="fas fa-keyboard text-primary me-1"></i>
|
||
<strong>Ctrl+S</strong> para guardar
|
||
</div>
|
||
<div class="mb-2">
|
||
<i class="fas fa-plus text-success me-1"></i>
|
||
<strong>Ctrl+N</strong> nueva partida
|
||
</div>
|
||
<div class="mb-2">
|
||
<i class="fas fa-arrow-right text-info me-1"></i>
|
||
<strong>Tab</strong> siguiente campo
|
||
</div>
|
||
<div class="mb-0">
|
||
<i class="fas fa-search text-warning me-1"></i>
|
||
Escribe para buscar productos
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ✅ NUEVO: Modal de Atajos Rápidos -->
|
||
<div class="modal fade" id="shortcutsModal" tabindex="-1" aria-labelledby="shortcutsModalLabel" aria-hidden="true">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<div class="modal-header bg-primary text-white">
|
||
<h5 class="modal-title" id="shortcutsModalLabel">
|
||
<i class="fas fa-keyboard me-2"></i>
|
||
Atajos Rápidos y Guía de Uso
|
||
</h5>
|
||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="row">
|
||
<!-- Atajos de Teclado -->
|
||
<div class="col-md-6">
|
||
<h6 class="text-primary mb-3">
|
||
<i class="fas fa-keyboard me-1"></i>
|
||
Atajos de Teclado
|
||
</h6>
|
||
<div class="shortcut-list">
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">Ctrl + S</span>
|
||
<span class="shortcut-desc">Guardar formulario</span>
|
||
</div>
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">Ctrl + N</span>
|
||
<span class="shortcut-desc">Agregar nueva partida</span>
|
||
</div>
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">Tab</span>
|
||
<span class="shortcut-desc">Siguiente campo</span>
|
||
</div>
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">↑ ↓</span>
|
||
<span class="shortcut-desc">Navegar sugerencias</span>
|
||
</div>
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">Enter</span>
|
||
<span class="shortcut-desc">Seleccionar sugerencia</span>
|
||
</div>
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">Esc</span>
|
||
<span class="shortcut-desc">Cerrar menús</span>
|
||
</div>
|
||
<div class="shortcut-item mb-2">
|
||
<span class="shortcut-key">Alt + T</span>
|
||
<span class="shortcut-desc">Mostrar/Ocultar templates</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Funciones Inteligentes -->
|
||
<div class="col-md-6">
|
||
<h6 class="text-success mb-3">
|
||
<i class="fas fa-magic me-1"></i>
|
||
Funciones Inteligentes
|
||
</h6>
|
||
<div class="feature-list">
|
||
<div class="feature-item mb-3">
|
||
<div class="fw-bold text-success">
|
||
<i class="fas fa-search me-1"></i>
|
||
Autocompletado Inteligente
|
||
</div>
|
||
<small class="text-muted">
|
||
Escribe en "Descripción" para buscar productos frecuentes
|
||
</small>
|
||
</div>
|
||
|
||
<div class="feature-item mb-3">
|
||
<div class="fw-bold text-info">
|
||
<i class="fas fa-calculator me-1"></i>
|
||
Cálculo Automático
|
||
</div>
|
||
<small class="text-muted">
|
||
Los totales y precios unitarios se calculan automáticamente
|
||
</small>
|
||
</div>
|
||
|
||
<div class="feature-item mb-3">
|
||
<div class="fw-bold text-warning">
|
||
<i class="fas fa-copy me-1"></i>
|
||
Copia de Pedimentos
|
||
</div>
|
||
<small class="text-muted">
|
||
Haz clic en cualquier pedimento del panel derecho para copiarlo
|
||
</small>
|
||
</div>
|
||
|
||
<div class="feature-item mb-3">
|
||
<div class="fw-bold text-primary">
|
||
<i class="fas fa-magic me-1"></i>
|
||
Templates Personalizados
|
||
</div>
|
||
<small class="text-muted">
|
||
Crea y usa templates para llenar formularios rápidamente
|
||
</small>
|
||
</div>
|
||
|
||
<div class="feature-item mb-0">
|
||
<div class="fw-bold text-secondary">
|
||
<i class="fas fa-cloud-upload-alt me-1"></i>
|
||
Drag & Drop
|
||
</div>
|
||
<small class="text-muted">
|
||
Arrastra imágenes directamente al área de carga
|
||
</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<hr>
|
||
|
||
<!-- Barra de Acceso Rápido Explicada -->
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<h6 class="text-warning mb-3">
|
||
<i class="fas fa-zap me-1"></i>
|
||
Botones de Acceso Rápido
|
||
</h6>
|
||
<div class="row">
|
||
<div class="col-md-4">
|
||
<div class="quick-help-item mb-2">
|
||
<button class="btn btn-sm btn-outline-primary me-2" disabled>
|
||
<i class="fas fa-calendar-day"></i> Hoy
|
||
</button>
|
||
<small>Establece fecha actual</small>
|
||
</div>
|
||
<div class="quick-help-item mb-2">
|
||
<button class="btn btn-sm btn-outline-primary me-2" disabled>
|
||
<i class="fas fa-dollar-sign"></i> USD
|
||
</button>
|
||
<small>Moneda a USD</small>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<div class="quick-help-item mb-2">
|
||
<button class="btn btn-sm btn-outline-primary me-2" disabled>
|
||
<i class="fas fa-times"></i> Sin Vinc.
|
||
</button>
|
||
<small>No existe vinculación</small>
|
||
</div>
|
||
<div class="quick-help-item mb-2">
|
||
<button class="btn btn-sm btn-outline-primary me-2" disabled>
|
||
<i class="fas fa-ship"></i> FOB
|
||
</button>
|
||
<small>INCOTERM FOB</small>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<div class="quick-help-item mb-2">
|
||
<button class="btn btn-sm btn-outline-primary me-2" disabled>
|
||
<i class="fas fa-flag-usa"></i> USA
|
||
</button>
|
||
<small>País Estados Unidos</small>
|
||
</div>
|
||
<div class="quick-help-item mb-2">
|
||
<button class="btn btn-sm btn-outline-primary me-2" disabled>
|
||
<i class="fas fa-percentage"></i> General
|
||
</button>
|
||
<small>Tasa General (todas)</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||
<i class="fas fa-times me-1"></i>
|
||
Cerrar
|
||
</button>
|
||
<button type="button" class="btn btn-primary" onclick="localStorage.setItem('shortcuts-shown', 'false')" data-bs-dismiss="modal">
|
||
<i class="fas fa-eye me-1"></i>
|
||
Mostrar al iniciar próxima vez
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ✅ REMOVIDO: Indicadores flotantes antiguos (ahora están en el modal) -->
|
||
|
||
<!-- Choices.js JS -->
|
||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"></script>
|
||
|
||
<script>
|
||
// ✅ CARGAR TEMPLATES DESDE BASE DE DATOS (VERSIÓN CORREGIDA)
|
||
function loadTemplatesFromDatabase() {
|
||
alert('DEBUG: loadTemplatesFromDatabase llamada');
|
||
console.log('🔄 Cargando templates desde la base de datos...');
|
||
const $container = $('#templates-container');
|
||
const $loading = $('#templates-loading');
|
||
|
||
console.log('🔄 Cargando templates desde la base de datos...');
|
||
$loading.show();
|
||
|
||
$.ajax({
|
||
url: '/IMPORTADORES/templates_rapidos/ajax_obtener_templates',
|
||
method: 'GET',
|
||
dataType: 'json',
|
||
beforeSend: function() {
|
||
alert('DEBUG: AJAX a /IMPORTADORES/templates_rapidos/ajax_obtener_templates');
|
||
},
|
||
timeout: 10000,
|
||
success: function(response) {
|
||
console.log('📦 Respuesta completa recibida:', response);
|
||
$loading.hide();
|
||
$container.empty();
|
||
|
||
// ✅ MANEJAR ERROR SI EXISTE
|
||
if (response.error) {
|
||
console.error('❌ Error del servidor:', response.error);
|
||
mostrarErrorTemplates($container, response.error, response.message);
|
||
return;
|
||
}
|
||
|
||
// ✅ NUEVA LÓGICA: Usar la respuesta mejorada del endpoint
|
||
const templates = response.templates || [];
|
||
const templatesPersonales = response.templates_personales || [];
|
||
const templatesOtros = response.templates_otros || [];
|
||
const count = response.count || 0;
|
||
const countPersonales = response.count_personales || 0;
|
||
|
||
console.log(`✅ Templates cargados:`, {
|
||
total: count,
|
||
personales: countPersonales,
|
||
otros: templatesOtros.length
|
||
});
|
||
|
||
// ✅ MOSTRAR TODOS LOS TEMPLATES (SIN FILTROS ADICIONALES)
|
||
if (templates && templates.length > 0) {
|
||
// Priorizar templates personales primero, luego otros
|
||
const templatesPriorizados = [
|
||
...templatesPersonales,
|
||
...templatesOtros.slice(0, 5) // Máximo 5 templates de otros
|
||
];
|
||
|
||
if (templatesPriorizados.length > 0) {
|
||
// Mostrar mensaje informativo
|
||
if (countPersonales > 0) {
|
||
$container.append(`
|
||
<div class="alert alert-info alert-sm py-2 mb-3">
|
||
<i class="fas fa-info-circle me-1"></i>
|
||
<strong>Tienes ${countPersonales} template${countPersonales > 1 ? 's' : ''} personalizado${countPersonales > 1 ? 's' : ''}</strong>
|
||
${templatesOtros.length > 0 ? ` + ${templatesOtros.length} disponible${templatesOtros.length > 1 ? 's' : ''} de tu agencia/sistema` : ''}
|
||
</div>
|
||
`);
|
||
}
|
||
|
||
templatesPriorizados.forEach(function(template, index) {
|
||
const esPersonal = template.es_mio === true;
|
||
const badgeColor = esPersonal ? 'primary' : (template.ambito === 'agencia' ? 'info' : 'secondary');
|
||
const badgeText = esPersonal ? 'Mío' : (template.ambito === 'agencia' ? 'Agencia' : 'Sistema');
|
||
|
||
const $item = $(`
|
||
<div class="template-item animate__animated animate__fadeInUp"
|
||
data-template-id="${template.id}"
|
||
style="animation-delay: ${index * 0.1}s;">
|
||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||
<div class="template-name">
|
||
${template.icono || '📋'} ${template.nombre}
|
||
<span class="badge bg-${badgeColor} ms-2 small">${badgeText}</span>
|
||
</div>
|
||
${esPersonal ? `
|
||
<div class="dropdown">
|
||
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||
<i class="fas fa-cog"></i>
|
||
</button>
|
||
<ul class="dropdown-menu dropdown-menu-end">
|
||
<li><a class="dropdown-item" href="#" onclick="editTemplate(${template.id})">
|
||
<i class="fas fa-edit me-1"></i>Editar
|
||
</a></li>
|
||
<li><a class="dropdown-item text-danger" href="#" onclick="deleteTemplate(${template.id})">
|
||
<i class="fas fa-trash me-1"></i>Eliminar
|
||
</a></li>
|
||
</ul>
|
||
</div>
|
||
` : ''}
|
||
</div>
|
||
<div class="template-desc">${template.descripcion || 'Template ' + badgeText.toLowerCase()}</div>
|
||
<div class="mt-2 d-flex justify-content-between align-items-center">
|
||
<small class="text-muted">
|
||
<i class="fas fa-mouse-pointer me-1"></i>Usado ${template.veces_usado || 0} veces
|
||
</small>
|
||
<button class="btn btn-sm btn-primary" onclick="aplicarTemplateDirecto(${template.id})">
|
||
<i class="fas fa-magic me-1"></i>Usar Template
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`);
|
||
|
||
// Evento click para aplicar template (en toda la card excepto botones)
|
||
$item.on('click', function(e) {
|
||
if ($(e.target).closest('button, .dropdown, .dropdown-menu').length > 0) return;
|
||
aplicarTemplateDirecto(template.id);
|
||
});
|
||
|
||
$container.append($item);
|
||
});
|
||
|
||
// Mensaje adicional si hay más templates disponibles
|
||
if (templatesOtros.length > 5) {
|
||
$container.append(`
|
||
<div class="text-center mt-3">
|
||
<a href="/IMPORTADORES/templates_rapidos/lista" class="btn btn-sm btn-outline-info" target="_blank">
|
||
<i class="fas fa-list me-1"></i>
|
||
Ver todos los templates (${templates.length} disponibles)
|
||
</a>
|
||
</div>
|
||
`);
|
||
}
|
||
}
|
||
} else {
|
||
// No hay templates, mostrar mensaje de ayuda
|
||
mostrarMensajeSinTemplates($container);
|
||
}
|
||
},
|
||
error: function(xhr, status, error) {
|
||
console.error('❌ Error AJAX:', {
|
||
status: status,
|
||
error: error,
|
||
responseText: xhr.responseText,
|
||
statusCode: xhr.status
|
||
});
|
||
|
||
$loading.hide();
|
||
|
||
let errorMessage = 'Error desconocido';
|
||
let suggestion = '';
|
||
|
||
if (xhr.status === 403) {
|
||
errorMessage = 'No tienes permisos para ver los templates';
|
||
suggestion = 'Verifica que tengas una sesión activa';
|
||
} else if (xhr.status === 404) {
|
||
errorMessage = 'Endpoint de templates no encontrado';
|
||
suggestion = 'Verifica la configuración del servidor';
|
||
} else if (xhr.status === 500) {
|
||
errorMessage = 'Error interno del servidor';
|
||
suggestion = 'Revisa los logs del servidor';
|
||
} else if (status === 'timeout') {
|
||
errorMessage = 'La petición tardó demasiado tiempo';
|
||
suggestion = 'Verifica tu conexión a internet';
|
||
} else {
|
||
errorMessage = `Error ${xhr.status}: ${error}`;
|
||
suggestion = 'Error de comunicación con el servidor';
|
||
}
|
||
|
||
mostrarErrorTemplates($container, errorMessage, suggestion);
|
||
}
|
||
});
|
||
}
|
||
|
||
// ✅ NUEVA FUNCIÓN: Aplicar template directamente por ID
|
||
function aplicarTemplateDirecto(templateId) {
|
||
console.log('📝 Aplicando template ID:', templateId);
|
||
// Buscar el template en la respuesta cacheada o hacer petición
|
||
const $templateItem = $(`.template-item[data-template-id="${templateId}"]`);
|
||
// Efecto visual inmediato
|
||
$templateItem.addClass('animate__pulse');
|
||
setTimeout(() => $templateItem.removeClass('animate__pulse'), 1000);
|
||
// Hacer petición para obtener los detalles completos del template
|
||
$.ajax({
|
||
url: '/IMPORTADORES/templates_rapidos/ajax_obtener_templates',
|
||
method: 'GET',
|
||
dataType: 'json',
|
||
success: function(response) {
|
||
// Buscar en todas las colecciones posibles
|
||
let template = null;
|
||
if (response.templates && Array.isArray(response.templates)) {
|
||
template = response.templates.find(t => t.id == templateId);
|
||
}
|
||
if (!template && response.templates_personales && Array.isArray(response.templates_personales)) {
|
||
template = response.templates_personales.find(t => t.id == templateId);
|
||
}
|
||
if (!template && response.templates_otros && Array.isArray(response.templates_otros)) {
|
||
template = response.templates_otros.find(t => t.id == templateId);
|
||
}
|
||
if (template) {
|
||
applyDatabaseTemplate(template);
|
||
// Registrar uso del template
|
||
$.post('/IMPORTADORES/templates_rapidos/ajax_usar_template', {
|
||
id_template: templateId
|
||
});
|
||
showFloatingNotification(`Template "${template.nombre}" aplicado correctamente`, 'success');
|
||
} else {
|
||
showFloatingNotification('Template no encontrado', 'error');
|
||
}
|
||
},
|
||
error: function() {
|
||
showFloatingNotification('Error al aplicar template', 'error');
|
||
}
|
||
});
|
||
}
|
||
|
||
// ✅ FUNCIÓN MEJORADA: Mostrar mensaje cuando no hay templates
|
||
function mostrarMensajeSinTemplates($container) {
|
||
$container.html(`
|
||
<div class="text-center text-muted py-4">
|
||
<i class="fas fa-magic fa-3x mb-3 text-muted"></i>
|
||
<h6 class="text-muted">¡Crea tu primer template!</h6>
|
||
<p class="small text-muted mb-3">
|
||
Los templates te ayudan a llenar formularios automáticamente<br>
|
||
con configuraciones que usas frecuentemente
|
||
</p>
|
||
<div class="d-grid gap-2 d-md-block">
|
||
<a href="/IMPORTADORES/templates_rapidos/crear" class="btn btn-success btn-sm" target="_blank">
|
||
<i class="fas fa-plus me-1"></i>Crear Mi Primer Template
|
||
</a>
|
||
<button type="button" class="btn btn-outline-info btn-sm" onclick="mostrarEjemploTemplates()">
|
||
<i class="fas fa-question-circle me-1"></i>¿Cómo funcionan?
|
||
</button>
|
||
</div>
|
||
<div class="mt-3 p-3 bg-light rounded">
|
||
<small class="text-muted">
|
||
<strong>💡 Ejemplos de templates útiles:</strong><br>
|
||
🇨🇳 "Importación China" - FOB + CNY + General<br>
|
||
🇺🇸 "Importación USA" - FOB + USD + TLC<br>
|
||
🏢 "Comercializadora" - FOB + USD + COMERCIALIZADORA
|
||
</small>
|
||
</div>
|
||
</div>
|
||
`);
|
||
}
|
||
|
||
// ✅ NUEVAS FUNCIONES PARA GESTIÓN DE TEMPLATES
|
||
function editTemplate(templateId) {
|
||
window.open(`/IMPORTADORES/templates_rapidos/editar?id=${templateId}`, '_blank');
|
||
}
|
||
|
||
function deleteTemplate(templateId) {
|
||
Swal.fire({
|
||
title: '¿Eliminar template?',
|
||
text: 'Esta acción no se puede deshacer',
|
||
icon: 'warning',
|
||
showCancelButton: true,
|
||
confirmButtonColor: '#dc3545',
|
||
cancelButtonColor: '#6c757d',
|
||
confirmButtonText: 'Sí, eliminar',
|
||
cancelButtonText: 'Cancelar'
|
||
}).then((result) => {
|
||
if (result.isConfirmed) {
|
||
$.ajax({
|
||
url: `/IMPORTADORES/templates_rapidos/eliminar?id=${templateId}`,
|
||
method: 'GET',
|
||
success: function() {
|
||
showFloatingNotification('Template eliminado correctamente', 'success');
|
||
loadTemplatesFromDatabase(); // Recargar lista
|
||
},
|
||
error: function() {
|
||
showFloatingNotification('Error al eliminar template', 'error');
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// ✅ FUNCIÓN PARA MOSTRAR EJEMPLO DE TEMPLATES
|
||
function mostrarEjemploTemplates() {
|
||
Swal.fire({
|
||
title: '🎯 ¿Cómo funcionan los Templates?',
|
||
html: `
|
||
<div class="text-start">
|
||
<div class="mb-3">
|
||
<h6 class="text-primary mb-2">
|
||
<i class="fas fa-magic me-1"></i>
|
||
¿Qué son los Templates?
|
||
</h6>
|
||
<p class="small text-muted mb-0">
|
||
Los templates son configuraciones predefinidas que te permiten llenar formularios de importación
|
||
automáticamente con valores que usas frecuentemente.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<h6 class="text-success mb-2">
|
||
<i class="fas fa-lightbulb me-1"></i>
|
||
Ejemplos prácticos:
|
||
</h6>
|
||
<div class="small">
|
||
<div class="mb-2">
|
||
<strong>📦 "Importación China":</strong><br>
|
||
<span class="text-muted">FOB + CNY + General + Sin vinculación</span>
|
||
</div>
|
||
<div class="mb-2">
|
||
<strong>🇺🇸 "Importación USA":</strong><br>
|
||
<span class="text-muted">FOB + USD + TLC + Estados Unidos</span>
|
||
</div>
|
||
<div class="mb-2">
|
||
<strong>🏢 "Comercializadora":</strong><br>
|
||
<span class="text-muted">FOB + USD + COMERCIALIZADORA + Con vinculación</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<h6 class="text-warning mb-2">
|
||
<i class="fas fa-rocket me-1"></i>
|
||
Beneficios:
|
||
</h6>
|
||
<ul class="small text-muted mb-0">
|
||
<li>Ahorra tiempo rellenando campos repetitivos</li>
|
||
<li>Evita errores al usar configuraciones probadas</li>
|
||
<li>Acelera el proceso de creación de solicitudes</li>
|
||
<li>Personalizable según tus necesidades</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="alert alert-info small">
|
||
<i class="fas fa-info-circle me-1"></i>
|
||
<strong>Tip:</strong> Crea un template para cada tipo de importación que manejes regularmente.
|
||
</div>
|
||
</div>
|
||
`,
|
||
icon: 'question',
|
||
showCancelButton: true,
|
||
confirmButtonText: '<i class="fas fa-plus me-1"></i>Crear Mi Primer Template',
|
||
cancelButtonText: 'Entendido',
|
||
confirmButtonColor: '#28a745',
|
||
cancelButtonColor: '#6c757d'
|
||
}).then((result) => {
|
||
if (result.isConfirmed) {
|
||
window.open('/IMPORTADORES/templates_rapidos/crear', '_blank');
|
||
}
|
||
});
|
||
}
|
||
|
||
// ✅ FUNCIÓN PARA MOSTRAR ERRORES DE TEMPLATES
|
||
function mostrarErrorTemplates($container, errorMessage, suggestion = '', serverResponse = '') {
|
||
$container.html(`
|
||
<div class="text-center text-danger py-3">
|
||
<i class="fas fa-exclamation-triangle fa-2x mb-2"></i>
|
||
<div class="fw-bold">Error al cargar templates</div>
|
||
<div class="small text-muted mt-1">${errorMessage}</div>
|
||
${suggestion ? `<div class="small text-info mt-1">${suggestion}</div>` : ''}
|
||
${serverResponse}
|
||
<div class="mt-3 d-grid gap-2 d-md-flex justify-content-center">
|
||
<button class="btn btn-sm btn-outline-primary" onclick="loadTemplatesFromDatabase()">
|
||
<i class="fas fa-redo-alt me-1"></i>Reintentar
|
||
</button>
|
||
<a href="/IMPORTADORES/templates_rapidos/crear" class="btn btn-sm btn-outline-success" target="_blank">
|
||
<i class="fas fa-plus me-1"></i>Crear Template
|
||
</a>
|
||
<button class="btn btn-sm btn-outline-info" onclick="abrirDiagnostico()">
|
||
<i class="fas fa-wrench me-1"></i>Diagnóstico
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`);
|
||
}
|
||
|
||
// ✅ FUNCIÓN PARA ABRIR DIAGNÓSTICO
|
||
function abrirDiagnostico() {
|
||
window.open('/IMPORTADORES/test_templates.php', '_blank');
|
||
}
|
||
|
||
// ✅ MEJORAR LA INICIALIZACIÓN DEL TOGGLE DE TEMPLATES
|
||
$(document).ready(function() {
|
||
// Forzar carga de templates si el panel ya está expandido al cargar la página
|
||
if ($('#template-selector').hasClass('show')) {
|
||
alert('DEBUG: Panel de templates expandido al cargar');
|
||
loadTemplatesFromDatabase();
|
||
}
|
||
// Configurar el toggle de templates con eventos mejorados
|
||
$('#toggle-templates').on('click', function() {
|
||
alert('DEBUG: Click en toggle-templates');
|
||
const $this = $(this);
|
||
const $text = $('#toggle-text');
|
||
const $actions = $('#templates-quick-actions');
|
||
|
||
// Cambiar texto del botón según el estado
|
||
setTimeout(() => {
|
||
if ($('#template-selector').hasClass('show')) {
|
||
alert('DEBUG: Panel de templates expandido tras toggle');
|
||
$text.html('<i class="fas fa-eye-slash me-1"></i>Ocultar Templates');
|
||
$actions.slideDown(200);
|
||
|
||
// Cargar templates solo cuando se muestre
|
||
if ($('#templates-container').children().length <= 1) {
|
||
loadTemplatesFromDatabase();
|
||
}
|
||
} else {
|
||
$text.html('<i class="fas fa-eye me-1"></i>Mostrar Mis Templates');
|
||
$actions.slideUp(200);
|
||
}
|
||
}, 100);
|
||
});
|
||
|
||
// Botón de refresh templates
|
||
$('#refresh-templates').on('click', function() {
|
||
$(this).find('i').addClass('fa-spin');
|
||
loadTemplatesFromDatabase();
|
||
setTimeout(() => {
|
||
$(this).find('i').removeClass('fa-spin');
|
||
}, 1000);
|
||
});
|
||
|
||
// Mostrar siempre las acciones rápidas cuando no hay templates
|
||
$('#templates-quick-actions').show();
|
||
});
|
||
|
||
// ===================== CARGA DINÁMICA DE PROVEEDORES =====================
|
||
function cargarProveedores() {
|
||
const proveedorEl = document.getElementById('proveedor_id');
|
||
proveedorEl.innerHTML = '<option value="">Cargando proveedores…</option>';
|
||
fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||
.then(res => res.json())
|
||
.then(json => {
|
||
proveedorEl.innerHTML = '<option value="">-- Selecciona Proveedor --</option>';
|
||
(json.results || []).forEach(item => {
|
||
const opt = document.createElement('option');
|
||
opt.value = item.id;
|
||
opt.textContent = item.text;
|
||
proveedorEl.appendChild(opt);
|
||
});
|
||
})
|
||
.catch(() => {
|
||
proveedorEl.innerHTML = '<option value="">Error cargando proveedores</option>';
|
||
});
|
||
}
|
||
// ===================== CARGA DINÁMICA DE PEDIMENTOS =====================
|
||
function cargarPedimentosReferencia() {
|
||
const panel = document.getElementById('pedimentos-referencia');
|
||
panel.innerHTML = '<div class="spinner-border spinner-border-sm" role="status"><span class="visually-hidden">Cargando...</span></div><div class="small mt-1">Cargando pedimentos...</div>';
|
||
fetch('/IMPORTADORES/solicitud_importacion/ajax_pedimentos_catalogo')
|
||
.then(res => res.json())
|
||
.then(json => {
|
||
if (!json || !json.data || !json.data.length) {
|
||
panel.innerHTML = '<div class="text-muted small">No hay pedimentos recientes.</div>';
|
||
return;
|
||
}
|
||
panel.innerHTML = '';
|
||
json.data.forEach(ped => {
|
||
const div = document.createElement('div');
|
||
div.className = 'pedimento-item';
|
||
div.innerHTML = `<span class="pedimento-numero">${ped.numero}</span><div class="pedimento-cliente">${ped.cliente || ''}</div><div class="pedimento-meta"><span class="pedimento-clave">${ped.clave || ''}</span><span class="pedimento-fecha">${ped.fecha || ''}</span></div>`;
|
||
div.onclick = function() {
|
||
const input = document.getElementById('pedimento');
|
||
input.value = ped.numero;
|
||
div.classList.add('copiado');
|
||
setTimeout(() => div.classList.remove('copiado'), 1200);
|
||
input.focus();
|
||
};
|
||
panel.appendChild(div);
|
||
});
|
||
})
|
||
.catch(() => {
|
||
panel.innerHTML = '<div class="text-danger small">Error al cargar pedimentos.</div>';
|
||
});
|
||
}
|
||
// ===================== INICIALIZACIÓN =====================
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
cargarProveedores();
|
||
cargarPedimentosReferencia();
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|