Merge branch 'fix/varios' into 'main'

Fix/varios

See merge request jjimenez/safekat!784
This commit is contained in:
Ignacio Martinez Navajas
2025-05-05 18:14:05 +00:00
6 changed files with 86 additions and 33 deletions

View File

@ -3,6 +3,7 @@ namespace App\Controllers\Importadores;
use App\Controllers\BaseResourceController; use App\Controllers\BaseResourceController;
use App\Entities\Catalogo\CatalogoLibroEntity; use App\Entities\Catalogo\CatalogoLibroEntity;
use App\Models\Presupuestos\PresupuestoModel;
use App\Models\Catalogo\CatalogoLibroModel; use App\Models\Catalogo\CatalogoLibroModel;
use App\Controllers\Presupuestos\Presupuestocliente; use App\Controllers\Presupuestos\Presupuestocliente;
use App\Services\PresupuestoService; use App\Services\PresupuestoService;
@ -58,37 +59,51 @@ class ImportadorCatalogo extends BaseResourceController
{ {
$json = $this->request->getJSON(); $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([ return $this->response->setJSON([
'apto' => false, '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([ return $this->response->setJSON([
'apto' => false, '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(); $catalogoModel = new CatalogoLibroModel();
// 1. Buscar por ISBN exacto // 2. Buscar por ISBN exacto
$libroPorIsbn = $catalogoModel->where('isbn', $input)->first(); $libroPorIsbn = $catalogoModel->where('isbn', $input)->first();
if ($libroPorIsbn) { if ($libroPorIsbn) {
return $this->response->setJSON([ return $this->response->setJSON([
'apto' => true 'apto' => true
]); ]);
} }
// 2. Buscar por EAN sin guiones // 3. Buscar por EAN sin guiones
$eanLimpio = str_replace('-', '', $input); $eanLimpio = str_replace('-', '', $input);
$libroPorEan = $catalogoModel
$libroPorEan = $catalogoModel->where('REPLACE(ean, "-", "")', $eanLimpio)->first(); ->where('REPLACE(ean, "-", "")', $eanLimpio, false) // false para evitar escapado automático
->first();
if ($libroPorEan) { if ($libroPorEan) {
return $this->response->setJSON([ return $this->response->setJSON([
@ -96,7 +111,7 @@ class ImportadorCatalogo extends BaseResourceController
]); ]);
} }
// No encontrado // 4. No encontrado
return $this->response->setJSON([ return $this->response->setJSON([
'apto' => false, 'apto' => false,
'reason' => 'No encontrado en catálogo' 'reason' => 'No encontrado en catálogo'
@ -105,6 +120,7 @@ class ImportadorCatalogo extends BaseResourceController
public function importarFila() public function importarFila()
{ {
$json = $this->request->getJSON(); $json = $this->request->getJSON();

View File

@ -10,6 +10,7 @@ use App\Models\Tarifas\Acabados\ServicioAcabadoModel;
use App\Models\Clientes\ClienteModel; use App\Models\Clientes\ClienteModel;
class CatalogoLibroEntity extends Entity class CatalogoLibroEntity extends Entity
{ {
protected $attributes = [ protected $attributes = [
'id' => null, 'id' => null,
'cliente_id' => null, 'cliente_id' => null,
@ -44,8 +45,6 @@ class CatalogoLibroEntity extends Entity
'sello' => null, 'sello' => null,
'paginas' => 0, 'paginas' => 0,
'tipo_impresion' => null, 'tipo_impresion' => null,
'solapas_ancho' => 0.00,
'cubiertas_ancho' => 0.00,
'comentarios' => '', 'comentarios' => '',
'negro_paginas' => null, 'negro_paginas' => null,
'negro_papel' => null, 'negro_papel' => null,
@ -63,6 +62,8 @@ class CatalogoLibroEntity extends Entity
'cubierta_papel' => null, 'cubierta_papel' => null,
'cubierta_papel_id' => null, 'cubierta_papel_id' => null,
'cubierta_gramaje' => null, 'cubierta_gramaje' => null,
'cubierta_ancho_solapas' => 0.00,
'cubierta_acabado_id' => null,
'cubierta_acabado' => null, 'cubierta_acabado' => null,
'cubierta_pod_papel_id' => null, 'cubierta_pod_papel_id' => null,
'cubierta_pod_gramaje' => null, 'cubierta_pod_gramaje' => null,
@ -70,10 +71,12 @@ class CatalogoLibroEntity extends Entity
'sobrecubierta_papel' => null, 'sobrecubierta_papel' => null,
'sobrecubierta_papel_id' => null, 'sobrecubierta_papel_id' => null,
'sobrecubierta_gramaje' => null, 'sobrecubierta_gramaje' => null,
'sobrecubierta_acabado_id' => null,
'sobrecubierta_acabado' => null, 'sobrecubierta_acabado' => null,
'sobrecubierta_pod_papel_id' => null, 'sobrecubierta_pod_papel_id' => null,
'sobrecubierta_ancho_solapas' => 0.00,
'sobrecubierta_pod_gramaje' => null, 'sobrecubierta_pod_gramaje' => null,
'encuardenacion_id' => 'null', 'encuadernacion_id' => null,
'ubicacion' => null, 'ubicacion' => null,
'created_at' => null, 'created_at' => null,
'updated_at' => null, 'updated_at' => null,
@ -97,8 +100,6 @@ class CatalogoLibroEntity extends Entity
'num_ilustr_color' => '?int', 'num_ilustr_color' => '?int',
'num_ilustr_bn' => '?int', 'num_ilustr_bn' => '?int',
'paginas' => 'int', 'paginas' => 'int',
'solapas_ancho' => 'float',
'cubiertas_ancho' => 'float',
'negro_paginas' => '?int', 'negro_paginas' => '?int',
'negro_gramaje' => '?float', 'negro_gramaje' => '?float',
'negro_papel_id' => '?int', 'negro_papel_id' => '?int',
@ -113,15 +114,19 @@ class CatalogoLibroEntity extends Entity
'cubierta_gramaje' => '?float', 'cubierta_gramaje' => '?float',
'cubierta_papel_id' => '?int', 'cubierta_papel_id' => '?int',
'cubierta_pod_papel_id' => '?int', 'cubierta_pod_papel_id' => '?int',
'cubierta_ancho_solapas' => 'float',
'cubierta_pod_gramaje' => '?float', 'cubierta_pod_gramaje' => '?float',
'cubierta_acabado_id' => '?int',
'sobrecubierta_paginas' => '?int', 'sobrecubierta_paginas' => '?int',
'sobrecubierta_gramaje' => '?float', 'sobrecubierta_gramaje' => '?float',
'sobrecubierta_papel_id' => '?int', 'sobrecubierta_papel_id' => '?int',
'sobrecubierta_pod_papel_id' => '?int', 'sobrecubierta_pod_papel_id' => '?int',
'sobrecubierta_ancho_solapas' => 'float',
'sobrecubierta_pod_gramaje' => '?float', 'sobrecubierta_pod_gramaje' => '?float',
'sobrecubierta_acabado_id' => '?int',
'encuadernacion_id' => '?int',
'fecha_disponibilidad' => 'datetime', 'fecha_disponibilidad' => 'datetime',
'fecha_public' => 'datetime', 'fecha_public' => 'datetime',
]; ];
public function getClienteName() public function getClienteName()

View File

@ -721,7 +721,7 @@ return [
"menu_digitalizacion" => "Digitalización", "menu_digitalizacion" => "Digitalización",
"menu_importadores" => "Importadores", "menu_importadores" => "Importadores",
"menu_importadores_catalogo" => "Desde catálogo", "menu_importadores_catalogo" => "RA-MA", //"Desde catálogo",
"menu_importadores_bubok" => "Bubok", "menu_importadores_bubok" => "Bubok",
"menu_catalogo" => "Catálogo", "menu_catalogo" => "Catálogo",

View File

@ -25,11 +25,13 @@ if (auth()->user()->can('catalogo.menu')) {
</a> </a>
</li> </li>
<?php } ?> <?php } ?>
<li class="menu-item"> <?php if (auth()->user()->inGroup('beta')) { ?>
<a href="<?= site_url("catalogo/catalogo/importar") ?>" class="menu-link beta"> <li class="menu-item">
<?= lang("App.menu_catalogo_importar") ?> <a href="<?= site_url("catalogo/catalogo/importar") ?>" class="menu-link beta">
</a> <?= lang("App.menu_catalogo_importar") ?>
</li> </a>
</li>
<?php } ?>
</ul> </ul>
</li> </li>
<?php } ?> <?php } ?>

View File

@ -31,6 +31,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro',
@ -42,6 +43,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro',
@ -54,6 +56,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro',
@ -66,6 +69,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro', tipo: () => this.tipo_impresion.val().includes('hq') ? 'negrohq' : 'negro',
@ -79,6 +83,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color',
@ -90,6 +95,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color',
@ -102,6 +108,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color',
@ -114,6 +121,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'interior',
sopalas: 0, sopalas: 0,
lomo: 0, lomo: 0,
tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color', tipo: () => this.tipo_impresion.val().includes('hq') ? 'colorhq' : 'color',
@ -126,6 +134,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'cubierta',
sopalas: () => $('#cubierta_ancho_solapas').val(), sopalas: () => $('#cubierta_ancho_solapas').val(),
lomo: () => 0, lomo: () => 0,
tipo: 'colorhq', tipo: 'colorhq',
@ -138,6 +147,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'cubierta',
sopalas: () => $('#cubierta_ancho_solapas').val(), sopalas: () => $('#cubierta_ancho_solapas').val(),
lomo: () => 0, lomo: () => 0,
tipo: 'colorhq', tipo: 'colorhq',
@ -151,6 +161,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'cubierta',
sopalas: () => $('#cubierta_ancho_solapas').val(), sopalas: () => $('#cubierta_ancho_solapas').val(),
lomo: 0, lomo: 0,
tipo: 'colorhq', tipo: 'colorhq',
@ -163,6 +174,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'cubierta',
sopalas: () => $('#cubierta_ancho_solapas').val(), sopalas: () => $('#cubierta_ancho_solapas').val(),
lomo: 0, lomo: 0,
tipo: 'colorhq', tipo: 'colorhq',
@ -184,10 +196,10 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'sobrecubierta',
sopalas: () => $('#sobrecubierta_ancho_solapas').val(), sopalas: () => $('#sobrecubierta_ancho_solapas').val(),
lomo: () => 0, lomo: () => 0,
tipo: 'colorhq', tipo: 'colorhq',
uso: 'sobrecubierta',
}); });
this.selectPapelSobrecubiertaPod = new ClassSelect($("#sobrecubierta_pod_papel_id"), '/presupuestoadmin/papelgenerico', "Seleccione un papel", false, this.selectPapelSobrecubiertaPod = new ClassSelect($("#sobrecubierta_pod_papel_id"), '/presupuestoadmin/papelgenerico', "Seleccione un papel", false,
@ -196,10 +208,10 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'sobrecubierta',
sopalas: () => $('#sobrecubierta_ancho_solapas').val(), sopalas: () => $('#sobrecubierta_ancho_solapas').val(),
lomo: () => 0, lomo: () => 0,
tipo: 'colorhq', tipo: 'colorhq',
uso: 'sobrecubierta',
}); });
this.selectGramajeSobrecubierta = new ClassSelect($('#sobrecubierta_gramaje'), '/presupuestoadmin/papelgramaje', 'Seleccione un gramaje', false, this.selectGramajeSobrecubierta = new ClassSelect($('#sobrecubierta_gramaje'), '/presupuestoadmin/papelgramaje', 'Seleccione un gramaje', false,
@ -209,6 +221,7 @@ class Catalogo {
tirada: () => this.tirada_no_pod, tirada: () => this.tirada_no_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'sobrecubierta',
sopalas: () => $('#sobrecubierta_ancho_solapas').val(), sopalas: () => $('#sobrecubierta_ancho_solapas').val(),
lomo: 0, lomo: 0,
tipo: 'colorhq', tipo: 'colorhq',
@ -221,6 +234,7 @@ class Catalogo {
tirada: () => this.tirada_pod, tirada: () => this.tirada_pod,
ancho: () => this.getDimensionLibro().ancho, ancho: () => this.getDimensionLibro().ancho,
alto: () => this.getDimensionLibro().alto, alto: () => this.getDimensionLibro().alto,
uso: 'sobrecubierta',
sopalas: () => $('#sobrecubierta_ancho_solapas').val(), sopalas: () => $('#sobrecubierta_ancho_solapas').val(),
lomo: 0, lomo: 0,
tipo: 'colorhq', tipo: 'colorhq',

View File

@ -57,7 +57,8 @@ document.addEventListener('DOMContentLoaded', function () {
headerMap[name.toLowerCase()] = idx; 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) { if (missing.length > 0) {
Swal.fire({ Swal.fire({
title: 'Error', title: 'Error',
@ -73,7 +74,19 @@ document.addEventListener('DOMContentLoaded', function () {
const rows = []; const rows = [];
for (let i = 1; i < data.length; i++) { 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 // Llamar backend para validar la fila
const result = await validarFila(rowData); const result = await validarFila(rowData);
@ -163,7 +176,8 @@ document.addEventListener('DOMContentLoaded', function () {
// Actualizar campo "Notas" con el enlace // Actualizar campo "Notas" con el enlace
if (skUrl) { if (skUrl) {
const notasHtml = `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-secondary">Ver presupuesto</a>`; const skId = result.data?.sk_id ?? '';
const notasHtml = `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-secondary">Ver presupuesto (${skId})</a>`;
// La columna de notas es la posición 6 (índice 6) // La columna de notas es la posición 6 (índice 6)
rowData[6] = notasHtml; rowData[6] = notasHtml;
dataTable.row($row).data(rowData).draw(false); // Redibujar la fila SIN perder scroll ni filtros 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) { if (result.price_warning) {
html = skUrl ? `La fila se importó exitosamente, pero el precio se ha ajustado debajo de costes.<br><br><a href="${skUrl}" target="_blank" class="btn btn-primary mt-2">Ver presupuesto</a>` html = skUrl ? `La fila se importó exitosamente, pero el precio se ha ajustado debajo de costes.<br><br><a href="${skUrl}" target="_blank" class="btn btn-primary mt-2">Ver presupuesto</a>`
: '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'; icon = 'warning';
} }
@ -284,10 +298,12 @@ document.addEventListener('DOMContentLoaded', function () {
idsNoAjustados.push(result.data.sk_id); idsNoAjustados.push(result.data.sk_id);
} }
const skId = result.data?.sk_id ?? '';
if (skUrl) { if (skUrl) {
fila.rowData[6] = `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto</a>`; fila.rowData[6] = `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto (${skId})</a>`;
} else { } else {
fila.rowData[6] = `<span class="badge bg-success">Importado</span>`; fila.rowData[6] = `<span class="badge bg-success">Importado (${skId})</span>`;
} }
} else { } else {
fila.rowData[6] = `<span class="badge bg-danger">${result.message ?? 'Error desconocido'}</span>`; fila.rowData[6] = `<span class="badge bg-danger">${result.message ?? 'Error desconocido'}</span>`;