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 ]); } }