282 lines
7.7 KiB
PHP
Executable File
282 lines
7.7 KiB
PHP
Executable File
<?php
|
|
namespace App\Models;
|
|
|
|
use App\Support\ArchivioPaths;
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
|
|
class Fornitore extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $table = 'fornitori';
|
|
|
|
protected $fillable = [
|
|
'amministratore_id',
|
|
'rubrica_id',
|
|
'codice_univoco',
|
|
'ragione_sociale',
|
|
'nome',
|
|
'cognome',
|
|
'partita_iva',
|
|
'codice_fiscale',
|
|
'indirizzo',
|
|
'civico',
|
|
'cap',
|
|
'citta',
|
|
'provincia',
|
|
'nazione',
|
|
'email',
|
|
'pec',
|
|
'iban',
|
|
'intestazione_cc_esatta',
|
|
'bic',
|
|
'modalita_pagamento_predefinita',
|
|
'escludi_righe_fe',
|
|
'fe_features',
|
|
'operational_config',
|
|
'telefono',
|
|
'telefono_country_code',
|
|
'cellulare',
|
|
'cellulare_country_code',
|
|
'sito_web',
|
|
'tags',
|
|
'legacy_descrizione',
|
|
'note',
|
|
'regime_fiscale_id',
|
|
'tipologia_cassa_id',
|
|
'aliquota_iva_id',
|
|
'is_tecnorepair_primary',
|
|
'old_id',
|
|
];
|
|
|
|
protected $casts = [
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime',
|
|
'escludi_righe_fe' => 'boolean',
|
|
'fe_features' => 'array',
|
|
'operational_config' => 'array',
|
|
'is_tecnorepair_primary' => 'boolean',
|
|
];
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function getFeFeaturesSafeAttribute(): array
|
|
{
|
|
try {
|
|
if (! Schema::hasColumn('fornitori', 'fe_features')) {
|
|
return [];
|
|
}
|
|
} catch (\Throwable) {
|
|
return [];
|
|
}
|
|
|
|
return is_array($this->fe_features ?? null) ? $this->fe_features : [];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function getOperationalConfigSafeAttribute(): array
|
|
{
|
|
try {
|
|
if (! Schema::hasColumn('fornitori', 'operational_config')) {
|
|
return [];
|
|
}
|
|
} catch (\Throwable) {
|
|
return [];
|
|
}
|
|
|
|
return is_array($this->operational_config ?? null) ? $this->operational_config : [];
|
|
}
|
|
|
|
protected static function booted(): void
|
|
{
|
|
static::creating(function (Fornitore $fornitore) {
|
|
// Allinea sempre il codice univoco al codice della Rubrica (unica sorgente di verità).
|
|
if ((empty($fornitore->codice_univoco) || ! is_string($fornitore->codice_univoco)) && (int) ($fornitore->rubrica_id ?? 0) > 0) {
|
|
$rubricaCode = RubricaUniversale::query()
|
|
->whereKey((int) $fornitore->rubrica_id)
|
|
->value('codice_univoco');
|
|
if (is_string($rubricaCode) && $rubricaCode !== '') {
|
|
$fornitore->codice_univoco = $rubricaCode;
|
|
}
|
|
}
|
|
|
|
if (empty($fornitore->codice_univoco) && $fornitore->shouldGenerateCodiceUnivocoLocally()) {
|
|
$fornitore->codice_univoco = $fornitore->generateLocalCodiceUnivoco();
|
|
}
|
|
});
|
|
|
|
static::created(function (Fornitore $fornitore) {
|
|
try {
|
|
$base = ArchivioPaths::fornitoreBase($fornitore);
|
|
if (! $base) {
|
|
return;
|
|
}
|
|
|
|
foreach ([
|
|
'documenti',
|
|
'rubrica',
|
|
'fe',
|
|
'prodotti',
|
|
'comunicazioni',
|
|
'tecnorepair/imports',
|
|
'tecnorepair/allegati',
|
|
'temp/upload',
|
|
'temp/processing',
|
|
'logs',
|
|
] as $folder) {
|
|
Storage::disk('local')->makeDirectory($base . '/' . $folder);
|
|
}
|
|
} catch (\Throwable) {
|
|
// ignore
|
|
}
|
|
});
|
|
}
|
|
|
|
protected function shouldGenerateCodiceUnivocoLocally(): bool
|
|
{
|
|
return $this->getConnection()->getDriverName() !== 'mysql';
|
|
}
|
|
|
|
protected function generateLocalCodiceUnivoco(): string
|
|
{
|
|
do {
|
|
$code = strtoupper(Str::random(8));
|
|
} while (self::where('codice_univoco', $code)->exists());
|
|
|
|
return $code;
|
|
}
|
|
|
|
/**
|
|
* Relazione con Amministratore
|
|
*/
|
|
public function amministratore()
|
|
{
|
|
return $this->belongsTo(Amministratore::class, 'amministratore_id', 'id');
|
|
}
|
|
|
|
public function rubrica()
|
|
{
|
|
return $this->belongsTo(RubricaUniversale::class, 'rubrica_id');
|
|
}
|
|
|
|
public function regimeFiscale()
|
|
{
|
|
return $this->belongsTo(RegimeFiscale::class, 'regime_fiscale_id');
|
|
}
|
|
|
|
public function tipologiaCassa()
|
|
{
|
|
return $this->belongsTo(TipologiaCassa::class, 'tipologia_cassa_id');
|
|
}
|
|
|
|
public function aliquotaIva()
|
|
{
|
|
return $this->belongsTo(AliquotaIva::class, 'aliquota_iva_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Tickets assegnati
|
|
*/
|
|
public function ticketsAssegnati()
|
|
{
|
|
return $this->hasMany(Ticket::class, 'assegnato_a_fornitore_id', 'id');
|
|
}
|
|
|
|
public function ticketInterventi()
|
|
{
|
|
return $this->hasMany(TicketIntervento::class, 'fornitore_id', 'id');
|
|
}
|
|
|
|
public function dipendenti()
|
|
{
|
|
return $this->hasMany(FornitoreDipendente::class, 'fornitore_id', 'id');
|
|
}
|
|
|
|
public function tecnorepairSchede(): HasMany
|
|
{
|
|
return $this->hasMany(AssistenzaTecnorepairScheda::class, 'fornitore_id', 'id');
|
|
}
|
|
|
|
public function productSerials(): HasMany
|
|
{
|
|
return $this->hasMany(ProductSerial::class, 'fornitore_id', 'id');
|
|
}
|
|
|
|
public function products(): HasMany
|
|
{
|
|
return $this->hasMany(Product::class, 'default_fornitore_id', 'id');
|
|
}
|
|
|
|
public function productOffers(): HasMany
|
|
{
|
|
return $this->hasMany(ProductOffer::class, 'fornitore_id', 'id');
|
|
}
|
|
|
|
public function getIsTecnoRepairCenterAttribute(): bool
|
|
{
|
|
if ((bool) ($this->is_tecnorepair_primary ?? false)) {
|
|
return true;
|
|
}
|
|
|
|
$label = Str::upper(trim((string) ($this->ragione_sociale ?? '')));
|
|
|
|
return $label !== '' && Str::contains($label, 'NETHOME');
|
|
}
|
|
|
|
/**
|
|
* @return array<string,int>
|
|
*/
|
|
public function getTecnoRepairStatsAttribute(): array
|
|
{
|
|
$base = $this->tecnorepairSchede();
|
|
|
|
return [
|
|
'total' => (int) (clone $base)->count(),
|
|
'open' => (int) (clone $base)->whereIn('status_bucket', ['open', 'waiting'])->count(),
|
|
'closed' => (int) (clone $base)->where('status_bucket', 'closed')->count(),
|
|
'serials' => (int) $this->productSerials()->count(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Accessor per l'indirizzo completo
|
|
*/
|
|
public function getIndirizzoCompletoAttribute()
|
|
{
|
|
$parts = [];
|
|
|
|
if ($this->indirizzo) {
|
|
$parts[] = $this->indirizzo;
|
|
}
|
|
if ($this->cap && $this->citta) {
|
|
$parts[] = $this->cap . ' ' . $this->citta;
|
|
}
|
|
if ($this->provincia) {
|
|
$parts[] = '(' . $this->provincia . ')';
|
|
}
|
|
|
|
return implode(', ', $parts);
|
|
}
|
|
|
|
/**
|
|
* Scope per ricerca
|
|
*/
|
|
public function scopeSearch($query, $search)
|
|
{
|
|
return $query->where(function ($q) use ($search) {
|
|
$q->where('ragione_sociale', 'like', "%{$search}%")
|
|
->orWhere('email', 'like', "%{$search}%")
|
|
->orWhere('telefono', 'like', "%{$search}%")
|
|
->orWhere('partita_iva', 'like', "%{$search}%");
|
|
});
|
|
}
|
|
}
|