Revisión 2.1
This commit is contained in:
@@ -44,7 +44,7 @@
|
||||
<option value="">-- Selecciona un transportista --</option>
|
||||
<?php foreach ($transportistas as $t): ?>
|
||||
<option value="<?= $t['id_transportista'] ?>">
|
||||
<?= htmlspecialchars($t['nombre']) ?>
|
||||
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre'] . ' - ' . $t['ciudad_nombre'] . ' - ' . $t['domicilio']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
@@ -65,6 +65,11 @@
|
||||
<input name="numero_licencia" id="numero_licencia" type="text" maxlength="11" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="numero_gafete" class="form-label">Número de Gafete</label>
|
||||
<input name="numero_gafete" id="numero_gafete" type="text" maxlength="24" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="telefono" class="form-label">Teléfono</label>
|
||||
<input name="telefono" id="telefono" type="tel" maxlength="11" class="form-control">
|
||||
@@ -101,6 +106,7 @@
|
||||
const nombre = document.getElementById('nombre').value.trim();
|
||||
const apellido = document.getElementById('apellido').value.trim();
|
||||
const numero_licencia = document.getElementById('numero_licencia').value.trim();
|
||||
const numero_gafete = document.getElementById('numero_gafete').value.trim();
|
||||
const telefono = document.getElementById('telefono').value.trim();
|
||||
const email = document.getElementById('email').value.trim();
|
||||
const fecha_ingreso = document.getElementById('fecha_ingreso').value;
|
||||
@@ -132,6 +138,11 @@
|
||||
document.getElementById('numero_licencia').focus();
|
||||
return;
|
||||
}
|
||||
if (!numero_gafete) {
|
||||
Swal.fire({ icon: 'error', title: 'Número de Gafete requerido', text: 'Por favor ingresa el número de gafete.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('numero_gafete').focus();
|
||||
return;
|
||||
}
|
||||
if (!soloNumerosRegex.test(numero_licencia)) {
|
||||
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545'
|
||||
});
|
||||
@@ -175,9 +186,22 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
|
||||
this.submit();
|
||||
// VALIDACIÓN ASÍNCRONA DE DUPLICADO DE GAFETE
|
||||
fetch(`/IMPORTADORES/choferes/validarNumeroGafete?numero_gafete=${encodeURIComponent(numero_gafete)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.existe) {
|
||||
Swal.fire({ icon: 'error', title: 'Número de Gafete duplicado', text: 'El número de gafete ya está en uso, por favor ingresa uno diferente.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('numero_gafete').focus();
|
||||
} else {
|
||||
// Si no existe, enviamos el formulario
|
||||
e.target.submit();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error validando el número de gafete:', error);
|
||||
Swal.fire({ icon: 'error', title: 'Error de validación', text: 'No fue posible validar el número de gafete. Intenta de nuevo.', confirmButtonColor: '#dc3545' });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<?php foreach ($transportistas as $t): ?>
|
||||
<option value="<?= $t['id_transportista'] ?>"
|
||||
<?= $chofer['transportista_id'] == $t['id_transportista'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($t['nombre']) ?>
|
||||
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre'] . ' - ' . $t['ciudad_nombre'] . ' - ' . $t['domicilio']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
@@ -76,6 +76,13 @@
|
||||
value="<?= htmlspecialchars($chofer['numero_licencia']) ?>" required>
|
||||
</div>
|
||||
|
||||
<!-- Gafete -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="numero_gafete" class="form-label">Número de Gafete</label>
|
||||
<input name="numero_gafete" id="numero_gafete" type="text" maxlength="24" class="form-control"
|
||||
value="<?= htmlspecialchars($chofer['numero_gafete']) ?>" required>
|
||||
</div>
|
||||
|
||||
<!-- Teléfono -->
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="telefono" class="form-label">Teléfono</label>
|
||||
@@ -138,6 +145,7 @@
|
||||
const nombre = document.getElementById('nombre').value.trim();
|
||||
const apellido = document.getElementById('apellido').value.trim();
|
||||
const numero_licencia = document.getElementById('numero_licencia').value.trim();
|
||||
const numero_gafete = document.getElementById('numero_gafete').value.trim();
|
||||
const telefono = document.getElementById('telefono').value.trim();
|
||||
const email = document.getElementById('email').value.trim();
|
||||
const fecha_ingreso = document.getElementById('fecha_ingreso').value;
|
||||
@@ -169,6 +177,11 @@
|
||||
document.getElementById('numero_licencia').focus();
|
||||
return;
|
||||
}
|
||||
if (!numero_gafete) {
|
||||
Swal.fire({ icon: 'error', title: 'Número de Gafete requerido', text: 'Por favor ingresa el número de gafete.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('numero_gafete').focus();
|
||||
return;
|
||||
}
|
||||
if (!soloNumerosRegex.test(numero_licencia)) {
|
||||
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('Clave').focus();
|
||||
@@ -211,9 +224,24 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
// VALIDACIÓN ASÍNCRONA DE DUPLICADO DE GAFETE
|
||||
const id_chofer = document.querySelector('input[name="id_chofer"]').value;
|
||||
|
||||
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
|
||||
this.submit();
|
||||
fetch(`/IMPORTADORES/choferes/validarNumeroGafete?numero_gafete=${encodeURIComponent(numero_gafete)}&id_chofer={id_chofer}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.existe) {
|
||||
Swal.fire({ icon: 'error', title: 'Número de Gafete duplicado', text: 'El número de gafete ya está en uso, por favor ingresa uno diferente.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('numero_gafete').focus();
|
||||
} else {
|
||||
// Si no existe, enviamos el formulario
|
||||
e.target.submit();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error validando el número de gafete:', error);
|
||||
Swal.fire({ icon: 'error', title: 'Error de validación', text: 'No fue posible validar el número de gafete. Intenta de nuevo.', confirmButtonColor: '#dc3545' });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<th>#</th>
|
||||
<th>Nombre Completo</th>
|
||||
<th>Licencia</th>
|
||||
<th>Gafete</th>
|
||||
<th>Teléfono</th>
|
||||
<th>Email</th>
|
||||
<th>Ingreso</th>
|
||||
@@ -60,6 +61,7 @@
|
||||
<td><?= $c['id_chofer'] ?></td>
|
||||
<td><?= htmlspecialchars($c['nombre_completo']) ?></td>
|
||||
<td><?= htmlspecialchars($c['numero_licencia']) ?></td>
|
||||
<td><?= htmlspecialchars($c['numero_gafete']) ?></td>
|
||||
<td><?= htmlspecialchars($c['telefono']) ?></td>
|
||||
<td><?= htmlspecialchars($c['email']) ?></td>
|
||||
<td>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<button type="submit" class="btn btn-success w-100">
|
||||
<i class="fas fa-plus"></i> Registrar Estado
|
||||
</button>
|
||||
<a href="/IMPORTADORES/agentes/lista" class="btn btn-secondary ms-2">Cancelar</a>
|
||||
<a href="/IMPORTADORES/locaciones/lista" class="btn btn-secondary ms-2">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<!-- Nueva Ciudad -->
|
||||
<div class="col-md">
|
||||
<div class="card p-4 bg-white shadow-sm">
|
||||
<form id="ciudadForm" action="/IMPORTADORES/agentes/guadarCiudad" method="POST" enctype="multipart/form-data">
|
||||
<form id="ciudadForm" action="/IMPORTADORES/locaciones/guadarCiudad" method="POST" enctype="multipart/form-data">
|
||||
<h4 class="mb-4 text-dark">➕ Nueva Ciudad</h4>
|
||||
<!-- País -->
|
||||
<div class="col-md-12">
|
||||
@@ -102,7 +102,7 @@
|
||||
<button type="submit" class="btn btn-success w-100">
|
||||
<i class="fas fa-plus"></i> Registrar Ciudad
|
||||
</button>
|
||||
<a href="/IMPORTADORES/agentes/lista" class="btn btn-secondary ms-2">Cancelar</a>
|
||||
<a href="/IMPORTADORES/locaciones/lista" class="btn btn-secondary ms-2">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -117,7 +117,7 @@
|
||||
selectElement.innerHTML = '<option>Cargando...</option>';
|
||||
selectElement.disabled = true;
|
||||
|
||||
fetch(`/IMPORTADORES/agentes/estados?pais=${paisId}`)
|
||||
fetch(`/IMPORTADORES/locaciones/estados?pais=${paisId}`)
|
||||
.then(response => response.json())
|
||||
.then(estados => {
|
||||
selectElement.innerHTML = '<option value="">Selecciona estado</option>';
|
||||
@@ -193,7 +193,7 @@
|
||||
entidad: entidadValue
|
||||
});
|
||||
|
||||
fetch('/IMPORTADORES/agentes/guardarEstado', {
|
||||
fetch('/IMPORTADORES/locaciones/guardarEstado', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
@@ -241,7 +241,7 @@
|
||||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Guardando...';
|
||||
submitBtn.disabled = true;
|
||||
|
||||
fetch('/IMPORTADORES/agentes/guardarCiudad', {
|
||||
fetch('/IMPORTADORES/locaciones/guardarCiudad', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
/* Asegurar que las pestañas sean completamente visibles */
|
||||
.nav-tabs .nav-item:first-child .nav-link { margin-left: 0; }
|
||||
.nav-tabs .nav-item:last-child .nav-link { margin-right: 0; }
|
||||
.tab-content { padding: 5px; }
|
||||
.tab-content { padding: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -119,7 +119,7 @@
|
||||
<div class="col-md-10">
|
||||
<input name="razon_social" id="razon_social" type="text" class="form-control" required>
|
||||
</div>
|
||||
</div><hr><br>
|
||||
</div><hr>
|
||||
|
||||
<div class="col mb-3">
|
||||
<P>Capturar para el llenado de la Manifestación de Valor</P>
|
||||
@@ -251,7 +251,7 @@
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: right;">
|
||||
<button type="submit" class="btn btn-success">Guardar</button>
|
||||
<button type="submit" class="btn btn-primary">Registrar</button>
|
||||
<a href="/IMPORTADORES/patente/lista" class="btn btn-secondary ms-2">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<h4 class="mb-4">📦 Panel del Importador</h4>
|
||||
<h4 class="mb-4">📦 Panel de Patentes</h4>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
@@ -45,8 +45,8 @@
|
||||
<h5 class="text-primary">Ver patentes</h5>
|
||||
<p>Revisa y gestiona las patentes.</p>
|
||||
<a href="/IMPORTADORES/patente/lista"
|
||||
class="btn btn-primary btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/transportes/lista' ? 'active' : '' ?>">
|
||||
Ver transportes
|
||||
class="btn btn-primary btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/transportes/lista' ? 'active' : '' ?>">
|
||||
Ver patentes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,8 +56,8 @@
|
||||
<h5 class="text-success">Nueva patente</h5>
|
||||
<p>Agrega nuevas patentes:</p>
|
||||
<a href="/IMPORTADORES/patente/alta"
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/transportistas/lista' ? 'active' : '' ?>">
|
||||
Ver transportistas
|
||||
class="btn btn-success btn-sm mt-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/transportistas/lista' ? 'active' : '' ?>">
|
||||
Registrar nueva patente
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
/* Asegurar que las pestañas sean completamente visibles */
|
||||
.nav-tabs .nav-item:first-child .nav-link { margin-left: 0; }
|
||||
.nav-tabs .nav-item:last-child .nav-link { margin-right: 0; }
|
||||
.tab-content { padding: 5px; }
|
||||
.tab-content { padding: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -124,11 +124,11 @@
|
||||
<input name="razon_social" id="razon_social" type="text" class="form-control"
|
||||
value="<?= htmlspecialchars($agente['razon_social'] ?? '') ?>" required>
|
||||
</div>
|
||||
</div><hr><br>
|
||||
</div><hr>
|
||||
|
||||
<div class="col mb-3">
|
||||
<P>Capturar para el llenado de la Manifestación de Valor</P>
|
||||
<p>Datos del Agente Aduanal:</p>
|
||||
<p style="font-weight: bold;">Datos del Agente Aduanal:</p>
|
||||
<div class="row mb-3">
|
||||
<label for="mf_nombre" class="col-md-2 col-form-label">Nombre(s)</label>
|
||||
<div class="col-md-9">
|
||||
@@ -274,7 +274,7 @@
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: right;">
|
||||
<button type="submit" class="btn btn-success">Guardar</button>
|
||||
<button type="submit" class="btn btn-success">💾 Guardar</button>
|
||||
<a href="/IMPORTADORES/patente/lista" class="btn btn-secondary ms-2">Cancelar</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="foto_solicitud" class="form-label">Foto de la solicitud</label>
|
||||
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
||||
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
@@ -217,135 +217,134 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"></script>
|
||||
|
||||
<script>
|
||||
// 1) Inicializar Choices para todos los selects excepto proveedor_id
|
||||
document.querySelectorAll('.searchable:not(#proveedor_id)').forEach(el => {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Primero cargamos proveedores, luego inicializamos Choices en todos los selects
|
||||
cargarProveedores().then(() => {
|
||||
inicializarChoicesGlobal();
|
||||
});
|
||||
|
||||
// Inicializamos los eventos adicionales
|
||||
inicializarEventos();
|
||||
});
|
||||
|
||||
// 2) Cargar proveedores dinámicamente
|
||||
const proveedorEl = document.getElementById('proveedor_id');
|
||||
let proveedorChoices = null;
|
||||
// Función para cargar proveedores (retorna promesa)
|
||||
function cargarProveedores() {
|
||||
const proveedorEl = document.getElementById('proveedor_id');
|
||||
|
||||
return fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return 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(err => {
|
||||
console.error('❌ Error cargando proveedores:', err);
|
||||
proveedorEl.innerHTML = '<option value="">Error cargando proveedores</option>';
|
||||
});
|
||||
}
|
||||
|
||||
fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||||
.then(res => res.ok ? res.json() : Promise.reject(res.status))
|
||||
.then(json => {
|
||||
proveedorEl.innerHTML = '<option value="">-- Selecciona Proveedor --</option>';
|
||||
json.results.forEach(item => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = item.id;
|
||||
opt.text = item.text;
|
||||
proveedorEl.add(opt);
|
||||
// Inicializamos Choices globalmente (todos los .searchable)
|
||||
function inicializarChoicesGlobal() {
|
||||
document.querySelectorAll('.searchable').forEach(el => {
|
||||
if (el._choices) el._choices.destroy(); // destruye instancia previa si existe
|
||||
el._choices = new Choices(el, {
|
||||
searchEnabled: true,
|
||||
itemSelectText: '',
|
||||
shouldSort: false,
|
||||
searchFields: ['label'] // 🔐 Solo busca en el texto visible
|
||||
});
|
||||
// destruir instancia previa si existe
|
||||
if (proveedorChoices) proveedorChoices.destroy();
|
||||
proveedorChoices = new Choices(proveedorEl, {
|
||||
searchEnabled: true,
|
||||
itemSelectText: '',
|
||||
shouldSort: false
|
||||
});
|
||||
}
|
||||
|
||||
// Eventos principales del formulario
|
||||
function inicializarEventos() {
|
||||
// Agregar partidas dinámicamente
|
||||
document.getElementById('add-partida').addEventListener('click', () => {
|
||||
const tbody = document.querySelector('#tabla-partidas tbody');
|
||||
const idx = tbody.querySelectorAll('tr').length;
|
||||
const row = document.createElement('tr');
|
||||
|
||||
row.innerHTML = `
|
||||
<td><input name="partidas[${idx}][descripcion]" class="form-control"></td>
|
||||
<td><input name="partidas[${idx}][cantidad_comercial]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[${idx}][cantidad_tarifa]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td>
|
||||
<select name="partidas[${idx}][unidad_comercial_id]" class="form-select searchable">
|
||||
<option value="">-- Unidad --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td><input name="partidas[${idx}][valor_factura]" type="number" step="0.01" class="form-control valor-partida"></td>
|
||||
<td><input name="partidas[${idx}][peso_bruto]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td>
|
||||
<select name="partidas[${idx}][tasa_preferencial]" class="form-select searchable">
|
||||
<option value="">-- Selecciona --</option>
|
||||
<option>General</option><option>TLC</option><option>PROSEC</option><option>ALADI</option><option>COMERCIALIZADORA</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="hide"><input name="partidas[${idx}][precio_unitario]" type="number" class="form-control"></td>
|
||||
<td class="hide"><input name="partidas[${idx}][oma_factura]" class="form-control"></td>
|
||||
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
||||
`;
|
||||
|
||||
tbody.appendChild(row);
|
||||
// Inicializamos Choices en los nuevos selects
|
||||
row.querySelectorAll('.searchable').forEach(el => {
|
||||
el._choices = new Choices(el, {
|
||||
searchEnabled: true,
|
||||
itemSelectText: '',
|
||||
shouldSort: false
|
||||
});
|
||||
});
|
||||
// seleccionar valor actual
|
||||
const current = "<?= htmlspecialchars($factura['proveedor_id'], ENT_QUOTES) ?>";
|
||||
if (current) {
|
||||
proveedorChoices.setChoiceByValue(current);
|
||||
});
|
||||
|
||||
// Eliminar partidas
|
||||
document.querySelector('#tabla-partidas tbody').addEventListener('click', e => {
|
||||
if (e.target.matches('.remove-row')) {
|
||||
const row = e.target.closest('tr');
|
||||
row.querySelectorAll('.searchable').forEach(el => {
|
||||
if (el._choices) el._choices.destroy();
|
||||
});
|
||||
row.remove();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error cargando proveedores:', err);
|
||||
proveedorEl.innerHTML = '<option value="">No fue posible cargar proveedores</option>';
|
||||
});
|
||||
|
||||
// 3) Agregar partida dinámica
|
||||
document.getElementById('add-partida').addEventListener('click', () => {
|
||||
const tbody = document.querySelector('#tabla-partidas tbody');
|
||||
const idx = tbody.querySelectorAll('tr').length;
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td><input name="partidas[\${idx}][descripcion]" class="form-control"></td>
|
||||
<td><input name="partidas[\${idx}][cantidad_comercial]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[\${idx}][cantidad_tarifa]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td>
|
||||
<select name="partidas[\${idx}][unidad_comercial_id]" class="form-select searchable">
|
||||
<option value="">-- Unidad --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td><input name="partidas[\${idx}][valor_factura]" type="number" step="0.01" class="form-control valor-partida"></td>
|
||||
<td><input name="partidas[\${idx}][peso_bruto]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td>
|
||||
<select name="partidas[\${idx}][tasa_preferencial]" class="form-select searchable">
|
||||
<option value="">-- Selecciona --</option>
|
||||
<option>General</option><option>TLC</option><option>PROSEC</option><option>ALADI</option><option>COMERCIALIZADORA</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="hide"><input name="partidas[\${idx}][precio_unitario]" type="number" class="form-control"></td>
|
||||
<td class="hide"><input name="partidas[\${idx}][oma_factura]" class="form-control"></td>
|
||||
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
// Re-inicializar Choices.js en los nuevos selects
|
||||
row.querySelectorAll('.searchable').forEach(el => {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
// Control overflow tabla cuando se abre el dropdown
|
||||
document.addEventListener('click', function(e) {
|
||||
const tableContainer = document.querySelector('.table-responsive');
|
||||
if (!tableContainer) return;
|
||||
if (e.target.closest('.choices__inner')) {
|
||||
tableContainer.style.overflow = 'visible';
|
||||
} else {
|
||||
tableContainer.style.overflow = 'auto';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Manejador para controlar el overflow al abrir dropdowns
|
||||
document.addEventListener('click', function(e) {
|
||||
const tableContainer = document.querySelector('.table-responsive');
|
||||
if (!tableContainer) return;
|
||||
|
||||
if (e.target.closest('.choices__inner')) {
|
||||
tableContainer.style.overflow = 'visible';
|
||||
} else {
|
||||
tableContainer.style.overflow = 'auto';
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelector('#tabla-partidas tbody').addEventListener('click', e => {
|
||||
if (e.target.matches('.remove-row')) e.target.closest('tr').remove();
|
||||
});
|
||||
|
||||
// validate suma partidas == valor_factura
|
||||
$('#solicitudForm').submit(function(e){
|
||||
const total = parseFloat($('#valor_factura').val())||0;
|
||||
let sum = 0;
|
||||
$('.valor-partida').each(function(){ sum += parseFloat($(this).val())||0; });
|
||||
if(Math.abs(sum - total) > 0.001){
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
icon:'error',
|
||||
title:'Error de validación',
|
||||
text:`La suma de partidas (${sum.toFixed(2)}) no coincide con Valor Factura (${total.toFixed(2)}).`
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// proveedores script (no modificado)
|
||||
document.querySelectorAll('.searchable').forEach(el => {
|
||||
if (el.id !== 'proveedor_id') {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
}
|
||||
});
|
||||
const proveedorEl = document.getElementById('proveedor_id');
|
||||
fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||||
.then(res => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return 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.text = item.text;
|
||||
proveedorEl.add(opt);
|
||||
});
|
||||
if (proveedorEl._choice) proveedorEl._choice.destroy();
|
||||
new Choices(proveedorEl, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error cargando proveedores:', err);
|
||||
proveedorEl.innerHTML = '<option value="">No fue posible cargar proveedores</option>';
|
||||
// Validación suma de partidas al enviar
|
||||
$('#solicitudForm').submit(function(e){
|
||||
const total = parseFloat($('#valor_factura').val()) || 0;
|
||||
let sum = 0;
|
||||
$('.valor-partida').each(function(){ sum += parseFloat($(this).val()) || 0; });
|
||||
if(Math.abs(sum - total) > 0.001){
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
icon:'error',
|
||||
title:'Error de validación',
|
||||
text:`La suma de partidas (${sum.toFixed(2)}) no coincide con Valor Factura (${total.toFixed(2)}).`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="foto_solicitud" class="form-label">Foto de la solicitud</label>
|
||||
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
||||
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control" accept="image/*">
|
||||
</div>
|
||||
</div>
|
||||
@@ -243,7 +243,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Choices.js & jQuery -->
|
||||
<!-- Choices.js JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
@@ -29,6 +29,13 @@
|
||||
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
|
||||
}
|
||||
.card { border-radius: 12px; }
|
||||
/* Forzar z-index más alto para modales anidados */
|
||||
.modal { z-index: 9999 !important; }
|
||||
.modal-backdrop { z-index: 9998 !important; }
|
||||
/* Asegurar que el contenido del modal esté por encima */
|
||||
.modal-dialog { z-index: 10000 !important; position: relative; }
|
||||
/* Opcional: Mejorar la apariencia del overlay */
|
||||
.modal-backdrop.show { opacity: 0.5; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -39,12 +46,20 @@
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Contenedor *</label>
|
||||
<input name="vehiculo" id="vehiculo" class="form-control" required>
|
||||
<div class="d-flex align-items-center">
|
||||
<input name="vehiculo" id="vehiculo" class="form-control" maxlength="20" required>
|
||||
<button type="button" class="btn btn-outline-secondary ms-2" data-bs-toggle="modal" data-bs-target="#infoContenedor" style="border: none;">ℹ️</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Identificador fiscal *</label>
|
||||
<input name="identificador_fiscal" id="identFiscal" class="form-control" required>
|
||||
<label class="form-label">Identificación fiscal *</label>
|
||||
<div class="d-flex align-items-center">
|
||||
<input name="identificador_fiscal" id="ident_fiscal" class="form-control" maxlength="20" required>
|
||||
<button type="button" class="btn btn-outline-secondary ms-2" data-bs-toggle="modal" data-bs-target="#infoIdentificacion" style="border: none;">ℹ️</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Foto (opcional)</label>
|
||||
<input type="file" name="foto" id="foto" class="form-control" accept="image/*">
|
||||
@@ -55,7 +70,7 @@
|
||||
<option value="">Selecciona...</option>
|
||||
<?php foreach($transportistas as $tr): ?>
|
||||
<option value="<?= $tr['id_transportista'] ?>">
|
||||
<?= htmlspecialchars(($tr['clave_identificador'] . ' - ' . $tr['nombre'])) ?>
|
||||
<?= htmlspecialchars(($tr['clave_identificador'] . ' - ' . $tr['nombre'] . ' - ' . $tr['ciudad_nombre'] . ' - ' . $tr['domicilio'])) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
@@ -68,38 +83,70 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Modales movidos FUERA del formulario -->
|
||||
<!-- Modal de ayuda - Contenedor -->
|
||||
<div class="modal fade" id="infoContenedor" tabindex="-1" aria-labelledby="infoContenedorLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="infoContenedorLabel">Info - Contenedor</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<strong>• Número económico del vehículo.</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal de ayuda - Identificación Fiscal -->
|
||||
<div class="modal fade" id="infoIdentificacion" tabindex="-1" aria-labelledby="infoIdentificacionLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="infoIdentificacionLabel">Info - Identificación Fiscal</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
• Si el medio de transporte es <strong>vehículo terrestre</strong>, se anotarán las <strong>placas de circulación</strong> del mismo.<br><br>
|
||||
• Si el medio de transporte es <strong>ferrocarril</strong>, se anotará el <strong>número de furgón o plataforma</strong>.<br><br>
|
||||
• Si el medio de transporte es <strong>marítimo</strong>, se anotará el <strong>nombre de la embarcación</strong>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('formTransCrear').addEventListener('submit', function(e) {
|
||||
e.preventDefault(); // Prevenir envío por defecto
|
||||
|
||||
// Campos que validamos:
|
||||
const veh = document.getElementById('vehiculo').value.trim();
|
||||
const fisc = document.getElementById('identFiscal').value.trim();
|
||||
const trans = document.getElementById('transportista').value;
|
||||
const fotoF = document.getElementById('foto').files[0];
|
||||
const vehiculo = document.getElementById('vehiculo').value.trim();
|
||||
const ident_fiscal = document.getElementById('ident_fiscal').value.trim();
|
||||
const transportista = document.getElementById('transportista').value;
|
||||
const fotoF = document.getElementById('foto').files[0];
|
||||
|
||||
// Validaciones de campos obligatorios
|
||||
if (!veh) {
|
||||
e.preventDefault();
|
||||
Swal.fire({ icon:'error', title:'Vehículo requerido', text:'Por favor ingresa el nombre del vehículo.', confirmButtonColor: '#dc3545'});
|
||||
document.querySelector('input[name="veh"]').focus();
|
||||
if (!vehiculo) {
|
||||
Swal.fire({ icon:'error', title:'Contenedor requerido', text:'Por favor ingresa el número económico del vehículo.', confirmButtonColor: '#dc3545'});
|
||||
document.getElementById('vehiculo').focus();
|
||||
return;
|
||||
}
|
||||
if (!fisc) {
|
||||
e.preventDefault();
|
||||
Swal.fire({ icon:'error', title:'Identificador fiscal requerido', text:'Por favor ingresa el identificador fiscal.', confirmButtonColor: '#dc3545' });
|
||||
document.querySelector('input[name="fisc"]').focus();
|
||||
if (!ident_fiscal) {
|
||||
Swal.fire({ icon:'error', title:'Identificación fiscal requerida', text:'Por favor ingresa la identificación fiscal.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('ident_fiscal').focus();
|
||||
return;
|
||||
}
|
||||
if (!trans) {
|
||||
e.preventDefault();
|
||||
if (!transportista) {
|
||||
Swal.fire({ icon:'error', title:'Transportista no seleccionado', text:'Debes elegir un transportista.', confirmButtonColor: '#dc3545' });
|
||||
document.querySelector('input[name="trans"]').focus();
|
||||
document.getElementById('transportista').focus();
|
||||
return;
|
||||
}
|
||||
if (fotoF && fotoF.size > 2 * 1024 * 1024) { // 2 MB
|
||||
e.preventDefault();
|
||||
return Swal.fire({ icon:'error', title:'Foto demasiado grande', text:'La imagen no debe exceder 2 MB.' });
|
||||
}
|
||||
// Si todas las validaciones pasan, el formulario se envía.
|
||||
this.submit();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -41,13 +41,19 @@
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Contenedor *</label>
|
||||
<input name="vehiculo" id="vehEdit" class="form-control"
|
||||
value="<?= htmlspecialchars($t['vehiculo']) ?>" required>
|
||||
<div class="d-flex align-items-center">
|
||||
<input name="vehiculo" id="vehiculo" class="form-control" maxlength="20"
|
||||
value="<?= htmlspecialchars($t['vehiculo']) ?>" required>
|
||||
<button type="button" class="btn btn-outline-secondary ms-2" data-bs-toggle="modal" data-bs-target="#infoContenedor" style="border: none;">ℹ️</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Identificador fiscal *</label>
|
||||
<input name="identificador_fiscal" id="fiscEdit" class="form-control"
|
||||
value="<?= htmlspecialchars($t['identificador_fiscal']) ?>" required>
|
||||
<label class="form-label">Identificación fiscal *</label>
|
||||
<div class="d-flex align-items-center">
|
||||
<input name="identificador_fiscal" id="identificador_fiscal" class="form-control" maxlength="20"
|
||||
value="<?= htmlspecialchars($t['identificador_fiscal']) ?>" required>
|
||||
<button type="button" class="btn btn-outline-secondary ms-2" data-bs-toggle="modal" data-bs-target="#infoIdentificacion" style="border: none;">ℹ️</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Foto actual</label><br>
|
||||
@@ -59,15 +65,15 @@
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Reemplazar foto (opcional)</label>
|
||||
<input type="file" name="foto" id="fotoEdit" class="form-control" accept="image/*">
|
||||
<input type="file" name="foto" id="foto" class="form-control" accept="image/*">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Transportista *</label>
|
||||
<select name="id_transportista" id="trEdit" class="form-select" required>
|
||||
<select name="id_transportista" id="transportista" class="form-select" required>
|
||||
<?php foreach($transportistas as $tr): ?>
|
||||
<option value="<?= $tr['id_transportista'] ?>"
|
||||
<?= $tr['id_transportista']==$t['id_transportista']?'selected':'' ?>>
|
||||
<?= htmlspecialchars($tr['nombre']) ?>
|
||||
<?= htmlspecialchars(($tr['clave_identificador'] . ' - ' . $tr['nombre'] . ' - ' . $tr['ciudad_nombre'] . ' - ' . $tr['domicilio'])) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
@@ -80,38 +86,70 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Modales movidos FUERA del formulario -->
|
||||
<!-- Modal de ayuda - Contenedor -->
|
||||
<div class="modal fade" id="infoContenedor" tabindex="-1" aria-labelledby="infoContenedorLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="infoContenedorLabel">Info - Contenedor</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<strong>• Número económico del vehículo.</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal de ayuda - Identificación Fiscal -->
|
||||
<div class="modal fade" id="infoIdentificacion" tabindex="-1" aria-labelledby="infoIdentificacionLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="infoIdentificacionLabel">Info - Identificación Fiscal</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
• Si el medio de transporte es <strong>vehículo terrestre</strong>, se anotarán las <strong>placas de circulación</strong> del mismo.<br><br>
|
||||
• Si el medio de transporte es <strong>ferrocarril</strong>, se anotará el <strong>número de furgón o plataforma</strong>.<br><br>
|
||||
• Si el medio de transporte es <strong>marítimo</strong>, se anotará el <strong>nombre de la embarcación</strong>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('formTransEdit').addEventListener('submit', function(e) {
|
||||
e.preventDefault(); // Prevenir envío por defecto
|
||||
|
||||
// Campos que validamos:
|
||||
const veh = document.getElementById('vehEdit').value.trim();
|
||||
const fisc = document.getElementById('fiscEdit').value.trim();
|
||||
const trans = document.getElementById('trEdit').value;
|
||||
const fotoF = document.getElementById('fotoEdit').files[0];
|
||||
const veh = document.getElementById('vehiculo').value.trim();
|
||||
const fisc = document.getElementById('identificador_fiscal').value.trim();
|
||||
const trans = document.getElementById('transportista').value;
|
||||
const fotoF = document.getElementById('foto').files[0];
|
||||
|
||||
// Validaciones de campos obligatorios
|
||||
if (!veh) {
|
||||
e.preventDefault();
|
||||
Swal.fire({ icon:'error', title:'Vehículo requerido', text:'Por favor ingresa el nombre del vehículo.', confirmButtonColor: '#dc3545'});
|
||||
document.querySelector('input[name="veh"]').focus();
|
||||
Swal.fire({ icon:'error', title:'Contenedor requerido', text:'Por favor ingresa el número económico del vehículo.', confirmButtonColor: '#dc3545'});
|
||||
document.getElementById('vehiculo').focus();
|
||||
return;
|
||||
}
|
||||
if (!fisc) {
|
||||
e.preventDefault();
|
||||
Swal.fire({ icon:'error', title:'Identificador fiscal requerido', text:'Por favor ingresa el identificador fiscal.', confirmButtonColor: '#dc3545' });
|
||||
document.querySelector('input[name="fisc"]').focus();
|
||||
Swal.fire({ icon:'error', title:'Identificación fiscal requerida', text:'Por favor ingresa la identificación fiscal.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('identificador_fiscal').focus();
|
||||
return;
|
||||
}
|
||||
if (!trans) {
|
||||
e.preventDefault();
|
||||
Swal.fire({ icon:'error', title:'Transportista no seleccionado', text:'Debes elegir un transportista.', confirmButtonColor: '#dc3545' });
|
||||
document.querySelector('input[name="trans"]').focus();
|
||||
document.getElementById('transportista').focus();
|
||||
return;
|
||||
}
|
||||
if (fotoF && fotoF.size > 2 * 1024 * 1024) { // 2 MB
|
||||
e.preventDefault();
|
||||
return Swal.fire({ icon:'error', title:'Foto demasiado grande', text:'La imagen no debe exceder 2 MB.' });
|
||||
}
|
||||
// Si todas las validaciones pasan, el formulario se envía.
|
||||
this.submit();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<label class="form-label">Archivo CSV *</label>
|
||||
<input type="file" name="csv" accept=".csv" class="form-control" required>
|
||||
</div>
|
||||
<p>Descarga la plantilla y llena las columnas: <code>contenedor, identificador_fiscal, id_transportista</code>.</p>
|
||||
<p>Descarga la plantilla y llena las columnas: <code>contenedor, identificación_fiscal, id_transportista</code>.</p>
|
||||
<a href="/IMPORTADORES/public/downloads/transportes_masivo_template.csv" class="btn btn-outline-secondary mb-3">
|
||||
📥 Descargar plantilla
|
||||
</a><br>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="curp" class="form-label">CURP *</label>
|
||||
<input name="curp" id="curp" class="form-control" maxlength="18" required>
|
||||
<input name="curp" id="curp" class="form-control" maxlength="18">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="caat" class="form-label">Código CAAT *</label>
|
||||
<label for="caat" class="form-label">Código caat *</label>
|
||||
<input name="caat" id="caat" class="form-control" maxlength="20" required>
|
||||
</div>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
<div class="col-md-8">
|
||||
<label for="domicilio" class="form-label">Domicilio *</label>
|
||||
<input name="domicilio" id="domicilio" class="form-control" required>
|
||||
<input name="domicilio" id="domicilio" class="form-control" maxlength="100" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -123,7 +123,6 @@
|
||||
const curpRegex = /^[A-Z]{4}[0-9]{6}[HM](AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS)[A-Z]{3}[A-Z0-9]{2}$/;
|
||||
const rfcRegex = /^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/;
|
||||
const telefonoRegex = /^\d{3}\s\d{7}$/;
|
||||
const soloNumerosRegex = /^[0-9]+$/;
|
||||
|
||||
// Validaciones de campos obligatorios
|
||||
if (!clave) {
|
||||
@@ -151,11 +150,6 @@
|
||||
document.getElementById('rfc').focus();
|
||||
return;
|
||||
}
|
||||
if (!curp) {
|
||||
Swal.fire({ icon: 'error', title: 'Campo requerido', text: 'El CURP es obligatorio.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('curp').focus();
|
||||
return;
|
||||
}
|
||||
// Validación de CURP (solo si se ingresó)
|
||||
if (curp && !curpRegex.test(curp)) {
|
||||
Swal.fire({ icon: 'error', title: 'CURP inválido', text: 'El CURP no tiene el formato correcto.', confirmButtonColor: '#dc3545'
|
||||
@@ -179,12 +173,7 @@
|
||||
return;
|
||||
}
|
||||
if (!caat) {
|
||||
Swal.fire({ icon: 'error', title: 'Campo requerido', text: 'El código CAAT es obligatorio.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('caat').focus();
|
||||
return;
|
||||
}
|
||||
if (!soloNumerosRegex.test(caat)) {
|
||||
Swal.fire({ icon: 'error', title: 'Código CAAT inválido', text: 'El código caat solo puede contener números.', confirmButtonColor: '#dc3545' });
|
||||
Swal.fire({ icon: 'error', title: 'Campo requerido', text: 'El código caat es obligatorio.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('caat').focus();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
id="telefono" class="form-control" maxlength="11" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Código CAAT</label>
|
||||
<label class="form-label">Código caat</label>
|
||||
<input name="caat" value="<?= htmlspecialchars($t['caat']) ?>"
|
||||
id="caat" class="form-control" maxlength="20" required>
|
||||
</div>
|
||||
@@ -140,7 +140,6 @@
|
||||
const curpRegex = /^[A-Z]{4}[0-9]{6}[HM](AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS)[A-Z]{3}[A-Z0-9]{2}$/;
|
||||
const rfcRegex = /^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/;
|
||||
const telefonoRegex = /^\d{3}\s\d{7}$/;
|
||||
const soloNumerosRegex = /^[0-9]+$/;
|
||||
|
||||
// Validaciones de campos obligatorios
|
||||
if (!clave) {
|
||||
@@ -168,11 +167,6 @@
|
||||
document.getElementById('rfc').focus();
|
||||
return;
|
||||
}
|
||||
if (!curp) {
|
||||
Swal.fire({ icon: 'error', title: 'Campo requerido', text: 'El CURP es obligatorio.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('curp').focus();
|
||||
return;
|
||||
}
|
||||
// Validación de CURP (solo si se ingresó)
|
||||
if (curp && !curpRegex.test(curp)) {
|
||||
Swal.fire({ icon: 'error', title: 'CURP inválido', text: 'El CURP no tiene el formato correcto.', confirmButtonColor: '#dc3545'
|
||||
@@ -196,12 +190,7 @@
|
||||
return;
|
||||
}
|
||||
if (!caat) {
|
||||
Swal.fire({ icon: 'error', title: 'Campo requerido', text: 'El código CAAT es obligatorio.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('caat').focus();
|
||||
return;
|
||||
}
|
||||
if (!soloNumerosRegex.test(caat)) {
|
||||
Swal.fire({ icon: 'error', title: 'Código CAAT inválido', text: 'El código caat solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||
Swal.fire({ icon: 'error', title: 'Campo requerido', text: 'El código caat es obligatorio.', confirmButtonColor: '#dc3545' });
|
||||
document.getElementById('caat').focus();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,29 +67,30 @@
|
||||
$('#transportistas-table').DataTable({
|
||||
serverSide: true,
|
||||
processing: true,
|
||||
searchDelay: 500, // espera 500 ms antes de lanzar la búsqueda
|
||||
deferRender: true, // renderiza las filas sólo cuando tiene los datos
|
||||
ajax: {
|
||||
url: '/IMPORTADORES/transportistas/ajax_lista',
|
||||
type: 'GET'
|
||||
},
|
||||
columns: [
|
||||
{ data: 0 },
|
||||
{ data: 1 },
|
||||
{ data: 2 },
|
||||
{ data: 3 },
|
||||
{ data: 4 },
|
||||
{ data: 5 },
|
||||
{ data: 0 }, // ID
|
||||
{ data: 1 }, // Código
|
||||
{ data: 2 }, // Nombre
|
||||
{ data: 3 }, // RFC
|
||||
{ data: 4 }, // Ciudad
|
||||
{ data: 5 }, // Fecha
|
||||
{
|
||||
data: null,
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
render: function(row) {
|
||||
const id = row[0];
|
||||
return `
|
||||
render: function(data, type, row) {
|
||||
const id = row[0];
|
||||
return `
|
||||
<a href="/IMPORTADORES/transportistas/editar?id=${id}" class="btn btn-sm btn-primary">✏️</a>
|
||||
<button class="btn btn-sm btn-danger" onclick="confirmDelete(${id})">🗑️</button>
|
||||
`;
|
||||
`;
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
language: {
|
||||
|
||||
Reference in New Issue
Block a user