2514 lines
91 KiB
PHP
2514 lines
91 KiB
PHP
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>📄 Manifestación de Valor - Pedimentos</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 href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.5/dist/signature_pad.umd.min.js"></script>
|
|
<style>
|
|
/* Modern Professional Styling */
|
|
:root {
|
|
--primary-color: #343a40;
|
|
--secondary-color: #495057;
|
|
--accent-color: #0d6efd;
|
|
--success-color: #198754;
|
|
--info-color: #0dcaf0;
|
|
--light-bg: #f8f9fa;
|
|
--card-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
|
--card-shadow-hover: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
|
--border-radius: 0.75rem;
|
|
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.sidebar {
|
|
width: var(--sidebar-width, 280px);
|
|
height: 100vh;
|
|
background: linear-gradient(180deg, #343a40 0%, #495057 100%);
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
padding-top: 56px;
|
|
z-index: 1040;
|
|
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.sidebar .nav-link {
|
|
font-weight: 600;
|
|
color: white;
|
|
transition: var(--transition);
|
|
border-radius: 0.5rem;
|
|
margin: 0.25rem 0.75rem;
|
|
}
|
|
|
|
.sidebar .nav-link:hover, .sidebar .nav-link.active {
|
|
background: linear-gradient(135deg, #495057 0%, #6c757d 100%);
|
|
color: #fff;
|
|
transform: translateX(5px);
|
|
}
|
|
|
|
.content {
|
|
margin-top: 56px;
|
|
padding: 2rem;
|
|
position: relative;
|
|
z-index: 1;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.content { margin-left: var(--sidebar-width, 280px); }
|
|
}
|
|
|
|
@media (max-width: 767.98px) {
|
|
.content { margin-left: 0; padding: 1rem; }
|
|
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
|
|
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
|
|
}
|
|
|
|
/* Enhanced Card Styling */
|
|
.card {
|
|
border-radius: var(--border-radius);
|
|
border: none;
|
|
box-shadow: var(--card-shadow);
|
|
backdrop-filter: blur(10px);
|
|
background: rgba(255, 255, 255, 0.95);
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.card-hover:hover {
|
|
transform: translateY(-4px);
|
|
box-shadow: var(--card-shadow-hover);
|
|
}
|
|
|
|
/* Professional Header Styling */
|
|
.page-header {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
border-radius: var(--border-radius);
|
|
padding: 2rem;
|
|
margin-bottom: 2rem;
|
|
color: white;
|
|
box-shadow: var(--card-shadow-hover);
|
|
}
|
|
|
|
.page-header h4 {
|
|
margin: 0;
|
|
font-weight: 700;
|
|
font-size: 1.75rem;
|
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.page-header .subtitle {
|
|
opacity: 0.9;
|
|
margin-top: 0.5rem;
|
|
font-size: 1rem;
|
|
font-weight: 400;
|
|
}
|
|
|
|
/* DataTable Enhancements */
|
|
table.dataTable thead th {
|
|
background: linear-gradient(135deg, #343a40 0%, #495057 100%);
|
|
color: #fff;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.5px;
|
|
padding: 1rem 0.75rem;
|
|
border: none;
|
|
}
|
|
|
|
table.dataTable tbody td {
|
|
padding: 0.875rem 0.75rem;
|
|
border-bottom: 1px solid #f1f3f4;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
table.dataTable tbody tr:hover {
|
|
background-color: #f8f9fa;
|
|
transform: scale(1.002);
|
|
}
|
|
|
|
/* Animation Classes */
|
|
.fade-in-up {
|
|
animation: fadeInUp 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(30px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
/* Enhanced Button Styling */
|
|
.btn-animated {
|
|
transition: var(--transition);
|
|
position: relative;
|
|
overflow: hidden;
|
|
font-weight: 600;
|
|
letter-spacing: 0.025em;
|
|
}
|
|
|
|
.btn-animated:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.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%;
|
|
}
|
|
|
|
/* Modern Card Grid System */
|
|
.pedimentos-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
gap: 1.5rem;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
@media (max-width: 576px) {
|
|
.pedimentos-grid {
|
|
grid-template-columns: 1fr;
|
|
gap: 1rem;
|
|
}
|
|
}
|
|
|
|
.pedimento-card {
|
|
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
|
border-radius: var(--border-radius);
|
|
padding: 1.5rem;
|
|
box-shadow: var(--card-shadow);
|
|
border: 2px solid #e9ecef;
|
|
transition: var(--transition);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.pedimento-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 4px;
|
|
background: linear-gradient(90deg, var(--accent-color), var(--success-color));
|
|
}
|
|
|
|
.pedimento-card:hover {
|
|
transform: translateY(-8px);
|
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
border-color: var(--accent-color);
|
|
}
|
|
|
|
.pedimento-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.pedimento-numero {
|
|
font-size: 1.25rem;
|
|
font-weight: 700;
|
|
color: var(--accent-color);
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.pedimento-status {
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 2rem;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.status-activo {
|
|
background: linear-gradient(135deg, #d1e7dd, #a3cfbb);
|
|
color: var(--success-color);
|
|
}
|
|
|
|
.status-inactivo {
|
|
background: linear-gradient(135deg, #e2e3e5, #ced4da);
|
|
color: #6c757d;
|
|
}
|
|
|
|
.pedimento-info {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 0.5rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid #f1f3f4;
|
|
}
|
|
|
|
.info-row:last-child {
|
|
border-bottom: none;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.info-label {
|
|
font-weight: 600;
|
|
color: #6c757d;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.info-value {
|
|
font-weight: 500;
|
|
color: #495057;
|
|
}
|
|
|
|
.pedimento-actions {
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.btn-mve {
|
|
flex: 1;
|
|
background: linear-gradient(135deg, #17a2b8 0%, #138496 100%);
|
|
border: none;
|
|
color: white;
|
|
padding: 0.75rem 1rem;
|
|
border-radius: 0.5rem;
|
|
font-weight: 600;
|
|
transition: var(--transition);
|
|
text-transform: uppercase;
|
|
font-size: 0.875rem;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.btn-mve:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px rgba(23, 162, 184, 0.3);
|
|
color: white;
|
|
}
|
|
|
|
/* KPI Band */
|
|
.kpi-card {
|
|
border-left: 6px solid var(--accent-color);
|
|
}
|
|
.kpi-value {
|
|
font-size: 1.6rem;
|
|
font-weight: 800;
|
|
line-height: 1;
|
|
}
|
|
.kpi-label {
|
|
color: #6c757d;
|
|
font-weight: 600;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
|
|
/* Search and Filter Bar */
|
|
.filter-bar {
|
|
background: rgba(255, 255, 255, 0.95);
|
|
padding: 1.5rem;
|
|
border-radius: var(--border-radius);
|
|
box-shadow: var(--card-shadow);
|
|
margin-bottom: 2rem;
|
|
backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.search-input {
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 2rem;
|
|
padding: 0.75rem 1.5rem;
|
|
font-size: 1rem;
|
|
transition: var(--transition);
|
|
width: 100%;
|
|
}
|
|
|
|
.search-input:focus {
|
|
border-color: var(--accent-color);
|
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
outline: none;
|
|
}
|
|
|
|
.filter-select {
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 0.5rem;
|
|
padding: 0.75rem 1rem;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.filter-select:focus {
|
|
border-color: var(--accent-color);
|
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
outline: none;
|
|
}
|
|
|
|
/* Loading and Empty States */
|
|
.loading-spinner {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
min-height: 200px;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 3rem 1rem;
|
|
color: #6c757d;
|
|
}
|
|
|
|
.empty-state i {
|
|
font-size: 4rem;
|
|
margin-bottom: 1rem;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* Modern Slide Panel System */
|
|
.slide-panel {
|
|
position: fixed;
|
|
top: 0;
|
|
right: -100%;
|
|
width: 70%;
|
|
max-width: 900px;
|
|
height: 100vh;
|
|
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
|
box-shadow: -10px 0 30px rgba(0, 0, 0, 0.2);
|
|
z-index: 99999;
|
|
transition: right 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
overflow-y: auto;
|
|
border-radius: 1rem 0 0 1rem;
|
|
}
|
|
|
|
.slide-panel.active {
|
|
right: 0;
|
|
}
|
|
|
|
.slide-overlay {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
z-index: 99998;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: all 0.3s ease;
|
|
backdrop-filter: blur(5px);
|
|
}
|
|
|
|
.slide-overlay.active {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
|
|
.panel-header {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 2rem;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
}
|
|
|
|
.panel-title {
|
|
margin: 0;
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.panel-subtitle {
|
|
margin: 0.5rem 0 0 0;
|
|
opacity: 0.9;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.panel-close {
|
|
position: absolute;
|
|
top: 1.5rem;
|
|
right: 2rem;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border: none;
|
|
color: white;
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.panel-close:hover {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
.panel-body {
|
|
padding: 2rem;
|
|
}
|
|
|
|
.panel-section {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.section-card {
|
|
background: rgba(255, 255, 255, 0.8);
|
|
border-radius: var(--border-radius);
|
|
padding: 1.5rem;
|
|
box-shadow: var(--card-shadow);
|
|
border: 2px solid #f1f3f4;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.section-card:hover {
|
|
border-color: #e9ecef;
|
|
box-shadow: var(--card-shadow-hover);
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 1.5rem;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 2px solid #f1f3f4;
|
|
}
|
|
|
|
.section-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 1rem;
|
|
color: white;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.section-info h6 {
|
|
margin: 0;
|
|
font-weight: 700;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.section-info small {
|
|
color: #6c757d;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Step Navigation */
|
|
.step-nav {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin: 2rem 0;
|
|
gap: 0.75rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.step-btn {
|
|
padding: 0.5rem 1rem;
|
|
border: 2px solid #e9ecef;
|
|
background: white;
|
|
border-radius: 1.5rem;
|
|
font-weight: 600;
|
|
font-size: 0.875rem;
|
|
transition: var(--transition);
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
color: #495057;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
user-select: none;
|
|
white-space: nowrap;
|
|
min-width: fit-content;
|
|
}
|
|
|
|
.step-btn:focus {
|
|
outline: none;
|
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
.step-btn.active {
|
|
background: var(--accent-color);
|
|
border-color: var(--accent-color);
|
|
color: white !important;
|
|
}
|
|
|
|
.step-btn:hover:not(.active) {
|
|
border-color: var(--accent-color);
|
|
color: var(--accent-color);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
/* Enhanced Responsive Design */
|
|
|
|
/* Large Tablets and Small Desktops */
|
|
@media (max-width: 992px) {
|
|
.slide-panel {
|
|
width: 85%;
|
|
max-width: 800px;
|
|
}
|
|
|
|
.pedimento-card {
|
|
margin-bottom: 1rem;
|
|
}
|
|
}
|
|
|
|
/* Tablets */
|
|
@media (max-width: 768px) {
|
|
.slide-panel {
|
|
width: 95%;
|
|
border-radius: 1rem 0 0 0;
|
|
}
|
|
|
|
.pedimentos-grid {
|
|
grid-template-columns: 1fr;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.panel-header {
|
|
padding: 1.5rem 1rem;
|
|
}
|
|
|
|
.panel-body {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.step-nav {
|
|
gap: 0.5rem;
|
|
margin: 1.5rem 0;
|
|
}
|
|
|
|
.step-btn {
|
|
padding: 0.4rem 0.75rem;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.step-btn i {
|
|
font-size: 0.875rem;
|
|
margin-right: 0.25rem !important;
|
|
}
|
|
|
|
/* Hacer formularios más compactos en tablets */
|
|
.section-card {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.row.mb-3 {
|
|
padding: 1rem;
|
|
margin-bottom: 1rem !important;
|
|
}
|
|
|
|
/* Ajustar el grid de formularios para tablets */
|
|
.row .col-md-4, .row .col-md-6 {
|
|
margin-bottom: 1rem;
|
|
}
|
|
}
|
|
|
|
/* Mobile Phones */
|
|
@media (max-width: 576px) {
|
|
.content {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.page-header {
|
|
padding: 1.5rem 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.page-header h4 {
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.filter-bar {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.slide-panel {
|
|
width: 100%;
|
|
border-radius: 1rem 0 0 0;
|
|
right: -100%;
|
|
}
|
|
|
|
.step-nav {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.step-btn {
|
|
width: 100%;
|
|
max-width: 280px;
|
|
justify-content: center;
|
|
padding: 0.75rem 1rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* Formularios mobile-first */
|
|
.section-card {
|
|
padding: 0.75rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.section-header {
|
|
flex-direction: column;
|
|
text-align: center;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.section-icon {
|
|
margin-right: 0;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
/* Hacer todos los campos full-width en mobile */
|
|
.row .col-md-3,
|
|
.row .col-md-4,
|
|
.row .col-md-6 {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
/* Pedimento cards más compactas */
|
|
.pedimento-card {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.pedimento-header {
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.info-row {
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.info-label {
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.btn-mve {
|
|
font-size: 0.875rem;
|
|
padding: 0.75rem;
|
|
}
|
|
}
|
|
|
|
/* Extra Small Devices */
|
|
@media (max-width: 400px) {
|
|
.page-header h4 {
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
.pedimento-numero {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.step-btn {
|
|
font-size: 0.75rem;
|
|
padding: 0.5rem 0.75rem;
|
|
}
|
|
|
|
.section-card {
|
|
padding: 0.5rem;
|
|
}
|
|
}
|
|
|
|
/* Enhanced Factura Selection Styling */
|
|
.factura-item {
|
|
border: 2px solid #e9ecef;
|
|
border-radius: var(--border-radius);
|
|
padding: 1rem;
|
|
margin-bottom: 0.75rem;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.factura-item::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: -100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.1), transparent);
|
|
transition: left 0.5s;
|
|
}
|
|
|
|
.factura-item:hover {
|
|
border-color: var(--accent-color);
|
|
box-shadow: 0 4px 12px rgba(13, 110, 253, 0.15);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.factura-item:hover::before {
|
|
left: 100%;
|
|
}
|
|
|
|
.factura-item.selected {
|
|
border-color: var(--success-color);
|
|
background: linear-gradient(135deg, #d1e7dd 0%, #a3cfbb 100%);
|
|
box-shadow: 0 6px 20px rgba(25, 135, 84, 0.2);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.factura-numero {
|
|
font-weight: 700;
|
|
color: var(--accent-color);
|
|
font-size: 1.1rem;
|
|
margin-bottom: 0.25rem;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.factura-numero::before {
|
|
content: '📄';
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
.factura-item.selected .factura-numero {
|
|
color: var(--success-color);
|
|
}
|
|
|
|
.factura-item.selected .factura-numero::before {
|
|
content: '✅';
|
|
}
|
|
|
|
.factura-details {
|
|
font-size: 0.875rem;
|
|
color: #6c757d;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.factura-item.selected .factura-details {
|
|
color: #495057;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Status Badge Enhancements */
|
|
.badge {
|
|
font-weight: 600;
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: 2rem;
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.025em;
|
|
}
|
|
|
|
/* Enhanced Form Controls */
|
|
.form-control {
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 0.5rem;
|
|
padding: 0.75rem 1rem;
|
|
transition: var(--transition);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--accent-color);
|
|
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
outline: none;
|
|
}
|
|
|
|
.form-label {
|
|
font-weight: 600;
|
|
color: #495057;
|
|
margin-bottom: 0.5rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* Enhanced Radio Buttons */
|
|
.form-check-input[type="radio"] {
|
|
border: 2px solid #dee2e6;
|
|
margin-top: 0.125rem;
|
|
width: 1.25rem;
|
|
height: 1.25rem;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.form-check-input[type="radio"]:checked {
|
|
background-color: var(--success-color);
|
|
border-color: var(--success-color);
|
|
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='2' fill='%23fff'/%3E%3C/svg%3E");
|
|
}
|
|
|
|
.form-check-input[type="radio"]:focus {
|
|
border-color: var(--success-color);
|
|
box-shadow: 0 0 0 0.2rem rgba(25, 135, 84, 0.25);
|
|
}
|
|
|
|
.form-check-label {
|
|
font-weight: 500;
|
|
color: #495057;
|
|
margin-left: 0.5rem;
|
|
}
|
|
|
|
.form-check-inline {
|
|
margin-right: 1rem;
|
|
}
|
|
|
|
/* Form Section Styling */
|
|
.row.mb-3 {
|
|
background: rgba(255, 255, 255, 0.7);
|
|
border-radius: 0.75rem;
|
|
padding: 1.25rem;
|
|
margin-bottom: 1.5rem !important;
|
|
border: 1px solid #f1f3f4;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.row.mb-3:hover {
|
|
background: rgba(255, 255, 255, 0.9);
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
/* Modal Footer Enhancement */
|
|
.modal-footer {
|
|
background: #f8f9fa;
|
|
border-top: 2px solid #e9ecef;
|
|
padding: 1.5rem 2rem;
|
|
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
|
}
|
|
|
|
.modal-footer .btn {
|
|
padding: 0.75rem 2rem;
|
|
font-weight: 600;
|
|
border-radius: 2rem;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
/* Save Button Special Styling */
|
|
#btnGuardarDatosMVE {
|
|
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
|
|
border: none;
|
|
color: white;
|
|
padding: 0.875rem 2rem;
|
|
border-radius: 2rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
|
|
transition: var(--transition);
|
|
}
|
|
|
|
#btnGuardarDatosMVE:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px rgba(0, 123, 255, 0.4);
|
|
}
|
|
|
|
/* Loading States */
|
|
.spinner-border {
|
|
width: 2rem;
|
|
height: 2rem;
|
|
border-width: 0.25rem;
|
|
}
|
|
|
|
/* Alert Enhancements */
|
|
.alert {
|
|
border-radius: 0.75rem;
|
|
border: none;
|
|
font-weight: 500;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.alert-warning {
|
|
background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
|
|
color: #856404;
|
|
}
|
|
|
|
.alert-danger {
|
|
background: linear-gradient(135deg, #f8d7da 0%, #f5c6cb 100%);
|
|
color: #721c24;
|
|
}
|
|
|
|
/* Ensure SweetAlert2 toasts are always on top of slide panel */
|
|
.swal2-container {
|
|
z-index: 200000 !important;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="content">
|
|
<div class="page-header fade-in-up">
|
|
<h4>📄 Manifestación de Valor - Pedimentos</h4>
|
|
<p class="subtitle mb-0">Gestiona y solicita manifestaciones de valor para tus pedimentos de importación</p>
|
|
</div>
|
|
<!-- Barra de búsqueda y filtros -->
|
|
<div class="filter-bar fade-in-up">
|
|
<div class="row g-3 align-items-end">
|
|
<div class="col-12 col-md-6 col-lg-5">
|
|
<label class="form-label fw-bold text-muted mb-2 d-block d-md-none">Buscar:</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-white border-end-0" style="border: 2px solid #e9ecef; border-radius: 2rem 0 0 2rem;">
|
|
<i class="fas fa-search text-muted"></i>
|
|
</span>
|
|
<input type="text" class="search-input border-start-0" id="searchInput" placeholder="Buscar por pedimento, RFC o cliente..." style="border-radius: 0 2rem 2rem 0;">
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3 col-lg-3">
|
|
<label class="form-label fw-bold text-muted mb-2 d-block d-md-none">Estado:</label>
|
|
<select class="filter-select form-select" id="statusFilter">
|
|
<option value="">Todos los estados</option>
|
|
<option value="Activo">Activos</option>
|
|
<option value="Inactivo">Inactivos</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-6 col-md-3 col-lg-3">
|
|
<label class="form-label fw-bold text-muted mb-2 d-block d-md-none">Mostrar:</label>
|
|
<div class="d-flex align-items-center gap-2">
|
|
<span class="text-muted fw-bold d-none d-md-inline">Mostrar:</span>
|
|
<select class="filter-select form-select" id="perPageFilter">
|
|
<option value="10">10 por página</option>
|
|
<option value="25" selected>25 por página</option>
|
|
<option value="50">50 por página</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-md-12 col-lg-4 d-flex align-items-center justify-content-lg-end">
|
|
<ul class="nav nav-pills ms-auto" id="viewTabs">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" href="#" data-view="pendientes">Pendientes <span class="badge bg-secondary ms-1" id="countPend">0</span></a>
|
|
</li>
|
|
<li class="nav-item ms-2">
|
|
<a class="nav-link" href="#" data-view="completos">Completos <span class="badge bg-secondary ms-1" id="countComp">0</span></a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Grid de pedimentos -->
|
|
<div class="fade-in-up">
|
|
<!-- KPI Band -->
|
|
<div id="kpiBand" class="row g-3 mb-3">
|
|
<div class="col-12 col-md-4">
|
|
<div class="card p-3 kpi-card">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<div class="kpi-label">Total (filtrados)</div>
|
|
<div id="kpiTotal" class="kpi-value">0</div>
|
|
</div>
|
|
<i class="fas fa-list text-primary" style="font-size: 1.5rem;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-md-4">
|
|
<div class="card p-3 kpi-card" style="border-left-color:#fd7e14;">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<div class="kpi-label">Pendientes</div>
|
|
<div id="kpiPend" class="kpi-value">0</div>
|
|
</div>
|
|
<i class="fas fa-hourglass-half text-warning" style="font-size: 1.5rem;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-md-4">
|
|
<div class="card p-3 kpi-card" style="border-left-color:#198754;">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<div class="kpi-label">Completos</div>
|
|
<div id="kpiComp" class="kpi-value">0</div>
|
|
</div>
|
|
<i class="fas fa-check-circle text-success" style="font-size: 1.5rem;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="pedimentosContainer">
|
|
<div class="loading-spinner">
|
|
<div class="spinner-border text-primary" style="width: 3rem; height: 3rem;">
|
|
<span class="visually-hidden">Cargando...</span>
|
|
</div>
|
|
<p class="mt-3 text-muted fw-bold">Cargando pedimentos...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Paginación -->
|
|
<div class="d-flex justify-content-between align-items-center mt-4" id="paginationContainer" style="display: none !important;">
|
|
<div class="text-muted">
|
|
Mostrando <span id="showingFrom">0</span> a <span id="showingTo">0</span> de <span id="totalRecords">0</span> registros <span id="viewLabel"></span>
|
|
</div>
|
|
<nav>
|
|
<ul class="pagination mb-0" id="pagination">
|
|
<!-- Pagination buttons will be generated here -->
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Slide Panel para MVE -->
|
|
<div class="slide-overlay" id="slideOverlay"></div>
|
|
<div class="slide-panel" id="slidePanel">
|
|
<div class="panel-header">
|
|
<h4 class="panel-title">📋 Manifestación de Valor</h4>
|
|
<p class="panel-subtitle">Pedimento: <span id="panelPedimento"></span></p>
|
|
<button class="panel-close" id="panelClose">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="panel-body">
|
|
<!-- Selección de Facturas -->
|
|
<div class="panel-section">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: linear-gradient(135deg, #17a2b8, #138496);">
|
|
<i class="fas fa-file-invoice"></i>
|
|
</div>
|
|
<div class="section-info">
|
|
<h6>Facturas del Pedimento</h6>
|
|
<small>Selecciona la factura para procesar</small>
|
|
</div>
|
|
</div>
|
|
<div id="facturasContainer" style="max-height: 300px; overflow-y: auto;">
|
|
<!-- Las facturas se cargan aquí -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navegación por pasos -->
|
|
<div class="step-nav" id="stepNavigation" style="display: none;">
|
|
<button class="step-btn active" data-step="65" onclick="cambiarSeccionMVE('65')">
|
|
<i class="fas fa-plus-circle me-2"></i>Art. 65
|
|
</button>
|
|
<button class="step-btn" data-step="66" onclick="cambiarSeccionMVE('66')">
|
|
<i class="fas fa-minus-circle me-2"></i>Art. 66
|
|
</button>
|
|
<button class="step-btn" data-step="precio-pagado" onclick="cambiarSeccionMVE('precio-pagado')">
|
|
<i class="fas fa-money-bill-wave me-2"></i>Precio Pagado
|
|
</button>
|
|
<button class="step-btn" data-step="precio-pagar" onclick="cambiarSeccionMVE('precio-pagar')">
|
|
<i class="fas fa-credit-card me-2"></i>Precio por Pagar
|
|
</button>
|
|
<button class="step-btn" data-step="compenso-pago" onclick="cambiarSeccionMVE('compenso-pago')">
|
|
<i class="fas fa-balance-scale me-2"></i>Compenso Pago
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Formularios MVE -->
|
|
<!-- Sección de Artículo 65 -->
|
|
<div class="panel-section" id="art65Panel" style="display: none;">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: linear-gradient(135deg, #28a745, #20c997);">
|
|
<i class="fas fa-plus"></i>
|
|
</div>
|
|
<div class="section-info">
|
|
<h6>Artículo 65 - Incrementables</h6>
|
|
<small>Conceptos que incrementan el valor en aduana</small>
|
|
</div>
|
|
</div>
|
|
<div id="art65Form">
|
|
<!-- Los formularios Art 65 se cargarán aquí dinámicamente -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección de Artículo 66 -->
|
|
<div class="panel-section" id="art66Panel" style="display: none;">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: linear-gradient(135deg, #0d6efd, #0dcaf0);">
|
|
<i class="fas fa-minus"></i>
|
|
</div>
|
|
<div class="section-info">
|
|
<h6>Artículo 66 - Decrementables</h6>
|
|
<small>Conceptos que no forman parte del valor en aduana</small>
|
|
</div>
|
|
</div>
|
|
<div id="art66Form">
|
|
<!-- Los formularios Art 66 se cargarán aquí dinámicamente -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección de Precio Pagado -->
|
|
<div class="panel-section" id="precioPagadoPanel" style="display: none;">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: linear-gradient(135deg, #28a745, #20c997);">
|
|
<i class="fas fa-money-bill-wave"></i>
|
|
</div>
|
|
<div class="section-info">
|
|
<h6>Precio Pagado</h6>
|
|
<small>Montos ya pagados por las mercancías</small>
|
|
</div>
|
|
</div>
|
|
<div id="precioPagadoForm">
|
|
<!-- Los formularios de Precio Pagado se cargarán aquí dinámicamente -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección de Precio por Pagar -->
|
|
<div class="panel-section" id="precioPagarPanel" style="display: none;">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: linear-gradient(135deg, #ffc107, #fd7e14);">
|
|
<i class="fas fa-credit-card"></i>
|
|
</div>
|
|
<div class="section-info">
|
|
<h6>Precio por Pagar</h6>
|
|
<small>Montos pendientes de pago</small>
|
|
</div>
|
|
</div>
|
|
<div id="precioPagarForm">
|
|
<!-- Los formularios de Precio por Pagar se cargarán aquí dinámicamente -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sección de Compenso Pago -->
|
|
<div class="panel-section" id="compensoPagoPanel" style="display: none;">
|
|
<div class="section-card">
|
|
<div class="section-header">
|
|
<div class="section-icon" style="background: linear-gradient(135deg, #6f42c1, #e83e8c);">
|
|
<i class="fas fa-balance-scale"></i>
|
|
</div>
|
|
<div class="section-info">
|
|
<h6>Compenso Pago</h6>
|
|
<small>Ajustes y compensaciones de pago</small>
|
|
</div>
|
|
</div>
|
|
<div id="compensoPagoForm">
|
|
<!-- Los formularios de Compenso Pago se cargarán aquí dinámicamente -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Acción principal -->
|
|
<div class="panel-section">
|
|
<div class="d-flex gap-3 justify-content-end">
|
|
<button type="button" class="btn btn-success btn-animated" id="btnConfirmarMVE" style="display: none;">
|
|
<i class="fas fa-paper-plane me-2"></i>Solicitar Manifestación ahora
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
let pedimentoSeleccionado = null;
|
|
let facturaSeleccionadaId = null;
|
|
let importadorRFC = null;
|
|
let allPedimentos = [];
|
|
let filteredPedimentos = [];
|
|
let currentPage = 1;
|
|
let perPage = 25;
|
|
let pedimentosCompletos = new Set();
|
|
let pedimentoEstados = new Map(); // pedimento_id -> { total_facturas, respondidas, completo }
|
|
let activeView = 'pendientes';
|
|
|
|
// Cargar datos iniciales
|
|
cargarPedimentos();
|
|
|
|
// Configurar eventos de filtros
|
|
$('#searchInput').on('input', function() {
|
|
filtrarPedimentos();
|
|
});
|
|
|
|
// -------- AUTOGUARDADO POR SECCIÓN ---------
|
|
const debounce = (fn, delay=600) => {
|
|
let t; return function() { clearTimeout(t); const ctx=this, args=arguments; t=setTimeout(()=>fn.apply(ctx,args), delay); };
|
|
};
|
|
|
|
// Normaliza diferentes formatos de fecha a 'YYYY-MM-DD' para inputs type="date"
|
|
function formatDateInput(val) {
|
|
if (!val) return '';
|
|
if (val instanceof Date && !isNaN(val)) {
|
|
return val.toISOString().slice(0,10);
|
|
}
|
|
let s = String(val).trim();
|
|
if (!s) return '';
|
|
// Si ya viene como YYYY-MM-DD o con hora, tomar los primeros 10
|
|
if (/^\d{4}-\d{2}-\d{2}/.test(s)) return s.slice(0,10);
|
|
// Formato YYYY/MM/DD
|
|
if (/^\d{4}\/\d{1,2}\/\d{1,2}$/.test(s)) {
|
|
const [y,m,d] = s.split('/');
|
|
return `${y}-${String(m).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
|
|
}
|
|
// Formato DD/MM/YYYY o MM/DD/YYYY (intentar deducir)
|
|
if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(s)) {
|
|
const [a,b,y] = s.split('/');
|
|
// Si el primer número > 12, asumimos DD/MM/YYYY
|
|
if (parseInt(a,10) > 12) {
|
|
return `${y}-${String(b).padStart(2,'0')}-${String(a).padStart(2,'0')}`;
|
|
}
|
|
// Si el segundo > 12, asumimos MM/DD/YYYY
|
|
if (parseInt(b,10) > 12) {
|
|
return `${y}-${String(a).padStart(2,'0')}-${String(b).padStart(2,'0')}`;
|
|
}
|
|
// Ambiguo: por defecto DD/MM/YYYY
|
|
return `${y}-${String(b).padStart(2,'0')}-${String(a).padStart(2,'0')}`;
|
|
}
|
|
// Intentar parseo general
|
|
const d = new Date(s);
|
|
if (!isNaN(d)) return d.toISOString().slice(0,10);
|
|
return '';
|
|
}
|
|
|
|
// Etiquetas legibles por sección para validar campos vacíos
|
|
const etiquetasSecciones = {
|
|
'65': {
|
|
fecha_transporte: 'Art. 65 - Fecha transporte',
|
|
importe_transporte: 'Art. 65 - Importe transporte',
|
|
fecha_descuentos: 'Art. 65 - Fecha descuentos',
|
|
importe_descuentos: 'Art. 65 - Importe descuentos',
|
|
fecha_posteriores: 'Art. 65 - Fecha gastos posteriores',
|
|
importe_posteriores: 'Art. 65 - Importe gastos posteriores',
|
|
fecha_contribuciones: 'Art. 65 - Fecha contribuciones',
|
|
importe_contribuciones: 'Art. 65 - Importe contribuciones',
|
|
fecha_pagos_vendedor: 'Art. 65 - Fecha pagos al vendedor',
|
|
importe_pagos_vendedor: 'Art. 65 - Importe pagos al vendedor'
|
|
},
|
|
'66': {
|
|
fecha_comisiones: 'Art. 66 - Fecha comisiones',
|
|
importe_comisiones: 'Art. 66 - Importe comisiones',
|
|
cargo_comisiones: 'Art. 66 - ¿Comisiones a cargo del importador?',
|
|
fecha_envases: 'Art. 66 - Fecha envases',
|
|
importe_envases: 'Art. 66 - Importe envases',
|
|
cargo_envases: 'Art. 66 - ¿Envases a cargo del importador?',
|
|
fecha_embalaje: 'Art. 66 - Fecha embalaje',
|
|
importe_embalaje: 'Art. 66 - Importe embalaje',
|
|
cargo_embalaje: 'Art. 66 - ¿Embalaje a cargo del importador?',
|
|
fecha_transporte_dec: 'Art. 66 - Fecha transporte (dec.)',
|
|
importe_transporte_dec: 'Art. 66 - Importe transporte (dec.)',
|
|
cargo_transporte_dec: 'Art. 66 - ¿Transporte (dec.) a cargo del importador?',
|
|
fecha_ingenieria: 'Art. 66 - Fecha ingeniería',
|
|
importe_ingenieria: 'Art. 66 - Importe ingeniería',
|
|
cargo_ingenieria: 'Art. 66 - ¿Ingeniería a cargo del importador?',
|
|
fecha_regalias: 'Art. 66 - Fecha regalías',
|
|
importe_regalias: 'Art. 66 - Importe regalías',
|
|
cargo_regalias: 'Art. 66 - ¿Regalías a cargo del importador?',
|
|
fecha_producto: 'Art. 66 - Fecha producto',
|
|
importe_producto: 'Art. 66 - Importe producto',
|
|
cargo_producto: 'Art. 66 - ¿Producto a cargo del importador?'
|
|
},
|
|
'precio_pagado': {
|
|
fecha_precio_pagado: 'Precio Pagado - Fecha de pago',
|
|
importe_precio_pagado: 'Precio Pagado - Importe pagado',
|
|
moneda_precio_pagado: 'Precio Pagado - Moneda',
|
|
forma_pago_precio_pagado: 'Precio Pagado - Forma de pago',
|
|
referencia_precio_pagado: 'Precio Pagado - Referencia de pago'
|
|
},
|
|
'precio_pagar': {
|
|
fecha_limite_pago: 'Precio por Pagar - Fecha límite',
|
|
importe_precio_pagar: 'Precio por Pagar - Importe pendiente',
|
|
moneda_precio_pagar: 'Precio por Pagar - Moneda',
|
|
terminos_precio_pagar: 'Precio por Pagar - Términos de pago',
|
|
observaciones_precio_pagar: 'Precio por Pagar - Observaciones'
|
|
},
|
|
'compenso': {
|
|
fecha_compenso: 'Compenso - Fecha',
|
|
importe_compenso: 'Compenso - Importe',
|
|
tipo_compenso: 'Compenso - Tipo',
|
|
motivo_compenso: 'Compenso - Motivo',
|
|
documentos_compenso: 'Compenso - Documentos',
|
|
descripcion_compenso: 'Compenso - Descripción'
|
|
}
|
|
};
|
|
|
|
function validarSecciones() {
|
|
const secciones = ['65','66','precio_pagado','precio_pagar','compenso'];
|
|
const faltantes = {};
|
|
let completos = true;
|
|
secciones.forEach(sec => {
|
|
const datos = recolectarDatos(sec);
|
|
const etiquetas = etiquetasSecciones[sec] || {};
|
|
const vacios = [];
|
|
Object.keys(etiquetas).forEach(k => {
|
|
let v = datos[k];
|
|
// Para radios cargo_*, considerar vacío si no hay Si/No
|
|
if (k.startsWith('cargo_')) {
|
|
if (!v || (v !== 'Si' && v !== 'No')) vacios.push(etiquetas[k]);
|
|
} else {
|
|
if (v === undefined || v === null || String(v).trim() === '') vacios.push(etiquetas[k]);
|
|
}
|
|
});
|
|
if (vacios.length > 0) {
|
|
completos = false;
|
|
faltantes[sec] = vacios;
|
|
}
|
|
});
|
|
return { completos, faltantes };
|
|
}
|
|
|
|
function recolectarDatos(seccion) {
|
|
if (seccion === '65') {
|
|
return {
|
|
fecha_transporte: $('#fecha_transporte').val(),
|
|
importe_transporte: $('#importe_transporte').val(),
|
|
fecha_descuentos: $('#fecha_descuentos').val(),
|
|
importe_descuentos: $('#importe_descuentos').val(),
|
|
fecha_posteriores: $('#fecha_posteriores').val(),
|
|
importe_posteriores: $('#importe_posteriores').val(),
|
|
fecha_contribuciones: $('#fecha_contribuciones').val(),
|
|
importe_contribuciones: $('#importe_contribuciones').val(),
|
|
fecha_pagos_vendedor: $('#fecha_pagos_vendedor').val(),
|
|
importe_pagos_vendedor: $('#importe_pagos_vendedor').val()
|
|
};
|
|
}
|
|
if (seccion === '66') {
|
|
return {
|
|
fecha_comisiones: $('#fecha_comisiones').val(),
|
|
importe_comisiones: $('#importe_comisiones').val(),
|
|
cargo_comisiones: $('input[name="cargo_comisiones"]:checked').val(),
|
|
fecha_envases: $('#fecha_envases').val(),
|
|
importe_envases: $('#importe_envases').val(),
|
|
cargo_envases: $('input[name="cargo_envases"]:checked').val(),
|
|
fecha_embalaje: $('#fecha_embalaje').val(),
|
|
importe_embalaje: $('#importe_embalaje').val(),
|
|
cargo_embalaje: $('input[name="cargo_embalaje"]:checked').val(),
|
|
fecha_transporte_dec: $('#fecha_transporte_dec').val(),
|
|
importe_transporte_dec: $('#importe_transporte_dec').val(),
|
|
cargo_transporte_dec: $('input[name="cargo_transporte_dec"]:checked').val(),
|
|
fecha_ingenieria: $('#fecha_ingenieria').val(),
|
|
importe_ingenieria: $('#importe_ingenieria').val(),
|
|
cargo_ingenieria: $('input[name="cargo_ingenieria"]:checked').val(),
|
|
fecha_regalias: $('#fecha_regalias').val(),
|
|
importe_regalias: $('#importe_regalias').val(),
|
|
cargo_regalias: $('input[name="cargo_regalias"]:checked').val(),
|
|
fecha_producto: $('#fecha_producto').val(),
|
|
importe_producto: $('#importe_producto').val(),
|
|
cargo_producto: $('input[name="cargo_producto"]:checked').val()
|
|
};
|
|
}
|
|
if (seccion === 'precio_pagado') {
|
|
return {
|
|
fecha_precio_pagado: $('#fecha_precio_pagado').val(),
|
|
importe_precio_pagado: $('#importe_precio_pagado').val(),
|
|
moneda_precio_pagado: $('#moneda_precio_pagado').val(),
|
|
forma_pago_precio_pagado: $('#forma_pago_precio_pagado').val(),
|
|
referencia_precio_pagado: $('#referencia_precio_pagado').val()
|
|
};
|
|
}
|
|
if (seccion === 'precio_pagar') {
|
|
return {
|
|
fecha_limite_pago: $('#fecha_limite_pago').val(),
|
|
importe_precio_pagar: $('#importe_precio_pagar').val(),
|
|
moneda_precio_pagar: $('#moneda_precio_pagar').val(),
|
|
terminos_precio_pagar: $('#terminos_precio_pagar').val(),
|
|
observaciones_precio_pagar: $('#observaciones_precio_pagar').val()
|
|
};
|
|
}
|
|
if (seccion === 'compenso') {
|
|
return {
|
|
fecha_compenso: $('#fecha_compenso').val(),
|
|
importe_compenso: $('#importe_compenso').val(),
|
|
tipo_compenso: $('#tipo_compenso').val(),
|
|
motivo_compenso: $('#motivo_compenso').val(),
|
|
documentos_compenso: $('#documentos_compenso').val(),
|
|
descripcion_compenso: $('#descripcion_compenso').val()
|
|
};
|
|
}
|
|
return {};
|
|
}
|
|
|
|
// Toast helper
|
|
const lastToastAt = { };
|
|
function toastGuardado(seccion) {
|
|
const ahora = Date.now();
|
|
if (lastToastAt[seccion] && (ahora - lastToastAt[seccion] < 1200)) return; // evita spam
|
|
lastToastAt[seccion] = ahora;
|
|
const nombres = { '65': 'Art. 65', '66': 'Art. 66', 'precio_pagado': 'Precio Pagado', 'precio_pagar': 'Precio por Pagar', 'compenso': 'Compenso Pago' };
|
|
const titulo = (nombres[seccion] || 'Sección') + ' guardado';
|
|
Swal.fire({
|
|
toast: true,
|
|
position: 'top-end',
|
|
icon: 'success',
|
|
title: titulo,
|
|
showConfirmButton: false,
|
|
timer: 1600,
|
|
timerProgressBar: true
|
|
});
|
|
}
|
|
|
|
function guardarSeccion(seccion) {
|
|
if (!facturaSeleccionadaId || !pedimentoSeleccionado) return;
|
|
const datos = recolectarDatos(seccion);
|
|
$.ajax({
|
|
url: '/IMPORTADORES/mve/ajax_guardar_seccion',
|
|
method: 'POST',
|
|
dataType: 'json',
|
|
data: {
|
|
id_factura: facturaSeleccionadaId,
|
|
id_pedimento: pedimentoSeleccionado,
|
|
seccion: seccion,
|
|
datos: JSON.stringify(datos)
|
|
},
|
|
success: function(resp) {
|
|
if (resp && resp.success) {
|
|
$(`.mve-badge[data-factura-id="${facturaSeleccionadaId}"]`).removeClass('bg-secondary').addClass('bg-success').text('MVE respondido');
|
|
toastGuardado(seccion);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Asociar eventos de autoguardado
|
|
$(document).on('input change', '#art65Form input, #art65Form select, #art65Form textarea', debounce(()=>guardarSeccion('65')));
|
|
$(document).on('input change', '#art66Form input, #art66Form select, #art66Form textarea', debounce(()=>guardarSeccion('66')));
|
|
$(document).on('input change', '#precioPagadoForm input, #precioPagadoForm select, #precioPagadoForm textarea', debounce(()=>guardarSeccion('precio_pagado')));
|
|
$(document).on('input change', '#precioPagarForm input, #precioPagarForm select, #precioPagarForm textarea', debounce(()=>guardarSeccion('precio_pagar')));
|
|
$(document).on('input change', '#compensoPagoForm input, #compensoPagoForm select, #compensoPagoForm textarea', debounce(()=>guardarSeccion('compenso')));
|
|
|
|
$('#statusFilter').on('change', function() {
|
|
filtrarPedimentos();
|
|
});
|
|
|
|
$('#perPageFilter').on('change', function() {
|
|
perPage = parseInt($(this).val());
|
|
currentPage = 1;
|
|
renderizarPedimentos();
|
|
});
|
|
// Tabs de vista (pendientes / completos)
|
|
$(document).on('click', '#viewTabs .nav-link', function(e){
|
|
e.preventDefault();
|
|
const view = $(this).data('view');
|
|
if (view && view !== activeView) {
|
|
activeView = view;
|
|
$('#viewTabs .nav-link').removeClass('active');
|
|
$(this).addClass('active');
|
|
currentPage = 1;
|
|
renderizarPedimentos();
|
|
}
|
|
});
|
|
|
|
function cargarPedimentos() {
|
|
$('#pedimentosContainer').html(`
|
|
<div class="loading-spinner">
|
|
<div class="spinner-border text-primary" style="width: 3rem; height: 3rem;">
|
|
<span class="visually-hidden">Cargando...</span>
|
|
</div>
|
|
<p class="mt-3 text-muted fw-bold">Cargando pedimentos...</p>
|
|
</div>
|
|
`);
|
|
|
|
const reqLista = $.ajax({
|
|
url: '/IMPORTADORES/catalogo_pedimentos/ajax_lista',
|
|
method: 'GET',
|
|
data: { draw: 1, start: 0, length: 1000 },
|
|
dataType: 'json'
|
|
});
|
|
|
|
const reqEstados = $.ajax({
|
|
url: '/IMPORTADORES/cove/ajax_estado_pedimentos',
|
|
method: 'GET',
|
|
dataType: 'json'
|
|
});
|
|
|
|
$.when(reqLista, reqEstados).done(function(lResp, eResp) {
|
|
const response = lResp[0];
|
|
const estados = eResp[0];
|
|
if (response.data && response.data.length > 0) {
|
|
allPedimentos = response.data;
|
|
pedimentosCompletos = new Set();
|
|
pedimentoEstados = new Map();
|
|
if (estados && estados.success && Array.isArray(estados.data)) {
|
|
estados.data.forEach(function(row){
|
|
const pid = String(row.pedimento_id);
|
|
pedimentoEstados.set(pid, row);
|
|
if (row && (row.completo === 1 || row.completo === true)) {
|
|
pedimentosCompletos.add(pid);
|
|
}
|
|
});
|
|
}
|
|
filteredPedimentos = [...allPedimentos];
|
|
renderizarPedimentos();
|
|
} else {
|
|
mostrarEstadoVacio();
|
|
}
|
|
}).fail(function(){
|
|
$('#pedimentosContainer').html(`
|
|
<div class="empty-state">
|
|
<i class="fas fa-exclamation-triangle text-warning"></i>
|
|
<h5>Error al cargar datos</h5>
|
|
<p>No se pudieron cargar los pedimentos. Por favor, intenta de nuevo.</p>
|
|
<button class="btn btn-primary" onclick="cargarPedimentos()">Reintentar</button>
|
|
</div>
|
|
`);
|
|
});
|
|
}
|
|
|
|
function filtrarPedimentos() {
|
|
const searchTerm = $('#searchInput').val().toLowerCase();
|
|
const statusFilter = $('#statusFilter').val();
|
|
|
|
filteredPedimentos = allPedimentos.filter(pedimento => {
|
|
const matchesSearch = !searchTerm ||
|
|
pedimento[1].toLowerCase().includes(searchTerm) || // Pedimento
|
|
pedimento[2].toLowerCase().includes(searchTerm) || // RFC
|
|
pedimento[3].toLowerCase().includes(searchTerm); // Nombre
|
|
|
|
const matchesStatus = !statusFilter || pedimento[5] === statusFilter;
|
|
|
|
return matchesSearch && matchesStatus;
|
|
});
|
|
|
|
currentPage = 1;
|
|
renderizarPedimentos();
|
|
updateKPIs();
|
|
}
|
|
|
|
function getActiveList() {
|
|
// Lista filtrada por texto/estado y dividida por vista
|
|
if (activeView === 'completos') {
|
|
return filteredPedimentos.filter(p => pedimentosCompletos.has(String(p[0])));
|
|
}
|
|
// default pendientes
|
|
return filteredPedimentos.filter(p => !pedimentosCompletos.has(String(p[0])));
|
|
}
|
|
|
|
function updateCounters() {
|
|
const pendCount = filteredPedimentos.filter(p => !pedimentosCompletos.has(String(p[0]))).length;
|
|
const compCount = filteredPedimentos.filter(p => pedimentosCompletos.has(String(p[0]))).length;
|
|
$('#countPend').text(pendCount);
|
|
$('#countComp').text(compCount);
|
|
}
|
|
function updateKPIs() {
|
|
const total = filteredPedimentos.length;
|
|
const comp = filteredPedimentos.filter(p => pedimentosCompletos.has(String(p[0]))).length;
|
|
const pend = total - comp;
|
|
$('#kpiTotal').text(total);
|
|
$('#kpiPend').text(pend);
|
|
$('#kpiComp').text(comp);
|
|
}
|
|
|
|
function renderizarPedimentos() {
|
|
if (filteredPedimentos.length === 0) {
|
|
mostrarEstadoVacio();
|
|
return;
|
|
}
|
|
|
|
updateCounters();
|
|
updateKPIs();
|
|
const listaActiva = getActiveList();
|
|
if (listaActiva.length === 0) {
|
|
mostrarEstadoVacio();
|
|
return;
|
|
}
|
|
|
|
const startIndex = (currentPage - 1) * perPage;
|
|
const endIndex = startIndex + perPage;
|
|
const pedimentosPagina = listaActiva.slice(startIndex, endIndex);
|
|
|
|
function cardHtml(pedimento, completo) {
|
|
const [id, numero, rfc, cliente, fecha, status] = pedimento;
|
|
const statusClass = status === 'Activo' ? 'status-activo' : 'status-inactivo';
|
|
const badge = completo ? '<span class="badge bg-success ms-2">MVE completa</span>' : '';
|
|
const est = pedimentoEstados.get(String(id));
|
|
const avance = est ? `${est.respondidas || 0}/${est.total_facturas || 0}` : '-';
|
|
const totalF = est ? parseInt(est.total_facturas || 0, 10) : 0;
|
|
const respF = est ? parseInt(est.respondidas || 0, 10) : 0;
|
|
const pct = totalF > 0 ? Math.round((respF / totalF) * 100) : 0;
|
|
const barClass = pct === 100 ? 'bg-success' : (pct === 0 ? 'bg-secondary' : 'bg-info');
|
|
return `
|
|
<div class="pedimento-card" data-id="${id}">
|
|
<div class="pedimento-header">
|
|
<div class="pedimento-numero">
|
|
<i class="fas fa-file-alt me-2"></i>${numero}
|
|
</div>
|
|
<div class="d-flex align-items-center gap-2">
|
|
${badge}
|
|
<div class="pedimento-status ${statusClass}">${status}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pedimento-info">
|
|
<div class="info-row">
|
|
<span class="info-label">RFC Cliente:</span>
|
|
<span class="info-value">${rfc}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Cliente:</span>
|
|
<span class="info-value">${cliente}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Fecha:</span>
|
|
<span class="info-value">${fecha}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label">Avance MVE:</span>
|
|
<span class="info-value">${avance}</span>
|
|
</div>
|
|
<div class="progress mt-1" style="height:6px;">
|
|
<div class="progress-bar ${barClass}" role="progressbar" style="width: ${pct}%;" aria-valuenow="${pct}" aria-valuemin="0" aria-valuemax="100"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pedimento-actions">
|
|
<button class="btn-mve" onclick="abrirPanelMVE('${id}', '${numero}')">
|
|
<i class="fas fa-calculator me-2"></i>${completo ? 'Ver MVE' : 'Solicitar MVE'}
|
|
</button>
|
|
</div>
|
|
</div>`;
|
|
}
|
|
|
|
let html = '<div class="pedimentos-grid">';
|
|
pedimentosPagina.forEach(p => {
|
|
const isCompleto = pedimentosCompletos.has(String(p[0]));
|
|
html += cardHtml(p, isCompleto);
|
|
});
|
|
html += '</div>';
|
|
$('#pedimentosContainer').html(html);
|
|
|
|
// Actualizar información de paginación
|
|
actualizarPaginacion();
|
|
}
|
|
|
|
function mostrarEstadoVacio() {
|
|
$('#pedimentosContainer').html(`
|
|
<div class="empty-state">
|
|
<i class="fas fa-inbox"></i>
|
|
<h5>No hay pedimentos ${activeView === 'completos' ? 'completos' : 'pendientes'}</h5>
|
|
<p>No se encontraron pedimentos con los filtros seleccionados en esta vista.</p>
|
|
</div>
|
|
`);
|
|
$('#paginationContainer').hide();
|
|
}
|
|
|
|
function actualizarPaginacion() {
|
|
const listaActiva = getActiveList();
|
|
const total = listaActiva.length;
|
|
const totalPages = Math.ceil(total / perPage);
|
|
const startIndex = (currentPage - 1) * perPage;
|
|
const endIndex = Math.min(startIndex + perPage, total);
|
|
|
|
$('#showingFrom').text(total === 0 ? 0 : startIndex + 1);
|
|
$('#showingTo').text(endIndex);
|
|
$('#totalRecords').text(total);
|
|
$('#viewLabel').text(activeView === 'completos' ? '(completos)' : '(pendientes)');
|
|
|
|
if (totalPages <= 1) {
|
|
$('#paginationContainer').hide();
|
|
return;
|
|
}
|
|
|
|
$('#paginationContainer').show();
|
|
|
|
let paginationHtml = '';
|
|
|
|
// Botón anterior
|
|
if (currentPage > 1) {
|
|
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="cambiarPagina(${currentPage - 1})">Anterior</a></li>`;
|
|
}
|
|
|
|
// Números de página
|
|
for (let i = Math.max(1, currentPage - 2); i <= Math.min(totalPages, currentPage + 2); i++) {
|
|
const activeClass = i === currentPage ? 'active' : '';
|
|
paginationHtml += `<li class="page-item ${activeClass}"><a class="page-link" href="#" onclick="cambiarPagina(${i})">${i}</a></li>`;
|
|
}
|
|
|
|
// Botón siguiente
|
|
if (currentPage < totalPages) {
|
|
paginationHtml += `<li class="page-item"><a class="page-link" href="#" onclick="cambiarPagina(${currentPage + 1})">Siguiente</a></li>`;
|
|
}
|
|
|
|
$('#pagination').html(paginationHtml);
|
|
}
|
|
|
|
window.cambiarPagina = function(page) {
|
|
currentPage = page;
|
|
renderizarPedimentos();
|
|
$('html, body').animate({scrollTop: 0}, 300);
|
|
};
|
|
|
|
// Función global para cambiar sección
|
|
window.cambiarSeccionMVE = function(seccion) {
|
|
console.log('Cambiando a sección:', seccion);
|
|
$('.step-btn').removeClass('active');
|
|
$(`.step-btn[data-step="${seccion}"]`).addClass('active');
|
|
mostrarSeccion(seccion.toString());
|
|
};
|
|
|
|
// Funciones del Panel Deslizante
|
|
window.abrirPanelMVE = function(id, pedimento) {
|
|
pedimentoSeleccionado = id;
|
|
$('#panelPedimento').text(pedimento);
|
|
|
|
// Mostrar panel
|
|
$('#slideOverlay').addClass('active');
|
|
$('#slidePanel').addClass('active');
|
|
|
|
// Cargar cabecera del pedimento (para RFC del importador)
|
|
cargarHeaderPedimento(id);
|
|
|
|
// Cargar facturas
|
|
cargarFacturasPedimento(id);
|
|
|
|
// Reset panel state
|
|
$('#stepNavigation').hide();
|
|
$('#art65Panel, #art66Panel').hide();
|
|
$('#btnConfirmarMVE').hide();
|
|
facturaSeleccionadaId = null;
|
|
};
|
|
|
|
function cargarHeaderPedimento(idPedimento) {
|
|
$.ajax({
|
|
url: '/IMPORTADORES/catalogo_pedimentos/ajax_pedimento',
|
|
method: 'GET',
|
|
data: { id: idPedimento },
|
|
dataType: 'json'
|
|
}).done(function(resp){
|
|
if (resp && resp.success && resp.data) {
|
|
importadorRFC = resp.data.rfc_importador || null;
|
|
} else {
|
|
importadorRFC = null;
|
|
}
|
|
}).fail(function(){ importadorRFC = null; });
|
|
}
|
|
|
|
function cargarFacturasPedimento(idPedimento) {
|
|
$('#facturasContainer').html(`
|
|
<div class="text-center py-3">
|
|
<div class="spinner-border text-primary"></div>
|
|
<div class="mt-2">Cargando facturas...</div>
|
|
</div>
|
|
`);
|
|
|
|
// Cargar facturas y estados MVE en paralelo
|
|
const reqFacturas = $.ajax({
|
|
url: '/IMPORTADORES/catalogo_pedimentos/ajax_facturas',
|
|
method: 'GET',
|
|
data: { pedimento_id: idPedimento },
|
|
dataType: 'json'
|
|
});
|
|
|
|
const reqEstados = $.ajax({
|
|
url: '/IMPORTADORES/cove/ajax_estado_facturas',
|
|
method: 'GET',
|
|
data: { pedimento_id: idPedimento },
|
|
dataType: 'json'
|
|
});
|
|
|
|
$.when(reqFacturas, reqEstados).done(function(fResp, eResp) {
|
|
const response = fResp[0];
|
|
const estadosRaw = eResp[0];
|
|
const facturas = (response && response.success && Array.isArray(response.data)) ? response.data : [];
|
|
const estados = (estadosRaw && estadosRaw.success && Array.isArray(estadosRaw.data)) ? estadosRaw.data : [];
|
|
const mapaEstados = {};
|
|
estados.forEach(s => { mapaEstados[s.factura_id] = s; });
|
|
|
|
if (facturas.length > 0) {
|
|
let html = '';
|
|
facturas.forEach(function(f) {
|
|
const id = f.id;
|
|
const numero = f.numero_factura || '';
|
|
const fecha = (f.fecha_factura || '').toString().substring(0,10);
|
|
const montoRaw = (typeof f.valor_factura !== 'undefined') ? f.valor_factura : (typeof f.valor_dolares !== 'undefined' ? f.valor_dolares : null);
|
|
const monto = (montoRaw !== null && montoRaw !== undefined && montoRaw !== '') ? parseFloat(montoRaw).toLocaleString() : '-';
|
|
|
|
const est = mapaEstados[id];
|
|
const respondido = est && (est.respondido === 1 || est.respondido === true);
|
|
const badge = respondido
|
|
? `<span class="badge bg-success ms-2 mve-badge" data-factura-id="${id}">MVE respondido</span>`
|
|
: `<span class="badge bg-secondary ms-2 mve-badge" data-factura-id="${id}">MVE pendiente</span>`;
|
|
|
|
html += `
|
|
<div class="factura-item" data-factura-id="${id}" onclick="seleccionarFactura('${numero}', ${id})">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="factura-numero">${numero}</div>
|
|
${badge}
|
|
</div>
|
|
<div class="factura-details">Fecha: ${fecha || '-'} | Monto: $${monto}</div>
|
|
</div>
|
|
`;
|
|
});
|
|
$('#facturasContainer').html(html);
|
|
} else {
|
|
$('#facturasContainer').html(`
|
|
<div class="alert alert-warning">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
No hay facturas relacionadas a este pedimento.
|
|
</div>
|
|
`);
|
|
}
|
|
}).fail(function() {
|
|
$('#facturasContainer').html(`
|
|
<div class="alert alert-danger">
|
|
<i class="fas fa-times-circle me-2"></i>
|
|
Error al cargar facturas.
|
|
</div>
|
|
`);
|
|
});
|
|
}
|
|
|
|
// Cerrar panel
|
|
$('#panelClose, #slideOverlay').on('click', function() {
|
|
$('#slideOverlay').removeClass('active');
|
|
$('#slidePanel').removeClass('active');
|
|
});
|
|
|
|
// Prevenir cierre al hacer click dentro del panel
|
|
$('#slidePanel').on('click', function(e) {
|
|
e.stopPropagation();
|
|
});
|
|
|
|
window.seleccionarFactura = function(numeroFactura, idFactura) {
|
|
if (!idFactura || idFactura === 'undefined' || idFactura === 'null') {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Error',
|
|
text: 'ID de factura no válido.',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
return;
|
|
}
|
|
|
|
facturaSeleccionadaId = parseInt(idFactura);
|
|
|
|
// Actualizar selección visual
|
|
$('.factura-item').removeClass('selected');
|
|
$(`.factura-item:contains(${numeroFactura})`).addClass('selected');
|
|
|
|
// Asegurar que todos los formularios existan antes de cargar datos
|
|
if ($('#art65Form').children().length === 0) generarFormularioArt65();
|
|
if ($('#art66Form').children().length === 0) generarFormularioArt66();
|
|
if ($('#precioPagadoForm').children().length === 0) generarFormularioPrecioPagado();
|
|
if ($('#precioPagarForm').children().length === 0) generarFormularioPrecioPagar();
|
|
if ($('#compensoPagoForm').children().length === 0) generarFormularioCompenso();
|
|
|
|
// Mostrar navegación de pasos y botón de solicitud
|
|
$('#stepNavigation').show();
|
|
$('#btnConfirmarMVE').show();
|
|
|
|
// Mostrar Art. 65 por defecto y cargar datos existentes
|
|
mostrarSeccion('65');
|
|
cargarDatosMVEFactura(facturaSeleccionadaId);
|
|
};
|
|
|
|
function mostrarSeccion(seccion) {
|
|
console.log('Showing section:', seccion);
|
|
|
|
// Ocultar todos los paneles
|
|
$('#art65Panel, #art66Panel, #precioPagadoPanel, #precioPagarPanel, #compensoPagoPanel').hide();
|
|
|
|
// Mostrar el panel correspondiente
|
|
if (seccion === '65') {
|
|
console.log('Showing Art 65 panel');
|
|
$('#art65Panel').show();
|
|
if ($('#art65Form').children().length === 0) generarFormularioArt65();
|
|
} else if (seccion === '66') {
|
|
console.log('Showing Art 66 panel');
|
|
$('#art66Panel').show();
|
|
if ($('#art66Form').children().length === 0) generarFormularioArt66();
|
|
} else if (seccion === 'precio-pagado') {
|
|
console.log('Showing Precio Pagado panel');
|
|
$('#precioPagadoPanel').show();
|
|
if ($('#precioPagadoForm').children().length === 0) generarFormularioPrecioPagado();
|
|
} else if (seccion === 'precio-pagar') {
|
|
$('#precioPagarPanel').show();
|
|
if ($('#precioPagarForm').children().length === 0) generarFormularioPrecioPagar();
|
|
} else if (seccion === 'compenso-pago') {
|
|
console.log('Showing Compenso Pago panel');
|
|
if ($('#compensoPagoForm').children().length === 0) generarFormularioCompenso();
|
|
}
|
|
|
|
// Verificar que se mostró correctamente
|
|
console.log('Panels visible:', {
|
|
art65: $('#art65Panel').is(':visible'),
|
|
art66: $('#art66Panel').is(':visible'),
|
|
precioPagado: $('#precioPagadoPanel').is(':visible'),
|
|
precioPagar: $('#precioPagarPanel').is(':visible'),
|
|
compensoPago: $('#compensoPagoPanel').is(':visible')
|
|
});
|
|
}
|
|
|
|
function generarFormularioArt65() {
|
|
const campos = [
|
|
{
|
|
label: 'Gastos de transporte, seguros y conexos (carga y descarga) erogados con posterioridad:',
|
|
fecha_id: 'fecha_transporte',
|
|
importe_id: 'importe_transporte'
|
|
},
|
|
{
|
|
label: 'Información de descuentos especiales para aplicar en el momento de la compraventa:',
|
|
fecha_id: 'fecha_descuentos',
|
|
importe_id: 'importe_descuentos'
|
|
},
|
|
{
|
|
label: 'Gastos posteriores a la importación por construcción, instalación, armado, montaje, mantenimiento o asistencia técnica:',
|
|
fecha_id: 'fecha_posteriores',
|
|
importe_id: 'importe_posteriores'
|
|
},
|
|
{
|
|
label: 'Contribuciones y cuotas compensatorias aplicables en territorio nacional:',
|
|
fecha_id: 'fecha_contribuciones',
|
|
importe_id: 'importe_contribuciones'
|
|
},
|
|
{
|
|
label: 'Pagos de importador al vendedor por dividendos u otros que no guarden relación directa con las mercancías importadas:',
|
|
fecha_id: 'fecha_pagos_vendedor',
|
|
importe_id: 'importe_pagos_vendedor'
|
|
}
|
|
];
|
|
|
|
let html = '';
|
|
campos.forEach(campo => {
|
|
html += `
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">${campo.label}</label>
|
|
</div>
|
|
<div class="col-12 col-md-6 col-lg-6">
|
|
<label class="form-label">Fecha de erogación:</label>
|
|
<input type="date" class="form-control" id="${campo.fecha_id}">
|
|
</div>
|
|
<div class="col-12 col-md-6 col-lg-6">
|
|
<label class="form-label">Importe (MN):</label>
|
|
<input type="number" step="0.01" class="form-control" id="${campo.importe_id}">
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
$('#art65Form').html(html);
|
|
}
|
|
|
|
function generarFormularioArt66() {
|
|
const campos = [
|
|
{
|
|
label: 'Comisiones y gastos de corretaje, excepto comisiones de compra:',
|
|
fecha_id: 'fecha_comisiones',
|
|
importe_id: 'importe_comisiones',
|
|
cargo_name: 'cargo_comisiones'
|
|
},
|
|
{
|
|
label: 'Costo de los envases o embalajes que formen un todo con las mercancías:',
|
|
fecha_id: 'fecha_envases',
|
|
importe_id: 'importe_envases',
|
|
cargo_name: 'cargo_envases'
|
|
},
|
|
{
|
|
label: 'Gastos de embalaje (mano de obra y/o materiales):',
|
|
fecha_id: 'fecha_embalaje',
|
|
importe_id: 'importe_embalaje',
|
|
cargo_name: 'cargo_embalaje'
|
|
},
|
|
{
|
|
label: 'Gastos de transporte, seguros y conexos (como manejo, carga y descarga) erogados antes de los momentos señalados en el artículo 56, fracción I de la Ley:',
|
|
fecha_id: 'fecha_transporte_dec',
|
|
importe_id: 'importe_transporte_dec',
|
|
cargo_name: 'cargo_transporte_dec'
|
|
},
|
|
{
|
|
label: 'Trabajos de ingeniería, creación y perfeccionamiento, artísticos, diseños, planos y croquis realizados fuera del territorio nacional:',
|
|
fecha_id: 'fecha_ingenieria',
|
|
importe_id: 'importe_ingenieria',
|
|
cargo_name: 'cargo_ingenieria'
|
|
},
|
|
{
|
|
label: 'Las regalías y derechos de licencia a pagar como condición de la venta de las mercancías a importar:',
|
|
fecha_id: 'fecha_regalias',
|
|
importe_id: 'importe_regalias',
|
|
cargo_name: 'cargo_regalias'
|
|
},
|
|
{
|
|
label: 'Valor de cualquier parte del producto de la enajenación, cesión o utilización, posteriores a la importación:',
|
|
fecha_id: 'fecha_producto',
|
|
importe_id: 'importe_producto',
|
|
cargo_name: 'cargo_producto'
|
|
}
|
|
];
|
|
|
|
let html = '';
|
|
campos.forEach(campo => {
|
|
html += `
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">${campo.label}</label>
|
|
</div>
|
|
<div class="col-12 col-md-6 col-lg-4">
|
|
<label class="form-label">Fecha de erogación:</label>
|
|
<input type="date" class="form-control" id="${campo.fecha_id}">
|
|
</div>
|
|
<div class="col-12 col-md-6 col-lg-4">
|
|
<label class="form-label">Importe (MN):</label>
|
|
<input type="number" step="0.01" class="form-control" id="${campo.importe_id}">
|
|
</div>
|
|
<div class="col-12 col-lg-4">
|
|
<label class="form-label">¿Está a cargo del importador?:</label>
|
|
<div class="d-flex gap-3 flex-wrap">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="${campo.cargo_name}" value="Si" id="${campo.cargo_name}_si">
|
|
<label class="form-check-label" for="${campo.cargo_name}_si">Sí</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="${campo.cargo_name}" value="No" id="${campo.cargo_name}_no">
|
|
<label class="form-check-label" for="${campo.cargo_name}_no">No</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
$('#art66Form').html(html);
|
|
}
|
|
|
|
function generarFormularioPrecioPagado() {
|
|
let html = `
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">Información del Precio Pagado:</label>
|
|
</div>
|
|
<div class="col-12 col-md-6 col-lg-4">
|
|
<label class="form-label">Fecha de pago:</label>
|
|
<input type="date" class="form-control" id="fecha_precio_pagado">
|
|
</div>
|
|
<div class="col-12 col-md-6 col-lg-4">
|
|
<label class="form-label">Importe pagado (MN):</label>
|
|
<input type="number" step="0.01" class="form-control" id="importe_precio_pagado">
|
|
</div>
|
|
<div class="col-12 col-lg-4">
|
|
<label class="form-label">Moneda:</label>
|
|
<select class="form-control" id="moneda_precio_pagado">
|
|
<option value="MXN">Peso Mexicano (MXN)</option>
|
|
<option value="USD">Dólar Americano (USD)</option>
|
|
<option value="EUR">Euro (EUR)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">Método de pago:</label>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Forma de pago:</label>
|
|
<select class="form-control" id="forma_pago_precio_pagado">
|
|
<option value="">Seleccionar...</option>
|
|
<option value="transferencia">Transferencia bancaria</option>
|
|
<option value="cheque">Cheque</option>
|
|
<option value="efectivo">Efectivo</option>
|
|
<option value="carta_credito">Carta de crédito</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Referencia de pago:</label>
|
|
<input type="text" class="form-control" id="referencia_precio_pagado" placeholder="Núm. de referencia">
|
|
</div>
|
|
</div>
|
|
`;
|
|
$('#precioPagadoForm').html(html);
|
|
}
|
|
|
|
function generarFormularioPrecioPagar() {
|
|
let html = `
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">Información del Precio por Pagar:</label>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Fecha límite de pago:</label>
|
|
<input type="date" class="form-control" id="fecha_limite_pago">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Importe pendiente (MN):</label>
|
|
<input type="number" step="0.01" class="form-control" id="importe_precio_pagar">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Moneda:</label>
|
|
<select class="form-control" id="moneda_precio_pagar">
|
|
<option value="MXN">Peso Mexicano (MXN)</option>
|
|
<option value="USD">Dólar Americano (USD)</option>
|
|
<option value="EUR">Euro (EUR)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">Condiciones de pago:</label>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Términos de pago:</label>
|
|
<select class="form-control" id="terminos_precio_pagar">
|
|
<option value="">Seleccionar...</option>
|
|
<option value="contado">Al contado</option>
|
|
<option value="credito_30">Crédito 30 días</option>
|
|
<option value="credito_60">Crédito 60 días</option>
|
|
<option value="credito_90">Crédito 90 días</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Observaciones:</label>
|
|
<textarea class="form-control" id="observaciones_precio_pagar" rows="2" placeholder="Observaciones adicionales"></textarea>
|
|
</div>
|
|
</div>
|
|
`;
|
|
$('#precioPagarForm').html(html);
|
|
}
|
|
|
|
function generarFormularioCompenso() {
|
|
let html = `
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">Información del Compenso de Pago:</label>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Fecha de compensación:</label>
|
|
<input type="date" class="form-control" id="fecha_compenso">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Importe a compensar (MN):</label>
|
|
<input type="number" step="0.01" class="form-control" id="importe_compenso">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Tipo de compensación:</label>
|
|
<select class="form-control" id="tipo_compenso">
|
|
<option value="">Seleccionar...</option>
|
|
<option value="descuento">Descuento comercial</option>
|
|
<option value="bonificacion">Bonificación</option>
|
|
<option value="devolucion">Devolución</option>
|
|
<option value="ajuste">Ajuste de precio</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12 mb-2">
|
|
<label class="form-label fw-bold">Justificación del compenso:</label>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Motivo:</label>
|
|
<select class="form-control" id="motivo_compenso">
|
|
<option value="">Seleccionar...</option>
|
|
<option value="defecto_mercancia">Defecto en mercancía</option>
|
|
<option value="error_facturacion">Error en facturación</option>
|
|
<option value="acuerdo_comercial">Acuerdo comercial</option>
|
|
<option value="otro">Otro</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label">Documentos de respaldo:</label>
|
|
<input type="text" class="form-control" id="documentos_compenso" placeholder="Núm. de documento">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-12">
|
|
<label class="form-label fw-bold">Descripción detallada:</label>
|
|
<textarea class="form-control" id="descripcion_compenso" rows="3" placeholder="Descripción detallada del motivo de compensación"></textarea>
|
|
</div>
|
|
</div>
|
|
`;
|
|
$('#compensoPagoForm').html(html);
|
|
}
|
|
|
|
function cargarDatosMVEFactura(idFactura) {
|
|
$.ajax({
|
|
url: '/IMPORTADORES/mve/ajax_obtener_datos_factura',
|
|
method: 'GET',
|
|
data: { id_factura: idFactura },
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
if (response.success && response.datos) {
|
|
if (response.datos.art65) {
|
|
const art65 = response.datos.art65;
|
|
$('#fecha_transporte').val(formatDateInput(art65.fecha_transporte));
|
|
$('#importe_transporte').val(art65.importe_transporte || '');
|
|
$('#fecha_descuentos').val(formatDateInput(art65.fecha_descuentos));
|
|
$('#importe_descuentos').val(art65.importe_descuentos || '');
|
|
$('#fecha_posteriores').val(formatDateInput(art65.fecha_posteriores));
|
|
$('#importe_posteriores').val(art65.importe_posteriores || '');
|
|
$('#fecha_contribuciones').val(formatDateInput(art65.fecha_contribuciones));
|
|
$('#importe_contribuciones').val(art65.importe_contribuciones || '');
|
|
$('#fecha_pagos_vendedor').val(formatDateInput(art65.fecha_pagos_vendedor));
|
|
$('#importe_pagos_vendedor').val(art65.importe_pagos_vendedor || '');
|
|
}
|
|
|
|
if (response.datos.art66) {
|
|
const art66 = response.datos.art66;
|
|
$('#fecha_comisiones').val(formatDateInput(art66.fecha_comisiones));
|
|
$('#importe_comisiones').val(art66.importe_comisiones || '');
|
|
$('input[name="cargo_comisiones"][value="' + (art66.cargo_comisiones || '') + '"]').prop('checked', true);
|
|
$('#fecha_envases').val(formatDateInput(art66.fecha_envases));
|
|
$('#importe_envases').val(art66.importe_envases || '');
|
|
$('input[name="cargo_envases"][value="' + (art66.cargo_envases || '') + '"]').prop('checked', true);
|
|
$('#fecha_embalaje').val(formatDateInput(art66.fecha_embalaje));
|
|
$('#importe_embalaje').val(art66.importe_embalaje || '');
|
|
$('input[name="cargo_embalaje"][value="' + (art66.cargo_embalaje || '') + '"]').prop('checked', true);
|
|
$('#fecha_transporte_dec').val(formatDateInput(art66.fecha_transporte_dec));
|
|
$('#importe_transporte_dec').val(art66.importe_transporte_dec || '');
|
|
$('input[name="cargo_transporte_dec"][value="' + (art66.cargo_transporte_dec || '') + '"]').prop('checked', true);
|
|
$('#fecha_ingenieria').val(formatDateInput(art66.fecha_ingenieria));
|
|
$('#importe_ingenieria').val(art66.importe_ingenieria || '');
|
|
$('input[name="cargo_ingenieria"][value="' + (art66.cargo_ingenieria || '') + '"]').prop('checked', true);
|
|
$('#fecha_regalias').val(formatDateInput(art66.fecha_regalias));
|
|
$('#importe_regalias').val(art66.importe_regalias || '');
|
|
$('input[name="cargo_regalias"][value="' + (art66.cargo_regalias || '') + '"]').prop('checked', true);
|
|
$('#fecha_producto').val(formatDateInput(art66.fecha_producto));
|
|
$('#importe_producto').val(art66.importe_producto || '');
|
|
$('input[name="cargo_producto"][value="' + (art66.cargo_producto || '') + '"]').prop('checked', true);
|
|
}
|
|
|
|
if (response.datos.precio_pagado) {
|
|
const pp = response.datos.precio_pagado;
|
|
$('#fecha_precio_pagado').val(formatDateInput(pp.fecha_precio_pagado));
|
|
$('#importe_precio_pagado').val(pp.importe_precio_pagado || '');
|
|
$('#moneda_precio_pagado').val(pp.moneda_precio_pagado || 'MXN');
|
|
$('#forma_pago_precio_pagado').val(pp.forma_pago_precio_pagado || '');
|
|
$('#referencia_precio_pagado').val(pp.referencia_precio_pagado || '');
|
|
}
|
|
|
|
if (response.datos.precio_pagar) {
|
|
const px = response.datos.precio_pagar;
|
|
$('#fecha_limite_pago').val(formatDateInput(px.fecha_limite_pago));
|
|
$('#importe_precio_pagar').val(px.importe_precio_pagar || '');
|
|
$('#moneda_precio_pagar').val(px.moneda_precio_pagar || 'MXN');
|
|
$('#terminos_precio_pagar').val(px.terminos_precio_pagar || '');
|
|
$('#observaciones_precio_pagar').val(px.observaciones_precio_pagar || '');
|
|
}
|
|
|
|
if (response.datos.compenso) {
|
|
const co = response.datos.compenso;
|
|
$('#fecha_compenso').val(formatDateInput(co.fecha_compenso));
|
|
$('#importe_compenso').val(co.importe_compenso || '');
|
|
$('#tipo_compenso').val(co.tipo_compenso || '');
|
|
$('#motivo_compenso').val(co.motivo_compenso || '');
|
|
$('#documentos_compenso').val(co.documentos_compenso || '');
|
|
$('#descripcion_compenso').val(co.descripcion_compenso || '');
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Botón Guardar MVE removido (autosave activo)
|
|
|
|
$('#btnConfirmarMVE').off('click').on('click', function() {
|
|
if (!facturaSeleccionadaId) {
|
|
Swal.fire({ icon: 'warning', title: 'Selecciona una factura', text: 'Primero selecciona una factura para solicitar la MVE.' });
|
|
return;
|
|
}
|
|
|
|
const { completos, faltantes } = validarSecciones();
|
|
|
|
if (completos) {
|
|
const rfcTxt = importadorRFC ? ` (RFC: ${importadorRFC})` : '';
|
|
const disclaimerHtml = `
|
|
<div class="text-start" style="font-size: 0.95rem;">
|
|
<p class="mb-2">Todos los datos están completos.</p>
|
|
<div class="p-3 border rounded" style="background:#fffef4">
|
|
<strong>Declaración del Importador${rfcTxt}:</strong>
|
|
<p class="mb-0 mt-2">
|
|
Declaro que la información presentada es verdadera, completa y libre de errores.
|
|
Reconozco que AduanaSoft actúa únicamente como plataforma de captura y no asume responsabilidad por el contenido, veracidad ni por las consecuencias derivadas de su transmisión.
|
|
</p>
|
|
</div>
|
|
</div>`;
|
|
|
|
Swal.fire({
|
|
icon: 'question',
|
|
title: 'Confirmar solicitud',
|
|
width: '60rem',
|
|
html: `
|
|
<div class="container-fluid text-start">
|
|
<div class="row g-3">
|
|
<div class="col-12 col-lg-6">
|
|
${disclaimerHtml}
|
|
</div>
|
|
<div class="col-12 col-lg-6">
|
|
<div class="mb-2"><strong>Firma autógrafa (opcional)</strong></div>
|
|
<div class="border rounded p-2" style="background:#fff">
|
|
<canvas id="firmaCanvas" style="width:100%;height:180px;border:1px dashed #ced4da;border-radius:6px;"></canvas>
|
|
<div class="d-flex justify-content-between align-items-center mt-2">
|
|
<input type="text" id="firmanteNombre" class="form-control form-control-sm me-2" placeholder="Nombre del firmante (opcional)">
|
|
<button type="button" id="btnLimpiarFirma" class="btn btn-sm btn-outline-secondary">Limpiar</button>
|
|
</div>
|
|
<small class="text-muted d-block mt-1">Puedes firmar con mouse o dedo si es pantalla táctil.</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
input: 'checkbox',
|
|
inputPlaceholder: 'Acepto y declaro bajo protesta de decir verdad',
|
|
inputValidator: (v) => !v && 'Debes aceptar la declaración para continuar',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Solicitar',
|
|
cancelButtonText: 'Cancelar',
|
|
didOpen: () => {
|
|
const canvas = document.getElementById('firmaCanvas');
|
|
// Ajuste de tamaño para alta densidad
|
|
const ratio = Math.max(window.devicePixelRatio || 1, 1);
|
|
const rect = canvas.getBoundingClientRect();
|
|
canvas.width = rect.width * ratio;
|
|
canvas.height = 180 * ratio;
|
|
canvas.getContext('2d').scale(ratio, ratio);
|
|
window.__sigPad = new SignaturePad(canvas, { backgroundColor: 'rgba(255,255,255,1)' });
|
|
document.getElementById('btnLimpiarFirma').addEventListener('click', ()=> window.__sigPad.clear());
|
|
},
|
|
preConfirm: () => {
|
|
if (!window.__sigPad || window.__sigPad.isEmpty()) {
|
|
Swal.showValidationMessage('Debes firmar para continuar');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}).then(res => {
|
|
if (res.isConfirmed) {
|
|
// Registrar acuse en backend
|
|
$.ajax({
|
|
url: '/IMPORTADORES/mve/ajax_registrar_solicitud',
|
|
method: 'POST',
|
|
dataType: 'json',
|
|
data: {
|
|
pedimento_id: pedimentoSeleccionado,
|
|
factura_id: facturaSeleccionadaId,
|
|
acepto: 1,
|
|
rfc_importador: importadorRFC,
|
|
firma_base64: (window.__sigPad && !window.__sigPad.isEmpty()) ? window.__sigPad.toDataURL('image/png') : '',
|
|
firmante: $('#firmanteNombre').val() || ''
|
|
},
|
|
}).done(function(r){
|
|
if (r && r.success) {
|
|
$('#slideOverlay').removeClass('active');
|
|
$('#slidePanel').removeClass('active');
|
|
Swal.fire({ icon: 'success', title: 'Solicitud enviada', text: 'Se ha solicitado la Manifestación de Valor para el pedimento ' + $('#panelPedimento').text(), confirmButtonText: 'OK' });
|
|
} else {
|
|
Swal.fire({ icon: 'error', title: 'No se pudo registrar', text: (r && r.message) ? r.message : 'Intenta nuevamente.' });
|
|
}
|
|
}).fail(function(){
|
|
Swal.fire({ icon: 'error', title: 'Error de red', text: 'No fue posible registrar la solicitud.' });
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
// Construir listado de faltantes
|
|
const nombres = { '65': 'Art. 65', '66': 'Art. 66', 'precio_pagado': 'Precio Pagado', 'precio_pagar': 'Precio por Pagar', 'compenso': 'Compenso Pago' };
|
|
let html = '<div class="text-start">';
|
|
Object.keys(faltantes).forEach(sec => {
|
|
html += `<div class="mb-2"><strong>${nombres[sec] || sec}:</strong><ul class="mt-1">`;
|
|
faltantes[sec].slice(0,8).forEach(f => { html += `<li>${f}</li>`; });
|
|
const extra = faltantes[sec].length - 8;
|
|
if (extra > 0) html += `<li>… y ${extra} más</li>`;
|
|
html += '</ul></div>';
|
|
});
|
|
html += '</div>';
|
|
const rfcTxt = importadorRFC ? ` (RFC: ${importadorRFC})` : '';
|
|
const disclaimerHtml = `
|
|
<div class="p-3 border rounded mt-3" style="background:#fffef4">
|
|
<strong>Declaración del Importador${rfcTxt}:</strong>
|
|
<p class="mb-0 mt-2">
|
|
Declaro que la información presentada es verdadera, completa y libre de errores.
|
|
Reconozco que AduanaSoft actúa únicamente como plataforma de captura y no asume responsabilidad por el contenido, veracidad ni por las consecuencias derivadas de su transmisión.
|
|
</p>
|
|
</div>`;
|
|
|
|
Swal.fire({
|
|
icon: 'warning',
|
|
title: 'Datos incompletos',
|
|
width: '60rem',
|
|
html: `
|
|
${html}
|
|
<div class="mt-2">Algunos campos están vacíos. ¿Deseas transmitir la solicitud así?</div>
|
|
<div class="container-fluid text-start mt-3">
|
|
<div class="row g-3">
|
|
<div class="col-12 col-lg-6">
|
|
${disclaimerHtml}
|
|
</div>
|
|
<div class="col-12 col-lg-6">
|
|
<div class="mb-2"><strong>Firma autógrafa (opcional)</strong></div>
|
|
<div class="border rounded p-2" style="background:#fff">
|
|
<canvas id="firmaCanvas" style="width:100%;height:180px;border:1px dashed #ced4da;border-radius:6px;"></canvas>
|
|
<div class="d-flex justify-content-between align-items-center mt-2">
|
|
<input type="text" id="firmanteNombre" class="form-control form-control-sm me-2" placeholder="Nombre del firmante (opcional)">
|
|
<button type="button" id="btnLimpiarFirma" class="btn btn-sm btn-outline-secondary">Limpiar</button>
|
|
</div>
|
|
<small class="text-muted d-block mt-1">Puedes firmar con mouse o dedo si es pantalla táctil.</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
input: 'checkbox',
|
|
inputPlaceholder: 'Acepto y declaro bajo protesta de decir verdad',
|
|
inputValidator: (v) => !v && 'Debes aceptar la declaración para continuar',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Transmitir de todos modos',
|
|
cancelButtonText: 'Completar datos',
|
|
didOpen: () => {
|
|
const canvas = document.getElementById('firmaCanvas');
|
|
const ratio = Math.max(window.devicePixelRatio || 1, 1);
|
|
const rect = canvas.getBoundingClientRect();
|
|
canvas.width = rect.width * ratio;
|
|
canvas.height = 180 * ratio;
|
|
canvas.getContext('2d').scale(ratio, ratio);
|
|
window.__sigPad = new SignaturePad(canvas, { backgroundColor: 'rgba(255,255,255,1)' });
|
|
document.getElementById('btnLimpiarFirma').addEventListener('click', ()=> window.__sigPad.clear());
|
|
},
|
|
preConfirm: () => {
|
|
if (!window.__sigPad || window.__sigPad.isEmpty()) {
|
|
Swal.showValidationMessage('Debes firmar para continuar');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}).then(res => {
|
|
if (res.isConfirmed) {
|
|
// Registrar acuse en backend (aun con faltantes)
|
|
$.ajax({
|
|
url: '/IMPORTADORES/mve/ajax_registrar_solicitud',
|
|
method: 'POST',
|
|
dataType: 'json',
|
|
data: {
|
|
pedimento_id: pedimentoSeleccionado,
|
|
factura_id: facturaSeleccionadaId,
|
|
acepto: 1,
|
|
rfc_importador: importadorRFC,
|
|
firma_base64: (window.__sigPad && !window.__sigPad.isEmpty()) ? window.__sigPad.toDataURL('image/png') : '',
|
|
firmante: $('#firmanteNombre').val() || ''
|
|
},
|
|
}).done(function(r){
|
|
if (r && r.success) {
|
|
$('#slideOverlay').removeClass('active');
|
|
$('#slidePanel').removeClass('active');
|
|
Swal.fire({ icon: 'success', title: 'Solicitud enviada', text: 'Se ha solicitado la Manifestación de Valor para el pedimento ' + $('#panelPedimento').text(), confirmButtonText: 'OK' });
|
|
} else {
|
|
Swal.fire({ icon: 'error', title: 'No se pudo registrar', text: (r && r.message) ? r.message : 'Intenta nuevamente.' });
|
|
}
|
|
}).fail(function(){
|
|
Swal.fire({ icon: 'error', title: 'Error de red', text: 'No fue posible registrar la solicitud.' });
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|