diff --git a/ci4/app/Controllers/Importadores/ImportadorCatalogo.php b/ci4/app/Controllers/Importadores/ImportadorCatalogo.php index e2ebb080..c77b0fea 100644 --- a/ci4/app/Controllers/Importadores/ImportadorCatalogo.php +++ b/ci4/app/Controllers/Importadores/ImportadorCatalogo.php @@ -3,6 +3,7 @@ namespace App\Controllers\Importadores; use App\Controllers\BaseResourceController; use App\Entities\Catalogo\CatalogoLibroEntity; +use App\Models\Presupuestos\PresupuestoModel; use App\Models\Catalogo\CatalogoLibroModel; use App\Controllers\Presupuestos\Presupuestocliente; use App\Services\PresupuestoService; @@ -45,7 +46,7 @@ class ImportadorCatalogo extends BaseResourceController $viewData = [ 'pageSubTitle' => lang('Basic.global.ManageAllRecords', [lang('Importador.importadorCatalogoTitle')]), - + ]; $viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class @@ -58,37 +59,51 @@ class ImportadorCatalogo extends BaseResourceController { $json = $this->request->getJSON(); - if (!$json || !isset($json->fila[0])) { + // Validación inicial del JSON y del ISBN + if (!$json || !isset($json->fila[0]) || empty(trim($json->fila[0]))) { return $this->response->setJSON([ 'apto' => false, - 'reason' => 'Datos inválidos' + 'reason' => 'ISBN no proporcionado o datos inválidos' ]); } - $input = trim($json->fila[0]); // Asumimos que 'input' es el primer campo de la fila + $input = trim($json->fila[0]); // ISBN + $refCliente = isset($json->fila[1]) ? trim($json->fila[1]) : null; - if (empty($input)) { + // Validar formato del refCliente (esperado: idpedido-idlinea) + if (empty($refCliente) || strpos($refCliente, '-') === false) { return $this->response->setJSON([ 'apto' => false, - 'reason' => 'ISBN no proporiconado' + 'reason' => 'Ref. cliente inválido' + ]); + } + + // 1. Comprobar duplicado en tabla de presupuestos + $presupuestoModel = new PresupuestoModel(); // Usa el modelo real que corresponda + $yaExiste = $presupuestoModel->where('referencia_cliente', $refCliente)->first(); + + if ($yaExiste) { + return $this->response->setJSON([ + 'apto' => false, + 'reason' => 'Referencia ya importada' ]); } $catalogoModel = new CatalogoLibroModel(); - // 1. Buscar por ISBN exacto + // 2. Buscar por ISBN exacto $libroPorIsbn = $catalogoModel->where('isbn', $input)->first(); - if ($libroPorIsbn) { return $this->response->setJSON([ 'apto' => true ]); } - // 2. Buscar por EAN sin guiones + // 3. Buscar por EAN sin guiones $eanLimpio = str_replace('-', '', $input); - - $libroPorEan = $catalogoModel->where('REPLACE(ean, "-", "")', $eanLimpio)->first(); + $libroPorEan = $catalogoModel + ->where('REPLACE(ean, "-", "")', $eanLimpio, false) // false para evitar escapado automático + ->first(); if ($libroPorEan) { return $this->response->setJSON([ @@ -96,7 +111,7 @@ class ImportadorCatalogo extends BaseResourceController ]); } - // No encontrado + // 4. No encontrado return $this->response->setJSON([ 'apto' => false, 'reason' => 'No encontrado en catálogo' @@ -105,6 +120,7 @@ class ImportadorCatalogo extends BaseResourceController + public function importarFila() { $json = $this->request->getJSON(); @@ -287,7 +303,7 @@ class ImportadorCatalogo extends BaseResourceController $response['data']['sk_id'], $precio_compra, $tirada, - null, + null, true ); if ($respuesta_ajuste['warning'] == true) { diff --git a/ci4/app/Entities/Catalogo/CatalogoLibroEntity.php b/ci4/app/Entities/Catalogo/CatalogoLibroEntity.php index e50d1a5f..780d544d 100644 --- a/ci4/app/Entities/Catalogo/CatalogoLibroEntity.php +++ b/ci4/app/Entities/Catalogo/CatalogoLibroEntity.php @@ -10,6 +10,7 @@ use App\Models\Tarifas\Acabados\ServicioAcabadoModel; use App\Models\Clientes\ClienteModel; class CatalogoLibroEntity extends Entity { + protected $attributes = [ 'id' => null, 'cliente_id' => null, @@ -44,8 +45,6 @@ class CatalogoLibroEntity extends Entity 'sello' => null, 'paginas' => 0, 'tipo_impresion' => null, - 'solapas_ancho' => 0.00, - 'cubiertas_ancho' => 0.00, 'comentarios' => '', 'negro_paginas' => null, 'negro_papel' => null, @@ -63,6 +62,8 @@ class CatalogoLibroEntity extends Entity 'cubierta_papel' => null, 'cubierta_papel_id' => null, 'cubierta_gramaje' => null, + 'cubierta_ancho_solapas' => 0.00, + 'cubierta_acabado_id' => null, 'cubierta_acabado' => null, 'cubierta_pod_papel_id' => null, 'cubierta_pod_gramaje' => null, @@ -70,10 +71,12 @@ class CatalogoLibroEntity extends Entity 'sobrecubierta_papel' => null, 'sobrecubierta_papel_id' => null, 'sobrecubierta_gramaje' => null, + 'sobrecubierta_acabado_id' => null, 'sobrecubierta_acabado' => null, 'sobrecubierta_pod_papel_id' => null, + 'sobrecubierta_ancho_solapas' => 0.00, 'sobrecubierta_pod_gramaje' => null, - 'encuardenacion_id' => 'null', + 'encuadernacion_id' => null, 'ubicacion' => null, 'created_at' => null, 'updated_at' => null, @@ -97,8 +100,6 @@ class CatalogoLibroEntity extends Entity 'num_ilustr_color' => '?int', 'num_ilustr_bn' => '?int', 'paginas' => 'int', - 'solapas_ancho' => 'float', - 'cubiertas_ancho' => 'float', 'negro_paginas' => '?int', 'negro_gramaje' => '?float', 'negro_papel_id' => '?int', @@ -113,15 +114,19 @@ class CatalogoLibroEntity extends Entity 'cubierta_gramaje' => '?float', 'cubierta_papel_id' => '?int', 'cubierta_pod_papel_id' => '?int', + 'cubierta_ancho_solapas' => 'float', 'cubierta_pod_gramaje' => '?float', + 'cubierta_acabado_id' => '?int', 'sobrecubierta_paginas' => '?int', 'sobrecubierta_gramaje' => '?float', 'sobrecubierta_papel_id' => '?int', 'sobrecubierta_pod_papel_id' => '?int', + 'sobrecubierta_ancho_solapas' => 'float', 'sobrecubierta_pod_gramaje' => '?float', + 'sobrecubierta_acabado_id' => '?int', + 'encuadernacion_id' => '?int', 'fecha_disponibilidad' => 'datetime', 'fecha_public' => 'datetime', - ]; public function getClienteName() diff --git a/ci4/app/Language/es/App.php b/ci4/app/Language/es/App.php index 085766ef..66873e89 100755 --- a/ci4/app/Language/es/App.php +++ b/ci4/app/Language/es/App.php @@ -721,7 +721,7 @@ return [ "menu_digitalizacion" => "Digitalización", "menu_importadores" => "Importadores", - "menu_importadores_catalogo" => "Desde catálogo", + "menu_importadores_catalogo" => "RA-MA", //"Desde catálogo", "menu_importadores_bubok" => "Bubok", "menu_catalogo" => "Catálogo", diff --git a/ci4/app/Views/themes/vuexy/main/menus/catalogo_menu.php b/ci4/app/Views/themes/vuexy/main/menus/catalogo_menu.php index 1f00317d..b03aece0 100755 --- a/ci4/app/Views/themes/vuexy/main/menus/catalogo_menu.php +++ b/ci4/app/Views/themes/vuexy/main/menus/catalogo_menu.php @@ -25,11 +25,13 @@ if (auth()->user()->can('catalogo.menu')) { - + user()->inGroup('beta')) { ?> + + \ No newline at end of file diff --git a/httpdocs/assets/js/safekat/pages/catalogo/catalogo.js b/httpdocs/assets/js/safekat/pages/catalogo/catalogo.js index 5a460f8e..9a9f1a58 100644 --- a/httpdocs/assets/js/safekat/pages/catalogo/catalogo.js +++ b/httpdocs/assets/js/safekat/pages/catalogo/catalogo.js @@ -31,6 +31,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', @@ -42,6 +43,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', @@ -54,6 +56,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', @@ -66,6 +69,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', @@ -79,6 +83,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', @@ -90,6 +95,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', @@ -102,6 +108,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', @@ -114,6 +121,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'interior', sopalas: 0, lomo: 0, tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', @@ -126,6 +134,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'cubierta', sopalas: () => $('#cubierta_ancho_solapas').val(), lomo: () => 0, tipo: 'colorhq', @@ -138,6 +147,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'cubierta', sopalas: () => $('#cubierta_ancho_solapas').val(), lomo: () => 0, tipo: 'colorhq', @@ -151,6 +161,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'cubierta', sopalas: () => $('#cubierta_ancho_solapas').val(), lomo: 0, tipo: 'colorhq', @@ -163,6 +174,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'cubierta', sopalas: () => $('#cubierta_ancho_solapas').val(), lomo: 0, tipo: 'colorhq', @@ -184,10 +196,10 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'sobrecubierta', sopalas: () => $('#sobrecubierta_ancho_solapas').val(), lomo: () => 0, tipo: 'colorhq', - uso: 'sobrecubierta', }); this.selectPapelSobrecubiertaPod = new ClassSelect($("#sobrecubierta_pod_papel_id"), '/presupuestoadmin/papelgenerico', "Seleccione un papel", false, @@ -196,10 +208,10 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'sobrecubierta', sopalas: () => $('#sobrecubierta_ancho_solapas').val(), lomo: () => 0, tipo: 'colorhq', - uso: 'sobrecubierta', }); this.selectGramajeSobrecubierta = new ClassSelect($('#sobrecubierta_gramaje'), '/presupuestoadmin/papelgramaje', 'Seleccione un gramaje', false, @@ -209,6 +221,7 @@ class Catalogo { tirada: () => this.tirada_no_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'sobrecubierta', sopalas: () => $('#sobrecubierta_ancho_solapas').val(), lomo: 0, tipo: 'colorhq', @@ -221,6 +234,7 @@ class Catalogo { tirada: () => this.tirada_pod, ancho: () => this.getDimensionLibro().ancho, alto: () => this.getDimensionLibro().alto, + uso: 'sobrecubierta', sopalas: () => $('#sobrecubierta_ancho_solapas').val(), lomo: 0, tipo: 'colorhq', 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 5b9e19c8..4423e5c5 100644 --- a/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js +++ b/httpdocs/assets/js/safekat/pages/importadores/catalogo/catalogo_tool.js @@ -57,7 +57,8 @@ document.addEventListener('DOMContentLoaded', function () { headerMap[name.toLowerCase()] = idx; }); - const missing = TABLE_COLUMNS.filter(col => !(col in headerMap)); + const requiredColumns = ["idpedido", ...TABLE_COLUMNS]; + const missing = requiredColumns.filter(col => !(col in headerMap)); if (missing.length > 0) { Swal.fire({ title: 'Error', @@ -73,7 +74,19 @@ document.addEventListener('DOMContentLoaded', function () { const rows = []; for (let i = 1; i < data.length; i++) { - const rowData = TABLE_COLUMNS.map(col => data[i][headerMap[col]] ?? ''); + // Leer columnas necesarias desde Excel + const input = data[i][headerMap["input"]] ?? ''; + const idlinea = data[i][headerMap["idlinea"]] ?? ''; + const idpedido = data[i][headerMap["idpedido"]] ?? ''; // aunque no esté en TABLE_COLUMNS, lo usamos aquí + const descripcion = data[i][headerMap["descripcion"]] ?? ''; + const cnt_pedida = data[i][headerMap["cnt_pedida"]] ?? ''; + const precio_compra = data[i][headerMap["precio_compra"]] ?? ''; + + // Componer Ref. Cliente + const refCliente = `${idpedido}-${idlinea}`; + + // Solo mostramos las columnas necesarias (como en el orden de DataTable HTML) + const rowData = [input, refCliente, descripcion, cnt_pedida, precio_compra]; // Llamar backend para validar la fila const result = await validarFila(rowData); @@ -163,7 +176,8 @@ document.addEventListener('DOMContentLoaded', function () { // Actualizar campo "Notas" con el enlace if (skUrl) { - const notasHtml = `Ver presupuesto`; + const skId = result.data?.sk_id ?? ''; + const notasHtml = `Ver presupuesto (${skId})`; // 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 @@ -176,7 +190,7 @@ document.addEventListener('DOMContentLoaded', function () { if (result.price_warning) { html = skUrl ? `La fila se importó exitosamente, pero el precio se ha ajustado debajo de costes.

Ver presupuesto` - : 'La fila se importó exitosamente, pero el precio se ha ajustado debajo de costes.'; + : 'La fila se importó exitosamente, pero el precio se ha ajustado debajo de costes.'; icon = 'warning'; } @@ -284,10 +298,12 @@ document.addEventListener('DOMContentLoaded', function () { idsNoAjustados.push(result.data.sk_id); } + const skId = result.data?.sk_id ?? ''; + if (skUrl) { - fila.rowData[6] = `Ver presupuesto`; + fila.rowData[6] = `Ver presupuesto (${skId})`; } else { - fila.rowData[6] = `Importado`; + fila.rowData[6] = `Importado (${skId})`; } } else { fila.rowData[6] = `${result.message ?? 'Error desconocido'}`;