mirror of
https://git.imnavajas.es/jjimenez/safekat.git
synced 2025-07-25 22:52:08 +00:00
Merge branch 'feat/catalogo' into 'main'
Feat/catalogo See merge request jjimenez/safekat!727
This commit is contained in:
214
ci4/app/Models/Catalogo/CatalogoLibroModel.php
Normal file
214
ci4/app/Models/Catalogo/CatalogoLibroModel.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Catalogo;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Entities\Catalogo\CatalogoLibroEntity;
|
||||
use App\Models\Clientes\ClienteModel;
|
||||
|
||||
class CatalogoLibroModel extends Model
|
||||
{
|
||||
protected $table = 'catalogo_libros';
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
protected $returnType = CatalogoLibroEntity::class;
|
||||
protected $useSoftDeletes = true;
|
||||
protected $useTimestamps = true;
|
||||
|
||||
protected $allowedFields = [
|
||||
'cliente_id',
|
||||
'proveedor_id',
|
||||
'cubierta_archivo',
|
||||
'ancho',
|
||||
'alto',
|
||||
'peso',
|
||||
'titulo',
|
||||
'autor',
|
||||
'autor_entidad',
|
||||
'traductor',
|
||||
'ilustrador',
|
||||
'idioma',
|
||||
'num_edic',
|
||||
'fecha_disponibilidad',
|
||||
'fecha_public',
|
||||
'num_fotos',
|
||||
'num_ilustr',
|
||||
'num_ilustr_color',
|
||||
'num_ilustr_bn',
|
||||
'coleccion',
|
||||
'isbn',
|
||||
'editorial',
|
||||
'resumen',
|
||||
'resumen_breve',
|
||||
'sello',
|
||||
'paginas',
|
||||
'tipo_impresion',
|
||||
'comentarios',
|
||||
'negro_paginas',
|
||||
'negro_papel_id',
|
||||
'negro_gramaje',
|
||||
'negro_pod_papel_id',
|
||||
'negro_pod_gramaje',
|
||||
'color_paginas',
|
||||
'color_papel_id',
|
||||
'color_gramaje',
|
||||
'color_pod_papel_id',
|
||||
'color_pod_gramaje',
|
||||
'cubierta_paginas',
|
||||
'cubierta_papel_id',
|
||||
'cubierta_gramaje',
|
||||
'cubierta_acabado_id',
|
||||
'cubierta_ancho_solapas',
|
||||
'cubierta_pod_papel_id',
|
||||
'cubierta_pod_gramaje',
|
||||
'sobrecubierta_paginas',
|
||||
'sobrecubierta_papel_id',
|
||||
'sobrecubierta_gramaje',
|
||||
'sobrecubierta_acabado_id',
|
||||
'sobrecubierta_ancho_solapas',
|
||||
'sobrecubierta_pod_papel_id',
|
||||
'sobrecubierta_pod_gramaje',
|
||||
'encuadernacion_id',
|
||||
'ubicacion',
|
||||
];
|
||||
|
||||
protected $useAutoIncrement = true;
|
||||
protected $protectFields = true;
|
||||
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $deletedField = 'deleted_at';
|
||||
|
||||
// Opcional: reglas de validación
|
||||
protected $validationRules = [
|
||||
'cliente_id' => 'required|is_natural_no_zero',
|
||||
'titulo' => 'required|string|min_length[2]|max_length[300]',
|
||||
'paginas' => 'required|integer|greater_than[0]',
|
||||
'ancho' => 'required|decimal|greater_than[0]',
|
||||
'alto' => 'required|decimal|greater_than[0]',
|
||||
'tipo_impresion' => 'required|in_list[negro,negrohq,color,colorhq]',
|
||||
'isbn' => 'required|regex_match[/^[\d-]+$/]',
|
||||
'encuadernacion_id' => 'required|is_natural_no_zero',
|
||||
];
|
||||
protected $validationMessages = [];
|
||||
protected $skipValidation = false;
|
||||
|
||||
protected $beforeInsert = ['asignarIsk', 'asignarEan', 'asignarCubiertaUrl'];
|
||||
protected $beforeUpdate = ['asignarEan', 'asignarCubiertaUrl'];
|
||||
|
||||
protected function asignarIsk(array $data): array
|
||||
{
|
||||
$data['data']['isk'] = model('App\Models\Catalogo\IdentificadorIskModel')->newIsk();
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function asignarEan(array $data): array
|
||||
{
|
||||
if (!empty($data['data']['isbn'])) {
|
||||
$ean = $this->generarEanDesdeIsbn($data['data']['isbn']);
|
||||
|
||||
if ($ean !== null) {
|
||||
$data['data']['ean'] = $ean;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function generarEanDesdeIsbn(string $isbn): ?string
|
||||
{
|
||||
// Elimina guiones o espacios y convierte a mayúsculas
|
||||
$isbn = preg_replace('/[^0-9X]/', '', strtoupper($isbn));
|
||||
|
||||
// Si ya es un ISBN-13 válido
|
||||
if (strlen($isbn) === 13 && preg_match('/^97[89][0-9]{10}$/', $isbn)) {
|
||||
return $isbn;
|
||||
}
|
||||
|
||||
// Si es un ISBN-10, lo convertimos a EAN-13
|
||||
if (strlen($isbn) === 10) {
|
||||
$isbnSinDigito = substr($isbn, 0, 9);
|
||||
$eanBase = '978' . $isbnSinDigito;
|
||||
$digitoControl = $this->calcularDigitoControlEan($eanBase);
|
||||
return $eanBase . $digitoControl;
|
||||
}
|
||||
|
||||
return null; // Formato inválido
|
||||
}
|
||||
|
||||
protected function asignarCubiertaUrl(array $data): array
|
||||
{
|
||||
// No sobreescribir si ya hay un archivo manual
|
||||
if (!empty($data['data']['cubierta_archivo'] ?? null)) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Usamos el EAN generado
|
||||
$ean = $data['data']['ean'] ?? null;
|
||||
|
||||
if ($ean && preg_match('/^\d{13}$/', $ean)) {
|
||||
$ean0 = substr($ean, 0, 7);
|
||||
$ean12 = substr($ean, 0, 12);
|
||||
$data['data']['cubierta_url'] = "https://static.cegal.es/imagenes/marcadas/$ean0/$ean12.gif";
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function calcularDigitoControlEan(string $eanBase): int
|
||||
{
|
||||
$suma = 0;
|
||||
|
||||
for ($i = 0; $i < 12; $i++) {
|
||||
$digito = (int) $eanBase[$i];
|
||||
$suma += ($i % 2 === 0) ? $digito : $digito * 3;
|
||||
}
|
||||
|
||||
$modulo = $suma % 10;
|
||||
return ($modulo === 0) ? 0 : 10 - $modulo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get resource data.
|
||||
*
|
||||
* @return \CodeIgniter\Database\BaseBuilder
|
||||
*/
|
||||
public function getDatatableQuery()
|
||||
{
|
||||
$builder = $this->db
|
||||
->table($this->table . " t1")
|
||||
->select("
|
||||
t1.id AS id,
|
||||
t1.titulo AS titulo,
|
||||
t2.nombre AS cliente,
|
||||
t1.num_edic AS edicion,
|
||||
t1.autor AS autor,
|
||||
t1.isbn AS isbn,
|
||||
t1.ean AS ean,
|
||||
t1.paginas AS paginas,
|
||||
t1.cubierta_archivo AS cubierta_archivo,
|
||||
t1.cubierta_url AS portada
|
||||
")
|
||||
->join('clientes t2', 't1.cliente_id = t2.id')
|
||||
->where('t1.deleted_at', null);
|
||||
return $builder;
|
||||
}
|
||||
|
||||
public function getClientList($search = "")
|
||||
{
|
||||
$clienteModel = new ClienteModel();
|
||||
|
||||
$query = $clienteModel->builder()
|
||||
->select('id, nombre as name') // O el campo que quieras usar como "name"
|
||||
->where('deleted_at', null);
|
||||
if ($search != "") {
|
||||
$query->groupStart()
|
||||
->orLike("nombre", $search)
|
||||
->groupEnd();
|
||||
}
|
||||
return $query->get()->getResultObject();
|
||||
}
|
||||
|
||||
}
|
||||
79
ci4/app/Models/Catalogo/IdentificadorIskModel.php
Normal file
79
ci4/app/Models/Catalogo/IdentificadorIskModel.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?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.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user