Merge branch 'feat/importador_libros_catalogo_antiguo' into 'main'

Feat/importador libros catalogo antiguo

See merge request jjimenez/safekat!838
This commit is contained in:
Ignacio Martinez Navajas
2025-06-02 09:13:15 +00:00
12 changed files with 445 additions and 1913 deletions

View File

@ -0,0 +1,55 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use Config\Database;
use App\Models\Catalogo\IdentificadorIsknModel;
class CatalogoLibroAsignarIskn extends BaseCommand
{
protected $group = 'custom';
protected $name = 'catalogo:libro-asignar-iskn';
protected $description = 'Asigna ISKN directamente en la base de datos a los libros que no lo tienen.';
public function run(array $params)
{
$db = Database::connect();
$modelISKN = new IdentificadorIsknModel();
// Obtener todos los libros sin ISKN
$libros = $db->table('catalogo_libros')
->select('id')
->where('iskn IS NULL')
->where('deleted_at IS NULL')
->get()
->getResultArray();
if (empty($libros)) {
CLI::write('No hay libros sin ISKN por asignar.', 'green');
return;
}
CLI::write('Asignando ISKN a ' . count($libros) . ' libros...', 'yellow');
$i = 1;
foreach ($libros as $libro) {
$iskn = $modelISKN->newIskn();
if ($iskn !== null) {
$db->table('catalogo_libros')
->where('id', $libro['id'])
->update(['iskn' => $iskn]);
CLI::write("[{$i}] ISKN '{$iskn}' asignado a libro ID {$libro['id']}", 'cyan');
} else {
CLI::error("[{$i}] No se pudo generar ISKN para libro ID {$libro['id']}");
}
$i++;
}
CLI::write('Proceso finalizado.', 'green');
}
}

View File

