diff --git a/ci4/app/Config/Routes/ImportadoresRoutes.php b/ci4/app/Config/Routes/ImportadoresRoutes.php
index df3ffa12..ca54d7aa 100644
--- a/ci4/app/Config/Routes/ImportadoresRoutes.php
+++ b/ci4/app/Config/Routes/ImportadoresRoutes.php
@@ -18,6 +18,7 @@ $routes->group('importador', ['namespace' => 'App\Controllers\Importadores'], fu
* AJAX
*========================**/
$routes->post('validar-fila', 'ImportadorCatalogo::validarFila');
+ $routes->post('importar-fila', 'ImportadorCatalogo::importarFila');
});
diff --git a/ci4/app/Controllers/Importadores/ImportadorCatalogo.php b/ci4/app/Controllers/Importadores/ImportadorCatalogo.php
index 7c82e02a..61bf9714 100644
--- a/ci4/app/Controllers/Importadores/ImportadorCatalogo.php
+++ b/ci4/app/Controllers/Importadores/ImportadorCatalogo.php
@@ -4,8 +4,7 @@ namespace App\Controllers\Importadores;
use App\Controllers\BaseResourceController;
use App\Entities\Catalogo\CatalogoLibroEntity;
use App\Models\Catalogo\CatalogoLibroModel;
-use App\Models\Clientes\ClienteModel;
-use Hermawan\DataTables\DataTable;
+use App\Controllers\Presupuestos\Presupuestocliente;
class ImportadorCatalogo extends BaseResourceController
{
@@ -57,134 +56,6 @@ class ImportadorCatalogo extends BaseResourceController
}
- public function add()
- {
-
- if ($this->request->getPost()):
-
- $postData = $this->request->getPost();
-
- $sanitizedData = $this->sanitized($postData, true);
-
- $sanitizedData['user_created_id'] = auth()->user()->id;
- unset($sanitizedData['isk']);
-
- $noException = true;
- if ($successfulResult = $this->canValidate()):
-
- if ($this->canValidate()):
- try {
- $successfulResult = $this->model->skipValidation(true)->save($sanitizedData);
- } catch (\Exception $e) {
- $noException = false;
- $this->dealWithException($e);
- }
- else:
- $this->viewData['errorMessage'] = lang('Basic.global.formErr1', [lang('Basic.global.record')]);
- $this->session->setFlashdata('formErrors', $this->model->errors());
- endif;
-
- $thenRedirect = true; // Change this to false if you want your user to stay on the form after submission
- endif;
-
- if ($noException && $successfulResult):
-
- $id = $this->model->db->insertID();
-
- $message = lang('Basic.global.saveSuccess', [lang('Basic.global.record')]) . '.';
-
- if ($thenRedirect):
- if (!empty($this->indexRoute)):
- return redirect()->to(route_to($this->indexRoute))->with('sweet-success', $message);
- else:
- return $this->redirect2listView('sweet-success', $message);
- endif;
- else:
- $this->session->setFlashData('sweet-success', $message);
- endif;
-
- endif; // $noException && $successfulResult
-
- endif; // ($requestMethod === 'post')
-
- $this->viewData['catalogoLibrosEntity'] = isset($sanitizedData) ? new CatalogoLibroEntity($sanitizedData) : new CatalogoLibroEntity();
- $this->viewData['formAction'] = route_to('catalogoLibrosAdd');
- $this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('Catalogo.moduleTitle') . ' ' . lang('Basic.global.addNewSuffix');
-
- return $this->displayForm(__METHOD__);
- } // end function add()
-
- public function edit($requestedId = null)
- {
-
- if ($requestedId == null):
- return $this->redirect2listView();
- endif;
- $id = filter_var($requestedId, FILTER_SANITIZE_URL);
- $catalogoLibrosEntity = $this->model->find($id);
-
- if ($catalogoLibrosEntity == false):
- $message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Catalogo.pais')), $id]);
- return $this->redirect2listView('sweet-error', $message);
- endif;
-
- if ($this->request->getPost()):
-
- $postData = $this->request->getPost();
- $sanitizedData = $this->sanitized($postData, true);
- unset($sanitizedData['isk']);
- $sanitizedData['user_update_id'] = auth()->user()->id;
-
- $noException = true;
-
- if ($successfulResult = $this->canValidate()): // if ($successfulResult = $this->validate($this->formValidationRules) ) :
-
-
- if ($this->canValidate()):
- try {
- $successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
- } catch (\Exception $e) {
- $noException = false;
- $this->dealWithException($e);
- }
- else:
- $this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Catalogo.catalogo'))]);
- $this->session->setFlashdata('formErrors', $this->model->errors());
-
- endif;
-
- $catalogoLibrosEntity->fill($sanitizedData);
- $thenRedirect = false;
- endif;
-
- if ($noException && $successfulResult):
- $id = $catalogoLibrosEntity->id ?? $id;
- $message = lang('Basic.global.updateSuccess', [lang('Basic.global.record')]) . '.';
-
- if ($thenRedirect):
- if (!empty($this->indexRoute)):
- return redirect()->to(route_to($this->indexRoute))->with('sweet-success', $message);
- else:
- return $this->redirect2listView('sweet-success', $message);
- endif;
- else:
- $this->session->setFlashData('sweet-success', $message);
- endif;
-
- endif; // $noException && $successfulResult
- endif; // ($requestMethod === 'post')
-
-
- $this->viewData['catalogoLibrosEntity'] = $catalogoLibrosEntity;
- $this->viewData['formAction'] = route_to('catalogoLibrosEdit', $id);
- $this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Catalogo.moduleTitle') . ' ' . lang('Basic.global.edit3');
-
-
- return $this->displayForm(__METHOD__, $id);
- } // end function edit(...)
-
-
-
public function validarFila()
{
$json = $this->request->getJSON();
@@ -234,4 +105,244 @@ class ImportadorCatalogo extends BaseResourceController
]);
}
+
+
+ public function importarFila()
+ {
+ $json = $this->request->getJSON();
+
+ if (!$json || !isset($json->fila[0])) {
+ return $this->response->setJSON([
+ 'success' => false,
+ 'message' => 'Datos inválidos.'
+ ]);
+ }
+
+ // Mapear cada columna a una variable
+ $isbn = isset($json->fila[0]) ? trim($json->fila[0]) : null;
+ $refCliente = isset($json->fila[1]) ? trim($json->fila[1]) : null;
+ //$descripcion = isset($json->fila[2]) ? trim($json->fila[2]) : null;
+ $tirada = isset($json->fila[3]) ? (float) $json->fila[3] : null;
+ //$precio_compra = isset($json->fila[4]) ? (float) $json->fila[4] : null;
+
+ if (empty($isbn)) {
+ return $this->response->setJSON([
+ 'success' => false,
+ 'message' => 'Input vacío o no proporcionado.'
+ ]);
+ }
+
+ $catalogoModel = new CatalogoLibroModel();
+
+ // 1. Buscar por ISBN exacto
+ $libro = $catalogoModel->where('isbn', $isbn)->first();
+
+ // 2. Si no, buscar por EAN sin guiones
+ if (!$libro) {
+ $eanLimpio = str_replace('-', '', $isbn);
+
+ $libro = $catalogoModel->where('REPLACE(ean, "-", "")', $eanLimpio)->first();
+ }
+
+ if (!$libro) {
+ return $this->response->setJSON([
+ 'success' => false,
+ 'message' => 'No se encontró el libro en el catálogo.'
+ ]);
+ }
+
+ // Aquí ya tenemos el libro correcto.
+ // Ahora se prepara la "inserción" o el "registro" a importar
+ // Variables intermedias
+ $colorPaginas = (int) ($libro->color_paginas ?? 0);
+ $negroPaginas = (int) ($libro->negro_paginas ?? 0);
+ $papelInteriorDiferente = ($colorPaginas > 0 && $negroPaginas > 0) ? 1 : 0;
+
+ // --- Interior (lo que cambiamos ahora)
+ if ($papelInteriorDiferente) {
+ // Mixto: páginas en negro + color
+ $interior = [
+ 'papelInterior' => [
+ 'negro' => $libro->negro_papel_id,
+ 'color' => $libro->color_papel_id,
+ ],
+ 'gramajeInterior' => [
+ 'negro' => $libro->negro_gramaje,
+ 'color' => $libro->color_gramaje,
+ ]
+ ];
+ } else {
+ // SOLO un tipo: negro O color
+ $colorPaginas = (int)($libro->color_paginas ?? 0);
+ $negroPaginas = (int)($libro->negro_paginas ?? 0);
+
+ if ($colorPaginas > 0 && $negroPaginas == 0) {
+ // Libro completamente en color
+ $interior = [
+ 'papelInterior' => $libro->color_papel_id,
+ 'gramajeInterior' => $libro->color_gramaje,
+ ];
+ } else {
+ // Libro completamente en blanco y negro
+ $interior = [
+ 'papelInterior' => $libro->negro_papel_id,
+ 'gramajeInterior' => $libro->negro_gramaje,
+ ];
+ }
+ }
+
+ // Sobrecubierta
+ $sobrecubierta = [];
+ if (!is_null($libro->sobrecubierta_paginas)) {
+ $sobrecubierta['papel'] = $libro->sobrecubierta_papel_id;
+ $sobrecubierta['gramaje'] = $libro->sobrecubierta_gramaje;
+ $sobrecubierta['solapas'] = $libro->sobrecubierta_solapas;
+ $sobrecubierta['acabado'] = $libro->sobrecubierta_acabado_id;
+ }
+
+
+ $dataToImport = [
+ 'selectedTirada' => $tirada,
+ 'datosCabecera' => [
+ 'titulo' => $libro->titulo,
+ 'autor' => $libro->autor,
+ 'isbn' => $isbn,
+ 'coleccion' => $libro->coleccion,
+ 'referenciaCliente' => $refCliente
+ ],
+ 'tirada' => array_values(array_filter([
+ $tirada,
+ null,
+ null,
+ null,
+ ])),
+ 'tamanio' => [
+ 'ancho' => $libro->ancho,
+ 'alto' => $libro->alto
+ ],
+ 'tipo' => "",
+ 'tipo_presupuesto_id' => $libro->encuadernacion_id,
+ 'clienteId' => 251,
+ 'isColor' => (in_array(strtolower($libro->tipo_impresion), ['color', 'colorhq']) ? 1 : 0),
+ 'isHq' => (in_array(strtolower($libro->tipo_impresion), ['negrohq', 'colorhq']) ? 1 : 0),
+ 'paginas' => $libro->paginas,
+ 'paginasColor' => $colorPaginas,
+ 'papelInteriorDiferente' => $papelInteriorDiferente,
+ 'paginasCuadernillo' => 32,
+
+ 'interior' => $interior,
+
+ 'cubierta' => [
+ 'papelCubierta' => $libro->cubierta_papel_id,
+ 'gramajeCubierta' => $libro->cubierta_gramaje,
+ 'solapas' => $libro->cubierta_ancho_solapas,
+ 'acabado' => $libro->cubierta_acabado_id,
+ 'cabezada' => 'WHI',
+ 'lomoRedondo' => 0
+ ],
+
+ 'guardas' => [],
+ 'sobrecubierta' => $sobrecubierta,
+ 'faja' => [],
+
+ 'entrega_taller' => 1,
+ ];
+
+ /*return $this->response->setJSON([
+ 'success' => true,
+ 'message' => 'Libro encontrado y preparado para importar.',
+ 'data' => $dataToImport
+ ]);*/
+
+
+ // Procedemos a intentar guardar el presupuesto
+ // Instancia de presupuesto cliente
+ $presupuestocliente = new Presupuestocliente();
+ try {
+ $response = $presupuestocliente->guardar($dataToImport);
+
+ // DEBUG LINE
+ //return $this->respond($response);
+
+ if (!isset($response['sk_id'])) {
+ return $this->respond([
+ 'status' => 400,
+ 'error' => 'Missing sk_id',
+ 'message' => 'El identificador sk_id es requerido pero no se recibió.'
+ ], 400);
+ }
+
+ $response = [
+ 'status' => 200,
+ 'error' => null,
+ 'data' => [
+ 'sk_id' => $response['sk_id'],
+ 'sk_url' => $response['sk_url'] ?? null
+ ]
+ ];
+
+ return $this->respond($response);
+
+ } catch (\Exception $e) {
+
+ return $this->respond([
+ 'status' => 500,
+ 'error' => 'Server error',
+ 'message' => 'Error inesperado durante el procesado',
+ 'debug' => $e->getMessage()
+ ]);
+
+ }
+
+ }
+
+
+
+ public function guardar()
+ {
+ helper(['form']);
+
+ // Access the entire POST data
+ $post_data = $this->request->getJSON(true);
+
+ //return $this->respond(var_dump($post_data));
+
+ // Instancia de presupuesto cliente
+ $presupuestocliente = new Presupuestocliente();
+ try {
+ $response = $presupuestocliente->guardar($post_data);
+
+ // DEBUG LINE
+ //return $this->respond($response);
+
+ if (!isset($response['sk_id'])) {
+ return $this->respond([
+ 'status' => 400,
+ 'error' => 'Missing sk_id',
+ 'message' => 'El identificador sk_id es requerido pero no se recibió.'
+ ], 400);
+ }
+
+ $response = [
+ 'status' => 200,
+ 'error' => null,
+ 'data' => [
+ 'sk_id' => $response['sk_id'],
+ 'sk_url' => $response['sk_url'] ?? null
+ ]
+ ];
+
+ return $this->respond($response);
+
+ } catch (\Exception $e) {
+
+ return $this->respond([
+ 'status' => 500,
+ 'error' => 'Server error',
+ 'message' => 'Error inesperado durante el procesado'
+ ]);
+
+ }
+ }
+
}
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 a7b2e8dc..c5a008f2 100644
--- a/ci4/app/Views/themes/vuexy/form/importador/catalogo/viewImportadorCatalogoTool.php
+++ b/ci4/app/Views/themes/vuexy/form/importador/catalogo/viewImportadorCatalogoTool.php
@@ -35,40 +35,33 @@
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 8fce7010..923fe0a2 100644
--- a/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js
+++ b/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js
@@ -19,6 +19,18 @@ document.addEventListener('DOMContentLoaded', function () {
order: [[1, 'asc']]
});
+ // Crear filtros por columna en el segundo
+ $('#excelTable thead tr:eq(1) th').each(function (i) {
+ if (![0, 6, 7].includes(i)) { // No poner input en Checkbox, Notas ni Acciones
+ $(this).html('');
+ $('input', this).on('keyup change', function () {
+ if (dataTable.column(i).search() !== this.value) {
+ dataTable.column(i).search(this.value).draw();
+ }
+ });
+ }
+ });
+
document.getElementById('excelFile').addEventListener('change', function (e) {
const file = e.target.files[0];
if (!file) return;
@@ -64,38 +76,39 @@ document.addEventListener('DOMContentLoaded', function () {
const rowData = TABLE_COLUMNS.map(col => data[i][headerMap[col]] ?? '');
// Llamar backend para validar la fila
- const isValid = await validarFila(rowData);
+ const result = await validarFila(rowData);
let checkboxHtml = '';
let actionBtnsHtml = '';
+ let notaHtml = '';
- if (isValid) {
+ if (result.apto) {
checkboxHtml = ``;
-
+ notaHtml = '';
actionBtnsHtml = `
-
-
-
-
- `;
+
+
+
+
+ `;
} else {
checkboxHtml = ``;
-
+ notaHtml = `${result.reason}`;
actionBtnsHtml = `
-
- No Apto
-
-
- `;
+
+ No Apto
+
+
+ `;
}
- rows.push([checkboxHtml, ...rowData, actionBtnsHtml]);
+ rows.push([checkboxHtml, ...rowData, notaHtml, actionBtnsHtml]);
}
dataTable.clear().rows.add(rows).draw();
@@ -114,11 +127,10 @@ document.addEventListener('DOMContentLoaded', function () {
body: JSON.stringify({ fila: rowData })
});
- const result = await response.json();
- return result.apto === true;
+ return await response.json();
} catch (error) {
console.error('Error validando fila', error);
- return false;
+ return { apto: false, reason: 'Error conexión' };
}
}
@@ -127,25 +139,92 @@ document.addEventListener('DOMContentLoaded', 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 tbody').off('click', '.importRow').on('click', '.importRow', async function () {
+ const $row = $(this).closest('tr');
+ const rowData = dataTable.row($row).data();
+ if (!rowData) return;
- document.getElementById('importBtn').addEventListener('click', function () {
- const selectedRows = [];
+ const fila = rowData.slice(1, 6); // solo datos de negocio
- 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
+ try {
+ const response = await fetch('/importador/catalogo/importar-fila', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-TOKEN': '= csrf_hash() ?>'
+ },
+ body: JSON.stringify({ fila: fila })
+ });
+
+ const result = await response.json();
+
+ if (response.ok && result.status === 200) {
+ const skUrl = result.data?.sk_url ?? null;
+
+ // Actualizar campo "Notas" con el enlace
+ if (skUrl) {
+ const notasHtml = `Ver presupuesto`;
+ // La columna de notas es la posición 6 (índice 6)
+ rowData[6] = notasHtml;
+ dataTable.row($row).data(rowData).draw(false); // Redibujar la fila SIN perder scroll ni filtros
+ }
+
+ Swal.fire({
+ title: 'Importado correctamente',
+ html: skUrl
+ ? `La fila se importó exitosamente.
Ver presupuesto`
+ : 'La fila se importó exitosamente.',
+ icon: 'success',
+ confirmButtonText: 'Aceptar',
+ buttonsStyling: true,
+ customClass: { confirmButton: 'btn btn-success' }
+ });
+ } else {
+ Swal.fire({
+ title: 'Error',
+ text: result.message ?? 'Hubo un error al importar esta fila.',
+ icon: 'error',
+ confirmButtonText: 'Aceptar',
+ buttonsStyling: true,
+ customClass: { confirmButton: 'btn btn-danger' }
+ });
+ }
+ } catch (error) {
+ console.error('Error en la llamada a importar-fila:', error);
+ Swal.fire({
+ title: 'Error',
+ text: 'Error de comunicación con el servidor.',
+ icon: 'error',
+ confirmButtonText: 'Aceptar',
+ buttonsStyling: true,
+ customClass: { confirmButton: 'btn btn-danger' }
+ });
}
});
- if (selectedRows.length === 0) {
+
+ // Select All funcional
+ $('#selectAll').off('change').on('change', function () {
+ const checked = $(this).is(':checked');
+ $('#excelTable tbody input.select-row:enabled').prop('checked', checked);
+ });
+ }
+
+ /* Importacion */
+ document.getElementById('importBtn').addEventListener('click', function () {
+ const filasAptas = [];
+
+ dataTable.rows().every(function () {
+ const rowNode = this.node();
+ const checkbox = $(rowNode).find('input.select-row');
+
+ if (checkbox.length > 0 && checkbox.is(':checked') && !checkbox.is(':disabled')) {
+ const rowData = this.data();
+ filasAptas.push({ fila: rowData.slice(1, 6), rowNode: rowNode, rowData: rowData });
+ }
+ });
+
+ if (filasAptas.length === 0) {
Swal.fire({
title: 'Atención',
text: 'No hay filas aptas seleccionadas para importar.',
@@ -157,35 +236,66 @@ document.addEventListener('DOMContentLoaded', function () {
return;
}
- fetch('/importar', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'X-CSRF-TOKEN': '= csrf_hash() ?>'
- },
- 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: 'Error importando datos.',
- icon: 'error',
- confirmButtonText: 'Aceptar',
- buttonsStyling: true,
- customClass: { confirmButton: 'btn btn-danger' }
- });
+ Swal.fire({
+ title: '¿Confirmar importación?',
+ text: `Se van a importar ${filasAptas.length} filas.`,
+ icon: 'warning',
+ showCancelButton: true,
+ confirmButtonText: 'Sí, importar',
+ cancelButtonText: 'Cancelar',
+ reverseButtons: true,
+ buttonsStyling: true,
+ customClass: {
+ confirmButton: 'btn btn-primary',
+ cancelButton: 'btn btn-secondary'
+ }
+ }).then(async (result) => {
+ if (!result.isConfirmed) return;
+
+ for (const fila of filasAptas) {
+ try {
+ const response = await fetch('/importador/catalogo/importar-fila', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-TOKEN': '= csrf_hash() ?>'
+ },
+ body: JSON.stringify({ fila: fila.fila })
+ });
+
+ const result = await response.json();
+
+ if (response.ok && result.status === 200) {
+ const skUrl = result.data?.sk_url ?? null;
+
+ if (skUrl) {
+ fila.rowData[6] = `Ver presupuesto`;
+ } else {
+ fila.rowData[6] = `Importado`;
+ }
+ } else {
+ fila.rowData[6] = `${result.message ?? 'Error desconocido'}`;
+ }
+
+ dataTable.row(fila.rowNode).data(fila.rowData).draw(false);
+
+ } catch (error) {
+ console.error('Error importando fila:', error);
+ fila.rowData[6] = `Error de comunicación`;
+ dataTable.row(fila.rowNode).data(fila.rowData).draw(false);
+ }
+ }
+
+ Swal.fire({
+ title: 'Importación finalizada',
+ text: 'Se han procesado todas las filas seleccionadas.',
+ icon: 'success',
+ confirmButtonText: 'Aceptar',
+ buttonsStyling: true,
+ customClass: { confirmButton: 'btn btn-success' }
});
+ });
});
+
});