457 lines
17 KiB
PHP
457 lines
17 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\UnitaImmobiliare;
|
|
use App\Models\Stabile;
|
|
use App\Models\Soggetto;
|
|
use App\Models\SubentroUnita;
|
|
use App\Models\ComposizioneUnita;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class UnitaImmobiliareController extends Controller
|
|
{
|
|
/**
|
|
* Display the specified resource with advanced dashboard.
|
|
*/
|
|
public function show(UnitaImmobiliare $unita)
|
|
{
|
|
// Verifica accesso
|
|
if ($unita->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
$unita->load([
|
|
'stabile',
|
|
'soggetti',
|
|
'subentri.soggettoNuovo',
|
|
'subentri.soggettoPrecedente',
|
|
'composizioni',
|
|
'strutturaFisica'
|
|
]);
|
|
|
|
$analytics = $this->calcolaAnalytics($unita);
|
|
|
|
return view('admin.unita.show', compact('unita', 'analytics'));
|
|
}
|
|
|
|
/**
|
|
* Show the form for creating a new resource.
|
|
*/
|
|
public function create(Stabile $stabile)
|
|
{
|
|
// Verifica che l'utente possa accedere a questo stabile
|
|
if ($stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
return view('admin.unita_immobiliari.create', compact('stabile'));
|
|
}
|
|
|
|
/**
|
|
* Store a newly created resource in storage.
|
|
*/
|
|
public function store(Request $request, Stabile $stabile)
|
|
{
|
|
// Verifica che l'utente possa accedere a questo stabile
|
|
if ($stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
$request->validate([
|
|
'stabile_id' => 'required|exists:stabili,id',
|
|
'denominazione' => 'required|string|max:255',
|
|
'interno' => 'nullable|string|max:255',
|
|
'scala' => 'nullable|string|max:255',
|
|
'piano' => 'nullable|integer',
|
|
'fabbricato' => 'nullable|string|max:255',
|
|
// Superfici
|
|
'superficie_commerciale' => 'nullable|numeric|min:0|max:99999999.99',
|
|
'superficie_calpestabile' => 'nullable|numeric|min:0|max:99999999.99',
|
|
'superficie_balconi' => 'nullable|numeric|min:0|max:99999999.99',
|
|
'superficie_terrazzi' => 'nullable|numeric|min:0|max:99999999.99',
|
|
// Conteggi
|
|
'numero_vani' => 'nullable|integer|min:0',
|
|
'numero_bagni' => 'nullable|integer|min:0',
|
|
'numero_balconi' => 'nullable|integer|min:0',
|
|
// Classificazioni
|
|
'classe_energetica' => 'nullable|string|max:5',
|
|
'stato_conservazione' => 'nullable|in:ottimo,buono,discreto,cattivo',
|
|
'anno_costruzione' => 'nullable|integer|min:1800|max:' . date('Y'),
|
|
'anno_ristrutturazione' => 'nullable|integer|min:1800|max:' . date('Y'),
|
|
// Millesimi
|
|
'millesimi_proprieta' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_riscaldamento' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_ascensore' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_scale' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_pulizie' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_custom_1' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_custom_2' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_custom_3' => 'nullable|numeric|min:0|max:9999.9999',
|
|
// Opzioni
|
|
'calcolo_automatico_millesimi' => 'boolean',
|
|
'necessita_lavori' => 'boolean',
|
|
'notifiche_subentri' => 'boolean',
|
|
// Note
|
|
'note_tecniche' => 'nullable|string',
|
|
]);
|
|
|
|
$data = $request->all();
|
|
$data['created_by'] = auth()->id();
|
|
|
|
$unitaImmobiliare = UnitaImmobiliare::create($data);
|
|
|
|
// Calcola automaticamente i millesimi se richiesto
|
|
if ($request->calcolo_automatico_millesimi) {
|
|
$millesimi = $unitaImmobiliare->calcolaMillesimiAutomatici();
|
|
$unitaImmobiliare->update($millesimi);
|
|
}
|
|
|
|
return redirect()->route('admin.stabili.show', $stabile)
|
|
->with('success', 'Unità immobiliare creata con successo.');
|
|
}
|
|
|
|
/**
|
|
* Show the form for editing the specified resource.
|
|
*/
|
|
public function edit(UnitaImmobiliare $unitaImmobiliare)
|
|
{
|
|
// Verifica che l'utente possa modificare questa unità
|
|
if ($unitaImmobiliare->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
return view('admin.unita_immobiliari.edit', compact('unitaImmobiliare'));
|
|
}
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*/
|
|
public function update(Request $request, UnitaImmobiliare $unitaImmobiliare)
|
|
{
|
|
// Verifica che l'utente possa modificare questa unità
|
|
if ($unitaImmobiliare->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
$request->validate([
|
|
'stabile_id' => 'required|exists:stabili,id',
|
|
'denominazione' => 'required|string|max:255',
|
|
'interno' => 'nullable|string|max:255',
|
|
'scala' => 'nullable|string|max:255',
|
|
'piano' => 'nullable|integer',
|
|
// Superfici
|
|
'superficie_commerciale' => 'nullable|numeric|min:0|max:99999999.99',
|
|
'superficie_calpestabile' => 'nullable|numeric|min:0|max:99999999.99',
|
|
'superficie_balconi' => 'nullable|numeric|min:0|max:99999999.99',
|
|
'superficie_terrazzi' => 'nullable|numeric|min:0|max:99999999.99',
|
|
// Conteggi
|
|
'numero_vani' => 'nullable|integer|min:0',
|
|
'numero_bagni' => 'nullable|integer|min:0',
|
|
'numero_balconi' => 'nullable|integer|min:0',
|
|
// Classificazioni
|
|
'classe_energetica' => 'nullable|string|max:5',
|
|
'stato_conservazione' => 'nullable|in:ottimo,buono,discreto,cattivo',
|
|
'anno_costruzione' => 'nullable|integer|min:1800|max:' . date('Y'),
|
|
'anno_ristrutturazione' => 'nullable|integer|min:1800|max:' . date('Y'),
|
|
// Millesimi
|
|
'millesimi_proprieta' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_riscaldamento' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_ascensore' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_scale' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_pulizie' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_custom_1' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_custom_2' => 'nullable|numeric|min:0|max:9999.9999',
|
|
'millesimi_custom_3' => 'nullable|numeric|min:0|max:9999.9999',
|
|
// Opzioni
|
|
'necessita_lavori' => 'boolean',
|
|
'calcolo_automatico_millesimi' => 'boolean',
|
|
'notifiche_subentri' => 'boolean',
|
|
// Note
|
|
'note_tecniche' => 'nullable|string',
|
|
]);
|
|
|
|
$data = $request->all();
|
|
$data['updated_by'] = auth()->id();
|
|
|
|
$unitaImmobiliare->update($data);
|
|
|
|
return redirect()->route('admin.stabili.show', $unitaImmobiliare->stabile)
|
|
->with('success', 'Unità immobiliare aggiornata con successo.');
|
|
}
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*/
|
|
public function destroy(UnitaImmobiliare $unitaImmobiliare)
|
|
{
|
|
// Verifica che l'utente possa eliminare questa unità
|
|
if ($unitaImmobiliare->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
$stabile = $unitaImmobiliare->stabile;
|
|
$unitaImmobiliare->delete();
|
|
|
|
return redirect()->route('admin.stabili.show', $stabile)
|
|
->with('success', 'Unità immobiliare eliminata con successo.');
|
|
}
|
|
|
|
// === METODI AVANZATI ===
|
|
|
|
/**
|
|
* Ricalcola automaticamente i millesimi
|
|
*/
|
|
public function ricalcolaMillesimi(UnitaImmobiliare $unita)
|
|
{
|
|
if ($unita->stabile->amministratore_id !== auth()->user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
if (!$unita->calcolo_automatico_millesimi) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Calcolo automatico disabilitato per questa unità'
|
|
], 400);
|
|
}
|
|
|
|
try {
|
|
$nuoviMillesimi = $unita->calcolaMillesimiAutomatici();
|
|
|
|
if (empty($nuoviMillesimi)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Impossibile calcolare i millesimi automaticamente'
|
|
], 400);
|
|
}
|
|
|
|
$unita->update($nuoviMillesimi);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Millesimi ricalcolati automaticamente',
|
|
'data' => $nuoviMillesimi
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Errore durante il calcolo: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crea un nuovo subentro
|
|
*/
|
|
public function creaSubentro(Request $request, UnitaImmobiliare $unita)
|
|
{
|
|
if ($unita->stabile->amministratore_id !== auth()->user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
$request->validate([
|
|
'soggetto_nuovo_id' => 'required|exists:soggetti,id',
|
|
'data_subentro' => 'required|date',
|
|
'tipo_subentro' => 'required|in:vendita,eredita,donazione,locazione,comodato',
|
|
'quota' => 'required|numeric|min:0|max:1',
|
|
'numero_atto' => 'nullable|string|max:100',
|
|
'data_atto' => 'nullable|date',
|
|
'notaio' => 'nullable|string|max:200',
|
|
'prezzo_vendita' => 'nullable|numeric|min:0'
|
|
]);
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
$nuovoSoggetto = Soggetto::findOrFail($request->soggetto_nuovo_id);
|
|
|
|
$subentro = $unita->generaSubentroAutomatico($nuovoSoggetto, $request->all());
|
|
|
|
// Aggiorna relazione soggetti_unita_immobiliari se il subentro è automaticamente approvato
|
|
if ($request->has('approva_automaticamente') && $request->approva_automaticamente) {
|
|
$this->completaSubentro($subentro);
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Subentro creato con successo',
|
|
'subentro_id' => $subentro->id
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Errore durante la creazione del subentro: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Approva un subentro
|
|
*/
|
|
public function approvaSubentro(SubentroUnita $subentro)
|
|
{
|
|
if ($subentro->unitaImmobiliare->stabile->amministratore_id !== auth()->user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
if ($subentro->stato_subentro !== 'proposto') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Il subentro deve essere in stato "proposto" per essere approvato'
|
|
], 400);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
$subentro->update([
|
|
'stato_subentro' => 'completato',
|
|
'data_completamento' => now(),
|
|
'ripartizioni_aggiornate' => true
|
|
]);
|
|
|
|
// Completa il passaggio di proprietà
|
|
$this->completaSubentro($subentro);
|
|
|
|
DB::commit();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Subentro approvato e completato'
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Errore durante l\'approvazione: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crea una nuova composizione unità
|
|
*/
|
|
public function creaComposizione(Request $request, UnitaImmobiliare $unita)
|
|
{
|
|
if ($unita->stabile->amministratore_id !== auth()->user()->amministratore->id_amministratore ?? null) {
|
|
abort(403);
|
|
}
|
|
|
|
$request->validate([
|
|
'tipo_operazione' => 'required|in:unione,divisione,modifica',
|
|
'data_operazione' => 'required|date',
|
|
'unita_originale_id' => 'nullable|exists:unita_immobiliari,id',
|
|
'superficie_trasferita' => 'nullable|numeric|min:0',
|
|
'vani_trasferiti' => 'nullable|integer|min:0',
|
|
'numero_pratica' => 'nullable|string|max:100',
|
|
'note_variazione' => 'nullable|string'
|
|
]);
|
|
|
|
try {
|
|
$composizione = ComposizioneUnita::create([
|
|
'unita_originale_id' => $request->unita_originale_id,
|
|
'unita_risultante_id' => $unita->id,
|
|
'tipo_operazione' => $request->tipo_operazione,
|
|
'data_operazione' => $request->data_operazione,
|
|
'superficie_trasferita' => $request->superficie_trasferita,
|
|
'vani_trasferiti' => $request->vani_trasferiti,
|
|
'numero_pratica' => $request->numero_pratica,
|
|
'note_variazione' => $request->note_variazione,
|
|
'millesimi_automatici' => $unita->calcolo_automatico_millesimi,
|
|
'created_by' => auth()->id()
|
|
]);
|
|
|
|
// Ricalcola millesimi se automatico
|
|
if ($unita->calcolo_automatico_millesimi) {
|
|
$nuoviMillesimi = $unita->calcolaMillesimiAutomatici();
|
|
$unita->update($nuoviMillesimi);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Composizione creata con successo',
|
|
'composizione_id' => $composizione->id
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Errore durante la creazione: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
// === METODI PRIVATI ===
|
|
|
|
private function calcolaAnalytics(UnitaImmobiliare $unita): array
|
|
{
|
|
return [
|
|
'storico_subentri' => $unita->subentri()->count(),
|
|
'composizioni_totali' => $unita->composizioni()->count(),
|
|
'superficie_totale' => ($unita->superficie_commerciale ?? 0) +
|
|
($unita->superficie_balconi ?? 0) +
|
|
($unita->superficie_terrazzi ?? 0),
|
|
'percentuale_millesimi' => ($unita->millesimi_proprieta ?? 0) / 10, // Su base 100
|
|
'valore_catastale_stimato' => $this->stimaValoreCatastale($unita),
|
|
'trend_mercato' => $this->calcolaTrendMercato($unita),
|
|
'subentri_pending' => $unita->subentri()->pending()->count(),
|
|
'composizioni_pending' => $unita->composizioni()->pending()->count()
|
|
];
|
|
}
|
|
|
|
private function completaSubentro(SubentroUnita $subentro): void
|
|
{
|
|
$unita = $subentro->unitaImmobiliare;
|
|
|
|
// Chiudi relazione precedente se esiste
|
|
if ($subentro->soggetto_precedente_id) {
|
|
$unita->soggetti()
|
|
->wherePivot('soggetto_id', $subentro->soggetto_precedente_id)
|
|
->wherePivot('data_fine', null)
|
|
->updateExistingPivot($subentro->soggetto_precedente_id, [
|
|
'data_fine' => $subentro->data_subentro
|
|
]);
|
|
}
|
|
|
|
// Crea nuova relazione
|
|
$unita->soggetti()->attach($subentro->soggetto_nuovo_id, [
|
|
'quota' => $subentro->quota_nuova,
|
|
'tipo_diritto' => $this->getTipoDirittoFromSubentro($subentro->tipo_subentro),
|
|
'data_inizio' => $subentro->data_subentro,
|
|
'data_fine' => null
|
|
]);
|
|
}
|
|
|
|
private function getTipoDirittoFromSubentro(string $tipoSubentro): string
|
|
{
|
|
return match($tipoSubentro) {
|
|
'vendita', 'eredita', 'donazione' => 'proprietà',
|
|
'locazione' => 'locazione',
|
|
'comodato' => 'comodato',
|
|
default => 'proprietà'
|
|
};
|
|
}
|
|
|
|
private function stimaValoreCatastale(UnitaImmobiliare $unita): float
|
|
{
|
|
// Logica di stima basata su superficie e zona
|
|
$baseValue = ($unita->superficie_commerciale ?? 0) * 1500; // €1500/m² base
|
|
return round($baseValue, 2);
|
|
}
|
|
|
|
private function calcolaTrendMercato(UnitaImmobiliare $unita): array
|
|
{
|
|
// Placeholder per trend mercato
|
|
return [
|
|
'trend' => 'stabile',
|
|
'variazione_percentuale' => 0,
|
|
'ultimo_aggiornamento' => now()->toDateString()
|
|
];
|
|
}
|
|
} |