whereHas('stabile', function($q) { $q->where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null); }); // Filtro per stabile if ($request->filled('stabile_id')) { $query->where('stabile_id', $request->stabile_id); } // Filtro per categoria if ($request->filled('categoria')) { $query->where('categoria', $request->categoria); } // Filtro per stato if ($request->filled('stato')) { $query->where('stato', $request->stato); } // Ricerca per denominazione if ($request->filled('search')) { $query->where('denominazione', 'like', '%' . $request->search . '%'); } $vociSpesa = $query->orderBy('denominazione')->paginate(15); // Dati per i filtri $stabili = Stabile::where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null) ->orderBy('denominazione') ->get(); $categorie = VoceSpesa::distinct()->pluck('categoria')->filter()->sort(); return view('admin.voci-spesa.index', compact('vociSpesa', 'stabili', 'categorie')); } /** * Show the form for creating a new resource. */ public function create() { $stabili = Stabile::where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null) ->orderBy('denominazione') ->get(); $tabelleMillesimali = TabellaMillesimale::whereHas('stabile', function($q) { $q->where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null); }) ->orderBy('denominazione') ->get(); return view('admin.voci-spesa.create', compact('stabili', 'tabelleMillesimali')); } /** * Store a newly created resource in storage. */ public function store(Request $request) { $request->validate([ 'stabile_id' => 'required|exists:stabili,id', 'denominazione' => 'required|string|max:255', 'categoria' => 'required|string|max:100', 'sottocategoria' => 'nullable|string|max:100', 'descrizione' => 'nullable|string', 'importo_previsto' => 'nullable|numeric|min:0', 'periodicita' => 'nullable|in:una_tantum,mensile,trimestrale,semestrale,annuale', 'tabella_millesimale_default_id' => 'required|exists:tabelle_millesimali,id', 'ripartizione_personalizzata' => 'nullable|boolean', 'stato' => 'required|in:attiva,inattiva,archiviata', 'note' => 'nullable|string', 'tags' => 'nullable|string|max:500', ]); // Verifica che lo stabile appartenga all'amministratore $stabile = Stabile::where('id', $request->stabile_id) ->where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null) ->firstOrFail(); // Verifica che la tabella millesimale appartenga allo stabile $tabellaMillesimale = TabellaMillesimale::where('id', $request->tabella_millesimale_default_id) ->where('stabile_id', $request->stabile_id) ->firstOrFail(); $voceSpesa = VoceSpesa::create([ 'codice_spesa' => $this->generateCodiceSpesa(), 'stabile_id' => $request->stabile_id, 'denominazione' => $request->denominazione, 'categoria' => $request->categoria, 'sottocategoria' => $request->sottocategoria, 'descrizione' => $request->descrizione, 'importo_previsto' => $request->importo_previsto, 'periodicita' => $request->periodicita, 'tabella_millesimale_default_id' => $request->tabella_millesimale_default_id, 'ripartizione_personalizzata' => $request->boolean('ripartizione_personalizzata'), 'stato' => $request->stato, 'note' => $request->note, 'tags' => $request->tags, 'created_by' => Auth::id(), ]); return redirect()->route('admin.voci-spesa.index') ->with('success', 'Voce di spesa creata con successo.'); } /** * Display the specified resource. */ public function show(VoceSpesa $voceSpesa) { // Verifica autorizzazione $this->authorize('view', $voceSpesa); $voceSpesa->load(['stabile', 'tabellaMillesimaleDefault', 'ripartizioniSpese.dettagli.unitaImmobiliare']); return view('admin.voci-spesa.show', compact('voceSpesa')); } /** * Show the form for editing the specified resource. */ public function edit(VoceSpesa $voceSpesa) { // Verifica autorizzazione $this->authorize('update', $voceSpesa); $stabili = Stabile::where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null) ->orderBy('denominazione') ->get(); $tabelleMillesimali = TabellaMillesimale::where('stabile_id', $voceSpesa->stabile_id) ->orderBy('denominazione') ->get(); return view('admin.voci-spesa.edit', compact('voceSpesa', 'stabili', 'tabelleMillesimali')); } /** * Update the specified resource in storage. */ public function update(Request $request, VoceSpesa $voceSpesa) { // Verifica autorizzazione $this->authorize('update', $voceSpesa); $request->validate([ 'denominazione' => 'required|string|max:255', 'categoria' => 'required|string|max:100', 'sottocategoria' => 'nullable|string|max:100', 'descrizione' => 'nullable|string', 'importo_previsto' => 'nullable|numeric|min:0', 'periodicita' => 'nullable|in:una_tantum,mensile,trimestrale,semestrale,annuale', 'tabella_millesimale_default_id' => 'required|exists:tabelle_millesimali,id', 'ripartizione_personalizzata' => 'nullable|boolean', 'stato' => 'required|in:attiva,inattiva,archiviata', 'note' => 'nullable|string', 'tags' => 'nullable|string|max:500', ]); // Verifica che la tabella millesimale appartenga allo stabile $tabellaMillesimale = TabellaMillesimale::where('id', $request->tabella_millesimale_default_id) ->where('stabile_id', $voceSpesa->stabile_id) ->firstOrFail(); $voceSpesa->update([ 'denominazione' => $request->denominazione, 'categoria' => $request->categoria, 'sottocategoria' => $request->sottocategoria, 'descrizione' => $request->descrizione, 'importo_previsto' => $request->importo_previsto, 'periodicita' => $request->periodicita, 'tabella_millesimale_default_id' => $request->tabella_millesimale_default_id, 'ripartizione_personalizzata' => $request->boolean('ripartizione_personalizzata'), 'stato' => $request->stato, 'note' => $request->note, 'tags' => $request->tags, 'updated_by' => Auth::id(), ]); return redirect()->route('admin.voci-spesa.index') ->with('success', 'Voce di spesa aggiornata con successo.'); } /** * Remove the specified resource from storage. */ public function destroy(VoceSpesa $voceSpesa) { // Verifica autorizzazione $this->authorize('delete', $voceSpesa); // Verifica che non ci siano ripartizioni associate if ($voceSpesa->ripartizioniSpese()->exists()) { return redirect()->route('admin.voci-spesa.index') ->with('error', 'Impossibile eliminare la voce di spesa: esistono ripartizioni associate.'); } $voceSpesa->delete(); return redirect()->route('admin.voci-spesa.index') ->with('success', 'Voce di spesa eliminata con successo.'); } /** * Duplica una voce di spesa esistente */ public function duplicate(VoceSpesa $voceSpesa) { // Verifica autorizzazione $this->authorize('view', $voceSpesa); $nuovaVoceSpesa = $voceSpesa->replicate(); $nuovaVoceSpesa->codice_spesa = $this->generateCodiceSpesa(); $nuovaVoceSpesa->denominazione = $voceSpesa->denominazione . ' (Copia)'; $nuovaVoceSpesa->stato = 'inattiva'; $nuovaVoceSpesa->created_by = Auth::id(); $nuovaVoceSpesa->save(); return redirect()->route('admin.voci-spesa.edit', $nuovaVoceSpesa) ->with('success', 'Voce di spesa duplicata con successo.'); } /** * Ottieni le tabelle millesimali per uno stabile (AJAX) */ public function getTabelleMillesimali(Request $request) { $stabileId = $request->get('stabile_id'); if (!$stabileId) { return response()->json([]); } // Verifica che lo stabile appartenga all'amministratore $stabile = Stabile::where('id', $stabileId) ->where('amministratore_id', Auth::user()->amministratore->id_amministratore ?? null) ->first(); if (!$stabile) { return response()->json([]); } $tabelle = TabellaMillesimale::where('stabile_id', $stabileId) ->where('stato', 'attiva') ->orderBy('denominazione') ->get(['id', 'denominazione', 'tipo_tabella']); return response()->json($tabelle); } /** * Genera un codice spesa univoco */ private function generateCodiceSpesa(): string { do { $codice = 'SP' . strtoupper(Str::random(6)); } while (VoceSpesa::where('codice_spesa', $codice)->exists()); return $codice; } }