185 lines
5.2 KiB
PHP
185 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Support\Facades\URL;
|
|
|
|
class DocumentoArchivioFisicoItem extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $table = 'documento_archivio_fisico_items';
|
|
|
|
protected $fillable = [
|
|
'stabile_id',
|
|
'parent_id',
|
|
'documento_id',
|
|
'codice_univoco',
|
|
'qr_code_data',
|
|
'nfc_reference',
|
|
'voce_numero',
|
|
'voce_titolo',
|
|
'tipo_item',
|
|
'titolo',
|
|
'note',
|
|
'data_archiviazione',
|
|
'supporto_fisico',
|
|
'modello_etichetta',
|
|
'magazzino',
|
|
'scaffale',
|
|
'ripiano',
|
|
'ubicazione_dettaglio',
|
|
'stato',
|
|
'sort_order',
|
|
'metadati',
|
|
'created_by',
|
|
'updated_by',
|
|
];
|
|
|
|
protected $casts = [
|
|
'data_archiviazione' => 'date',
|
|
'sort_order' => 'integer',
|
|
'metadati' => 'array',
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime',
|
|
];
|
|
|
|
public const TIPI = [
|
|
'documento' => 'Documento cartaceo',
|
|
'busta_trasparente' => 'Busta trasparente con anelli da archiviare',
|
|
'cartella_tre_lembi' => 'Cartella a tre lembi',
|
|
'faldone_anelli' => 'Faldone con anelli',
|
|
'faldone_lacci' => 'Faldone con lacci',
|
|
'scatola' => 'Scatola',
|
|
];
|
|
|
|
public function stabile(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Stabile::class, 'stabile_id');
|
|
}
|
|
|
|
public function parent(): BelongsTo
|
|
{
|
|
return $this->belongsTo(self::class, 'parent_id');
|
|
}
|
|
|
|
public function children(): HasMany
|
|
{
|
|
return $this->hasMany(self::class, 'parent_id')->orderBy('sort_order')->orderBy('titolo');
|
|
}
|
|
|
|
public function documento(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Documento::class, 'documento_id');
|
|
}
|
|
|
|
public function creator(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'created_by');
|
|
}
|
|
|
|
public function updater(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'updated_by');
|
|
}
|
|
|
|
public function getTipoLabelAttribute(): string
|
|
{
|
|
return self::TIPI[$this->tipo_item] ?? $this->tipo_item;
|
|
}
|
|
|
|
public function getPercorsoFisicoAttribute(): string
|
|
{
|
|
$parts = [];
|
|
$current = $this;
|
|
|
|
while ($current instanceof self) {
|
|
$parts[] = trim($current->codice_univoco . ' ' . $current->titolo);
|
|
$current = $current->parent;
|
|
}
|
|
|
|
return implode(' / ', array_reverse(array_filter($parts)));
|
|
}
|
|
|
|
public function getQrCodeImageAttribute(): string
|
|
{
|
|
$data = trim((string) $this->qr_code_data);
|
|
|
|
if ($data !== '' && class_exists(\chillerlan\QRCode\QROptions::class) && class_exists(\chillerlan\QRCode\QRCode::class)) {
|
|
$options = new \chillerlan\QRCode\QROptions([
|
|
'outputType' => \chillerlan\QRCode\QRCode::OUTPUT_MARKUP_SVG,
|
|
'eccLevel' => \chillerlan\QRCode\QRCode::ECC_M,
|
|
'addQuietzone' => true,
|
|
'quietzoneSize' => 1,
|
|
'connectPaths' => true,
|
|
]);
|
|
|
|
$svg = (new \chillerlan\QRCode\QRCode($options))->render($data);
|
|
|
|
if (str_starts_with($svg, 'data:image/svg+xml;base64,')) {
|
|
$decoded = base64_decode(substr($svg, strlen('data:image/svg+xml;base64,')), true);
|
|
|
|
if (is_string($decoded) && $decoded !== '') {
|
|
$svg = $decoded;
|
|
}
|
|
}
|
|
|
|
return str_contains($svg, '<svg')
|
|
? str_replace('<svg ', '<svg aria-label="QR archivio fisico" role="img" ', $svg)
|
|
: $svg;
|
|
}
|
|
|
|
if ($data === '') {
|
|
return '<span aria-hidden="true"></span>';
|
|
}
|
|
|
|
return '<img alt="QR archivio fisico" src="https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=' . rawurlencode($data) . '">';
|
|
}
|
|
|
|
public static function generateCodice(int $stabileId): string
|
|
{
|
|
$prefix = 'AF-' . $stabileId . '-';
|
|
$sequence = 1;
|
|
|
|
do {
|
|
$code = $prefix . str_pad((string) $sequence, 4, '0', STR_PAD_LEFT);
|
|
$exists = self::query()->where('codice_univoco', $code)->exists();
|
|
$sequence++;
|
|
} while ($exists);
|
|
|
|
return $code;
|
|
}
|
|
|
|
public function refreshQrCodeData(): void
|
|
{
|
|
$url = URL::temporarySignedRoute(
|
|
'public.archivio-fisico.show',
|
|
now()->addYears(5),
|
|
['item' => $this->id]
|
|
);
|
|
|
|
$this->forceFill([
|
|
'qr_code_data' => $url,
|
|
])->saveQuietly();
|
|
}
|
|
|
|
protected static function booted(): void
|
|
{
|
|
static::creating(function (self $item): void {
|
|
if (trim((string) $item->codice_univoco) === '') {
|
|
$item->codice_univoco = self::generateCodice((int) $item->stabile_id);
|
|
}
|
|
});
|
|
|
|
static::created(function (self $item): void {
|
|
if (trim((string) $item->qr_code_data) === '') {
|
|
$item->refreshQrCodeData();
|
|
}
|
|
});
|
|
}
|
|
}
|