'datetime', 'ordered_at' => 'datetime', 'imported_at' => 'datetime', 'metadata' => 'array', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; public function amministratore(): BelongsTo { return $this->belongsTo(Amministratore::class, 'amministratore_id'); } public function fornitore(): BelongsTo { return $this->belongsTo(Fornitore::class, 'fornitore_id'); } public function allegati(): HasMany { return $this->hasMany(AssistenzaTecnorepairAllegato::class, 'scheda_id'); } public function productSerials(): HasMany { return $this->hasMany(ProductSerial::class, 'legacy_scheda_id'); } public function scopeForAmministratore(Builder $query, int $amministratoreId): Builder { return $query->where('amministratore_id', $amministratoreId); } public function scopeSearch(Builder $query, string $term): Builder { $term = trim($term); if ($term === '') { return $query; } return $query->where(function (Builder $inner) use ($term): void { $like = '%' . $term . '%'; $inner->where('legacy_numero_scheda', 'like', $like) ->orWhere('customer_name', 'like', $like) ->orWhere('customer_phone', 'like', $like) ->orWhere('customer_email', 'like', $like) ->orWhere('product_model', 'like', $like) ->orWhere('product_code', 'like', $like) ->orWhere('serial_number', 'like', $like) ->orWhere('serial_number_2', 'like', $like) ->orWhere('defect_reported', 'like', $like) ->orWhere('repair_description', 'like', $like); }); } public function scopeStatusBucket(Builder $query, string $bucket): Builder { if ($bucket === 'all') { return $query; } return $query->where('status_bucket', $bucket); } public function getDisplayTitleAttribute(): string { $numero = trim((string) ($this->legacy_numero_scheda ?? '')); $modello = trim((string) ($this->product_model ?? '')); if ($numero !== '' && $modello !== '') { return $numero . ' · ' . $modello; } return $numero !== '' ? $numero : ($modello !== '' ? $modello : 'Scheda TecnoRepair'); } public function getStatusColorAttribute(): string { return match ((string) $this->status_bucket) { 'closed' => 'emerald', 'waiting' => 'amber', 'open' => 'rose', default => 'slate', }; } public function getStatusBadgeClassesAttribute(): string { return match ((string) $this->status_bucket) { 'closed' => 'border-emerald-200 bg-emerald-50 text-emerald-800', 'waiting' => 'border-amber-200 bg-amber-50 text-amber-800', 'open' => 'border-rose-200 bg-rose-50 text-rose-800', default => 'border-slate-200 bg-slate-50 text-slate-700', }; } public function getRowClassesAttribute(): string { return match ((string) $this->status_bucket) { 'closed' => 'bg-emerald-50/70 hover:bg-emerald-50', 'waiting' => 'bg-amber-50/70 hover:bg-amber-50', 'open' => 'bg-rose-50/60 hover:bg-rose-50', default => 'bg-white hover:bg-slate-50', }; } public function getSerialLabelAttribute(): string { $parts = array_values(array_filter([ trim((string) ($this->serial_number ?? '')), trim((string) ($this->serial_number_2 ?? '')), ])); return $parts !== [] ? implode(' · ', $parts) : '-'; } public static function normalizeStatusBucket(?string $status): string { $value = Str::lower(trim((string) $status)); if ($value === '') { return 'other'; } if (Str::contains($value, ['chius', 'complet', 'consegn', 'ritirat', 'ok'])) { return 'closed'; } if (Str::contains($value, ['attesa', 'ordine', 'ricambi', 'preventiv', 'approv'])) { return 'waiting'; } return 'open'; } }