diff --git a/ci4/app/Config/Routes/ImportadoresRoutes.php b/ci4/app/Config/Routes/ImportadoresRoutes.php index 5bf2caca..df3ffa12 100644 --- a/ci4/app/Config/Routes/ImportadoresRoutes.php +++ b/ci4/app/Config/Routes/ImportadoresRoutes.php @@ -9,7 +9,7 @@ $routes->group('importador', ['namespace' => 'App\Controllers\Importadores'], fu /* Libros */ $routes->group('catalogo', ['namespace' => 'App\Controllers\Importadores'], function ($routes) { /**====================== - * CRUD + * Tool *========================**/ $routes->get('', 'ImportadorCatalogo::index', ['as' => 'importadorCatalogoTool']); @@ -17,6 +17,7 @@ $routes->group('importador', ['namespace' => 'App\Controllers\Importadores'], fu /**====================== * AJAX *========================**/ + $routes->post('validar-fila', 'ImportadorCatalogo::validarFila'); }); diff --git a/ci4/app/Controllers/Importadores/ImportadorCatalogo.php b/ci4/app/Controllers/Importadores/ImportadorCatalogo.php index 493fc4cb..7c82e02a 100644 --- a/ci4/app/Controllers/Importadores/ImportadorCatalogo.php +++ b/ci4/app/Controllers/Importadores/ImportadorCatalogo.php @@ -185,4 +185,53 @@ class ImportadorCatalogo extends BaseResourceController + public function validarFila() + { + $json = $this->request->getJSON(); + + if (!$json || !isset($json->fila[0])) { + return $this->response->setJSON([ + 'apto' => false, + 'reason' => 'Datos inválidos' + ]); + } + + $input = trim($json->fila[0]); // Asumimos que 'input' es el primer campo de la fila + + if (empty($input)) { + return $this->response->setJSON([ + 'apto' => false, + 'reason' => 'ISBN no proporiconado' + ]); + } + + $catalogoModel = new CatalogoLibroModel(); + + // 1. Buscar por ISBN exacto + $libroPorIsbn = $catalogoModel->where('isbn', $input)->first(); + + if ($libroPorIsbn) { + return $this->response->setJSON([ + 'apto' => true + ]); + } + + // 2. Buscar por EAN sin guiones + $eanLimpio = str_replace('-', '', $input); + + $libroPorEan = $catalogoModel->where('REPLACE(ean, "-", "")', $eanLimpio)->first(); + + if ($libroPorEan) { + return $this->response->setJSON([ + 'apto' => true + ]); + } + + // No encontrado + return $this->response->setJSON([ + 'apto' => false, + 'reason' => 'No encontrado en catálogo' + ]); + } + } diff --git a/ci4/app/Language/es/Importador.php b/ci4/app/Language/es/Importador.php index 930fe61a..8d4d36dd 100644 --- a/ci4/app/Language/es/Importador.php +++ b/ci4/app/Language/es/Importador.php @@ -9,6 +9,8 @@ return [ 'idlinea' => 'Ref. cliente', 'cnt_pedida' => 'Unidades', 'precio_compra' => 'Precio Compra', + 'importar' => 'Importar', + 'subirArchivo' => 'Cargar Excel proporcionado por RA-MA', 'libro' => 'libro', 'id' => 'ID', diff --git a/ci4/app/Views/themes/vuexy/form/importador/catalogo/viewImportadorCatalogoTool.php b/ci4/app/Views/themes/vuexy/form/importador/catalogo/viewImportadorCatalogoTool.php index e812993e..a7b2e8dc 100644 --- a/ci4/app/Views/themes/vuexy/form/importador/catalogo/viewImportadorCatalogoTool.php +++ b/ci4/app/Views/themes/vuexy/form/importador/catalogo/viewImportadorCatalogoTool.php @@ -10,47 +10,79 @@

-
- - -
+
+ -
- + +
- - - - - - - - - - - - - - - - - - - - + +
-
-
+
+ + +
+
+ +
+
-
- -
-
+ + + + + + + + + + + endSection() ?> diff --git a/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js b/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js index e72a8bfb..8fce7010 100644 --- a/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js +++ b/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js @@ -2,13 +2,21 @@ import Ajax from '../../../components/ajax.js'; document.addEventListener('DOMContentLoaded', function () { - // Columnas que espera la tabla (en el orden de HTML) const TABLE_COLUMNS = ["input", "idlinea", "descripcion", "cnt_pedida", "precio_compra"]; - let dataTable; // referencia al DataTable + let dataTable; dataTable = $('#excelTable').DataTable({ orderCellsTop: true, - fixedHeader: true + responsive: true, + scrollX: true, + lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500], + pageLength: 25, + lengthChange: true, + dom: 'lfrtip', + language: { + url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json" + }, + order: [[1, 'asc']] }); document.getElementById('excelFile').addEventListener('change', function (e) { @@ -28,124 +36,156 @@ document.addEventListener('DOMContentLoaded', function () { reader.readAsArrayBuffer(file); }); - function validateAndLoadDataTable(data) { + async function validateAndLoadDataTable(data) { if (data.length === 0) return; const headers = data[0].map(h => h.toString().trim()); - - // 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 + headerMap[name.toLowerCase()] = idx; }); - // Verificar si todas las columnas requeridas existen const missing = TABLE_COLUMNS.filter(col => !(col in headerMap)); if (missing.length > 0) { Swal.fire({ title: 'Error', - text: 'Faltan las siguientes columnas en el Excel: ' + missing.join(', '), + text: 'Faltan las siguientes columnas: ' + missing.join(', '), icon: 'error', confirmButtonText: 'Aceptar', buttonsStyling: true, - customClass: { - confirmButton: 'btn btn-danger' - } + customClass: { confirmButton: 'btn btn-danger' } }); - dataTable.clear().draw(); // limpia tabla + dataTable.clear().draw(); return; } const rows = []; for (let i = 1; i < data.length; i++) { - const row = []; + const rowData = TABLE_COLUMNS.map(col => data[i][headerMap[col]] ?? ''); - TABLE_COLUMNS.forEach(col => { - const idx = headerMap[col]; - row.push(data[i][idx] ?? ''); - }); + // Llamar backend para validar la fila + const isValid = await validarFila(rowData); - // Agregar botón al final - row.push(''); + let checkboxHtml = ''; + let actionBtnsHtml = ''; - rows.push(row); + if (isValid) { + checkboxHtml = ``; + + actionBtnsHtml = ` +
+ + +
+ `; + } else { + checkboxHtml = ``; + + actionBtnsHtml = ` +
+ No Apto + +
+ `; + } + + rows.push([checkboxHtml, ...rowData, actionBtnsHtml]); } dataTable.clear().rows.add(rows).draw(); - // Agregar eventos dinámicos para eliminar + setupEventListeners(); + } + + async function validarFila(rowData) { + try { + const response = await fetch('/importador/catalogo/validar-fila', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': '' + }, + body: JSON.stringify({ fila: rowData }) + }); + + const result = await response.json(); + return result.apto === true; + } catch (error) { + console.error('Error validando fila', error); + return false; + } + } + + function setupEventListeners() { $('#excelTable tbody').off('click', '.deleteRow').on('click', '.deleteRow', function () { dataTable.row($(this).parents('tr')).remove().draw(); }); + + $('#excelTable tbody').off('click', '.importRow').on('click', '.importRow', function () { + const rowData = dataTable.row($(this).parents('tr')).data(); + console.log('Importar esta fila:', rowData); + // Aquí podrías enviar sólo esta fila al servidor si quieres importar individualmente + }); } - $('#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', 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 () { - const allData = dataTable.rows().data().toArray(); - const rowsToSend = allData.map(row => row.slice(0, -1)); // sin botón - - if (rowsToSend.length === 0) { + const selectedRows = []; + + dataTable.rows().every(function () { + const data = this.data(); + const checkboxHtml = $(data[0]).find('input.select-row'); + if (checkboxHtml.length > 0 && checkboxHtml.is(':checked') && !checkboxHtml.is(':disabled')) { + selectedRows.push(data.slice(1, -1)); // sin checkbox ni botones + } + }); + + if (selectedRows.length === 0) { Swal.fire({ title: 'Atención', - text: 'No hay datos para importar.', + text: 'No hay filas aptas seleccionadas para importar.', icon: 'warning', confirmButtonText: 'Aceptar', buttonsStyling: true, - customClass: { - confirmButton: 'btn btn-warning' - } + customClass: { confirmButton: 'btn btn-warning' } }); return; } - + fetch('/importar', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '' }, - body: JSON.stringify({ data: rowsToSend }) + body: JSON.stringify({ data: selectedRows }) }).then(res => res.json()) - .then(response => { - 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' - } - }); - }); + .then(response => { + 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: 'Error importando datos.', + icon: 'error', + confirmButtonText: 'Aceptar', + buttonsStyling: true, + customClass: { confirmButton: 'btn btn-danger' } + }); + }); }); -}); \ No newline at end of file + +});