This commit is contained in:
2025-06-02 13:32:49 -06:00
parent c574183cee
commit 46a92a4415
19 changed files with 728 additions and 379 deletions

View File

@@ -99,7 +99,7 @@
</div>
<div class="col-md-4 mb-3">
<label for="pais_proveedor" class="form-label">País (Proveedor)</label>
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable">
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable" required>
<option value="">-- Selecciona País --</option>
<?php foreach($paises as $p): ?>
<option value="<?= htmlspecialchars($p['id_pais']) ?>"><?= htmlspecialchars($p['nombre']) ?></option>
@@ -108,7 +108,7 @@
</div>
<div class="col-md-4 mb-3">
<label for="tipo_moneda" class="form-label">Moneda</label>
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable">
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable" required>
<?php foreach(['MXN'=>'Peso Mexicano','USD'=>'Dólar USD','EUR'=>'Euro','CNY'=>'Yuan','GBP'=>'Libra GBP','JPY'=>'Yen'] as $code=>$label): ?>
<option value="<?= $code ?>"><?= "$label ($code)" ?></option>
<?php endforeach; ?>
@@ -139,7 +139,9 @@
<select id="transportista_id" name="transportista_id" class="form-select searchable" required>
<option value="">-- Selecciona --</option>
<?php foreach($transportistas as $t): ?>
<option value="<?= htmlspecialchars($t['id_transportista']) ?>"><?= htmlspecialchars($t['nombre']) ?></option>
<option value="<?= htmlspecialchars($t['id_transportista']) ?>">
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
@@ -148,7 +150,9 @@
<select id="chofer_id" name="chofer_id" class="form-select searchable" required>
<option value="">-- Selecciona Chofer --</option>
<?php foreach($choferes as $c): ?>
<option value="<?= htmlspecialchars($c['id_chofer']) ?>"><?= htmlspecialchars($c['nombre']) ?></option>
<option value="<?= htmlspecialchars($c['id_chofer']) ?>">
<?= htmlspecialchars($c['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
@@ -179,12 +183,12 @@
</thead>
<tbody>
<tr>
<td><input name="partidas[0][descripcion]" class="form-control w-100"></td>
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-100"></td>
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-100"></td>
<td><input name="partidas[0][descripcion]" class="form-control w-100" required></td>
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-100" min="0" required></td>
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-100" min="0" required></td>
<td>
<div class="mb-3">
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable" required>
<option value="">-- Unidad --</option>
<?php foreach($unidades_medida as $um): ?>
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
@@ -192,11 +196,11 @@
</select>
</div>
</td>
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-100"></td>
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-100"></td>
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-100" min="0" required></td>
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-100" min="0" required></td>
<td>
<div class="mb-3">
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
<select name="partidas[0][tasa_preferencial]" class="form-select searchable" required>
<option value="">-- Selecciona --</option>
<option>General</option>
<option>TLC</option>

View File

@@ -201,8 +201,8 @@
<?php endforeach; else: ?>
<tr>
<td><input name="partidas[0][descripcion]" class="form-control"></td>
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control"></td>
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control"></td>
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control" min="0"></td>
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control" min="0"></td>
<td>
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
<option value="">-- Unidad --</option>
@@ -211,8 +211,8 @@
<?php endforeach; ?>
</select>
</td>
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida"></td>
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control"></td>
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida" min="0"></td>
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control" min="0"></td>
<td>
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
<option value="">-- Selecciona --</option>
@@ -243,104 +243,125 @@
</div>
<!-- Choices.js & jQuery -->
<!-- Choices.js JS -->
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
<!-- 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>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<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 });
});
// 2) Cargar proveedores dinámicamente
const proveedorEl = document.getElementById('proveedor_id');
let proveedorChoices = null;
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);
});
// destruir instancia previa si existe
if (proveedorChoices) proveedorChoices.destroy();
proveedorChoices = new Choices(proveedorEl, {
searchEnabled: true,
itemSelectText: '',
shouldSort: false
});
// seleccionar valor actual
const current = '<?= htmlspecialchars($factura['proveedor_id'], ENT_QUOTES) ?>';
if (current) {
proveedorChoices.setChoiceByValue(current);
}
})
.catch(err => {
console.error('Error cargando proveedores:', err);
proveedorEl.innerHTML = '<option value="">No fue posible cargar proveedores</option>';
});
// 3) Agregar partida dinámica
// add-partida & validation script
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): ?>
<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>
<?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>
</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-init Choices para nuevos selects
// Re-inicializar Choices.js en los nuevos selects
row.querySelectorAll('.searchable').forEach(el => {
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
});
});
// 4) Remover partida
document.querySelector('#tabla-partidas tbody').addEventListener('click', e => {
if (e.target.matches('.remove-row')) {
e.target.closest('tr').remove();
// 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';
}
});
// 5) Validar suma de partidas
$('#solicitudForm').submit(function(e) {
const total = parseFloat($('.valor-total').val()) || 0;
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.01) {
$('.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)})`
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>
// ✅ DIFERENCIA PRINCIPAL: Inicializar Choices.js en partidas existentes
document.addEventListener('DOMContentLoaded', function() {
// Inicializar Choices.js en selects existentes de partidas (para edición)
document.querySelectorAll('#tabla-partidas .searchable').forEach(el => {
if (el.id !== 'proveedor_id') {
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
}
});
// Inicializar otros selects searchable (excepto proveedor_id que se maneja aparte)
document.querySelectorAll('.searchable').forEach(el => {
if (el.id !== 'proveedor_id' && !el.closest('#tabla-partidas')) {
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
}
});
});
// proveedores script - ✅ DIFERENCIA: Pre-seleccionar proveedor existente
const proveedorEl = document.getElementById('proveedor_id');
const proveedorActual = '<?= htmlspecialchars($factura['proveedor_clave'] ?? '') ?>'; // ← Proveedor actual
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;
// ✅ Pre-seleccionar si coincide con el proveedor actual
if (item.id === proveedorActual) {
opt.selected = true;
}
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>';
});
</script>
</body>
</html>
</html>

View File

@@ -1,3 +1,5 @@
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
@@ -82,7 +84,7 @@
</style>
</head>
<body>
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<div class="content">
<h4>📄 Solicitudes de Importación</h4>
<a href="/IMPORTADORES/solicitud_importacion/crear" class="btn btn-success mb-3"> Nueva Solicitud</a>
@@ -114,7 +116,7 @@
<td><?= htmlspecialchars($f['fecha_factura']) ?></td>
<td><?= htmlspecialchars($f['numero_pedimento']) ?></td>
<td><?= htmlspecialchars($f['incoterm']) ?></td>
<td><?= htmlspecialchars($f['pais_proveedor']) ?></td>
<td><?= htmlspecialchars($f['nombre_pais_proveedor']) ?></td>
<td><?= htmlspecialchars($f['tipo_moneda']) ?></td>
<td><?= number_format($f['valor_factura'],2) ?></td>
<td>