From 2d6fba0e605ae7af4d3130cc6085f1540a03b111 Mon Sep 17 00:00:00 2001 From: Pikappa2 Date: Wed, 9 Jul 2025 00:47:16 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Risoluzione=20errori=20migrazion?= =?UTF-8?q?i=20e=20aggiornamento=20DATA=5FARCHITECTURE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Corretti errori di foreign key nelle migrazioni - Rimosso userSetting() non definito e aggiunto helpers.php - Aggiornati modelli PianoRateizzazione e Rata con relazioni corrette - Aggiornato DATA_ARCHITECTURE.md con nuovi modelli per ripartizione spese - Corrette dipendenze tra tabelle nelle migrazioni --- app/Models/PianoRateizzazione.php | 8 + app/Models/Rata.php | 8 + app/helpers.php | 68 +++++ composer.json | 3 +- ...29_enhance_unita_immobiliari_structure.php | 38 ++- ...1_create_anagrafica_condominiale_table.php | 2 +- ...63341_create_contratti_locazione_table.php | 6 +- ...151345_create_ripartizione_spese_table.php | 17 ++ ...ate_dettaglio_ripartizione_spese_table.php | 9 + .../2025_07_08_151654_create_rate_table.php | 15 + ...51838_create_piano_rateizzazione_table.php | 16 + ..._07_08_223534_drop_ripartizione_tables.php | 27 ++ .../views/admin/voci-spesa/edit.blade.php | 201 +++++++++++++ .../views/admin/voci-spesa/show.blade.php | 276 ++++++++++++++++++ .../views/components/menu/sidebar.blade.php | 24 ++ 15 files changed, 705 insertions(+), 13 deletions(-) create mode 100644 app/helpers.php create mode 100644 database/migrations/2025_07_08_223534_drop_ripartizione_tables.php create mode 100644 resources/views/admin/voci-spesa/edit.blade.php create mode 100644 resources/views/admin/voci-spesa/show.blade.php diff --git a/app/Models/PianoRateizzazione.php b/app/Models/PianoRateizzazione.php index 302a9388..85727922 100644 --- a/app/Models/PianoRateizzazione.php +++ b/app/Models/PianoRateizzazione.php @@ -104,6 +104,14 @@ class PianoRateizzazione extends Model return $this->belongsTo(User::class, 'attivato_da'); } + /** + * Relazione con RipartizioneSpese + */ + public function ripartizione() + { + return $this->belongsTo(RipartizioneSpese::class, 'ripartizione_spese_id'); + } + /** * Relazione con Rate */ diff --git a/app/Models/Rata.php b/app/Models/Rata.php index 4038592d..917bbf42 100644 --- a/app/Models/Rata.php +++ b/app/Models/Rata.php @@ -105,6 +105,14 @@ class Rata extends Model return $this->belongsTo(PianoRateizzazione::class); } + /** + * Relazione con RipartizioneSpese + */ + public function ripartizione() + { + return $this->belongsTo(RipartizioneSpese::class, 'ripartizione_spese_id'); + } + /** * Relazione con UnitaImmobiliare */ diff --git a/app/helpers.php b/app/helpers.php new file mode 100644 index 00000000..01da63fe --- /dev/null +++ b/app/helpers.php @@ -0,0 +1,68 @@ +check()) { + return $default; + } + + $user = auth()->user(); + + // Se l'utente ha un campo settings + if (isset($user->settings) && is_array($user->settings)) { + return $user->settings[$key] ?? $default; + } + + // Se l'utente ha una relazione settings + if (method_exists($user, 'settings')) { + $setting = $user->settings()->where('key', $key)->first(); + return $setting ? $setting->value : $default; + } + + return $default; + } +} + +if (!function_exists('setUserSetting')) { + /** + * Imposta un'impostazione utente + * + * @param string $key + * @param mixed $value + * @return bool + */ + function setUserSetting($key, $value) + { + if (!auth()->check()) { + return false; + } + + $user = auth()->user(); + + // Se l'utente ha un campo settings + if (isset($user->settings)) { + $settings = is_array($user->settings) ? $user->settings : []; + $settings[$key] = $value; + $user->settings = $settings; + return $user->save(); + } + + // Se l'utente ha una relazione settings + if (method_exists($user, 'settings')) { + return $user->settings()->updateOrCreate( + ['key' => $key], + ['value' => $value] + ); + } + + return false; + } +} diff --git a/composer.json b/composer.json index a976a374..2600e13a 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,8 @@ "App\\": "app/" }, "files": [ - "app/Helpers/impostazioni.php" + "app/Helpers/impostazioni.php", + "app/helpers.php" ] }, "autoload-dev": { diff --git a/database/migrations/2025_07_07_223229_enhance_unita_immobiliari_structure.php b/database/migrations/2025_07_07_223229_enhance_unita_immobiliari_structure.php index 5beafb38..48cbe518 100644 --- a/database/migrations/2025_07_07_223229_enhance_unita_immobiliari_structure.php +++ b/database/migrations/2025_07_07_223229_enhance_unita_immobiliari_structure.php @@ -55,15 +55,37 @@ return new class extends Migration public function down(): void { Schema::table('unita_immobiliari', function (Blueprint $table) { - $table->dropIndex(['idx_unita_stabile_stato']); - $table->dropIndex(['idx_unita_tipo_utilizzo']); - $table->dropColumn([ - 'palazzina', 'tipo_utilizzo_id', 'millesimi_proprieta', - 'rendita_catastale', 'codice_univoco', 'stato' - ]); + // Rimuove gli indici solo se esistono - con controllo sicuro + try { + $table->dropIndex(['stabile_id', 'stato']); + } catch (\Exception $e) { + // Indice non esistente, ignora + } - if (Schema::hasColumn('unita_immobiliari', 'palazzina_old')) { - $table->renameColumn('palazzina_old', 'fabbricato'); + try { + $table->dropIndex(['tipo_utilizzo_id']); + } catch (\Exception $e) { + // Indice non esistente, ignora + } + + // Rimuove le colonne se esistono + if (Schema::hasColumn('unita_immobiliari', 'palazzina')) { + $table->dropColumn('palazzina'); + } + if (Schema::hasColumn('unita_immobiliari', 'tipo_utilizzo_id')) { + $table->dropColumn('tipo_utilizzo_id'); + } + if (Schema::hasColumn('unita_immobiliari', 'millesimi_proprieta')) { + $table->dropColumn('millesimi_proprieta'); + } + if (Schema::hasColumn('unita_immobiliari', 'rendita_catastale')) { + $table->dropColumn('rendita_catastale'); + } + if (Schema::hasColumn('unita_immobiliari', 'codice_univoco')) { + $table->dropColumn('codice_univoco'); + } + if (Schema::hasColumn('unita_immobiliari', 'stato')) { + $table->dropColumn('stato'); } }); } diff --git a/database/migrations/2025_07_07_223601_create_anagrafica_condominiale_table.php b/database/migrations/2025_07_07_223601_create_anagrafica_condominiale_table.php index cf7edf9d..cbf15668 100644 --- a/database/migrations/2025_07_07_223601_create_anagrafica_condominiale_table.php +++ b/database/migrations/2025_07_07_223601_create_anagrafica_condominiale_table.php @@ -21,7 +21,7 @@ return new class extends Migration $table->string('cognome')->nullable()->comment('Cognome (se persona fisica)'); $table->string('nome')->nullable()->comment('Nome (se persona fisica)'); $table->string('denominazione')->nullable()->comment('Denominazione (se persona giuridica)'); - $table->string('codice_fiscale', 16)->index()->comment('Codice fiscale'); + $table->string('codice_fiscale', 16)->comment('Codice fiscale'); $table->string('partita_iva', 11)->nullable()->comment('Partita IVA (se presente)'); // Dati nascita (solo per persone fisiche) diff --git a/database/migrations/2025_07_08_063341_create_contratti_locazione_table.php b/database/migrations/2025_07_08_063341_create_contratti_locazione_table.php index a8ec5581..fd0ea553 100644 --- a/database/migrations/2025_07_08_063341_create_contratti_locazione_table.php +++ b/database/migrations/2025_07_08_063341_create_contratti_locazione_table.php @@ -13,9 +13,9 @@ return new class extends Migration { Schema::create('contratti_locazione', function (Blueprint $table) { $table->id(); - $table->bigInteger('unita_immobiliare_id')->unsigned()->index()->comment('FK verso unita_immobiliari'); - $table->bigInteger('locatore_id')->unsigned()->index()->comment('FK verso anagrafica_condominiale (proprietario)'); - $table->bigInteger('conduttore_id')->unsigned()->index()->comment('FK verso anagrafica_condominiale (inquilino)'); + $table->bigInteger('unita_immobiliare_id')->unsigned()->comment('FK verso unita_immobiliari'); + $table->bigInteger('locatore_id')->unsigned()->comment('FK verso anagrafica_condominiale (proprietario)'); + $table->bigInteger('conduttore_id')->unsigned()->comment('FK verso anagrafica_condominiale (inquilino)'); $table->string('numero_contratto')->nullable()->comment('Numero identificativo contratto'); $table->date('data_contratto')->comment('Data stipula contratto'); diff --git a/database/migrations/2025_07_08_151345_create_ripartizione_spese_table.php b/database/migrations/2025_07_08_151345_create_ripartizione_spese_table.php index ab068435..987c66b2 100644 --- a/database/migrations/2025_07_08_151345_create_ripartizione_spese_table.php +++ b/database/migrations/2025_07_08_151345_create_ripartizione_spese_table.php @@ -13,7 +13,24 @@ return new class extends Migration { Schema::create('ripartizione_spese', function (Blueprint $table) { $table->id(); + $table->string('codice_ripartizione')->unique(); + $table->foreignId('voce_spesa_id')->constrained('voci_spesa')->cascadeOnDelete(); + $table->foreignId('stabile_id')->constrained('stabili')->cascadeOnDelete(); + $table->unsignedBigInteger('tabella_millesimale_id'); + $table->decimal('importo_totale', 10, 2); + $table->decimal('importo_ripartito', 10, 2)->default(0); + $table->string('tipo_ripartizione')->default('millesimale'); // millesimale, uguale, personalizzata + $table->date('data_ripartizione'); + $table->string('stato')->default('bozza'); // bozza, approvata, contabilizzata + $table->text('note')->nullable(); + $table->json('configurazione_ripartizione')->nullable(); + $table->foreignId('creato_da')->constrained('users'); + $table->timestamp('approvato_at')->nullable(); + $table->unsignedBigInteger('approvato_da')->nullable(); + $table->timestamp('contabilizzato_at')->nullable(); + $table->unsignedBigInteger('contabilizzato_da')->nullable(); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2025_07_08_151547_create_dettaglio_ripartizione_spese_table.php b/database/migrations/2025_07_08_151547_create_dettaglio_ripartizione_spese_table.php index 61aeff5f..d54875e2 100644 --- a/database/migrations/2025_07_08_151547_create_dettaglio_ripartizione_spese_table.php +++ b/database/migrations/2025_07_08_151547_create_dettaglio_ripartizione_spese_table.php @@ -13,7 +13,16 @@ return new class extends Migration { Schema::create('dettaglio_ripartizione_spese', function (Blueprint $table) { $table->id(); + $table->foreignId('ripartizione_spese_id')->constrained('ripartizione_spese')->cascadeOnDelete(); + $table->unsignedBigInteger('unita_immobiliare_id'); + $table->unsignedBigInteger('anagrafica_condominiale_id'); + $table->decimal('millesimi', 8, 3); + $table->decimal('importo_calcolato', 10, 2); + $table->decimal('importo_rettificato', 10, 2)->nullable(); + $table->string('motivo_rettifica')->nullable(); + $table->text('note')->nullable(); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2025_07_08_151654_create_rate_table.php b/database/migrations/2025_07_08_151654_create_rate_table.php index fa0afe45..a00997bf 100644 --- a/database/migrations/2025_07_08_151654_create_rate_table.php +++ b/database/migrations/2025_07_08_151654_create_rate_table.php @@ -13,7 +13,22 @@ return new class extends Migration { Schema::create('rate', function (Blueprint $table) { $table->id(); + $table->string('codice_rata')->unique(); + $table->foreignId('piano_rateizzazione_id')->constrained('piano_rateizzazione')->cascadeOnDelete(); + $table->foreignId('ripartizione_spese_id')->constrained('ripartizione_spese')->cascadeOnDelete(); + $table->integer('numero_rata'); + $table->decimal('importo_rata', 10, 2); + $table->date('data_scadenza'); + $table->string('stato')->default('attiva'); // attiva, pagata, scaduta, annullata + $table->date('data_pagamento')->nullable(); + $table->decimal('importo_pagato', 10, 2)->nullable(); + $table->string('modalita_pagamento')->nullable(); + $table->string('riferimento_pagamento')->nullable(); + $table->text('note')->nullable(); + $table->foreignId('registrato_da')->nullable()->constrained('users'); + $table->timestamp('registrato_at')->nullable(); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2025_07_08_151838_create_piano_rateizzazione_table.php b/database/migrations/2025_07_08_151838_create_piano_rateizzazione_table.php index 5d566655..22dc33ca 100644 --- a/database/migrations/2025_07_08_151838_create_piano_rateizzazione_table.php +++ b/database/migrations/2025_07_08_151838_create_piano_rateizzazione_table.php @@ -13,7 +13,23 @@ return new class extends Migration { Schema::create('piano_rateizzazione', function (Blueprint $table) { $table->id(); + $table->string('codice_piano')->unique(); + $table->foreignId('ripartizione_spese_id')->constrained('ripartizione_spese')->cascadeOnDelete(); + $table->foreignId('stabile_id')->constrained('stabili')->cascadeOnDelete(); + $table->string('descrizione'); + $table->string('tipo_piano')->default('standard'); // standard, personalizzato + $table->decimal('importo_totale', 10, 2); + $table->integer('numero_rate'); + $table->date('data_prima_rata'); + $table->string('frequenza')->default('mensile'); // mensile, bimestrale, trimestrale, semestrale + $table->string('stato')->default('attivo'); // attivo, sospeso, completato, annullato + $table->json('configurazione_rate')->nullable(); + $table->text('note')->nullable(); + $table->foreignId('creato_da')->constrained('users'); + $table->timestamp('attivato_at')->nullable(); + $table->foreignId('attivato_da')->nullable()->constrained('users'); $table->timestamps(); + $table->softDeletes(); }); } diff --git a/database/migrations/2025_07_08_223534_drop_ripartizione_tables.php b/database/migrations/2025_07_08_223534_drop_ripartizione_tables.php new file mode 100644 index 00000000..c1d1a0c5 --- /dev/null +++ b/database/migrations/2025_07_08_223534_drop_ripartizione_tables.php @@ -0,0 +1,27 @@ + +
+
+
+
+

