Files
termanager2/app/Livewire/Assegnazioni/Assegna.php
Francesco Picone 7d479a2c34 ++ Assegna aperta da "Assegna ->" della Home: senza l'elenco dei territori assegnati
La richiesta era per la pagina Assegna, non per la scheda del territorio:
annullata la modifica di f1f3408 (storico nascosto nella scheda) e ora il
link "Assegna ->" della Home porta ?dalla_home=1, con cui Assegna non
mostra ne' carica l'elenco "Territori Assegnati".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:28:56 +02:00

183 lines
7.1 KiB
PHP

<?php
namespace App\Livewire\Assegnazioni;
use App\Livewire\Concerns\InviaLink;
use App\Livewire\Concerns\RicordaRitorno;
use Livewire\Component;
use App\Models\Territorio;
use App\Models\Proclamatore;
use App\Models\Assegnazione;
use App\Models\AnnoTeocratico;
use Illuminate\Support\Facades\DB;
class Assegna extends Component
{
use RicordaRitorno;
use InviaLink;
public ?int $territorio_id = null;
public ?int $proclamatore_id = null;
public string $assigned_at = '';
// Optional pre-selection from parent context
public ?int $preselectedTerritorioId = null;
/**
* Aperta da "Assegna →" della Home (?dalla_home=1, lo mette solo la Home)
* la pagina serve ad assegnare quel territorio: l'elenco dei territori
* assegnati sotto il modulo non si mostra (né si carica).
*/
public bool $elencoNascosto = false;
public function mount(?int $territorioId = null)
{
$this->preselectedTerritorioId = $territorioId;
$this->territorio_id = $territorioId;
$this->assigned_at = now()->format('Y-m-d');
$this->elencoNascosto = request()->boolean('dalla_home');
// ?invia=<id>: riprende l'invio di un link rimasto in sospeso (dalla
// scheda del territorio).
if ($invia = request()->integer('invia')) {
$this->apriInvio($invia);
}
}
protected function rules(): array
{
return [
'territorio_id' => 'required|exists:territori,id',
'proclamatore_id' => 'required|exists:proclamatori,id',
'assigned_at' => 'required|date|before_or_equal:today',
];
}
public function save()
{
$this->validate();
$territorio = Territorio::findOrFail($this->territorio_id);
// Gli errori vanno sul campo e non in sessione: il messaggio flash
// sta nel telaio della pagina, che Livewire non ridisegna, e il
// rifiuto passerebbe inosservato.
if ($territorio->assegnazioneCorrente) {
$this->addError('territorio_id', "Il territorio {$territorio->numero} è già assegnato a {$territorio->assegnazioneCorrente->proclamatore->nome_completo}.");
return;
}
if (!$territorio->attivo) {
$this->addError('territorio_id', "Il territorio {$territorio->numero} è inattivo.");
return;
}
// Nel pacchetto di un gruppo di servizio: lo assegna il sorvegliante.
if ($territorio->gruppo_servizio_id) {
$this->addError('territorio_id', "Il territorio {$territorio->numero} è nel pacchetto del gruppo {$territorio->gruppo?->nome}: lo assegna il sorvegliante, oppure va prima tolto dal pacchetto.");
return;
}
$proclamatore = Proclamatore::findOrFail($this->proclamatore_id);
if (!$proclamatore->attivo) {
$this->addError('proclamatore_id', "Il proclamatore {$proclamatore->nome_completo} è inattivo.");
return;
}
$assignedDate = \Carbon\Carbon::parse($this->assigned_at);
$annoTeocratico = AnnoTeocratico::perData($assignedDate);
// Controllo e inserimento sotto lo stesso lock sulla riga del
// territorio: un doppio clic o due schede aperte non possono più
// superare entrambi il controllo e creare due assegnazioni aperte.
$esito = DB::transaction(function () use ($territorio, $assignedDate, $annoTeocratico) {
Territorio::whereKey($territorio->id)->lockForUpdate()->first();
$conflitto = Assegnazione::sovrappostaA($territorio->id, $assignedDate);
if ($conflitto) {
return "Il territorio {$territorio->numero} risulta assegnato {$conflitto->descrizionePeriodo()}: "
. ($conflitto->returned_at
? 'la data di assegnazione non può essere precedente al suo rientro.'
: 'registrane prima il rientro.');
}
return Assegnazione::create([
'territorio_id' => $this->territorio_id,
'proclamatore_id' => $this->proclamatore_id,
'anno_teocratico_id' => $annoTeocratico->id,
'assigned_at' => $assignedDate,
'created_by' => auth()->id(),
// C'è un link da mandare solo se il territorio ha il PDF.
'link_da_inviare' => (bool) $territorio->pdf_path,
]);
});
if (is_string($esito)) {
$this->addError('assigned_at', $esito);
return;
}
$assegnazione = $esito;
activity()->causedBy(auth()->user())
->performedOn($assegnazione)
// L'id, non il nome: nome e cognome sono cifrati nel database, e
// copiati qui in chiaro restavano leggibili anche dopo
// l'anonimizzazione. Il registro mostra il nome di oggi.
->withProperties([
'territorio' => $territorio->numero,
'proclamatore_id' => $proclamatore->id,
])
->log('assigned');
// Non si va avanti: si apre l'invio del link (vedi in cima).
$this->apriInvio($assegnazione->id);
}
// ─── Invio del link (trait InviaLink) ──────────────────────
protected function puoInviare(Assegnazione $assegnazione): bool
{
return auth()->user()->can('territori.assign');
}
protected function paginaDopoInvio(): string
{
return $this->destinazione(route('assegnazioni.assegna'));
}
public function render()
{
// Le opzioni dei campi di scelta con ricerca (<x-scelta>). Ci sono anche
// i territori già assegnati, che non si possono scegliere: cercandone
// uno si legge a chi è, invece di un "nessun risultato". La miniatura
// serve all'anteprima, che si aggiorna nel browser.
// Quelli nel pacchetto di un gruppo di servizio li assegna il
// sorvegliante: qui si trovano ma non si scelgono.
$territori = Territorio::attivi()
->with(['zona', 'tipologia', 'assegnazioneCorrente.proclamatore', 'gruppo'])
->get()
->sortBy('numero', SORT_NATURAL);
$opzioniTerritori = $territori
->map(fn (Territorio $t) => $t->opzioneScelta(match (true) {
(bool) $t->assegnazioneCorrente => 'già assegnato a ' . ($t->assegnazioneCorrente->proclamatore?->nome_completo ?? '—'),
(bool) $t->gruppo_servizio_id => 'nel pacchetto del gruppo ' . ($t->gruppo?->nome ?? ''),
default => null,
}) + array_filter(['miniatura' => $t->miniaturaUrl()]))
->values()
->all();
$opzioniProclamatori = Proclamatore::opzioniScelta(Proclamatore::attivi()->get());
// L'elenco dei territori assegnati sta in ElencoAssegnati.
return view('livewire.assegnazioni.assegna', [
'invio' => $this->invioCorrente(),
'opzioniTerritori' => $opzioniTerritori,
'opzioniProclamatori' => $opzioniProclamatori,
'anteprimaIniziale' => $this->territorio_id ? $territori->firstWhere('id', $this->territorio_id)?->miniaturaUrl() : null,
]);
}
}