++ gruppi: sorvegliante non piu' attivo scioglie il gruppo; dettagli del gruppo nella scheda e nel profilo
- Proclamatore::booted: reso non attivo, spostato nel cestino o anonimizzato, il sorvegliante scioglie il gruppo (territori non dati in reparto, membri liberi, utenza disattivata); il motivo va nel registro. L'elenco chiede conferma, la modifica avvisa sotto "Attivo". Un membro nel cestino esce dal gruppo. - Scheda del proclamatore: gruppo guidato con membri, pacchetto, da dare, assegnazioni dal gruppo, utenza e ultimo accesso; oppure gruppo di cui e' membro; gruppi sciolti guidati in passato. - Profilo del sorvegliante: il suo gruppo con gli stessi numeri. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,13 +38,17 @@ class ProclamatoreEdit extends Component
|
||||
|
||||
$this->validate();
|
||||
|
||||
// Un sorvegliante reso non attivo scioglie il gruppo (Proclamatore::booted).
|
||||
$gruppo = ! $this->attivo ? $this->proclamatore->gruppoSorvegliato() : null;
|
||||
|
||||
$this->proclamatore->update([
|
||||
'nome' => $this->nome,
|
||||
'cognome' => $this->cognome,
|
||||
'attivo' => $this->attivo,
|
||||
]);
|
||||
|
||||
session()->flash('success', "Proclamatore {$this->proclamatore->nome_completo} aggiornato.");
|
||||
$avviso = "Proclamatore {$this->proclamatore->nome_completo} aggiornato." . ($gruppo ? ' ' . ProclamatoreIndex::gruppoSciolto($gruppo) : '');
|
||||
session()->flash('success', $avviso);
|
||||
return $this->redirect($this->destinazione(route('proclamatori.index')), navigate: true);
|
||||
}
|
||||
|
||||
@@ -53,6 +57,7 @@ class ProclamatoreEdit extends Component
|
||||
return view('livewire.proclamatori.proclamatore-form', [
|
||||
'titolo' => "Modifica {$this->proclamatore->nome_completo}",
|
||||
'btnLabel' => 'Salva Modifiche',
|
||||
'gruppoSorvegliato' => $this->proclamatore->gruppoSorvegliato(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,13 @@ class ProclamatoreIndex extends Component
|
||||
$this->authorize('settings.manage');
|
||||
|
||||
$proclamatore = Proclamatore::findOrFail($id);
|
||||
$gruppo = $proclamatore->attivo ? $proclamatore->gruppoSorvegliato() : null;
|
||||
// Un sorvegliante reso non attivo scioglie il gruppo (Proclamatore::booted).
|
||||
$proclamatore->update(['attivo' => !$proclamatore->attivo]);
|
||||
|
||||
if ($gruppo) {
|
||||
$this->avvisa("{$proclamatore->nome_completo} non è più attivo. " . self::gruppoSciolto($gruppo));
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteProclamatore(int $id)
|
||||
@@ -71,14 +77,12 @@ class ProclamatoreIndex extends Component
|
||||
$this->avvisaErrore("Il proclamatore {$proclamatore->nome_completo} ha assegnazioni aperte. Rientra prima i territori.");
|
||||
return;
|
||||
}
|
||||
if ($this->sorveglianteDiUnGruppo($proclamatore, 'spostarlo nel cestino')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Nel cestino non resta membro di un gruppo.
|
||||
$proclamatore->update(['gruppo_servizio_id' => null]);
|
||||
// Nel cestino lascia il gruppo; se ne era il sorvegliante, il gruppo
|
||||
// si scioglie (Proclamatore::booted).
|
||||
$gruppo = $proclamatore->gruppoSorvegliato();
|
||||
$proclamatore->delete();
|
||||
$this->avvisa("Proclamatore {$proclamatore->nome_completo} spostato nel cestino.");
|
||||
$this->avvisa("Proclamatore {$proclamatore->nome_completo} spostato nel cestino." . ($gruppo ? ' ' . self::gruppoSciolto($gruppo) : ''));
|
||||
}
|
||||
|
||||
public function anonimizza(int $id)
|
||||
@@ -86,25 +90,15 @@ class ProclamatoreIndex extends Component
|
||||
$this->authorize('settings.manage');
|
||||
|
||||
$proclamatore = Proclamatore::findOrFail($id);
|
||||
if ($this->sorveglianteDiUnGruppo($proclamatore, 'anonimizzarlo')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$gruppo = $proclamatore->gruppoSorvegliato();
|
||||
$proclamatore->anonimizza();
|
||||
$this->avvisa("Dati personali del proclamatore anonimizzati (GDPR).");
|
||||
$this->avvisa("Dati personali del proclamatore anonimizzati (GDPR)." . ($gruppo ? ' ' . self::gruppoSciolto($gruppo) : ''));
|
||||
}
|
||||
|
||||
/** Il sorvegliante di un gruppo attivo si toglie sciogliendo il gruppo, non da qui. */
|
||||
private function sorveglianteDiUnGruppo(Proclamatore $proclamatore, string $azione): bool
|
||||
/** L'avviso quando un sorvegliante esce di scena: anche per ProclamatoreEdit. */
|
||||
public static function gruppoSciolto(GruppoServizio $gruppo): string
|
||||
{
|
||||
$gruppo = GruppoServizio::attivi()->where('sorvegliante_id', $proclamatore->id)->first();
|
||||
if (! $gruppo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->avvisaErrore("{$proclamatore->nome_completo} è il sorvegliante del gruppo {$gruppo->nome}: per {$azione} va prima sciolto il gruppo (Gruppi di servizio).");
|
||||
|
||||
return true;
|
||||
return "Era il sorvegliante del gruppo {$gruppo->nome}: il gruppo è stato sciolto, i territori non ancora dati sono tornati in reparto e la sua utenza è disattivata.";
|
||||
}
|
||||
|
||||
public function render()
|
||||
@@ -176,6 +170,8 @@ class ProclamatoreIndex extends Component
|
||||
|
||||
return view('livewire.proclamatori.proclamatore-index', [
|
||||
'proclamatori' => $proclamatori,
|
||||
// Per avvisare, prima di disattivare o cestinare, che il gruppo si scioglie.
|
||||
'gruppiSorvegliati' => GruppoServizio::attivi()->pluck('nome', 'sorvegliante_id'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use App\Livewire\Concerns\RicordaRitorno;
|
||||
use Livewire\Component;
|
||||
use App\Models\Proclamatore;
|
||||
use App\Models\Assegnazione;
|
||||
use App\Models\GruppoServizio;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class ProclamatoreShow extends Component
|
||||
{
|
||||
@@ -37,9 +39,25 @@ class ProclamatoreShow extends Component
|
||||
),
|
||||
];
|
||||
|
||||
// Gruppo di servizio: sorvegliante (con i dettagli del gruppo e della
|
||||
// sua utenza), membro, o sorvegliante di gruppi ormai sciolti.
|
||||
$gruppoSorvegliato = $this->proclamatore->gruppoSorvegliato();
|
||||
$utenza = $gruppoSorvegliato ? $this->proclamatore->utente : null;
|
||||
|
||||
return view('livewire.proclamatori.proclamatore-show', [
|
||||
'assegnazioniPerAnno' => $assegnazioni,
|
||||
'stats' => $stats,
|
||||
'gruppoSorvegliato' => $gruppoSorvegliato,
|
||||
'riepilogoGruppo' => $gruppoSorvegliato?->riepilogo(),
|
||||
'gruppoMembro' => $gruppoSorvegliato ? null : $this->proclamatore->gruppo()->with('sorvegliante')->first(),
|
||||
'gruppiPassati' => GruppoServizio::whereNotNull('sciolto_at')
|
||||
->where('sorvegliante_id', $this->proclamatore->id)
|
||||
->orderByDesc('sciolto_at')
|
||||
->get(),
|
||||
'utenza' => $utenza,
|
||||
'ultimoAccesso' => $utenza
|
||||
? Activity::whereMorphedTo('causer', $utenza)->where('description', 'login')->max('created_at')
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,13 @@ class Profile extends Component
|
||||
|
||||
public function render()
|
||||
{
|
||||
// Il sorvegliante vede qui i dettagli del suo gruppo di servizio.
|
||||
$gruppo = auth()->user()->gruppoSorvegliato();
|
||||
|
||||
return view('livewire.profile', [
|
||||
'user' => auth()->user(),
|
||||
'gruppo' => $gruppo,
|
||||
'riepilogoGruppo' => $gruppo?->riepilogo(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,4 +72,24 @@ class GruppoServizio extends Model
|
||||
{
|
||||
return $query->whereNull('sciolto_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* I numeri del gruppo per la scheda del proclamatore e il profilo del
|
||||
* sorvegliante: solo conteggi in SQL, nessun nome da decifrare.
|
||||
*
|
||||
* @return array{membri: int, pacchetto: int, da_dare: int, dati: int, assegnazioni: int}
|
||||
*/
|
||||
public function riepilogo(): array
|
||||
{
|
||||
$pacchetto = $this->territori()->count();
|
||||
$dati = $this->territori()->whereHas('assegnazioni', fn ($q) => $q->whereNull('returned_at'))->count();
|
||||
|
||||
return [
|
||||
'membri' => $this->membri()->count(),
|
||||
'pacchetto' => $pacchetto,
|
||||
'da_dare' => $pacchetto - $dati,
|
||||
'dati' => $dati,
|
||||
'assegnazioni' => $this->assegnazioni()->count(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,46 @@ class Proclamatore extends Model
|
||||
return $this->hasOne(User::class, 'proclamatore_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Un sorvegliante che non è più attivo — reso non attivo, spostato nel
|
||||
* cestino o anonimizzato — non guida più il gruppo: il gruppo si scioglie
|
||||
* (GruppiServizio::sciogli), da qualunque pagina arrivi la modifica. Un
|
||||
* membro nel cestino lascia il gruppo.
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::updated(function (self $proclamatore) {
|
||||
if ($proclamatore->wasChanged('attivo') && ! $proclamatore->attivo) {
|
||||
$proclamatore->lasciaIlGruppo('sorvegliante non più attivo');
|
||||
}
|
||||
});
|
||||
|
||||
static::deleted(function (self $proclamatore) {
|
||||
$proclamatore->lasciaIlGruppo('sorvegliante eliminato');
|
||||
});
|
||||
}
|
||||
|
||||
/** Il gruppo attivo di cui è sorvegliante, se c'è. */
|
||||
public function gruppoSorvegliato(): ?GruppoServizio
|
||||
{
|
||||
return GruppoServizio::attivi()->where('sorvegliante_id', $this->id)->first();
|
||||
}
|
||||
|
||||
private function lasciaIlGruppo(string $motivo): void
|
||||
{
|
||||
$gruppo = $this->gruppoSorvegliato();
|
||||
if ($gruppo) {
|
||||
app(\App\Services\GruppiServizio::class)->sciogli($gruppo, $motivo);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->trashed() && $this->gruppo_servizio_id) {
|
||||
static::withTrashed()->whereKey($this->id)->update(['gruppo_servizio_id' => null]);
|
||||
$this->gruppo_servizio_id = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -231,13 +231,13 @@ class GruppiServizio
|
||||
* fatte restano com'erano, con il loro riferimento al gruppo, che resta
|
||||
* nello storico come sciolto.
|
||||
*/
|
||||
public function sciogli(GruppoServizio $gruppo): void
|
||||
public function sciogli(GruppoServizio $gruppo, ?string $motivo = null): void
|
||||
{
|
||||
if ($gruppo->sciolto_at) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($gruppo) {
|
||||
DB::transaction(function () use ($gruppo, $motivo) {
|
||||
// Esce dal pacchetto solo quello non ancora dato: un territorio
|
||||
// assegnato resta del suo gruppo finché non rientra (Assegnazione
|
||||
// lo libera al rientro), così non può essere ridato due volte.
|
||||
@@ -258,7 +258,11 @@ class GruppiServizio
|
||||
$gruppo->update(['sciolto_at' => now()]);
|
||||
|
||||
activity()->causedBy(auth()->user())->performedOn($gruppo)
|
||||
->withProperties(['territori_liberati' => $liberati->all(), 'utente_disattivato' => $utente?->id])
|
||||
->withProperties(array_filter([
|
||||
'territori_liberati' => $liberati->all(),
|
||||
'utente_disattivato' => $utente?->id,
|
||||
'motivo' => $motivo,
|
||||
], fn ($v) => $v !== null))
|
||||
->log('gruppo_sciolto');
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user