+ Modifica Voce di Spesa +

+ +
+ +
+
+ @csrf + @method('PUT') + +
+ +
+
+ + + @error('denominazione') +
{{ $message }}
+ @enderror +
+ +
+
+
+ + + @error('categoria') +
{{ $message }}
+ @enderror +
+
+
+
+ + + @error('sottocategoria') +
{{ $message }}
+ @enderror +
+
+
+ +
+ + + @error('descrizione') +
{{ $message }}
+ @enderror +
+
+ + +
+
+
+
+ + + @error('importo_previsto') +
{{ $message }}
+ @enderror +
+
+
+
+ + + @error('periodicita') +
{{ $message }}
+ @enderror +
+
+
+ +
+ + + @error('tabella_millesimale_default_id') +
{{ $message }}
+ @enderror +
+ +
+
+ ripartizione_personalizzata) ? 'checked' : '' }}> + +
+ + Consente di modificare manualmente la ripartizione per singola unità immobiliare + +
+ +
+ + + @error('stato') +
{{ $message }}
+ @enderror +
+
+
+ +
+
+
+ + + + Utilizzare per categorizzare e cercare più facilmente le voci di spesa + + @error('tags') +
{{ $message }}
+ @enderror +
+
+
+
+ + + @error('note') +
{{ $message }}
+ @enderror +
+
+
+ +
+ + Annulla + + +
+
+
+
+
+
+ +@endsection diff --git a/resources/views/admin/voci-spesa/show.blade.php b/resources/views/admin/voci-spesa/show.blade.php new file mode 100644 index 00000000..8c5d5c89 --- /dev/null +++ b/resources/views/admin/voci-spesa/show.blade.php @@ -0,0 +1,276 @@ +@extends('layouts.app') + +@section('title', 'Voce di Spesa - ' . $voceSpesa->denominazione) + +@section('content') +
+
+
+
+
+

