343 lines
12 KiB
PHP
343 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Pages\Condomini;
|
|
|
|
use App\Models\Assemblea;
|
|
use App\Models\Convocazione;
|
|
use App\Models\OrdineGiorno;
|
|
use App\Models\AssembleaVoto;
|
|
use App\Models\AssembleaPresenza;
|
|
use App\Models\UnitaImmobiliare;
|
|
use App\Models\Soggetto;
|
|
use App\Models\TabellaMillesimale;
|
|
use App\Models\Stabile;
|
|
use App\Models\User;
|
|
use App\Support\StabileContext;
|
|
use BackedEnum;
|
|
use Filament\Actions\Action;
|
|
use Filament\Pages\Page;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use UnitEnum;
|
|
|
|
class GestioneAssemblea extends Page
|
|
{
|
|
protected static ?string $navigationLabel = 'Gestione Assemblea';
|
|
|
|
protected static ?string $title = 'Gestione Assemblea';
|
|
|
|
protected static ?string $slug = 'condomini/assemblee/{record}';
|
|
|
|
protected string $view = 'filament.pages.condomini.gestione-assemblea';
|
|
|
|
protected static bool $shouldRegisterNavigation = false;
|
|
|
|
public ?int $record = null; // ID dell'assemblea
|
|
|
|
public ?Assemblea $assemblea = null;
|
|
public ?Stabile $stabileAttivo = null;
|
|
|
|
// Gestione stato UI
|
|
public string $activeSubTab = 'odg'; // 'odg', 'convocazioni', 'presenze', 'voto_live'
|
|
|
|
// Form nuovo punto OdG
|
|
public ?int $odgNumeroPunto = null;
|
|
public ?string $odgTitolo = '';
|
|
public ?string $odgDescrizione = '';
|
|
public ?string $odgArticoloLegge = '';
|
|
public ?int $odgTabellaMillesimaleId = null;
|
|
|
|
// Form nuova presenza
|
|
public ?int $presenzaSoggettoId = null;
|
|
public ?int $presenzaUnitaId = null;
|
|
public string $presenzaTipo = 'personale';
|
|
public ?int $presenzaDelegatoId = null;
|
|
|
|
public static function canAccess(): bool
|
|
{
|
|
$user = Auth::user();
|
|
return $user instanceof User
|
|
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']);
|
|
}
|
|
|
|
public function mount(int $record): void
|
|
{
|
|
$this->record = $record;
|
|
$this->assemblea = Assemblea::with('stabile')->find($this->record);
|
|
if (!$this->assemblea) {
|
|
abort(404);
|
|
}
|
|
|
|
$this->stabileAttivo = $this->assemblea->stabile;
|
|
$this->resetOdgForm();
|
|
}
|
|
|
|
public function changeTab(string $tab): void
|
|
{
|
|
$this->activeSubTab = $tab;
|
|
}
|
|
|
|
// --- AZIONI GESTIONE ODG ---
|
|
public function resetOdgForm(): void
|
|
{
|
|
$this->odgNumeroPunto = (OrdineGiorno::where('assemblea_id', $this->record)->max('numero_punto') ?? 0) + 1;
|
|
$this->odgTitolo = '';
|
|
$this->odgDescrizione = '';
|
|
$this->odgArticoloLegge = '';
|
|
$this->odgTabellaMillesimaleId = null;
|
|
}
|
|
|
|
public function aggiungiPuntoOdG(): void
|
|
{
|
|
$this->validate([
|
|
'odgNumeroPunto' => 'required|integer',
|
|
'odgTitolo' => 'required|string|max:255',
|
|
'odgDescrizione' => 'required|string',
|
|
]);
|
|
|
|
OrdineGiorno::create([
|
|
'assemblea_id' => $this->record,
|
|
'numero_punto' => $this->odgNumeroPunto,
|
|
'titolo' => $this->odgTitolo,
|
|
'descrizione' => $this->odgDescrizione,
|
|
'articolo_legge' => $this->odgArticoloLegge,
|
|
'tabella_millesimale_id' => $this->odgTabellaMillesimaleId,
|
|
]);
|
|
|
|
$this->resetOdgForm();
|
|
$this->notification('Punto all\'ordine del giorno aggiunto!');
|
|
}
|
|
|
|
public function eliminaPuntoOdG(int $id): void
|
|
{
|
|
$punto = OrdineGiorno::find($id);
|
|
if ($punto) {
|
|
$punto->delete();
|
|
$this->notification('Punto OdG eliminato.');
|
|
}
|
|
}
|
|
|
|
// --- AZIONI GESTIONE CONVOCAZIONI ---
|
|
public function generaConvocazioniMassive(): void
|
|
{
|
|
if (!$this->stabileAttivo) return;
|
|
|
|
$unitaList = UnitaImmobiliare::where('stabile_id', $this->stabileAttivo->id)
|
|
->with(['rubricaRuoliAttivi.contatto', 'soggetti'])
|
|
->get();
|
|
|
|
$count = 0;
|
|
|
|
foreach ($unitaList as $unita) {
|
|
$ruoli = $unita->rubricaRuoliAttivi ?? collect();
|
|
foreach ($ruoli as $ruolo) {
|
|
$soggetto = $ruolo->contatto;
|
|
if (!$soggetto) continue;
|
|
|
|
$roleLabel = strtolower(trim((string)$ruolo->ruolo_standard));
|
|
$ruoloAbbr = 'C';
|
|
if (in_array($roleLabel, ['inquilino', 'locatario', 'conduttore'], true)) {
|
|
$ruoloAbbr = 'I';
|
|
}
|
|
|
|
$exists = Convocazione::where('assemblea_id', $this->record)
|
|
->where('soggetto_id', $soggetto->id)
|
|
->where('unita_immobiliare_id', $unita->id)
|
|
->exists();
|
|
|
|
if (!$exists) {
|
|
Convocazione::create([
|
|
'assemblea_id' => $this->record,
|
|
'unita_immobiliare_id' => $unita->id,
|
|
'soggetto_id' => $soggetto->id,
|
|
'ruolo' => $ruoloAbbr,
|
|
'consegnato_canale' => $soggetto->pec ? 'pec' : ($soggetto->email ? 'email' : ($soggetto->telefono ? 'whatsapp' : 'posta')),
|
|
'token_accesso' => Str::random(40),
|
|
]);
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
if ($ruoli->isEmpty()) {
|
|
$soggetti = $unita->soggetti ?? collect();
|
|
foreach ($soggetti as $s) {
|
|
$exists = Convocazione::where('assemblea_id', $this->record)
|
|
->where('soggetto_id', $s->id)
|
|
->where('unita_immobiliare_id', $unita->id)
|
|
->exists();
|
|
|
|
if (!$exists) {
|
|
Convocazione::create([
|
|
'assemblea_id' => $this->record,
|
|
'unita_immobiliare_id' => $unita->id,
|
|
'soggetto_id' => $s->id,
|
|
'ruolo' => 'C',
|
|
'consegnato_canale' => $s->pec ? 'pec' : ($s->email ? 'email' : ($s->telefono ? 'whatsapp' : 'posta')),
|
|
'token_accesso' => Str::random(40),
|
|
]);
|
|
$count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->notification("Generazione completata! Create {$count} convocazioni.");
|
|
}
|
|
|
|
public function cancellaTutteConvocazioni(): void
|
|
{
|
|
Convocazione::where('assemblea_id', $this->record)->delete();
|
|
$this->notification('Tutte le convocazioni sono state eliminate.');
|
|
}
|
|
|
|
public function inviaConvocazioneSingola(int $id): void
|
|
{
|
|
$conv = Convocazione::find($id);
|
|
if ($conv) {
|
|
$conv->update(['consegnato_at' => now()]);
|
|
$this->notification('Notifica di convocazione simulata inviata con successo!');
|
|
}
|
|
}
|
|
|
|
// --- GESTIONE PRESENZE ---
|
|
public function registraPresenzaCheckin(): void
|
|
{
|
|
$this->validate([
|
|
'presenzaSoggettoId' => 'required',
|
|
'presenzaUnitaId' => 'required',
|
|
'presenzaTipo' => 'required',
|
|
]);
|
|
|
|
AssembleaPresenza::create([
|
|
'assemblea_id' => $this->record,
|
|
'soggetto_id' => $this->presenzaSoggettoId,
|
|
'unita_immobiliare_id' => $this->presenzaUnitaId,
|
|
'tipo_partecipazione' => $this->presenzaTipo,
|
|
'delegato_soggetto_id' => $this->presenzaTipo === 'delega' ? $this->presenzaDelegatoId : null,
|
|
'ora_ingresso' => now(),
|
|
'qr_code_token' => Str::random(32),
|
|
]);
|
|
|
|
$this->presenzaSoggettoId = null;
|
|
$this->presenzaUnitaId = null;
|
|
$this->presenzaTipo = 'personale';
|
|
$this->presenzaDelegatoId = null;
|
|
|
|
$this->notification('Check-in presenza registrato!');
|
|
}
|
|
|
|
public function registraCheckout(int $id): void
|
|
{
|
|
$pres = AssembleaPresenza::find($id);
|
|
if ($pres) {
|
|
$pres->update(['ora_uscita' => now()]);
|
|
$this->notification('Check-out registrato.');
|
|
}
|
|
}
|
|
|
|
// --- GESTIONE VOTO LIVE ---
|
|
public function apriVotazionePunto(int $odgId): void
|
|
{
|
|
Cache::put("assemblea.{$this->record}.attivo_odg_id", $odgId, now()->addHours(6));
|
|
$this->notification('Votazione aperta per il punto selezionato!');
|
|
}
|
|
|
|
public function chiudiVotazioneCorrente(): void
|
|
{
|
|
Cache::forget("assemblea.{$this->record}.attivo_odg_id");
|
|
$this->notification('Votazione chiusa.');
|
|
}
|
|
|
|
// --- DATI E RELAZIONI ---
|
|
public function getTabelleMillesimaliProperty(): Collection
|
|
{
|
|
if (!$this->stabileAttivo) return collect();
|
|
return TabellaMillesimale::where('stabile_id', $this->stabileAttivo->id)->get();
|
|
}
|
|
|
|
public function getOrdineGiornoListProperty(): Collection
|
|
{
|
|
return OrdineGiorno::where('assemblea_id', $this->record)
|
|
->with('tabellaMillesimale')
|
|
->orderBy('numero_punto')
|
|
->get();
|
|
}
|
|
|
|
public function getConvocazioniListProperty(): Collection
|
|
{
|
|
return Convocazione::where('assemblea_id', $this->record)
|
|
->with(['soggetto', 'unitaImmobiliare'])
|
|
->get();
|
|
}
|
|
|
|
public function getPresenzeListProperty(): Collection
|
|
{
|
|
return AssembleaPresenza::where('assemblea_id', $this->record)
|
|
->with(['soggetto', 'unitaImmobiliare', 'delegatoSoggetto'])
|
|
->orderBy('ora_ingresso', 'desc')
|
|
->get();
|
|
}
|
|
|
|
public function getVotiLiveStatsProperty(): array
|
|
{
|
|
$attivoOdgId = Cache::get("assemblea.{$this->record}.attivo_odg_id");
|
|
if (!$attivoOdgId) return [];
|
|
|
|
$voti = AssembleaVoto::where('ordine_giorno_id', $attivoOdgId)
|
|
->with(['soggetto', 'unitaImmobiliare'])
|
|
->get();
|
|
|
|
$favorevoli = $voti->where('voto', 'favorevole');
|
|
$contrari = $voti->where('voto', 'contrario');
|
|
$astenuti = $voti->where('voto', 'astenuto');
|
|
|
|
return [
|
|
'odg_id' => $attivoOdgId,
|
|
'odg_punto' => OrdineGiorno::find($attivoOdgId),
|
|
'totale_teste' => $voti->count(),
|
|
'totale_millesimi' => $voti->sum('millesimi_voto'),
|
|
|
|
'favorevoli_teste' => $favorevoli->count(),
|
|
'favorevoli_millesimi' => $favorevoli->sum('millesimi_voto'),
|
|
|
|
'contrari_teste' => $contrari->count(),
|
|
'contrari_millesimi' => $contrari->sum('millesimi_voto'),
|
|
|
|
'astenuti_teste' => $astenuti->count(),
|
|
'astenuti_millesimi' => $astenuti->sum('millesimi_voto'),
|
|
|
|
'dettaglio_voti' => $voti,
|
|
];
|
|
}
|
|
|
|
public function getDisponibiliPresenzaSoggettiProperty(): Collection
|
|
{
|
|
if (!$this->stabileAttivo) return collect();
|
|
return Soggetto::whereHas('unitaImmobiliari', function($q) {
|
|
$q->where('stabile_id', $this->stabileAttivo->id);
|
|
})->orderBy('cognome')->orderBy('nome')->get();
|
|
}
|
|
|
|
public function getDisponibiliPresenzaUnitaProperty(): Collection
|
|
{
|
|
if (!$this->stabileAttivo) return collect();
|
|
return UnitaImmobiliare::where('stabile_id', $this->stabileAttivo->id)
|
|
->orderBy('palazzina')
|
|
->orderBy('scala')
|
|
->orderByRaw("CASE WHEN unita_immobiliari.interno REGEXP '^[0-9]+' THEN CAST(unita_immobiliari.interno AS UNSIGNED) ELSE 999999 END")
|
|
->orderBy('interno')
|
|
->get();
|
|
}
|
|
|
|
private function notification(string $message): void
|
|
{
|
|
$this->dispatch('notify', [
|
|
'status' => 'success',
|
|
'message' => $message
|
|
]);
|
|
}
|
|
}
|