'datetime', 'data_seconda_convocazione' => 'datetime', 'data_convocazione' => 'date', 'data_svolgimento' => 'date', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; /** * Relazione con Stabile */ public function stabile() { return $this->belongsTo(Stabile::class, 'stabile_id', 'id'); } /** * Relazione con Ordine del Giorno */ public function ordineGiorno() { return $this->hasMany(OrdineGiorno::class, 'assemblea_id')->orderBy('numero_punto'); } /** * Relazione con Convocazioni */ public function convocazioni() { return $this->hasMany(Convocazione::class, 'assemblea_id'); } /** * Relazione con Presenze */ public function presenze() { return $this->hasMany(PresenzaAssemblea::class, 'assemblea_id'); } /** * Relazione con Verbale */ public function verbale() { return $this->hasOne(Verbale::class, 'assemblea_id'); } /** * Relazione con Documenti */ public function documenti() { return $this->hasMany(DocumentoAssemblea::class, 'assemblea_id'); } /** * Relazione con User creatore */ public function creatoDa() { return $this->belongsTo(User::class, 'creato_da_user_id'); } /** * Scope per stato */ public function scopeStato($query, $stato) { return $query->where('stato', $stato); } /** * Scope per tipo */ public function scopeTipo($query, $tipo) { return $query->where('tipo', $tipo); } /** * Invia convocazioni massive */ public function inviaConvocazioni($canali = ['email'], $userId) { $unitaImmobiliari = $this->stabile->unitaImmobiliari()->with('proprieta.soggetto')->get(); $convocazioniInviate = 0; foreach ($unitaImmobiliari as $unita) { foreach ($unita->proprieta as $proprieta) { $soggetto = $proprieta->soggetto; foreach ($canali as $canale) { if ($this->verificaCanaleDisponibile($soggetto, $canale)) { $convocazione = $this->creaConvocazione($soggetto, $unita, $canale); if ($this->inviaConvocazione($convocazione)) { $convocazioniInviate++; // Registra nel protocollo $this->registraProtocollo($convocazione, $userId); } } } } } // Aggiorna stato assemblea $this->update([ 'stato' => 'convocata', 'data_convocazione' => now(), ]); return $convocazioniInviate; } /** * Verifica se il canale รจ disponibile per il soggetto */ private function verificaCanaleDisponibile($soggetto, $canale) { switch ($canale) { case 'email': return !empty($soggetto->email); case 'pec': return !empty($soggetto->pec); case 'whatsapp': case 'telegram': return !empty($soggetto->telefono); default: return true; } } /** * Crea record convocazione */ private function creaConvocazione($soggetto, $unita, $canale) { return Convocazione::create([ 'assemblea_id' => $this->id, 'soggetto_id' => $soggetto->id_soggetto, 'unita_immobiliare_id' => $unita->id_unita, 'canale_invio' => $canale, 'data_invio' => now(), 'esito_invio' => 'inviato', ]); } /** * Invia singola convocazione */ private function inviaConvocazione($convocazione) { // Implementazione invio basata sul canale // Qui si integrerebbe con servizi email, SMS, etc. // Simula invio riuscito $convocazione->update([ 'esito_invio' => 'consegnato', 'riferimento_invio' => 'REF-' . time(), ]); return true; } /** * Registra comunicazione nel protocollo */ private function registraProtocollo($convocazione, $userId) { $numeroProtocollo = $this->generaNumeroProtocollo(); RegistroProtocollo::create([ 'numero_protocollo' => $numeroProtocollo, 'tipo_comunicazione' => 'convocazione', 'assemblea_id' => $this->id, 'soggetto_destinatario_id' => $convocazione->soggetto_id, 'oggetto' => "Convocazione Assemblea {$this->tipo} - {$this->data_prima_convocazione->format('d/m/Y')}", 'canale' => $convocazione->canale_invio, 'data_invio' => $convocazione->data_invio, 'esito' => $convocazione->esito_invio, 'riferimento_esterno' => $convocazione->riferimento_invio, 'creato_da_user_id' => $userId, ]); } /** * Genera numero protocollo progressivo */ private function generaNumeroProtocollo() { $anno = date('Y'); $ultimoProtocollo = RegistroProtocollo::whereYear('created_at', $anno) ->orderBy('numero_protocollo', 'desc') ->first(); if ($ultimoProtocollo) { $numero = intval(substr($ultimoProtocollo->numero_protocollo, -4)) + 1; } else { $numero = 1; } return 'PROT/' . $anno . '/' . str_pad($numero, 4, '0', STR_PAD_LEFT); } /** * Calcola quorum assemblea */ public function calcolaQuorum() { $totaleMillesimi = $this->stabile->unitaImmobiliari()->sum('millesimi_proprieta'); $millesimiPresenti = $this->presenze()->sum('millesimi_rappresentati'); return [ 'totale_millesimi' => $totaleMillesimi, 'millesimi_presenti' => $millesimiPresenti, 'percentuale_presenza' => $totaleMillesimi > 0 ? ($millesimiPresenti / $totaleMillesimi) * 100 : 0, 'quorum_raggiunto' => $millesimiPresenti >= ($totaleMillesimi / 2), ]; } /** * Genera report presenze */ public function generaReportPresenze() { $presenze = $this->presenze()->with(['soggetto', 'unitaImmobiliare'])->get(); $quorum = $this->calcolaQuorum(); return [ 'quorum' => $quorum, 'presenze' => $presenze, 'totale_presenti' => $presenze->where('tipo_presenza', 'presente')->count(), 'totale_delegati' => $presenze->where('tipo_presenza', 'delegato')->count(), 'totale_assenti' => $this->stabile->unitaImmobiliari()->count() - $presenze->count(), ]; } }