with(['assemblea.stabile', 'soggetto', 'unitaImmobiliare']) ->firstOrFail(); $assemblea = $convocazione->assemblea; // Recupera Ordine del Giorno $odg = OrdineGiorno::where('assemblea_id', $assemblea->id) ->with('tabellaMillesimale') ->orderBy('numero_punto') ->get(); // Controlla se il soggetto ha deleghe attive per questa assemblea $deleghe = AssembleaPresenza::where('assemblea_id', $assemblea->id) ->where('tipo_partecipazione', 'delega') ->where('delegato_soggetto_id', $convocazione->soggetto_id) ->with(['unitaImmobiliare', 'soggetto']) ->get(); // Recupera i voti già espressi per questa convocazione/unità $votiEspressi = AssembleaVoto::where('assemblea_id', $assemblea->id) ->where('soggetto_id', $convocazione->soggetto_id) ->get() ->pluck('voto', 'ordine_giorno_id') ->toArray(); // Recupera i voti espressi per le deleghe $votiDeleghe = []; foreach ($deleghe as $delega) { $votiDeleghe[$delega->unita_immobiliare_id] = AssembleaVoto::where('assemblea_id', $assemblea->id) ->where('soggetto_id', $delega->soggetto_id) ->where('unita_immobiliare_id', $delega->unita_immobiliare_id) ->get() ->pluck('voto', 'ordine_giorno_id') ->toArray(); } // Recupera il punto attivo per la votazione (dal cache) $attivoOdgId = Cache::get("assemblea.{$assemblea->id}.attivo_odg_id"); return view('mobile.assemblea.convocazione-mobile', compact( 'convocazione', 'assemblea', 'odg', 'deleghe', 'votiEspressi', 'votiDeleghe', 'attivoOdgId' )); } public function confermaRicezione(Request $request, string $token) { $convocazione = Convocazione::where('token_accesso', $token)->firstOrFail(); $signatureData = $request->input('firma_dati'); $signaturePath = null; if ($signatureData && preg_match('/^data:image\/(\w+);base64,/', $signatureData, $type)) { $data = substr($signatureData, strpos($signatureData, ',') + 1); $data = base64_decode($data); if ($data !== false) { $signaturePath = 'firme/' . $token . '.png'; \Illuminate\Support\Facades\Storage::disk('public')->put($signaturePath, $data); } } $convocazione->update([ 'ricezione_confermata_at' => now(), 'ip_conferma' => $request->ip(), 'user_agent_conferma' => $request->userAgent(), 'firma_ricezione_percorso' => $signaturePath ? 'storage/' . $signaturePath : null, 'stato_ricezione' => 'confermato_online', ]); return response()->json([ 'success' => true, 'message' => 'Firma e ricezione registrate con successo!', 'ricezione_confermata_at' => $convocazione->ricezione_confermata_at->format('d/m/Y H:i'), ]); } public function downloadZip(string $token) { $convocazione = Convocazione::where('token_accesso', $token) ->with(['assemblea']) ->firstOrFail(); $assemblea = $convocazione->assemblea; $odg = OrdineGiorno::where('assemblea_id', $assemblea->id)->get(); $zipFileName = 'allegati_assemblea_' . $assemblea->id . '.zip'; $zipFilePath = storage_path('app/public/' . $zipFileName); $zip = new \ZipArchive(); if ($zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === true) { $hasFiles = false; foreach ($odg as $punto) { if ($punto->allegati && is_array($punto->allegati)) { foreach ($punto->allegati as $file) { $fullPath = storage_path('app/public/' . $file['path']); if (file_exists($fullPath)) { $zip->addFile($fullPath, $punto->numero_punto . '_' . $file['nome']); $hasFiles = true; } } } } $zip->close(); if ($hasFiles && file_exists($zipFilePath)) { return response()->download($zipFilePath)->deleteFileAfterSend(true); } } return redirect()->back()->with('error', 'Nessun allegato disponibile per il download.'); } public function updateAnagrafica(Request $request, string $token) { $convocazione = Convocazione::where('token_accesso', $token)->firstOrFail(); $request->validate([ 'email' => 'nullable|email|max:255', 'pec' => 'nullable|email|max:255', 'telefono' => 'nullable|string|max:50', 'indirizzo' => 'nullable|string|max:255', ]); $soggetto = $convocazione->soggetto; $datiAttuali = [ 'email' => $soggetto->email, 'pec' => $soggetto->pec, 'telefono' => $soggetto->telefono, 'indirizzo' => $soggetto->indirizzo_residenza ?? $soggetto->indirizzo, ]; $datiProposti = [ 'email' => $request->input('email'), 'pec' => $request->input('pec'), 'telefono' => $request->input('telefono'), 'indirizzo' => $request->input('indirizzo'), ]; \App\Models\RichiestaModifica::create([ 'unita_immobiliare_id' => $convocazione->unita_immobiliare_id, 'soggetto_richiedente_id' => $convocazione->soggetto_id, 'tipo_modifica' => 'recapiti', 'descrizione' => 'Aggiornamento recapiti conduttore/proprietario inviato dal portale assemblea.', 'dati_attuali' => $datiAttuali, 'dati_proposti' => $datiProposti, 'stato' => 'in_attesa', ]); return response()->json([ 'success' => true, 'message' => 'Richiesta di variazione anagrafica inviata allo studio. Verrà esaminata a breve dall\'amministratore!', ]); } public function vota(Request $request, string $token) { $convocazione = Convocazione::where('token_accesso', $token) ->with('assemblea') ->firstOrFail(); $assemblea = $convocazione->assemblea; $request->validate([ 'ordine_giorno_id' => 'required|integer', 'voto' => 'required|string|in:favorevole,contrario,astenuto', 'unita_immobiliare_id' => 'nullable|integer', 'soggetto_id' => 'nullable|integer', ]); $odgId = (int) $request->input('ordine_giorno_id'); $votoStr = $request->input('voto'); // Verifica se il punto è effettivamente aperto alla votazione $attivoOdgId = Cache::get("assemblea.{$assemblea->id}.attivo_odg_id"); if ((int)$attivoOdgId !== $odgId) { return response()->json([ 'success' => false, 'message' => 'Le votazioni per questo punto all\'ordine del giorno sono chiuse o non ancora aperte.', ], 422); } $odg = OrdineGiorno::findOrFail($odgId); // Se vota per una delega $unitaId = $request->input('unita_immobiliare_id') ?: $convocazione->unita_immobiliare_id; $soggettoId = $request->input('soggetto_id') ?: $convocazione->soggetto_id; // Se vota per delega, verifichiamo che la delega esista if ($soggettoId !== $convocazione->soggetto_id) { $hasDelega = AssembleaPresenza::where('assemblea_id', $assemblea->id) ->where('tipo_partecipazione', 'delega') ->where('soggetto_id', $soggettoId) ->where('unita_immobiliare_id', $unitaId) ->where('delegato_soggetto_id', $convocazione->soggetto_id) ->exists(); if (!$hasDelega) { return response()->json([ 'success' => false, 'message' => 'Non sei autorizzato a votare per questa delega.', ], 403); } } // Calcola millesimi per questa unità $millesimi = 0.000; if ($odg->tabella_millesimale_id) { $millesimi = DB::table('dettagli_tabelle_millesimali') ->where('tabella_millesimale_id', $odg->tabella_millesimale_id) ->where('unita_immobiliare_id', $unitaId) ->value('millesimi') ?: 0.000; } if ($millesimi <= 0) { // Fallback millesimi generali dell'unità $millesimi = DB::table('unita_immobiliari') ->where('id', $unitaId) ->value('millesimi_generali') ?: 0.000; } // Salva il voto AssembleaVoto::updateOrCreate( [ 'ordine_giorno_id' => $odgId, 'soggetto_id' => $soggettoId, 'unita_immobiliare_id' => $unitaId, ], [ 'assemblea_id' => $assemblea->id, 'voto' => $votoStr, 'millesimi_voto' => $millesimi, ] ); return response()->json([ 'success' => true, 'message' => 'Voto registrato con successo!', 'voto' => $votoStr, ]); } public function pollVotazioneAttiva(string $token) { $convocazione = Convocazione::where('token_accesso', $token)->firstOrFail(); $assemblea = $convocazione->assemblea; $attivoOdgId = Cache::get("assemblea.{$assemblea->id}.attivo_odg_id"); $punto = null; if ($attivoOdgId) { $odg = OrdineGiorno::find($attivoOdgId); if ($odg) { $punto = [ 'id' => $odg->id, 'numero' => $odg->numero_punto, 'titolo' => $odg->titolo, 'descrizione' => $odg->descrizione, ]; } } return response()->json([ 'attivo_odg_id' => $attivoOdgId, 'punto' => $punto, ]); } }