@ -0,0 +1,204 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
class CatalogoLibroImportar extends BaseCommand
{
protected $group = 'custom';
protected $name = 'catalogo:libro-importar';
protected $description = 'Importa los registros de catalogo_libro a catalogo_libros para un customer_id dado';
public function run(array $params)
{
$db = \Config\Database::connect();
$totalImportados = 0;
// Al inicio del método run()
$papeles = $db->table('lg_papel_generico')
->select('id, code')
->where('is_deleted', 0)
->get()
->getResultArray();
// Mapa code => id
$papelMap = [];
foreach ($papeles as $p) {
if (!empty($p['code'])) {
$papelMap[trim($p['code'])] = $p['id'];
}
}
// Mapa de acabados => id
$acabadosMap = [
'plastificado_brillo' => 1,
'plastificado_mate' => 5,
];
// Mapa de encuadernaciones => id
$encuadernacionMap = [
'RCHV' => 4, // cosido tapa blanda
'RCHVS' => 20, // cosido tapa blanda solapas
'RDF' => 1, // fresado tapa dura
'RF' => 2, // fresado tapa blanda
'RFS' => 2, // fresado tapa blanda solapas
'TDC' => 3, // cosido tapa dura
];
if (empty($params[0]) || !is_numeric($params[0])) {
CLI::error('Debes proporcionar un customer_id válido como parámetro.');
return;
}
$customerId = (int) $params[0];
CLI::write("Iniciando importación para customer_id = $customerId ...", 'yellow');
$libros = $db->table('catalogo_libro_antiguo_erp')
->where('customer_id', $customerId)
->where('deleted_at', null)
->get()
->getResultArray();
if (empty($libros)) {
CLI::write('No se encontraron registros para importar.', 'red');
return;
}
foreach ($libros as $libro) {
$nuevoLibro = [
'id' => $libro['id'],
'cliente_id' => $libro['customer_id'],
'proveedor_id' => null,
'user_created_id' => 1,
'user_update_id' => 1,
'cubierta_archivo' => $libro['cover_file'],
'cubierta_url' => $libro['cover_url'],
'ancho' => $libro['ancho'],
'alto' => $libro['alto'],
'peso' => $libro['peso'],
'titulo' => $libro['titulo'],
'autor' => $libro['autor'] ?? null,
'autor_entidad' => $libro['autor_entidad'],
'traductor' => $libro['traductor'],
'ilustrador' => $libro['ilustrador'],
'idioma' => $libro['idioma'],
'num_edic' => $libro['num_edic'],
'fecha_disponibilidad' => $libro['fecha_disponibilidad'],
'fecha_public' => $libro['fecha_public'],
'num_fotos' => $libro['num_fotos'],
'num_ilustr' => $libro['num_ilustr'],
'num_ilustr_color' => $libro['num_ilustr_color'],
'num_ilustr_bn' => $libro['num_ilustr_bn'],
'coleccion' => $libro['coleccion'] ?? null,
'isbn' => $libro['isbn'],
'ean' => $this->generarEAN($libro['isbn']),
'editorial' => $libro['editorial'],
'resumen' => $libro['resumen'],
'resumen_breve' => $libro['resumen_breve'],
'sello' => $libro['sello'],
'paginas' => $libro['paginas'],
'tipo_impresion' => $this->mapTipoImpresion($libro['tipo_impresion']),
'comentarios' => $libro['comentarios'],
'negro_paginas' => $libro['negro_paginas'],
'negro_papel_id' => $this->getPapelId($libro['negro_papel'], $papelMap),
'negro_gramaje' => $libro['negro_gramaje'],
'negro_pod_papel_id' => $this->getPapelId($libro['negro_papel'], $papelMap),
'negro_pod_gramaje' => $libro['negro_gramaje'],
'color_paginas' => $libro['color_paginas'],
'color_papel_id' => $this->getPapelId($libro['color_papel'], $papelMap),
'color_gramaje' => $libro['color_gramaje'],
'color_pod_papel_id' => $this->getPapelId($libro['color_papel'], $papelMap),
'color_pod_gramaje' => $libro['color_gramaje'],
'cubierta_paginas' => $libro['portada_paginas'],
'cubierta_papel_id' => $this->getPapelId($libro['portada_papel'], $papelMap),
'cubierta_gramaje' => $libro['portada_gramaje'],
'cubierta_pod_papel_id' => $this->getPapelId($libro['portada_papel'], $papelMap),
'cubierta_pod_gramaje' => $libro['portada_gramaje'],
'cubierta_acabado_id' => $this->getAcabadoId($libro['portada_acabado'], $acabadosMap),
'cubierta_ancho_solapas' => $libro['solapas_ancho'],
'sobrecubierta_paginas' => $libro['cubierta_paginas'],
'sobrecubierta_papel_id' => $this->getPapelId($libro['cubierta_papel'], $papelMap),
'sobrecubierta_gramaje' => $libro['cubierta_gramaje'],
'sobrecubierta_pod_papel_id' => $this->getPapelId($libro['cubierta_papel'], $papelMap),
'sobrecubierta_pod_gramaje' => $libro['cubierta_gramaje'],
'sobrecubierta_acabado_id' => $this->getAcabadoId($libro['cubierta_acabado'], $acabadosMap),
'sobrecubierta_ancho_solapas' => 0,
'encuadernacion_id' => $this->getEncuadernacionId($libro['encuardenacion'], $encuadernacionMap),
'ubicacion' => $libro['ubicacion'],
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
'deleted_at' => $libro['deleted_at'],
'iskn' => null,
];
$exists = $db->table('catalogo_libros')
->where('id', $libro['id'])
->countAllResults();
if ($exists == 0) {
$db->table('catalogo_libros')->insert($nuevoLibro);
$totalImportados++;
}else{
CLI::write("El libro con ISBN " . $libro['isbn'] . " ya existe para el cliente con id " . $customerId . ".", 'yellow');
}
}
CLI::write("Importación finalizada. Se insertaron " . $totalImportados . " registros.", 'green');
}
private function mapTipoImpresion($tipo)
{
switch ($tipo) {
case 'bn':
return 'negro';
case 'color':
return 'color';
case 'colorfoto':
return 'colorhq';
case 'bicolor':
return 'color';
default:
return null;
}
}
private function getPapelId(?string $code, array $map): ?int
{
if ($code === null)
return null;
$code = trim($code);
return $map[$code] ?? null;
}
private function getAcabadoId(?string $nombre, array $map): ?int
{
if ($nombre === null)
return null;
$nombre = trim($nombre);
return $map[$nombre] ?? null;
}
private function getEncuadernacionId(?string $codigo, array $map): ?int
{
if ($codigo === null)
return null;
$codigo = trim($codigo);
return $map[$codigo] ?? null;
}
private function generarEAN(?string $isbn): ?string
{
if ($isbn === null)
return null;
return str_replace('-', '', $isbn);
}
}

View File

