'datetime', 'updated_at' => 'datetime', 'cod_forn' => 'integer', 'escludi_righe_fe' => 'boolean', 'fe_features' => 'array', 'operational_config' => 'array', 'is_tecnorepair_primary' => 'boolean', ]; /** * @return array */ 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 */ 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 : []; } public function getSiaEffettivoAttribute(): ?string { $sia = trim((string) ($this->sia ?? '')); if ($sia !== '') { return $sia; } $fallback = trim((string) data_get($this->operational_config_safe, 'payment_identifiers.sia', '')); return $fallback !== '' ? $fallback : null; } /** * @return array */ public function catalogScopeSupplierIds(): array { $operationalConfig = $this->operational_config_safe; return collect(array_merge( [(int) $this->id], array_map('intval', (array) data_get($operationalConfig, 'merged_supplier_ids', [])), array_map('intval', (array) data_get($operationalConfig, 'catalog_import.fe_supplier_ids', [])) )) ->filter(fn(int $value): bool => $value > 0) ->unique() ->values() ->all(); } 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 { $fornitore->ensureArchiveStructure(); } catch (\Throwable) { // ignore } }); } public function ensureArchiveStructure(): void { $bases = array_values(array_filter([ ArchivioPaths::fornitoreBase($this), ArchivioPaths::fornitoreLegacyBase($this), ])); if ($bases === []) { return; } foreach ($bases as $base) { foreach ([ 'documenti', 'documenti/archivio_per_anno', 'rubrica', 'fe', 'fe/ricevute', 'prodotti', 'comunicazioni', 'tecnorepair/imports', 'tecnorepair/allegati', 'temp/upload', 'temp/processing', 'logs', 'google_drive', ] as $folder) { Storage::disk('local')->makeDirectory($base . '/' . $folder); } } } 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 */ 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}%"); }); } }