Revisión 2.1
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user