+ {{ $voceSpesa->denominazione }} + + {{ ucfirst($voceSpesa->stato) }} + +

+
+ + Modifica + +
+ @csrf + +
+ + Torna all'elenco + +
+
+ +
+
+ +
+
+
+
+ Informazioni Base +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Codice:{{ $voceSpesa->codice_spesa }}
Stabile:{{ $voceSpesa->stabile->denominazione }}
Categoria: + {{ $voceSpesa->categoria }} + @if($voceSpesa->sottocategoria) +
{{ $voceSpesa->sottocategoria }} + @endif +
Importo Previsto: + @if($voceSpesa->importo_previsto) + € {{ number_format($voceSpesa->importo_previsto, 2, ',', '.') }} + @else + Non specificato + @endif +
Periodicità: + @if($voceSpesa->periodicita) + {{ ucfirst(str_replace('_', ' ', $voceSpesa->periodicita)) }} + @else + Non specificata + @endif +
Ripartizione Personalizzata: + @if($voceSpesa->ripartizione_personalizzata) + + @else + No + @endif +
+
+
+
+ + +
+
+
+
+ Configurazione Ripartizione +
+
+
+ + + + + + + + + + + + + +
Tabella Millesimale Default: + {{ $voceSpesa->tabellaMillesimaleDefault->denominazione }} +
{{ $voceSpesa->tabellaMillesimaleDefault->tipo_tabella }} +
Ripartizioni Create: + {{ $voceSpesa->ripartizioniSpese->count() }} + @if($voceSpesa->ripartizioniSpese->count() > 0) +
+ Ultima: {{ $voceSpesa->ripartizioniSpese->first()->created_at->format('d/m/Y') }} + + @endif +
Totale Ripartito: + @php + $totaleRipartito = $voceSpesa->ripartizioniSpese->sum('importo_totale'); + @endphp + @if($totaleRipartito > 0) + € {{ number_format($totaleRipartito, 2, ',', '.') }} + @else + € 0,00 + @endif +
+
+
+
+
+ + + @if($voceSpesa->descrizione || $voceSpesa->note || $voceSpesa->tags) +
+
+
+
+
+ Descrizione e Note +
+
+
+ @if($voceSpesa->descrizione) +
+ Descrizione: +