@ -12,7 +12,7 @@ use App\Models\Presupuestos\ImportadorModel;
use App\Models\Presupuestos\PresupuestoModel;
use App\Models\Usuarios\GroupModel;
use App\Models\Catalogo\CatalogoLibroModel;
use App\Models\Catalogo\IdentificadorIskModel;
use App\Models\Catalogo\IdentificadorIsknModel;
use App\Services\PresupuestoService;
use CodeIgniter\Shield\Entities\User;
@ -34,25 +34,19 @@ class Test extends BaseController
{
$this->emailService = service('emailService');
$a= $this->emailService->send('prueba', 'Esto es una prueba', ['imnavajas@coit.es','imnavajas@gmail.com']);
echo var_dump($a);
/*$modelCL = new CatalogoLibroModel();
$modelISK = new IdentificadorIskModel();
$modelISKN = new IdentificadorIsknModel();
// Obtener todos los registros sin isk
$registros = $modelCL->where('isk', null)->findAll();
// Obtener todos los registros sin iskn
$registros = $modelCL->where('iskn', null)->findAll();
$i = 0;
foreach ($registros as $registro) {
$isk = $modelISK->newIsk();
$iskn = $modelISKN->newIskn();
$modelCL->update($registro->id, ['isk' => $isk]);
$modelCL->update($registro->id, ['iskn' => $iskn]);
echo "[" . $i++ . "]Asignado ISK {$isk} a ID {$registro->id}<br>";
echo "[" . $i++ . "]Asignado ISKN {$iskn} a ID {$registro->id}<br>";
}*/

View File

@ -0,0 +1,38 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class RenameIskToIskn extends Migration
{
public function up()
{
// Renombrar columna isk a iskn
$this->forge->modifyColumn('catalogo_libros', [
'isk' => [
'name' => 'iskn',
'type' => 'VARCHAR',
'constraint' => 64,
'null' => true,
'default' => null,
'collation' => 'utf8_unicode_ci',
],
]);
}
public function down()
{
// Revertir el nombre de iskn a isk
$this->forge->modifyColumn('catalogo_libros', [
'iskn' => [
'name' => 'isk',
'type' => 'VARCHAR',
'constraint' => 64,
'null' => true,
'default' => null,
'collation' => 'utf8_unicode_ci',
],
]);
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class RenameIdentificadoresIskToIskn extends Migration
{
public function up()
{
// Renombrar la tabla
$this->db->query('RENAME TABLE identificadores_isk TO identificadores_iskn');
// Eliminar el índice único existente sobre 'isk'
$this->db->query('ALTER TABLE identificadores_iskn DROP INDEX isk');
// Renombrar la columna 'isk' a 'iskn'
$this->forge->modifyColumn('identificadores_iskn', [
'isk' => [
'name' => 'iskn',
'type' => 'VARCHAR',
'constraint' => 64,
'null' => false,
'collation' => 'utf8_general_ci',
],
]);
// Crear nuevo índice único sobre 'iskn'
$this->db->query('ALTER TABLE identificadores_iskn ADD UNIQUE INDEX iskn (iskn)');
}
public function down()
{
// Eliminar índice único sobre 'iskn'
$this->db->query('ALTER TABLE identificadores_iskn DROP INDEX iskn');
// Renombrar la columna 'iskn' de nuevo a 'isk'
$this->forge->modifyColumn('identificadores_iskn', [
'iskn' => [
'name' => 'isk',
'type' => 'VARCHAR',
'constraint' => 64,
'null' => false,
'collation' => 'utf8_general_ci',
],
]);
// Restaurar índice único sobre 'isk'
$this->db->query('ALTER TABLE identificadores_iskn ADD UNIQUE INDEX isk (isk)');
// Renombrar la tabla de nuevo a su nombre original
$this->db->query('RENAME TABLE identificadores_iskn TO identificadores_isk');
}
}

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ class CatalogoLibroEntity extends Entity
'num_ilustr_color' => 0,
'num_ilustr_bn' => 0,
'coleccion' => '',
'isk' => null,
'iskn' => null,
'isbn' => null,
'ean' => null,
'editorial' => '',

View File

@ -4,7 +4,7 @@ namespace App\Entities\Catalogo;
use CodeIgniter\Entity\Entity;
class IdentificadorIsk extends Entity
class IdentificadorIskn extends Entity
{
protected $dates = ['created_at', 'updated_at'];
}

View File

@ -93,12 +93,12 @@ class CatalogoLibroModel extends Model
protected $validationMessages = [];
protected $skipValidation = false;
protected $beforeInsert = ['asignarIsk', 'asignarEan', 'asignarCubiertaUrl'];
protected $beforeInsert = ['asignarIskn', 'asignarEan', 'asignarCubiertaUrl'];
protected $beforeUpdate = ['asignarEan', 'asignarCubiertaUrl'];
protected function asignarIsk(array $data): array
protected function asignarIskn(array $data): array
{
$data['data']['isk'] = model('App\Models\Catalogo\IdentificadorIskModel')->newIsk();
$data['data']['iskn'] = model('App\Models\Catalogo\IdentificadorIsknModel')->newIskn();
return $data;
}

View File

@ -1,79 +0,0 @@
<?php
namespace App\Models\Catalogo;
use CodeIgniter\Model;
use RuntimeException;
class IdentificadorIskModel extends Model
{
protected $table = 'identificadores_isk';
protected $primaryKey = 'id';
protected $returnType = \App\Entities\Catalogo\IdentificadorIsk::class;
protected $useSoftDeletes = false; // No soft delete
protected $useTimestamps = true;
protected $allowedFields = ['isk'];
protected $beforeInsert = ['agregarIsk'];
/**
* Crea un nuevo registro con un ISK único y lo devuelve.
*/
public function newIsk(string $contexto = 'libro'): string
{
$isk = $this->generarIskUnico($contexto);
$this->insert(['isk' => $isk]);
return $isk;
}
/**
* Genera un ISK único validado contra la base de datos.
*/
private function generarIskUnico(string $contexto): string
{
do {
$isk = $this->generarIsk($contexto);
} while ($this->where('isk', $isk)->countAllResults() > 0);
return $isk;
}
/**
* Formato legible de ISK, ejemplo: isk_libro_20250419_ab12c
*/
private function generarIsk(string $contexto): string
{
$fecha = date('Ymd');
$random = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0, 5);
return "isk_{$contexto}_{$fecha}_{$random}";
}
/**
* Hook para generar el ISK automáticamente al insertar.
*/
protected function agregarIsk(array $data): array
{
if (!isset($data['data']['isk']) || empty($data['data']['isk'])) {
$data['data']['isk'] = $this->generarIskUnico('registro');
}
return $data;
}
// Bloqueo total de eliminaciones
public function delete($id = null, bool $purge = false)
{
throw new RuntimeException('La eliminación de registros está deshabilitada.');
}
public function deleteWhere($where)
{
throw new RuntimeException('La eliminación de registros está deshabilitada.');
}
public function deleteBatch($where)
{
throw new RuntimeException('La eliminación de registros está deshabilitada.');
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Models\Catalogo;
use CodeIgniter\Model;
use RuntimeException;
class IdentificadorIsknModel extends Model
{
protected $table = 'identificadores_iskn';
protected $primaryKey = 'id';
protected $returnType = \App\Entities\Catalogo\IdentificadorIskn::class;
protected $useSoftDeletes = false; // No soft delete
protected $useTimestamps = true;
protected $allowedFields = ['iskn'];
protected $beforeInsert = ['agregarIskn'];
/**
* Crea un nuevo registro con un ISKN único y lo devuelve.
*/
public function newIskn(string $contexto = 'libro'): string
{
$iskn = $this->generarIsknUnico($contexto);
$this->insert(['iskn' => $iskn]);
return $iskn;
}
/**
* Genera un ISKN único validado contra la base de datos.
*/
private function generarIsknUnico(string $contexto): string
{
do {
$iskn = $this->generarIskn($contexto);
} while ($this->where('iskn', $iskn)->countAllResults() > 0);
return $iskn;
}
/**
* Formato legible de ISKN, ejemplo: iskn_libro_20250419_ab12c
*/
private function generarIskn(string $contexto): string
{
$fecha = date('Ymd');
$random = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789'), 0, 5);
return "iskn_{$contexto}_{$fecha}_{$random}";
}
/**
* Hook para generar el ISKN automáticamente al insertar.
*/
protected function agregarIskn(array $data): array
{
if (!isset($data['data']['iskn']) || empty($data['data']['iskn'])) {
$data['data']['iskn'] = $this->generarIsknUnico('registro');
}
return $data;
}
// Bloqueo total de eliminaciones
public function delete($id = null, bool $purge = false)
{
throw new RuntimeException('La eliminación de registros está deshabilitada.');
}
public function deleteWhere($where)
{
throw new RuntimeException('La eliminación de registros está deshabilitada.');
}
public function deleteBatch($where)
{
throw new RuntimeException('La eliminación de registros está deshabilitada.');
}
}

View File

@ -70,9 +70,9 @@
</div>
<div class="col-md-3 mb-3">
<label for="isk" class="form-label">Identificador ISK</label>
<input type="text" id="isk" name="isk" class="form-control" readonly
value="<?= old('isk', $catalogoLibrosEntity->isk) ?>" maxlength="64"
<label for="iskn" class="form-label">Identificador ISKN</label>
<input type="text" id="iskn" name="iskn" class="form-control" readonly
value="<?= old('iskn', $catalogoLibrosEntity->iskn) ?>" maxlength="64"
style="background: #E8E8E8;">
</div>