Primo commit
This commit is contained in:
219
app/Models/Territorio.php
Normal file
219
app/Models/Territorio.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\Activitylog\Traits\LogsActivity;
|
||||
use Spatie\Activitylog\LogOptions;
|
||||
|
||||
class Territorio extends Model
|
||||
{
|
||||
use SoftDeletes, LogsActivity;
|
||||
|
||||
protected $table = 'territori';
|
||||
|
||||
protected $fillable = [
|
||||
'numero',
|
||||
'zona_id',
|
||||
'tipologia_id',
|
||||
'note',
|
||||
'confini',
|
||||
'pdf_path',
|
||||
'attivo',
|
||||
'prioritario',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'attivo' => 'boolean',
|
||||
'prioritario' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function getActivitylogOptions(): LogOptions
|
||||
{
|
||||
return LogOptions::defaults()
|
||||
->logOnly(['numero', 'zona_id', 'tipologia_id', 'attivo', 'prioritario', 'pdf_path'])
|
||||
->logOnlyDirty()
|
||||
->dontSubmitEmptyLogs();
|
||||
}
|
||||
|
||||
// ─── Relationships ─────────────────────────────────────────
|
||||
|
||||
public function zona()
|
||||
{
|
||||
return $this->belongsTo(Zona::class, 'zona_id');
|
||||
}
|
||||
|
||||
public function tipologia()
|
||||
{
|
||||
return $this->belongsTo(Tipologia::class, 'tipologia_id');
|
||||
}
|
||||
|
||||
public function assegnazioni()
|
||||
{
|
||||
return $this->hasMany(Assegnazione::class, 'territorio_id');
|
||||
}
|
||||
|
||||
public function assegnazioneCorrente()
|
||||
{
|
||||
return $this->hasOne(Assegnazione::class, 'territorio_id')
|
||||
->whereNull('returned_at')
|
||||
->latestOfMany('assigned_at');
|
||||
}
|
||||
|
||||
public function ultimaAssegnazione()
|
||||
{
|
||||
return $this->hasOne(Assegnazione::class, 'territorio_id')
|
||||
->latestOfMany('assigned_at');
|
||||
}
|
||||
|
||||
// ─── Computed State ─────────────────────────────────────────
|
||||
|
||||
public function getStatoAttribute(): string
|
||||
{
|
||||
if (!$this->attivo) {
|
||||
return 'inattivo';
|
||||
}
|
||||
|
||||
$corrente = $this->assegnazioneCorrente;
|
||||
if ($corrente) {
|
||||
$giorniAssegnato = Carbon::parse($corrente->assigned_at)->diffInDays(now());
|
||||
$sogliaSmarrito = Setting::getValue('giorni_per_smarrito', 120);
|
||||
|
||||
if ($giorniAssegnato > $sogliaSmarrito) {
|
||||
return 'da_rientrare';
|
||||
}
|
||||
return 'assegnato';
|
||||
}
|
||||
|
||||
return 'in_reparto';
|
||||
}
|
||||
|
||||
public function getAssegnatarioAttribute(): ?Proclamatore
|
||||
{
|
||||
return $this->assegnazioneCorrente?->proclamatore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Days since last return (or creation if never assigned).
|
||||
*/
|
||||
public function getGiorniGiacenzaAttribute(): int
|
||||
{
|
||||
$ultima = $this->ultimaAssegnazione;
|
||||
|
||||
if ($ultima && $ultima->returned_at) {
|
||||
return Carbon::parse($ultima->returned_at)->diffInDays(now());
|
||||
}
|
||||
|
||||
if (!$ultima) {
|
||||
return $this->created_at->diffInDays(now());
|
||||
}
|
||||
|
||||
// Currently assigned, no giacenza concept
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this territory "prioritario"?
|
||||
* Manual flag OR giacenza exceeds threshold (threshold always wins).
|
||||
*/
|
||||
public function getIsPrioritarioAttribute(): bool
|
||||
{
|
||||
if (!$this->attivo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->prioritario) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Threshold-based priority (only when in reparto)
|
||||
if ($this->stato === 'in_reparto') {
|
||||
$soglia = Setting::getValue('giorni_giacenza_prioritari', 180);
|
||||
return $this->giorni_giacenza > $soglia;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ─── Scopes ─────────────────────────────────────────────────
|
||||
|
||||
public function scopeAttivi($query)
|
||||
{
|
||||
return $query->where('attivo', true);
|
||||
}
|
||||
|
||||
public function scopeInReparto($query)
|
||||
{
|
||||
return $query->attivi()
|
||||
->whereDoesntHave('assegnazioni', function ($q) {
|
||||
$q->whereNull('returned_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function scopeAssegnato($query)
|
||||
{
|
||||
return $query->attivi()
|
||||
->whereHas('assegnazioni', function ($q) {
|
||||
$q->whereNull('returned_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function scopeDaRientrare($query)
|
||||
{
|
||||
$soglia = Setting::getValue('giorni_per_smarrito', 120);
|
||||
|
||||
return $query->attivi()
|
||||
->whereHas('assegnazioni', function ($q) use ($soglia) {
|
||||
$q->whereNull('returned_at')
|
||||
->where('assigned_at', '<=', now()->subDays($soglia));
|
||||
});
|
||||
}
|
||||
|
||||
public function scopeDaAssegnare($query)
|
||||
{
|
||||
$soglia = Setting::getValue('giorni_giacenza_da_assegnare', 120);
|
||||
|
||||
return $query->inReparto()
|
||||
->where(function ($q) use ($soglia) {
|
||||
// Territories whose last assignment returned > soglia days ago
|
||||
$q->whereHas('assegnazioni', function ($sub) use ($soglia) {
|
||||
$sub->whereNotNull('returned_at')
|
||||
->where('returned_at', '<=', now()->subDays($soglia))
|
||||
->whereRaw('id = (SELECT MAX(a2.id) FROM assegnazioni a2 WHERE a2.territorio_id = assegnazioni.territorio_id)');
|
||||
})
|
||||
// Or territories never assigned, created > soglia days ago
|
||||
->orWhere(function ($sub) use ($soglia) {
|
||||
$sub->doesntHave('assegnazioni')
|
||||
->where('created_at', '<=', now()->subDays($soglia));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function scopePrioritari($query)
|
||||
{
|
||||
$soglia = Setting::getValue('giorni_giacenza_prioritari', 180);
|
||||
|
||||
return $query->inReparto()
|
||||
->where(function ($q) use ($soglia) {
|
||||
// Manual priority flag
|
||||
$q->where('prioritario', true)
|
||||
// OR threshold-based
|
||||
->orWhere(function ($sub) use ($soglia) {
|
||||
$sub->whereHas('assegnazioni', function ($a) use ($soglia) {
|
||||
$a->whereNotNull('returned_at')
|
||||
->where('returned_at', '<=', now()->subDays($soglia))
|
||||
->whereRaw('id = (SELECT MAX(a2.id) FROM assegnazioni a2 WHERE a2.territorio_id = assegnazioni.territorio_id)');
|
||||
})
|
||||
->orWhere(function ($never) use ($soglia) {
|
||||
$never->doesntHave('assegnazioni')
|
||||
->where('created_at', '<=', now()->subDays($soglia));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user