{{ $voceSpesa->descrizione }}

+
+ @endif + + @if($voceSpesa->tags) +
+ Tags: +
+ @foreach(explode(',', $voceSpesa->tags) as $tag) + {{ trim($tag) }} + @endforeach +
+
+ @endif + + @if($voceSpesa->note) +
+ Note: +

{{ $voceSpesa->note }}

+
+ @endif +
+
+
+
+ @endif + + + @if($voceSpesa->ripartizioniSpese->count() > 0) +
+
+
+
+
+ Ripartizioni Associate +
+ + Nuova Ripartizione + +
+
+
+ + + + + + + + + + + + + @foreach($voceSpesa->ripartizioniSpese as $ripartizione) + + + + + + + + + @endforeach + +
CodiceDescrizioneImportoDataStatoAzioni
{{ $ripartizione->codice_ripartizione }}{{ $ripartizione->descrizione }}€ {{ number_format($ripartizione->importo_totale, 2, ',', '.') }}{{ $ripartizione->data_ripartizione->format('d/m/Y') }} + + {{ ucfirst($ripartizione->stato) }} + + + + + +
+
+
+
+
+
+ @endif + + +
+
+
+
+
+ Informazioni Sistema +
+
+
+
+
+ + Creato: {{ $voceSpesa->created_at->format('d/m/Y H:i:s') }} + @if($voceSpesa->createdBy) + da {{ $voceSpesa->createdBy->name }} + @endif + +
+
+ + Ultimo aggiornamento: {{ $voceSpesa->updated_at->format('d/m/Y H:i:s') }} + @if($voceSpesa->updatedBy) + da {{ $voceSpesa->updatedBy->name }} + @endif + +
+
+
+
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/components/menu/sidebar.blade.php b/resources/views/components/menu/sidebar.blade.php index a888e2bb..9a2e29e3 100644 --- a/resources/views/components/menu/sidebar.blade.php +++ b/resources/views/components/menu/sidebar.blade.php @@ -26,6 +26,30 @@ 'route' => $panelPrefix . 'soggetti.index', 'roles' => ['admin', 'super-admin', 'amministratore', 'collaboratore'], ], + [ + 'icon' => 'fa-solid fa-receipt', + 'label' => 'Voci di Spesa', + 'route' => $panelPrefix . 'voci-spesa.index', + 'roles' => ['admin', 'super-admin', 'amministratore'], + ], + [ + 'icon' => 'fa-solid fa-chart-pie', + 'label' => 'Ripartizioni Spesa', + 'route' => $panelPrefix . 'ripartizioni-spesa.index', + 'roles' => ['admin', 'super-admin', 'amministratore'], + ], + [ + 'icon' => 'fa-solid fa-credit-card', + 'label' => 'Piani Rateizzazione', + 'route' => $panelPrefix . 'piani-rateizzazione.index', + 'roles' => ['admin', 'super-admin', 'amministratore'], + ], + [ + 'icon' => 'fa-solid fa-calendar-check', + 'label' => 'Rate', + 'route' => $panelPrefix . 'rate.index', + 'roles' => ['admin', 'super-admin', 'amministratore'], + ], [ 'icon' => 'fa-solid fa-file-invoice-dollar', 'label' => __('menu.contabilita'),