Configurando logica de captacion del Excel

This commit is contained in:
unknown
2025-04-27 09:16:15 +02:00
parent ae456c8890
commit ff115f4f20
4 changed files with 129 additions and 40 deletions

View File

@ -45,7 +45,7 @@ class ImportadorCatalogo extends BaseResourceController
$viewData = [ $viewData = [
'currentModule' => static::$controllerSlug, 'currentModule' => static::$controllerSlug,
'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Catalogo.catalogo')]), 'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Importador.importadorCatalogoTitle')]),
'catalogoLibrosEntity' => new CatalogoLibroEntity(), 'catalogoLibrosEntity' => new CatalogoLibroEntity(),
'usingServerSideDataTable' => true, 'usingServerSideDataTable' => true,

View File

@ -1,18 +1,21 @@
<?php <?php
return [ return [
'moduleTitle' => 'Importador desde catálogo', 'moduleTitle' => 'Importadores',
'listingPage' => 'Listado de libros', 'importadorCatalogoTitle' => 'Importador desde catálogo',
'catalogo' => 'catálogo', 'catalogo' => 'catálogo',
'libro' => 'libro', 'input' => 'ISBN',
'descripcion' => 'Título',
'idlinea' => 'Ref. cliente',
'cnt_pedida' => 'Unidades',
'precio_compra' => 'Precio Compra',
'libro' => 'libro',
'id' => 'ID', 'id' => 'ID',
'clienteId' => 'Cliente', 'clienteId' => 'Cliente',
'cliente' => 'Cliente', 'cliente' => 'Cliente',
'proveedorId' => 'Proveedor',
'userCreatedId' => 'Usuario Creador', 'userCreatedId' => 'Usuario Creador',
'userUpdateId' => 'Usuario Actualizador', 'userUpdateId' => 'Usuario Actualizador',
'cubiertaArchivo' => 'Archivo de Cubierta',
'cubiertaUrl' => 'URL de Cubierta',
'portada' => 'Portada', 'portada' => 'Portada',
'ancho' => 'Ancho', 'ancho' => 'Ancho',
'alto' => 'Alto', 'alto' => 'Alto',

View File

@ -8,7 +8,7 @@
<div class="card card-info"> <div class="card card-info">
<div class="card-header"> <div class="card-header">
<h3 class="card-title"><?= lang('Importador.listingPage') ?></h3> <h3 class="card-title"><?= lang('Importador.importadorCatalogoTitle') ?></h3>
</div><!--//.card-header --> </div><!--//.card-header -->
<div class="card-body"> <div class="card-body">
<?= view('themes/_commonPartialsBs/_alertBoxes'); ?> <?= view('themes/_commonPartialsBs/_alertBoxes'); ?>
@ -19,18 +19,27 @@
<br> <br>
<button id="importBtn">Importar</button> <button id="importBtn">Importar</button>
<table id="excelTable" class="display"> <table id="excelTable" class="table table-striped table-hover" style="width: 100%;">
<thead> <thead>
<tr> <tr>
<th>cnt_pedida</th> <th><?= lang('Importador.input') ?></th>
<th>precio_compra</th> <th><?= lang('Importador.idlinea') ?></th>
<th>idlinea</th> <th><?= lang('Importador.descripcion') ?></th>
<th>input</th> <th><?= lang('Importador.cnt_pedida') ?></th>
<th>descripcion</th> <th><?= lang('Importador.precio_compra') ?></th>
<th>Acción</th> <th class="text-nowrap" style="min-width: 85px;"><?= lang('Basic.global.Action') ?></th>
</tr>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
</tbody> </tbody>
</table> </table>

View File

@ -1,12 +1,15 @@
import Ajax from '../../../components/ajax.js';
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
// Columnas requeridas // Columnas que espera la tabla (en el orden de HTML)
const REQUIRED_COLUMNS = ["cnt_pedida", "precio_compra", "idlinea", "input", "descripcion"]; const TABLE_COLUMNS = ["input", "idlinea", "descripcion", "cnt_pedida", "precio_compra"];
let dataTable; // referencia al DataTable let dataTable; // referencia al DataTable
dataTable = $('#excelTable').DataTable({
// Inicializa el DataTable vacío orderCellsTop: true,
dataTable = $('#excelTable').DataTable(); fixedHeader: true
});
document.getElementById('excelFile').addEventListener('change', function (e) { document.getElementById('excelFile').addEventListener('change', function (e) {
const file = e.target.files[0]; const file = e.target.files[0];
@ -26,37 +29,90 @@ document.addEventListener('DOMContentLoaded', function () {
}); });
function validateAndLoadDataTable(data) { function validateAndLoadDataTable(data) {
if (data.length === 0) return;
const headers = data[0].map(h => h.toString().trim()); const headers = data[0].map(h => h.toString().trim());
const missing = REQUIRED_COLUMNS.filter(col => !headers.includes(col)); // Crear un índice rápido de nombreColumna => posicion
const headerMap = {};
headers.forEach((name, idx) => {
headerMap[name.toLowerCase()] = idx; // pasar todo a minúsculas para evitar errores
});
// Verificar si todas las columnas requeridas existen
const missing = TABLE_COLUMNS.filter(col => !(col in headerMap));
if (missing.length > 0) { if (missing.length > 0) {
alert('Faltan las siguientes columnas en el Excel: ' + missing.join(', ')); Swal.fire({
title: 'Error',
text: 'Faltan las siguientes columnas en el Excel: ' + missing.join(', '),
icon: 'error',
confirmButtonText: 'Aceptar',
buttonsStyling: true,
customClass: {
confirmButton: 'btn btn-danger'
}
});
dataTable.clear().draw(); // limpia tabla dataTable.clear().draw(); // limpia tabla
return; return;
} }
const indexes = REQUIRED_COLUMNS.map(col => headers.indexOf(col));
const rows = []; const rows = [];
for (let i = 1; i < data.length; i++) { for (let i = 1; i < data.length; i++) {
const rowData = indexes.map(idx => data[i][idx] ?? ''); const row = [];
rowData.push('<button class="deleteRow">Eliminar</button>'); // Agrega botón
rows.push(rowData); TABLE_COLUMNS.forEach(col => {
const idx = headerMap[col];
row.push(data[i][idx] ?? '');
});
// Agregar botón al final
row.push('<button type="button" class="btn btn-danger btn-sm deleteRow">Eliminar</button>');
rows.push(row);
} }
dataTable.clear().rows.add(rows).draw(); dataTable.clear().rows.add(rows).draw();
// Agregar eventos a los nuevos botones de eliminar // Agregar eventos dinámicos para eliminar
$('#excelTable tbody').on('click', '.deleteRow', function () { $('#excelTable tbody').off('click', '.deleteRow').on('click', '.deleteRow', function () {
dataTable.row($(this).parents('tr')).remove().draw(); dataTable.row($(this).parents('tr')).remove().draw();
}); });
} }
$('#excelTable thead tr:eq(1) th').each(function (i) {
const title = $(this).text();
if (title.trim() !== '') { // Solo si el th tiene título
$(this).html('<input type="text" class="form-control form-control-sm" placeholder="Filtrar..." />');
$('input', this).on('keyup change', function () {
if (dataTable.column(i).search() !== this.value) {
dataTable
.column(i)
.search(this.value)
.draw();
}
});
}
});
document.getElementById('importBtn').addEventListener('click', function () { document.getElementById('importBtn').addEventListener('click', function () {
const allData = dataTable.rows().data().toArray(); const allData = dataTable.rows().data().toArray();
const rowsToSend = allData.map(row => row.slice(0, -1)); // sin botón
// Eliminar la última columna (botón) de cada fila if (rowsToSend.length === 0) {
const rowsToSend = allData.map(row => row.slice(0, -1)); Swal.fire({
title: 'Atención',
text: 'No hay datos para importar.',
icon: 'warning',
confirmButtonText: 'Aceptar',
buttonsStyling: true,
customClass: {
confirmButton: 'btn btn-warning'
}
});
return;
}
fetch('/importar', { fetch('/importar', {
method: 'POST', method: 'POST',
@ -66,9 +122,30 @@ document.addEventListener('DOMContentLoaded', function () {
}, },
body: JSON.stringify({ data: rowsToSend }) body: JSON.stringify({ data: rowsToSend })
}).then(res => res.json()) }).then(res => res.json())
.then(response => { .then(response => {
alert(response.message); Swal.fire({
}); title: 'Importación exitosa',
text: response.message,
icon: 'success',
confirmButtonText: 'Aceptar',
buttonsStyling: true,
customClass: {
confirmButton: 'btn btn-success'
}
});
})
.catch(error => {
console.error(error);
Swal.fire({
title: 'Error',
text: 'Hubo un problema al importar los datos.',
icon: 'error',
confirmButtonText: 'Aceptar',
buttonsStyling: true,
customClass: {
confirmButton: 'btn btn-danger'
}
});
});
}); });
}); });