🚀 NETGESCON - Laravel completo integrato nel repository principale
This commit is contained in:
parent
0e87d5ec4c
commit
1c3cf4c0c9
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 2d6fba0e605ae7af4d3130cc6085f1540a03b111
|
||||
18
netgescon-laravel/.editorconfig
Normal file
18
netgescon-laravel/.editorconfig
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
||||
65
netgescon-laravel/.env.example
Normal file
65
netgescon-laravel/.env.example
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
# APP_MAINTENANCE_STORE=database
|
||||
|
||||
PHP_CLI_SERVER_WORKERS=4
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=mdb_archivio
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
# CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_SCHEME=null
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
11
netgescon-laravel/.gitattributes
vendored
Normal file
11
netgescon-laravel/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
||||
12
netgescon-laravel/.github/FUNDING.yml
vendored
Normal file
12
netgescon-laravel/.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Supporta NetGesCon
|
||||
|
||||
Se vuoi sostenere lo sviluppo di NetGesCon, puoi farlo tramite i seguenti canali:
|
||||
|
||||
- [PayPal](https://www.paypal.com/donate/?hosted_button_id=NPBKFSJCEVSLN)
|
||||
- [Patreon](https://patreon.com/netgescon)
|
||||
|
||||
Grazie per il tuo supporto!
|
||||
|
||||
paypal: NPBKFSJCEVSLN
|
||||
patreon: netgescon
|
||||
custom: ["https://www.paypal.com/donate/?hosted_button_id=NPBKFSJCEVSLN", "https://patreon.com/netgescon"]
|
||||
116
netgescon-laravel/.gitignore
vendored
Normal file
116
netgescon-laravel/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
*.log
|
||||
.DS_Store
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpactor.json
|
||||
.phpunit.result.cache
|
||||
/.fleet
|
||||
/.idea
|
||||
/.nova
|
||||
/.phpunit.cache
|
||||
/.vscode
|
||||
/.zed
|
||||
/auth.json
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/storage/app/public
|
||||
/storage/framework
|
||||
/storage/logs
|
||||
/venv
|
||||
/vendor
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
npm-debug.log
|
||||
Thumbs.db
|
||||
yarn-error.log
|
||||
|
||||
# NetGesCon specifici - File sensibili
|
||||
.env*
|
||||
!.env.example
|
||||
.env.seeder
|
||||
|
||||
# Dati amministratori e backup
|
||||
/storage/app/amministratori/*/
|
||||
/storage/app/backup/
|
||||
/storage/app/temp/
|
||||
|
||||
# Password e chiavi private
|
||||
*.key
|
||||
*.pem
|
||||
*.p12
|
||||
*.pfx
|
||||
*_rsa
|
||||
*_dsa
|
||||
*_ecdsa
|
||||
*_ed25519
|
||||
|
||||
# ============================================
|
||||
# DOCUMENTAZIONE INTERNA - NON PUBBLICA
|
||||
# ============================================
|
||||
|
||||
# File di lavoro interno - Da escludere fino a stabilizzazione
|
||||
PROGRESS_LOG.md
|
||||
DATABASE_SCHEMA.md
|
||||
DATA_ARCHITECTURE.md
|
||||
API_ENDPOINTS.md
|
||||
UI_COMPONENTS.md
|
||||
DEVELOPMENT_IDEAS.md
|
||||
|
||||
# Sistema aggiornamenti - In sviluppo
|
||||
UPDATE_SYSTEM.md
|
||||
DISTRIBUTION_SYSTEM.md
|
||||
|
||||
# NetGesCon - Documentazione interna (non per repository pubblico)
|
||||
/docs/specifiche/
|
||||
/docs/logs/
|
||||
/docs/checklist/
|
||||
|
||||
# File di workflow e comunicazione interna
|
||||
/docs/PROTOCOLLO_COMUNICAZIONE.md
|
||||
/docs/PROCEDURA_OPERATIVA.md
|
||||
/docs/QUICK_REFERENCE.md
|
||||
/docs/miki.md
|
||||
|
||||
# Mantieni solo guide pubbliche e README
|
||||
!/docs/README.md
|
||||
!/docs/guide/
|
||||
!/docs/guide/api-guide.md
|
||||
!/docs/guide/install-guide.md
|
||||
|
||||
# File di sviluppo temporanei
|
||||
TODO_*.md
|
||||
TEMP_*.md
|
||||
DRAFT_*.md
|
||||
|
||||
# Log di sviluppo personali
|
||||
*_LOG.txt
|
||||
*_NOTES.txt
|
||||
SESSION_*.md
|
||||
PROGRESS_*.md
|
||||
|
||||
# ============================================
|
||||
# DOCUMENTAZIONE PUBBLICA - DA INCLUDERE
|
||||
# ============================================
|
||||
|
||||
# Questi file SONO inclusi nel repository:
|
||||
# README.md
|
||||
# INSTALL_LINUX.md
|
||||
# CONTRIBUTING.md (se creato)
|
||||
# LICENSE (se creato)
|
||||
# CHANGELOG.md (quando sarà pronto)
|
||||
|
||||
# Backup e dump database
|
||||
*.sql
|
||||
*.dump
|
||||
*.backup
|
||||
|
||||
# File di sviluppo
|
||||
.phpunit.result.cache
|
||||
.pest.result.cache
|
||||
coverage/
|
||||
*.coverage
|
||||
|
||||
21
netgescon-laravel/.rsyncignore
Normal file
21
netgescon-laravel/.rsyncignore
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
.git/
|
||||
node_modules/
|
||||
vendor/
|
||||
venv/
|
||||
storage/logs/
|
||||
storage/framework/cache/
|
||||
storage/framework/sessions/
|
||||
storage/framework/views/
|
||||
bootstrap/cache/
|
||||
database/schema/
|
||||
.env
|
||||
.env.local
|
||||
.env.example
|
||||
*.log
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
146
netgescon-laravel/AmministratoreController.php
Normal file
146
netgescon-laravel/AmministratoreController.php
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\SuperAdmin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Amministratore;
|
||||
use App\Models\User;
|
||||
use Spatie\Permission\Models\Role; // Aggiunto per Role
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Auth; // Aggiunto per Auth
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Facades\Gate; // Aggiunto per Gate
|
||||
|
||||
class AmministratoreController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
// Proteggi le rotte con i permessi di Spatie
|
||||
$this->middleware('permission:view-amministratori', ['only' => ['index']]); // Permesso per visualizzare la lista
|
||||
$this->middleware('permission:manage-amministratori', ['except' => ['index', 'show']]); // Permesso per tutte le altre azioni CRUD
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
// Gate::authorize('view-amministratori'); // Il middleware nel costruttore è sufficiente
|
||||
$amministratori = Amministratore::with('user')->paginate(10);
|
||||
return view('superadmin.amministratori.index', compact('amministratori'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
// Gate::authorize('manage-amministratori'); // Il middleware nel costruttore è sufficiente
|
||||
$usersWithoutAdminRole = User::doesntHave('amministratore')->get(); // Utenti non ancora associati a un amministratore
|
||||
return view('superadmin.amministratori.create', compact('usersWithoutAdminRole'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// Gate::authorize('manage-amministratori'); // Il middleware nel costruttore è sufficiente
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|string|email|max:255|unique:users,email',
|
||||
'password' => 'required|string|min:8|confirmed',
|
||||
'nome' => 'required|string|max:255',
|
||||
'cognome' => 'required|string|max:255',
|
||||
'denominazione_studio' => 'nullable|string|max:255',
|
||||
'partita_iva' => 'nullable|string|max:20|unique:amministratori,partita_iva',
|
||||
'codice_fiscale_studio' => 'nullable|string|max:20',
|
||||
'indirizzo_studio' => 'nullable|string|max:255',
|
||||
'cap_studio' => 'nullable|string|max:10',
|
||||
'citta_studio' => 'nullable|string|max:60',
|
||||
'provincia_studio' => 'nullable|string|max:2',
|
||||
'telefono_studio' => 'nullable|string|max:20',
|
||||
'email_studio' => 'nullable|string|email|max:255',
|
||||
'pec_studio' => 'nullable|string|email|max:255',
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
$user->assignRole('admin'); // Assegna il ruolo 'admin' al nuovo utente per coerenza con le rotte
|
||||
|
||||
Amministratore::create([
|
||||
'user_id' => $user->id,
|
||||
'nome' => $request->nome,
|
||||
'cognome' => $request->cognome,
|
||||
'denominazione_studio' => $request->denominazione_studio,
|
||||
'partita_iva' => $request->partita_iva,
|
||||
'codice_fiscale_studio' => $request->codice_fiscale_studio,
|
||||
'indirizzo_studio' => $request->indirizzo_studio,
|
||||
'cap_studio' => $request->cap_studio,
|
||||
'citta_studio' => $request->citta_studio,
|
||||
'provincia_studio' => $request->provincia_studio,
|
||||
'telefono_studio' => $request->telefono_studio,
|
||||
'email_studio' => $request->email_studio,
|
||||
'pec_studio' => $request->pec_studio,
|
||||
]);
|
||||
|
||||
return redirect()->route('superadmin.amministratori.index')->with('success', 'Amministratore creato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Amministratore $amministratore) // Aggiunto metodo edit
|
||||
{
|
||||
// Gate::authorize('manage-amministratori'); // Il middleware nel costruttore è sufficiente
|
||||
// Recupera gli utenti che non sono ancora collegati a un record Amministratore
|
||||
$usersWithoutAdminRole = User::doesntHave('amministratore')->get();
|
||||
// Includi l'utente attualmente collegato a questo amministratore nella lista
|
||||
$usersWithoutAdminRole = $usersWithoutAdminRole->merge([$amministratore->user]);
|
||||
return view('superadmin.amministratori.edit', compact('amministratore', 'usersWithoutAdminRole'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Amministratore $amministratore)
|
||||
{
|
||||
// Gate::authorize('manage-amministratori'); // Il middleware nel costruttore è sufficiente
|
||||
$request->validate([
|
||||
'user_id' => 'required|exists:users,id|unique:amministratori,user_id,' . $amministratore->id_amministratore . ',id_amministratore',
|
||||
'nome' => 'required|string|max:255',
|
||||
'cognome' => 'required|string|max:255',
|
||||
'denominazione_studio' => 'nullable|string|max:255',
|
||||
'partita_iva' => ['nullable', 'string', 'max:20', Rule::unique('amministratori')->ignore($amministratore->id_amministratore, 'id_amministratore')], // Corretto id a id_amministratore
|
||||
'codice_fiscale_studio' => 'nullable|string|max:20',
|
||||
'indirizzo_studio' => 'nullable|string|max:255',
|
||||
'cap_studio' => 'nullable|string|max:10',
|
||||
'citta_studio' => 'nullable|string|max:255',
|
||||
'provincia_studio' => 'nullable|string|max:2',
|
||||
'telefono_studio' => 'nullable|string|max:20',
|
||||
'email_studio' => 'nullable|email|max:255',
|
||||
'pec_studio' => 'nullable|email|max:255',
|
||||
]);
|
||||
|
||||
// Aggiorna i dati dell'amministratore
|
||||
$amministratore->update($request->all());
|
||||
|
||||
return redirect()->route('superadmin.amministratori.index')->with('success', 'Amministratore aggiornato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Amministratore $amministratore)
|
||||
{
|
||||
// Gate::authorize('manage-amministratori'); // Il middleware nel costruttore è sufficiente
|
||||
$amministratore->user->delete(); // Elimina anche l'utente associato
|
||||
$amministratore->delete();
|
||||
return redirect()->route('superadmin.amministratori.index')->with('success', 'Amministratore eliminato con successo.');
|
||||
}
|
||||
}
|
||||
1
netgescon-laravel/Database/.gitignore
vendored
Normal file
1
netgescon-laravel/Database/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
*.sqlite*
|
||||
17
netgescon-laravel/Database/Seeders/AmministratoreSeeder.php
Normal file
17
netgescon-laravel/Database/Seeders/AmministratoreSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class AmministratoreSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
23
netgescon-laravel/Database/Seeders/DatabaseSeeder.php
Normal file
23
netgescon-laravel/Database/Seeders/DatabaseSeeder.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Chiama solo il seeder che abbiamo creato.
|
||||
$this->call([
|
||||
// SuperAdminSeeder::class, // Questo seeder è ora inglobato in TestSetupSeeder
|
||||
\App\Console\Seeders\TestSetupSeeder::class, // Chiama il seeder principale di setup
|
||||
ImpostazioniSeeder::class,
|
||||
\App\Console\Seeders\AllegatiSeeder::class, // Seeder per allegati con struttura moderna
|
||||
]);
|
||||
}
|
||||
}
|
||||
17
netgescon-laravel/Database/Seeders/DemoDataSeeder.php
Normal file
17
netgescon-laravel/Database/Seeders/DemoDataSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DemoDataSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
56
netgescon-laravel/Database/Seeders/ImpostazioniSeeder.php
Normal file
56
netgescon-laravel/Database/Seeders/ImpostazioniSeeder.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ImpostazioniSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
DB::table('impostazioni')->insertOrIgnore([
|
||||
[
|
||||
'chiave' => 'sidebar_bg',
|
||||
'valore' => '#fde047',
|
||||
'descrizione' => 'Colore di sfondo sidebar (giallo)',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_text',
|
||||
'valore' => '#1e293b',
|
||||
'descrizione' => 'Colore testo sidebar',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_accent',
|
||||
'valore' => '#6366f1',
|
||||
'descrizione' => 'Colore accento sidebar (indigo)',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_bg_dark',
|
||||
'valore' => '#23272e',
|
||||
'descrizione' => 'Colore sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_text_dark',
|
||||
'valore' => '#f1f5f9',
|
||||
'descrizione' => 'Colore testo sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_accent_dark',
|
||||
'valore' => '#fbbf24',
|
||||
'descrizione' => 'Colore accento sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
117
netgescon-laravel/Database/Seeders/MovimentiContabiliSeeder.php
Normal file
117
netgescon-laravel/Database/Seeders/MovimentiContabiliSeeder.php
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class MovimentiContabiliSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$stabili = \App\Models\Stabile::take(3)->get();
|
||||
$gestioni = \App\Models\Gestione::take(2)->get();
|
||||
$fornitori = \App\Models\Fornitore::take(5)->get();
|
||||
$users = \App\Models\User::take(2)->get();
|
||||
|
||||
if ($stabili->isEmpty() || $gestioni->isEmpty() || $users->isEmpty()) {
|
||||
$this->command->info('Skipping MovimentiContabiliSeeder: missing related data');
|
||||
return;
|
||||
}
|
||||
|
||||
$movimenti = [
|
||||
// Prima nota - da confermare
|
||||
[
|
||||
'stabile_id' => $stabili->first()->id_stabile,
|
||||
'gestione_id' => $gestioni->first()->id,
|
||||
'fornitore_id' => $fornitori->isNotEmpty() ? $fornitori->first()->id : null,
|
||||
'stato_movimento' => 'prima_nota',
|
||||
'data_registrazione' => now()->subDays(5),
|
||||
'descrizione' => 'Fattura ENEL - Energia elettrica parti comuni',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 450.00,
|
||||
'iva' => 45.00,
|
||||
'importo_netto' => 495.00,
|
||||
'numero_documento' => 'FAT-2024-001',
|
||||
'data_documento' => now()->subDays(7),
|
||||
'creato_da' => $users->first()->id,
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabili->first()->id_stabile,
|
||||
'gestione_id' => $gestioni->first()->id,
|
||||
'stato_movimento' => 'prima_nota',
|
||||
'data_registrazione' => now()->subDays(3),
|
||||
'descrizione' => 'Rate condominiali gennaio 2025',
|
||||
'tipo_movimento' => 'entrata',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 2500.00,
|
||||
'importo_netto' => 2500.00,
|
||||
'creato_da' => $users->first()->id,
|
||||
],
|
||||
// Movimenti confermati
|
||||
[
|
||||
'stabile_id' => $stabili->first()->id_stabile,
|
||||
'gestione_id' => $gestioni->first()->id,
|
||||
'fornitore_id' => $fornitori->count() > 1 ? $fornitori->skip(1)->first()->id : null,
|
||||
'stato_movimento' => 'confermato',
|
||||
'data_registrazione' => now()->subDays(10),
|
||||
'data_conferma' => now()->subDays(8),
|
||||
'confermato_da' => $users->count() > 1 ? $users->skip(1)->first()->id : $users->first()->id,
|
||||
'descrizione' => 'Pulizia scale - Ditta XYZ',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 300.00,
|
||||
'iva' => 30.00,
|
||||
'importo_netto' => 330.00,
|
||||
'numero_documento' => 'FAT-2024-002',
|
||||
'data_documento' => now()->subDays(12),
|
||||
'creato_da' => $users->first()->id,
|
||||
],
|
||||
// Movimento straordinario
|
||||
[
|
||||
'stabile_id' => $stabili->count() > 1 ? $stabili->skip(1)->first()->id_stabile : $stabili->first()->id_stabile,
|
||||
'gestione_id' => $gestioni->count() > 1 ? $gestioni->skip(1)->first()->id : $gestioni->first()->id,
|
||||
'stato_movimento' => 'confermato',
|
||||
'data_registrazione' => now()->subDays(15),
|
||||
'data_conferma' => now()->subDays(12),
|
||||
'confermato_da' => $users->first()->id,
|
||||
'descrizione' => 'Riparazione ascensore - Intervento urgente',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'straordinario',
|
||||
'importo_totale' => 1500.00,
|
||||
'iva' => 150.00,
|
||||
'importo_netto' => 1650.00,
|
||||
'numero_documento' => 'FAT-2024-003',
|
||||
'data_documento' => now()->subDays(16),
|
||||
'note_interne' => 'Intervento urgente per guasto improvviso',
|
||||
'creato_da' => $users->first()->id,
|
||||
],
|
||||
// Girofondi
|
||||
[
|
||||
'stabile_id' => $stabili->first()->id_stabile,
|
||||
'gestione_id' => $gestioni->first()->id,
|
||||
'stato_movimento' => 'confermato',
|
||||
'data_registrazione' => now()->subDays(20),
|
||||
'data_conferma' => now()->subDays(18),
|
||||
'confermato_da' => $users->first()->id,
|
||||
'descrizione' => 'Trasferimento da fondo ordinario a fondo straordinario',
|
||||
'tipo_movimento' => 'girofondi',
|
||||
'categoria_movimento' => 'fondo',
|
||||
'importo_totale' => 1000.00,
|
||||
'importo_netto' => 1000.00,
|
||||
'note_interne' => 'Delibera assembleare N.5/2024',
|
||||
'creato_da' => $users->first()->id,
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($movimenti as $movimento) {
|
||||
\App\Models\MovimentoContabile::create($movimento);
|
||||
}
|
||||
|
||||
$this->command->info('Creati ' . count($movimenti) . ' movimenti contabili di test');
|
||||
}
|
||||
}
|
||||
17
netgescon-laravel/Database/Seeders/NewTestSeeder.php
Normal file
17
netgescon-laravel/Database/Seeders/NewTestSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class NewTestSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
27
netgescon-laravel/Database/Seeders/SuperAdminSeeder.php
Normal file
27
netgescon-laravel/Database/Seeders/SuperAdminSeeder.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class SuperAdminSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Cerca se l'utente esiste già per evitare duplicati
|
||||
if (!User::where('email', 'superadmin@example.com')->exists()) {
|
||||
User::create([
|
||||
'name' => 'Super Admin',
|
||||
'email' => 'superadmin@example.com',
|
||||
'password' => Hash::make('password'), // Cambiare in produzione!
|
||||
'role' => 'super-admin',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
netgescon-laravel/Database/Seeders/SuperAdminSeederOLD.php
Normal file
27
netgescon-laravel/Database/Seeders/SuperAdminSeederOLD.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class SuperAdminSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Cerca se l'utente esiste già per evitare duplicati
|
||||
if (!User::where('email', 'superadmin@example.com')->exists()) {
|
||||
User::create([
|
||||
'name' => 'Super Admin',
|
||||
'email' => 'superadmin@example.com',
|
||||
'password' => Hash::make('password'), // Cambiare in produzione!
|
||||
'role' => 'super-admin',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
netgescon-laravel/Database/Seeders/TestSeeder.php
Normal file
17
netgescon-laravel/Database/Seeders/TestSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TestSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
netgescon-laravel/Database/Seeders/TestSeeder2.php
Normal file
17
netgescon-laravel/Database/Seeders/TestSeeder2.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TestSeeder2 extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
372
netgescon-laravel/Database/Seeders/TestSetupSeeder.php
Normal file
372
netgescon-laravel/Database/Seeders/TestSetupSeeder.php
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\User;
|
||||
use App\Models\Amministratore;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\Soggetto;
|
||||
use App\Models\Proprieta;
|
||||
use App\Models\TabellaMillesimale;
|
||||
use App\Models\DettaglioTabellaMillesimale;
|
||||
use App\Models\PianoContiCondominio;
|
||||
use App\Models\Gestione;
|
||||
use App\Models\Preventivo;
|
||||
use App\Models\VocePreventivo;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
// Assicurati di avere i modelli e le migrazioni corretti prima di eseguire questo seeder.
|
||||
// Questo seeder crea un ambiente di test con un utente Super Admin, un Amministratore, un Condominio e alcune Unità Immobiliari con Soggetti associati.
|
||||
// Assicurati di eseguire questo seeder con il comando `php artisan db:seed --class=TestSetupSeeder` per popolare il database con i dati di test.
|
||||
// Puoi modificare le email e le password per adattarle alle tue esigenze di test.
|
||||
// Assicurati di avere i modelli e le migrazioni corretti prima di eseguire questo seeder.
|
||||
// Questo seeder è utile per testare le funzionalità del tuo gestionale senza dover inserire manualmente i dati ogni volta.
|
||||
// Puoi anche estendere questo seeder per aggiungere ulteriori dati di test come spese, entrate, verbali, ecc.
|
||||
// Assicurati di avere le relazioni corrette nei modelli Soggetto, UnitaImmobiliare e SoggettoUnita per gestire le associazioni tra soggetti e unità immobiliari.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
|
||||
|
||||
class TestSetupSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Pulisce la cache dei permessi
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
// 1. Crea i ruoli
|
||||
// Usa Spatie\Permission\Models\Role per assegnare i ruoli
|
||||
$superAdminRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'super-admin', 'guard_name' => 'web']);
|
||||
// Ruoli in italiano per la gestione condominiale
|
||||
$amministratoreRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']);
|
||||
$collaboratoreRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'collaboratore', 'guard_name' => 'web']);
|
||||
$condominoRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'condomino', 'guard_name' => 'web']);
|
||||
$fornitoreRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'fornitore', 'guard_name' => 'web']);
|
||||
$inquilinoRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'inquilino', 'guard_name' => 'web']);
|
||||
$ospiteRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'ospite', 'guard_name' => 'web']);
|
||||
$serviziRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'servizi', 'guard_name' => 'web']);
|
||||
$this->command->info('Ruoli creati/verificati.');
|
||||
|
||||
// Ruoli di base per sviluppo (rimosso uso di App\Models\Role e campo label)
|
||||
// Tutti i ruoli sono ora gestiti solo tramite Spatie\Permission\Models\Role
|
||||
|
||||
|
||||
// 2. Crea l'utente Super Admin
|
||||
// Rimosso il campo 'role' diretto, verrà assegnato tramite Spatie
|
||||
|
||||
$superAdmin = User::firstOrCreate(
|
||||
['email' => 'superadmin@example.com'],
|
||||
[
|
||||
'name' => 'Super Admin',
|
||||
'password' => Hash::make('password'), // Cambia questa password in produzione!
|
||||
'email_verified_at' => now(),
|
||||
|
||||
]
|
||||
);
|
||||
// Il ruolo 'super-admin' verrà assegnato tramite Spatie
|
||||
$this->command->info('Utente Super Admin creato/aggiornato: ' . $superAdmin->email); // Variabile corretta
|
||||
|
||||
// 2. Crea un Utente Amministratore
|
||||
$adminUser = User::firstOrCreate(
|
||||
['email' => 'admin@example.com'],
|
||||
[
|
||||
'name' => 'Amministratore Test',
|
||||
'password' => Hash::make('password'), // Cambia questa password in produzione!
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
// Il ruolo 'admin' verrà assegnato tramite Spatie
|
||||
$this->command->info('Utente Amministratore creato/aggiornato: ' . $adminUser->email);
|
||||
|
||||
// 3. Crea un Record Amministratore (collegato all'utente admin)
|
||||
$amministratore = Amministratore::firstOrCreate(
|
||||
['user_id' => $adminUser->id],
|
||||
[
|
||||
'nome' => 'Mario',
|
||||
'cognome' => 'Rossi',
|
||||
'denominazione_studio' => 'Studio Rossi Amministrazioni',
|
||||
'partita_iva' => '12345678901',
|
||||
'codice_fiscale_studio' => 'RSSMRA80A01H501K',
|
||||
'indirizzo_studio' => 'Via Roma 10',
|
||||
'cap_studio' => '00100',
|
||||
'citta_studio' => 'Roma',
|
||||
'provincia_studio' => 'RM',
|
||||
'telefono_studio' => '061234567',
|
||||
'email_studio' => 'studio.rossi@example.com',
|
||||
'pec_studio' => 'studio.rossi@pec.it',
|
||||
]
|
||||
);
|
||||
$this->command->info('Record Amministratore creato/aggiornato: ' . $amministratore->nome . ' ' . $amministratore->cognome);
|
||||
|
||||
// 4. Crea un Condominio di Test
|
||||
$stabile = Stabile::firstOrCreate(
|
||||
['denominazione' => 'Stabile Test Via Milano 1'],
|
||||
[
|
||||
'amministratore_id' => $amministratore->id, // Usa 'id' invece di 'id_amministratore'
|
||||
'indirizzo' => 'Via Milano 1',
|
||||
'cap' => '20100',
|
||||
'citta' => 'Milano',
|
||||
'provincia' => 'MI',
|
||||
'codice_fiscale' => 'CNDMLN00001A001A',
|
||||
'note' => 'Condominio di test per lo sviluppo.',
|
||||
'stato' => 'attivo',
|
||||
]
|
||||
);
|
||||
$this->command->info('Stabile di Test creato/aggiornato: ' . $stabile->denominazione);
|
||||
|
||||
// 5. Crea Unità Immobiliari di Test
|
||||
$unita1 = UnitaImmobiliare::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'interno' => '1', 'scala' => 'A', 'fabbricato' => 'Principale'],
|
||||
|
||||
|
||||
[
|
||||
'piano' => '1',
|
||||
'subalterno' => '1',
|
||||
'categoria_catastale' => 'A/3',
|
||||
'superficie' => 80.50,
|
||||
'vani' => 4.5,
|
||||
'indirizzo' => null,
|
||||
'note' => 'Appartamento di test A1',
|
||||
]
|
||||
);
|
||||
$unita2 = UnitaImmobiliare::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'interno' => '2', 'scala' => 'A', 'fabbricato' => 'Principale'],
|
||||
[
|
||||
'piano' => '1',
|
||||
'subalterno' => '2',
|
||||
'categoria_catastale' => 'A/3',
|
||||
'superficie' => 70.00,
|
||||
'vani' => 3.5,
|
||||
'indirizzo' => null,
|
||||
'note' => 'Appartamento di test A2',
|
||||
]
|
||||
);
|
||||
$this->command->info('Unità Immobiliari di Test create.');
|
||||
|
||||
// 6. Crea Soggetti di Test
|
||||
$soggettoProprietario1 = Soggetto::firstOrCreate(['email' => 'proprietario1@example.com'], ['nome' => 'Giuseppe', 'cognome' => 'Verdi', 'tipo' => 'proprietario', 'codice_fiscale' => 'VRDGPP80A01H501A']);
|
||||
$soggettoProprietario2 = Soggetto::firstOrCreate(['email' => 'proprietario2@example.com'], ['nome' => 'Maria', 'cognome' => 'Bianchi', 'tipo' => 'proprietario', 'codice_fiscale' => 'BNCMRA85B02H502B']);
|
||||
$soggettoInquilino = Soggetto::firstOrCreate(['email' => 'inquilino@example.com'], ['nome' => 'Luca', 'cognome' => 'Neri', 'tipo' => 'inquilino', 'codice_fiscale' => 'NRELCA90C03H503C']);
|
||||
$this->command->info('Soggetti di Test creati.');
|
||||
|
||||
// 7. Collega Soggetti alle Unità (Proprieta)
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoProprietario1->id ?? $soggettoProprietario1->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita1->id ?? $unita1->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'proprietario',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2020-01-01'
|
||||
]);
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoProprietario1->id ?? $soggettoProprietario1->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita2->id ?? $unita2->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'nudo_proprietario',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2022-03-01'
|
||||
]);
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoProprietario2->id ?? $soggettoProprietario2->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita2->id ?? $unita2->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'usufruttuario',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2022-03-01'
|
||||
]);
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoInquilino->id ?? $soggettoInquilino->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita1->id ?? $unita1->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'inquilino',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2023-06-15'
|
||||
]);
|
||||
$this->command->info('Relazioni Soggetto-Unità create.');
|
||||
|
||||
// 8. Crea una Tabella Millesimale di Test
|
||||
$tabellaA = TabellaMillesimale::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'nome_tabella_millesimale' => 'Tabella A - Proprietà'],
|
||||
['descrizione' => 'Ripartizione spese in base ai millesimi di proprietà generale.']
|
||||
);
|
||||
// Fix: recupera la chiave primaria corretta se non presente
|
||||
if (!$tabellaA->id) {
|
||||
// Prova a ricaricare dal DB se firstOrCreate restituisce un oggetto senza la chiave primaria
|
||||
$tabellaA = TabellaMillesimale::where('stabile_id', $stabile->id)
|
||||
->where('nome_tabella_millesimale', 'Tabella A - Proprietà')
|
||||
->first();
|
||||
}
|
||||
if (!$tabellaA || !$tabellaA->id) {
|
||||
$this->command->error('Errore: la tabella millesimale non è stata creata correttamente!');
|
||||
return;
|
||||
}
|
||||
$this->command->info('Tabella Millesimale di Test creata.');
|
||||
|
||||
// 9. Crea Dettagli Millesimali per le unità
|
||||
DettaglioTabellaMillesimale::firstOrCreate(
|
||||
['tabella_millesimale_id' => $tabellaA->id, 'unita_immobiliare_id' => $unita1->id ?? $unita1->id_unita],
|
||||
['millesimi' => 500.0000]
|
||||
);
|
||||
DettaglioTabellaMillesimale::firstOrCreate(
|
||||
['tabella_millesimale_id' => $tabellaA->id, 'unita_immobiliare_id' => $unita2->id ?? $unita2->id_unita],
|
||||
['millesimi' => 500.0000]
|
||||
);
|
||||
$this->command->info('Dettagli Millesimali creati.');
|
||||
|
||||
/*// 10. Crea una Gestione di Test
|
||||
$gestione2024 = Gestione::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'anno' => 2024, 'tipo' => 'ORDINARIA'],
|
||||
['data_inizio' => '2024-01-01', 'data_fine' => '2024-12-31', 'stato' => 'aperta']
|
||||
);
|
||||
$this->command->info('Gestione di Test creata.');*/
|
||||
|
||||
// 11. Crea un Piano dei Conti per lo Stabile (esempio base)
|
||||
$contoPulizie = PianoContiCondominio::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'codice' => 'SP.PUL'],
|
||||
['descrizione' => 'Spese di Pulizia Scale', 'tipo_conto' => 'ECONOMICO_COSTO']
|
||||
);
|
||||
$contoAssicurazione = PianoContiCondominio::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'codice' => 'SP.ASS'],
|
||||
['descrizione' => 'Assicurazione Fabbricato', 'tipo_conto' => 'ECONOMICO_COSTO']
|
||||
);
|
||||
$this->command->info('Piano dei Conti di Test creato.');
|
||||
|
||||
/*// 12. Crea un Preventivo di Test
|
||||
$preventivo2024 = Preventivo::firstOrCreate(
|
||||
['id_gestione' => $gestione2024->id_gestione],
|
||||
['descrizione' => 'Preventivo Ordinario 2024', 'stato' => 'APPROVATO']
|
||||
);
|
||||
$this->command->info('Preventivo di Test creato.');
|
||||
|
||||
// 13. Crea Voci di Preventivo
|
||||
VocePreventivo::firstOrCreate(['id_preventivo' => $preventivo2024->id_preventivo, 'id_piano_conto_condominio_pc' => $contoPulizie->id_conto_condominio_pc], ['importo_previsto' => 1200.00, 'id_tabella_millesimale_ripartizione' => $tabellaA->id_tabella_millesimale]);
|
||||
VocePreventivo::firstOrCreate(['id_preventivo' => $preventivo2024->id_preventivo, 'id_piano_conto_condominio_pc' => $contoAssicurazione->id_conto_condominio_pc], ['importo_previsto' => 800.00, 'id_tabella_millesimale_ripartizione' => $tabellaA->id_tabella_millesimale]);
|
||||
$this->command->info('Voci di Preventivo create.'); */
|
||||
|
||||
// Creazione Permessi (Esempio)
|
||||
$gestioneCondominiPermission = Permission::firstOrCreate(['name' => 'gestione-condomini']);
|
||||
$visualizzaReportPermission = Permission::firstOrCreate(['name' => 'visualizza-report']);
|
||||
|
||||
Permission::firstOrCreate(['name' => 'view-stabili']);
|
||||
Permission::firstOrCreate(['name' => 'manage-stabili']); // Permesso generico per le azioni CRUD
|
||||
|
||||
|
||||
// Permessi per la gestione utenti (Super Admin)
|
||||
Permission::firstOrCreate(['name' => 'create-users']);
|
||||
Permission::firstOrCreate(['name' => 'view-users']);
|
||||
Permission::firstOrCreate(['name' => 'manage-users']); // Include create, edit, delete, update role
|
||||
Permission::firstOrCreate(['name' => 'impersonate-users']);
|
||||
|
||||
// Permessi per la gestione amministratori (Super Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-amministratori']);
|
||||
Permission::firstOrCreate(['name' => 'manage-amministratori']); // Include create, edit, delete
|
||||
|
||||
// Permessi per la gestione categorie ticket (Super Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-categorie-ticket']);
|
||||
Permission::firstOrCreate(['name' => 'manage-categorie-ticket']); // Include create, edit, delete
|
||||
|
||||
// Permessi per la gestione soggetti (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-soggetti']);
|
||||
Permission::firstOrCreate(['name' => 'manage-soggetti']); // Include create, edit, delete
|
||||
|
||||
// Permessi per la gestione fornitori (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-fornitori']);
|
||||
Permission::firstOrCreate(['name' => 'manage-fornitori']);
|
||||
|
||||
// Permessi per la gestione ticket (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-tickets']);
|
||||
Permission::firstOrCreate(['name' => 'manage-tickets']);
|
||||
|
||||
// Permessi per la gestione unità immobiliari (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-unita-immobiliari']);
|
||||
Permission::firstOrCreate(['name' => 'manage-unita-immobiliari']);
|
||||
|
||||
// Permessi per le impostazioni e API Tokens (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-impostazioni']);
|
||||
Permission::firstOrCreate(['name' => 'manage-api-tokens']);
|
||||
Permission::firstOrCreate(['name' => 'view-rubrica']);
|
||||
|
||||
|
||||
// Aggiungi qui altri permessi specifici per il tuo progetto
|
||||
|
||||
|
||||
// Assegnazione Permessi ai Ruoli (Esempio)
|
||||
$amministratoreRole = \Spatie\Permission\Models\Role::where('name', 'amministratore')->first();
|
||||
$adminRole = \Spatie\Permission\Models\Role::where('name', 'admin')->first();
|
||||
$superAdminRole = \Spatie\Permission\Models\Role::where('name', 'super-admin')->first();
|
||||
|
||||
$amministratoreRole = \Spatie\Permission\Models\Role::where('name', 'amministratore')->first();
|
||||
if ($amministratoreRole) {
|
||||
$amministratoreRole->givePermissionTo([
|
||||
'visualizza-report',
|
||||
'view-stabili', 'manage-stabili',
|
||||
'view-soggetti', 'manage-soggetti',
|
||||
'view-fornitori', 'manage-fornitori',
|
||||
'view-tickets', 'manage-tickets',
|
||||
'view-unita-immobiliari', 'manage-unita-immobiliari',
|
||||
'view-impostazioni', 'manage-api-tokens', 'view-rubrica',
|
||||
]);
|
||||
} else {
|
||||
$this->command->warn("Ruolo 'amministratore' non trovato: permessi non assegnati.");
|
||||
}
|
||||
|
||||
|
||||
// Assegna i permessi al ruolo 'admin'
|
||||
$adminRole->givePermissionTo([
|
||||
'view-soggetti', 'manage-soggetti',
|
||||
'view-fornitori', 'manage-fornitori',
|
||||
'view-tickets', 'manage-tickets',
|
||||
'view-unita-immobiliari', 'manage-unita-immobiliari',
|
||||
'view-impostazioni', 'manage-api-tokens', 'view-rubrica',
|
||||
]);
|
||||
|
||||
|
||||
// Assegna il ruolo 'amministratore' all'utente di test per permettergli di gestire gli stabili
|
||||
if ($amministratoreRole) {
|
||||
$adminUser->assignRole('amministratore');
|
||||
} else {
|
||||
$this->command->warn("Ruolo 'amministratore' non trovato: non assegnato all'utente di test.");
|
||||
}
|
||||
|
||||
|
||||
// Assegna tutti i permessi al Super Admin
|
||||
$superAdminRole->givePermissionTo(Permission::all());
|
||||
$superAdmin->assignRole('super-admin');
|
||||
|
||||
$this->command->info('Setup di test completato con successo!');
|
||||
}
|
||||
}
|
||||
// Questo seeder crea un ambiente di test con un utente Super Admin, un Amministratore, un Condominio e alcune Unità Immobiliari con Soggetti associati.
|
||||
// Assicurati di eseguire questo seeder con il comando `php artisan db:seed --class=TestSetupSeeder` per popolare il database con i dati di test.
|
||||
// Puoi modificare le email e le password per adattarle alle tue esigenze di test.
|
||||
// Assicurati di avere i modelli e le migrazioni corretti prima di eseguire questo seeder.
|
||||
// Questo seeder è utile per testare le funzionalità del tuo gestionale senza dover inserire manualmente i dati ogni volta.
|
||||
// Puoi anche estendere questo seeder per aggiungere ulteriori dati di test come spese, entrate, verbali, ecc.
|
||||
// Assicurati di avere le relazioni corrette nei modelli Soggetto, UnitaImmobiliare e SoggettoUnita per gestire le associazioni tra soggetti e unità immobiliari.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Assicurati di eseguire il seeder in un ambiente di sviluppo o test, non in produzione, per evitare conflitti con i dati reali.
|
||||
// Ricorda di aggiornare le password e le email in produzione per garantire la sicurezza del tuo gestionale.
|
||||
// Questo seeder è progettato per essere eseguito una sola volta per impostare un ambiente di test iniziale.
|
||||
// Puoi eseguire nuovamente il seeder per ripristinare lo stato di test, ma fai attenzione a non duplicare i dati esistenti.
|
||||
// Se hai bisogno di modificare i dati di test, puoi farlo direttamente nel seeder o creare nuovi seeders per aggiungere ulteriori dati.
|
||||
// Assicurati di avere le dipendenze corrette nel tuo progetto Laravel per eseguire questo seeder senza errori.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Assicurati di eseguire il seeder in un ambiente di sviluppo o test, non in produzione, per evitare conflitti con i dati reali.
|
||||
// Ricorda di aggiornare le password e le email in produzione per garantire la sicurezza del tuo gestionale.
|
||||
// Questo seeder è progettato per essere eseguito una sola volta per impostare un ambiente di test iniziale.
|
||||
// Puoi eseguire nuovamente il seeder per ripristinare lo stato di test, ma fai attenzione a non duplicare i dati esistenti.
|
||||
// Se hai bisogno di modificare i dati di test, puoi farlo direttamente nel seeder o creare nuovi seeders per aggiungere ulteriori dati.
|
||||
// Assicurati di avere le dipendenze corrette nel tuo progetto Laravel per eseguire questo seeder senza errori.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
17
netgescon-laravel/Database/Seeders/UserRoleSeeder.php
Normal file
17
netgescon-laravel/Database/Seeders/UserRoleSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class UserRoleSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
16
netgescon-laravel/Database/Seeders/testseed.php
Normal file
16
netgescon-laravel/Database/Seeders/testseed.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\CondominioController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
Unchanged linesRoute::get('/', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
// Aggiungi qui altre rotte protette
|
||||
Route::resource('condomini', CondominioController::class);
|
||||
});
|
||||
|
||||
44
netgescon-laravel/Database/factories/UserFactory.php
Normal file
44
netgescon-laravel/Database/factories/UserFactory.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->longText('payload');
|
||||
$table->integer('last_activity')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->longText('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'stabili' è ora gestita dalla migration unificata delle anagrafiche.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'proprieta' e le relative FK sono ora gestite dalla migration unificata delle anagrafiche o da una migration master dedicata.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione delle tabelle di contabilità e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'richieste_modifiche' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'preventivi' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'bilanci' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'assemblee' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->string('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'fornitori' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'conti_condominio' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'tabelle_millesimali' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'dettagli_tabelle_millesimali' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'gestioni' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('voci_spesa')) {
|
||||
Schema::create('voci_spesa', function (Blueprint $table) {
|
||||
$table->bigIncrements('id_voce');
|
||||
$table->string('codice')->nullable()->unique();
|
||||
$table->string('descrizione');
|
||||
$table->string('tipo', 50)->nullable()->comment('ordinaria/straordinaria/riscaldamento/altro');
|
||||
$table->text('note')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('voci_spesa');
|
||||
}
|
||||
};
|
||||
// Questo file crea la tabella 'voci_spesa' per gestire le voci di spesa nel gestionale.
|
||||
// La tabella include:
|
||||
// - id_voce: ID univoco della voce di spesa
|
||||
// - codice: Codice univoco della voce di spesa
|
||||
// - descrizione: Descrizione della voce di spesa
|
||||
// - tipo: Tipo di spesa (ordinaria, straordinaria, riscaldamento, altro)
|
||||
// - note: Note aggiuntive sulla voce di spesa
|
||||
// - timestamps: Campi created_at e updated_at per la gestione delle date
|
||||
//
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('piani_conti_modello', function (Blueprint $table) {
|
||||
$table->bigIncrements('id'); // PK uniformata
|
||||
$table->string('codice', 20)->unique();
|
||||
$table->string('descrizione');
|
||||
$table->string('tipo_conto', 50)->comment('Es. PATRIMONIALE_ATTIVITA, ECONOMICO_COSTO, FINANZIARIO_ATTIVITA');
|
||||
$table->string('natura_saldo_tipico', 5)->nullable()->comment('DARE o AVERE');
|
||||
$table->boolean('is_conto_finanziario')->default(false);
|
||||
$table->text('note')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('piani_conti_modello');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
// Migration svuotata: la creazione della tabella 'piano_conti_condominio' e le relative FK sono ora gestite dalla migration unificata/master.
|
||||
// Questo file può essere cancellato dopo la bonifica.
|
||||
|
||||
return new class extends Illuminate\Database\Migrations\Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella transazioni_contabili è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella righe_movimenti_contabili è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Questa migration è stata svuotata perché la tabella 'preventivi' viene gestita da una migration successiva più completa.
|
||||
* Non eseguire alcuna operazione qui per evitare errori di tabella già esistente.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Tabella 'preventivi' già gestita da una migration successiva.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna operazione di rollback necessaria.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella contratti_locazione_attiva è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella scadenze_locazione è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('audit_logs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id_audit_log');
|
||||
$table->unsignedBigInteger('id_utente')->nullable(); // Utente che ha effettuato la modifica
|
||||
$table->string('nome_tabella', 100);
|
||||
$table->unsignedBigInteger('id_record_modificato'); // ID del record modificato
|
||||
$table->string('azione', 50); // INSERT, UPDATE, DELETE
|
||||
$table->jsonb('valori_precedenti')->nullable(); // Stato prima della modifica
|
||||
$table->jsonb('valori_nuovi')->nullable(); // Stato dopo la modifica
|
||||
$table->text('note')->nullable();
|
||||
$table->timestamps(); // created_at sarà la data_modifica
|
||||
// Potresti aggiungere una foreign key per id_utente
|
||||
// $table->foreign('id_utente')->references('id')->on('users')->onDelete('set null');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('audit_logs');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Migration patch svuotata: i campi protocollo sono ora gestiti nella migration master/unificata.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$teams = config('permission.teams');
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
|
||||
throw_if(empty($tableNames), new Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.'));
|
||||
throw_if($teams && empty($columnNames['team_foreign_key'] ?? null), new Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.'));
|
||||
|
||||
Schema::create($tableNames['permissions'], static function (Blueprint $table) {
|
||||
// $table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // permission id
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) {
|
||||
// $table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
// Popola ruoli di base
|
||||
DB::table('roles')->insertOrIgnore([
|
||||
['name' => 'super-admin', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'admin', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'collaboratore', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'condomino', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'fornitore', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'inquilino', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'ospite', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'servizi', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
]);
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
}
|
||||
|
||||
Schema::drop($tableNames['role_has_permissions']);
|
||||
Schema::drop($tableNames['model_has_roles']);
|
||||
Schema::drop($tableNames['model_has_permissions']);
|
||||
Schema::drop($tableNames['roles']);
|
||||
Schema::drop($tableNames['permissions']);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Migration patch svuotata: la tabella gestioni e i nuovi campi sono ora gestiti nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella richieste_modifiche è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella preventivi è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella bilanci è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: la tabella assemblee è ora gestita nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Migration legacy svuotata: le tabelle di rateizzazione sono ora gestite nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: le tabelle sono gestite dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Crea la tabella rate_emesse con tutte le foreign key.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('rate_emesse')) {
|
||||
Schema::create('rate_emesse', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('piano_rateizzazione_id');
|
||||
$table->unsignedBigInteger('unita_immobiliare_id');
|
||||
$table->unsignedBigInteger('soggetto_responsabile_id');
|
||||
$table->integer('numero_rata_progressivo');
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->decimal('importo_originario_unita', 15, 2);
|
||||
$table->decimal('percentuale_addebito_soggetto', 7, 4)->default(100.0000);
|
||||
$table->decimal('importo_addebitato_soggetto', 15, 2);
|
||||
$table->date('data_emissione');
|
||||
$table->date('data_scadenza');
|
||||
$table->string('stato_rata', 50)->default('EMESSA');
|
||||
$table->date('data_ultimo_pagamento')->nullable();
|
||||
$table->decimal('importo_pagato', 15, 2)->default(0.00);
|
||||
$table->text('note')->nullable();
|
||||
$table->unsignedBigInteger('transazione_contabile_emissione_id')->nullable();
|
||||
$table->unique(['piano_rateizzazione_id', 'unita_immobiliare_id', 'soggetto_responsabile_id', 'numero_rata_progressivo'], 'unique_rata_per_soggetto_unita');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
// Foreign key su piani_rateizzazione
|
||||
if (Schema::hasTable('rate_emesse') && Schema::hasTable('piani_rateizzazione')) {
|
||||
$fkExists = \Illuminate\Support\Facades\DB::select("SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'rate_emesse' AND COLUMN_NAME = 'piano_rateizzazione_id' AND CONSTRAINT_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL");
|
||||
if (empty($fkExists)) {
|
||||
Schema::table('rate_emesse', function (Blueprint $table) {
|
||||
$table->foreign('piano_rateizzazione_id')
|
||||
->references('id_piano_rateizzazione')
|
||||
->on('piani_rateizzazione')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
}
|
||||
// Foreign key su unita_immobiliari
|
||||
if (Schema::hasTable('rate_emesse') && Schema::hasTable('unita_immobiliari')) {
|
||||
$fkExists = \Illuminate\Support\Facades\DB::select("SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'rate_emesse' AND COLUMN_NAME = 'unita_immobiliare_id' AND CONSTRAINT_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL");
|
||||
if (empty($fkExists)) {
|
||||
Schema::table('rate_emesse', function (Blueprint $table) {
|
||||
$table->foreign('unita_immobiliare_id')
|
||||
->references('id_unita')
|
||||
->on('unita_immobiliari')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
}
|
||||
// Foreign key su soggetti
|
||||
if (Schema::hasTable('rate_emesse') && Schema::hasTable('soggetti')) {
|
||||
$fkExists = \Illuminate\Support\Facades\DB::select("SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'rate_emesse' AND COLUMN_NAME = 'soggetto_responsabile_id' AND CONSTRAINT_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL");
|
||||
if (empty($fkExists)) {
|
||||
Schema::table('rate_emesse', function (Blueprint $table) {
|
||||
$table->foreign('soggetto_responsabile_id')
|
||||
->references('id_soggetto')
|
||||
->on('soggetti')
|
||||
->onDelete('restrict');
|
||||
});
|
||||
}
|
||||
}
|
||||
// Foreign key su transazioni_contabili
|
||||
if (Schema::hasTable('rate_emesse') && Schema::hasTable('transazioni_contabili')) {
|
||||
$fkExists = \Illuminate\Support\Facades\DB::select("SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'rate_emesse' AND COLUMN_NAME = 'transazione_contabile_emissione_id' AND CONSTRAINT_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL");
|
||||
if (empty($fkExists)) {
|
||||
Schema::table('rate_emesse', function (Blueprint $table) {
|
||||
$table->foreign('transazione_contabile_emissione_id')
|
||||
->references('id_transazione')
|
||||
->on('transazioni_contabili')
|
||||
->onDelete('set null');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('rate_emesse');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Migration patch svuotata: la tabella rate_emesse e le FK sono ora gestite nella migration master/unificata.
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Nessuna azione: la tabella viene gestita dalla migration master.
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Crea tutte le tabelle anagrafiche principali e le relative foreign key.
|
||||
* Ordine di creazione: amministratori -> fornitori -> soggetti -> stabili -> unita_immobiliari
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// --- Amministratori ---
|
||||
Schema::create('amministratori', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nome');
|
||||
$table->string('cognome');
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->string('denominazione_studio')->nullable();
|
||||
$table->string('partita_iva')->nullable()->unique();
|
||||
$table->string('codice_fiscale_studio')->nullable();
|
||||
$table->string('indirizzo_studio')->nullable();
|
||||
$table->string('cap_studio', 10)->nullable();
|
||||
$table->string('citta_studio', 60)->nullable();
|
||||
$table->string('provincia_studio', 2)->nullable();
|
||||
$table->string('telefono_studio')->nullable();
|
||||
$table->string('email_studio')->nullable();
|
||||
$table->string('pec_studio')->nullable();
|
||||
$table->string('codice_univoco', 8)->unique();
|
||||
$table->timestamps();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// --- Fornitori ---
|
||||
Schema::create('fornitori', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('old_id')->nullable()->unique()->comment('ID dal vecchio gestionale');
|
||||
$table->unsignedBigInteger('amministratore_id');
|
||||
$table->string('ragione_sociale');
|
||||
$table->string('partita_iva', 20)->nullable();
|
||||
$table->string('codice_fiscale', 20)->nullable();
|
||||
$table->string('indirizzo')->nullable();
|
||||
$table->string('cap', 10)->nullable();
|
||||
$table->string('citta', 60)->nullable();
|
||||
$table->string('provincia', 2)->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('pec')->nullable();
|
||||
$table->string('telefono')->nullable();
|
||||
$table->timestamps();
|
||||
$table->foreign('amministratore_id')->references('id')->on('amministratori')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// --- Soggetti ---
|
||||
Schema::create('soggetti', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('old_id')->nullable()->unique()->comment('ID dal vecchio gestionale');
|
||||
$table->string('nome')->nullable();
|
||||
$table->string('cognome')->nullable();
|
||||
$table->string('ragione_sociale')->nullable();
|
||||
$table->string('codice_fiscale', 16)->nullable()->index();
|
||||
$table->string('partita_iva', 11)->nullable()->index();
|
||||
$table->string('email')->nullable()->index();
|
||||
$table->string('telefono')->nullable();
|
||||
$table->string('indirizzo')->nullable();
|
||||
$table->string('cap', 10)->nullable();
|
||||
$table->string('citta', 60)->nullable();
|
||||
$table->string('provincia', 2)->nullable();
|
||||
$table->enum('tipo', ['proprietario', 'inquilino', 'usufruttuario', 'altro']);
|
||||
$table->string('codice_univoco', 8)->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// --- Stabili ---
|
||||
Schema::create('stabili', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('amministratore_id');
|
||||
$table->string('denominazione');
|
||||
$table->string('indirizzo');
|
||||
$table->string('cap', 10);
|
||||
$table->string('citta', 60);
|
||||
$table->string('provincia', 2);
|
||||
$table->string('codice_fiscale', 20)->nullable()->unique();
|
||||
$table->text('note')->nullable();
|
||||
$table->json('rate_ordinarie_mesi')->nullable();
|
||||
$table->json('rate_riscaldamento_mesi')->nullable();
|
||||
$table->text('descrizione_rate')->nullable();
|
||||
$table->string('stato', 50)->default('attivo');
|
||||
$table->integer('old_id')->nullable()->unique();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->foreign('amministratore_id')->references('id')->on('amministratori')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// --- Piano Conti Condominio ---
|
||||
Schema::create('piano_conti_condominio', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('stabile_id');
|
||||
$table->string('codice', 20);
|
||||
$table->string('descrizione');
|
||||
$table->string('tipo_conto', 20)->nullable();
|
||||
$table->boolean('attivo')->default(true);
|
||||
$table->timestamps();
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade');
|
||||
$table->unique(['stabile_id', 'codice'], 'unique_conto_per_stabile');
|
||||
});
|
||||
|
||||
// --- Unita Immobiliari ---
|
||||
Schema::create('unita_immobiliari', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('stabile_id');
|
||||
$table->string('fabbricato')->nullable();
|
||||
$table->string('interno')->nullable();
|
||||
$table->string('scala')->nullable();
|
||||
$table->string('piano')->nullable();
|
||||
$table->string('subalterno')->nullable();
|
||||
$table->string('categoria_catastale', 10)->nullable();
|
||||
$table->decimal('superficie', 8, 2)->nullable();
|
||||
$table->decimal('vani', 5, 2)->nullable();
|
||||
$table->string('indirizzo')->nullable()->comment('Indirizzo specifico se diverso da quello del condominio');
|
||||
$table->text('note')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// --- Proprieta ---
|
||||
Schema::create('proprieta', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('soggetto_id');
|
||||
$table->unsignedBigInteger('unita_immobiliare_id');
|
||||
$table->string('tipo_diritto', 50)->nullable();
|
||||
$table->decimal('percentuale_possesso', 7, 4)->nullable();
|
||||
$table->date('data_inizio')->nullable();
|
||||
$table->date('data_fine')->nullable();
|
||||
$table->timestamps();
|
||||
$table->foreign('soggetto_id')->references('id')->on('soggetti')->onDelete('cascade');
|
||||
$table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('cascade');
|
||||
$table->unique(['soggetto_id', 'unita_immobiliare_id', 'tipo_diritto'], 'unique_proprieta_per_unita_soggetto');
|
||||
});
|
||||
|
||||
// --- Tabelle Millesimali ---
|
||||
Schema::create('tabelle_millesimali', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('stabile_id');
|
||||
$table->string('nome_tabella_millesimale');
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->timestamps();
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade');
|
||||
$table->unique(['stabile_id', 'nome_tabella_millesimale'], 'unique_tabella_per_stabile');
|
||||
});
|
||||
|
||||
// --- Dettagli Tabelle Millesimali ---
|
||||
Schema::create('dettagli_tabelle_millesimali', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tabella_millesimale_id');
|
||||
$table->unsignedBigInteger('unita_immobiliare_id');
|
||||
$table->decimal('millesimi', 10, 4);
|
||||
$table->timestamps();
|
||||
$table->foreign('tabella_millesimale_id')->references('id')->on('tabelle_millesimali')->onDelete('cascade');
|
||||
$table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('cascade');
|
||||
$table->unique(['tabella_millesimale_id', 'unita_immobiliare_id'], 'unique_tabella_unita');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('dettagli_tabelle_millesimali');
|
||||
Schema::dropIfExists('tabelle_millesimali');
|
||||
Schema::dropIfExists('proprieta');
|
||||
Schema::dropIfExists('unita_immobiliari');
|
||||
Schema::dropIfExists('stabili');
|
||||
Schema::dropIfExists('soggetti');
|
||||
Schema::dropIfExists('fornitori');
|
||||
Schema::dropIfExists('amministratori');
|
||||
Schema::dropIfExists('piano_conti_condominio');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Crea la tabella allegati per la gestione degli allegati generici (morphable).
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('allegati', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('stabile_id')->nullable();
|
||||
$table->string('nome_file_originale');
|
||||
$table->string('nome_file_storage')->unique();
|
||||
$table->text('percorso_file_storage');
|
||||
$table->string('tipo_mime', 100);
|
||||
$table->bigInteger('dimensione_byte')->unsigned();
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->unsignedBigInteger('allegabile_id');
|
||||
$table->string('allegabile_type', 100);
|
||||
$table->unsignedBigInteger('id_utente_caricamento')->nullable();
|
||||
$table->string('tags')->nullable();
|
||||
$table->index(['allegabile_id', 'allegabile_type']);
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('set null');
|
||||
// $table->foreign('id_utente_caricamento')->references('id')->on('users')->onDelete('set null');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('allegati');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Crea tutte le tabelle e relazioni per la gestione dei ticket (categorie, ticket, aggiornamenti, messaggi, allegati).
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// --- Categorie Ticket ---
|
||||
Schema::create('categorie_ticket', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nome')->unique();
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// --- Tickets ---
|
||||
Schema::create('tickets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('stabile_id');
|
||||
$table->unsignedBigInteger('unita_immobiliare_id')->nullable();
|
||||
$table->unsignedBigInteger('soggetto_richiedente_id')->nullable();
|
||||
$table->unsignedBigInteger('aperto_da_user_id');
|
||||
$table->unsignedBigInteger('categoria_ticket_id')->nullable();
|
||||
$table->string('titolo');
|
||||
$table->text('descrizione');
|
||||
$table->string('luogo_intervento')->nullable()->comment('Es. Scala A, Piano 3, Interno 5');
|
||||
$table->enum('stato', [
|
||||
'Aperto', 'Preso in Carico', 'In Lavorazione', 'In Attesa Approvazione',
|
||||
'In Attesa Ricambi', 'Risolto', 'Chiuso', 'Annullato'
|
||||
])->default('Aperto');
|
||||
$table->enum('priorita', ['Bassa', 'Media', 'Alta', 'Urgente'])->default('Media');
|
||||
$table->unsignedBigInteger('assegnato_a_user_id')->nullable();
|
||||
$table->unsignedBigInteger('assegnato_a_fornitore_id')->nullable();
|
||||
$table->timestamp('data_apertura')->useCurrent();
|
||||
$table->date('data_scadenza_prevista')->nullable();
|
||||
$table->timestamp('data_risoluzione_effettiva')->nullable();
|
||||
$table->timestamp('data_chiusura_effettiva')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade');
|
||||
$table->foreign('unita_immobiliare_id')->references('id')->on('unita_immobiliari')->onDelete('set null');
|
||||
$table->foreign('soggetto_richiedente_id')->references('id')->on('soggetti')->onDelete('set null');
|
||||
$table->foreign('aperto_da_user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->foreign('categoria_ticket_id')->references('id')->on('categorie_ticket')->onDelete('set null');
|
||||
$table->foreign('assegnato_a_user_id')->references('id')->on('users')->onDelete('set null');
|
||||
$table->foreign('assegnato_a_fornitore_id')->references('id')->on('fornitori')->onDelete('set null');
|
||||
});
|
||||
|
||||
// --- Ticket Updates ---
|
||||
Schema::create('ticket_updates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('ticket_id');
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
$table->text('update_text')->comment("Testo dell'aggiornamento o nota interna");
|
||||
$table->timestamps();
|
||||
$table->foreign('ticket_id')->references('id')->on('tickets')->onDelete('cascade');
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
|
||||
});
|
||||
|
||||
// --- Ticket Messages ---
|
||||
Schema::create('ticket_messages', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('ticket_id');
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
$table->text('messaggio');
|
||||
$table->timestamps();
|
||||
$table->foreign('ticket_id')->references('id')->on('tickets')->onDelete('cascade');
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
|
||||
});
|
||||
|
||||
// --- Ticket Attachments ---
|
||||
Schema::create('ticket_attachments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('ticket_id')->constrained('tickets')->onDelete('cascade');
|
||||
$table->foreignId('ticket_update_id')->nullable()->constrained('ticket_updates')->onDelete('cascade');
|
||||
$table->foreignId('user_id')->comment('Utente che ha caricato l allegato')->constrained('users')->onDelete('cascade');
|
||||
$table->string('file_path');
|
||||
$table->string('original_file_name');
|
||||
$table->string('mime_type')->nullable();
|
||||
$table->unsignedBigInteger('size')->nullable()->comment('Dimensione in bytes');
|
||||
$table->string('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('ticket_attachments');
|
||||
Schema::dropIfExists('ticket_messages');
|
||||
Schema::dropIfExists('ticket_updates');
|
||||
Schema::dropIfExists('tickets');
|
||||
Schema::dropIfExists('categorie_ticket');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
// Migration svuotata: duplicata e non più necessaria, gestione ruoli/permessi demandata a Spatie/Permission.
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('documenti', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('protocollo')->nullable()->unique(); // es. 2025-0001
|
||||
$table->date('data_protocollo')->nullable();
|
||||
$table->string('tipo_documento')->nullable(); // Fattura, Contratto, Verbale, ecc.
|
||||
$table->unsignedBigInteger('stabile_id')->nullable();
|
||||
$table->unsignedBigInteger('fornitore_id')->nullable();
|
||||
$table->unsignedBigInteger('esercizio_contabile_id')->nullable();
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->decimal('importo', 12, 2)->nullable();
|
||||
$table->date('data_documento')->nullable();
|
||||
$table->string('nome_file');
|
||||
$table->string('path_file');
|
||||
$table->text('testo_estratto_ocr')->nullable();
|
||||
// Polimorfismo
|
||||
$table->unsignedBigInteger('documentable_id')->nullable()->index();
|
||||
$table->string('documentable_type')->nullable()->index();
|
||||
$table->timestamps();
|
||||
// FK opzionali
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('set null');
|
||||
$table->foreign('fornitore_id')->references('id')->on('fornitori')->onDelete('set null');
|
||||
// $table->foreign('esercizio_contabile_id')->references('id')->on('esercizi_contabili')->onDelete('set null'); // FK disabilitata: tabella non ancora presente
|
||||
});
|
||||
}
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('documenti');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('gestioni', function (Blueprint $table) {
|
||||
$table->id('id_gestione');
|
||||
$table->unsignedBigInteger('stabile_id');
|
||||
$table->year('anno_gestione');
|
||||
$table->string('tipo_gestione', 20)->default('Ord.'); // Ord., Risc., Straord.
|
||||
$table->date('data_inizio')->nullable();
|
||||
$table->date('data_fine')->nullable();
|
||||
$table->enum('stato', ['aperta', 'in_corso', 'chiusa'])->default('aperta');
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('cascade');
|
||||
$table->index(['stabile_id', 'anno_gestione']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('gestioni');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->string('key');
|
||||
$table->text('value')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->unique(['user_id', 'key']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('impostazioni', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('chiave')->unique();
|
||||
$table->string('valore')->nullable();
|
||||
$table->string('descrizione')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('impostazioni');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('movimenti_contabili', function (Blueprint $table) {
|
||||
// Aggiunge colonne mancanti per la nuova struttura
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'codice_movimento')) {
|
||||
$table->char('codice_movimento', 8)->unique()->after('id')->comment('Codice alfanumerico univoco 8 caratteri');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'stato_movimento')) {
|
||||
$table->enum('stato_movimento', ['prima_nota', 'bozza', 'confermato', 'chiuso'])->default('prima_nota')->after('documento_id');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'data_prima_nota')) {
|
||||
$table->timestamp('data_prima_nota')->nullable()->after('stato_movimento');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'data_conferma')) {
|
||||
$table->timestamp('data_conferma')->nullable()->after('data_prima_nota');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'confermato_da')) {
|
||||
$table->unsignedBigInteger('confermato_da')->nullable()->after('data_conferma');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'categoria_movimento')) {
|
||||
$table->enum('categoria_movimento', ['ordinario', 'straordinario', 'fondo', 'lavori'])->default('ordinario')->after('tipo_movimento');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'iva')) {
|
||||
$table->decimal('iva', 10, 2)->default(0)->after('ritenuta_acconto');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'dettagli_partita_doppia')) {
|
||||
$table->json('dettagli_partita_doppia')->nullable()->after('importo_netto')->comment('Struttura per dare/avere futuro');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'note_interne')) {
|
||||
$table->text('note_interne')->nullable()->after('dettagli_partita_doppia');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'creato_da')) {
|
||||
$table->unsignedBigInteger('creato_da')->nullable()->after('note_interne');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('movimenti_contabili', 'modificato_da')) {
|
||||
$table->unsignedBigInteger('modificato_da')->nullable()->after('creato_da');
|
||||
}
|
||||
});
|
||||
|
||||
// Aggiunge foreign keys dopo aver creato le colonne
|
||||
Schema::table('movimenti_contabili', function (Blueprint $table) {
|
||||
// Foreign keys solo se non esistono già
|
||||
if (Schema::hasColumn('movimenti_contabili', 'confermato_da')) {
|
||||
$table->foreign('confermato_da')->references('id')->on('users')->onDelete('set null');
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('movimenti_contabili', 'creato_da')) {
|
||||
$table->foreign('creato_da')->references('id')->on('users')->onDelete('set null');
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('movimenti_contabili', 'modificato_da')) {
|
||||
$table->foreign('modificato_da')->references('id')->on('users')->onDelete('set null');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('movimenti_contabili', function (Blueprint $table) {
|
||||
// Rimuove foreign keys
|
||||
$table->dropForeign(['confermato_da']);
|
||||
$table->dropForeign(['creato_da']);
|
||||
$table->dropForeign(['modificato_da']);
|
||||
|
||||
// Rimuove colonne aggiunte
|
||||
$table->dropColumn([
|
||||
'codice_movimento',
|
||||
'stato_movimento',
|
||||
'data_prima_nota',
|
||||
'data_conferma',
|
||||
'confermato_da',
|
||||
'categoria_movimento',
|
||||
'iva',
|
||||
'dettagli_partita_doppia',
|
||||
'note_interne',
|
||||
'creato_da',
|
||||
'modificato_da'
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Aggiorna la struttura della tabella allegati per renderla completamente
|
||||
* conforme alle best practice Laravel.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('allegati', function (Blueprint $table) {
|
||||
// Rinomina id_utente_caricamento in user_id per seguire lo standard Laravel
|
||||
if (Schema::hasColumn('allegati', 'id_utente_caricamento')) {
|
||||
$table->renameColumn('id_utente_caricamento', 'user_id');
|
||||
}
|
||||
|
||||
// Aggiungi timestamps se non esistono
|
||||
if (!Schema::hasColumn('allegati', 'created_at')) {
|
||||
$table->timestamps();
|
||||
}
|
||||
|
||||
// Aggiungi soft deletes per gestire cancellazioni logiche
|
||||
if (!Schema::hasColumn('allegati', 'deleted_at')) {
|
||||
$table->softDeletes();
|
||||
}
|
||||
|
||||
// Aggiungi codice alfanumerico unico per identificazione
|
||||
if (!Schema::hasColumn('allegati', 'codice_allegato')) {
|
||||
$table->string('codice_allegato', 8)->unique()->after('id');
|
||||
$table->index('codice_allegato');
|
||||
}
|
||||
|
||||
// Aggiungi foreign key per user_id (solo se la colonna esiste e non ha già la FK)
|
||||
try {
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
|
||||
} catch (\Exception $e) {
|
||||
// Foreign key potrebbe già esistere, ignora l'errore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('allegati', function (Blueprint $table) {
|
||||
// Rimuovi foreign key se esiste
|
||||
try {
|
||||
$table->dropForeign(['user_id']);
|
||||
} catch (\Exception $e) {
|
||||
// Foreign key potrebbe non esistere, ignora l'errore
|
||||
}
|
||||
|
||||
// Rimuovi le colonne aggiunte se esistono
|
||||
if (Schema::hasColumn('allegati', 'codice_allegato')) {
|
||||
$table->dropColumn('codice_allegato');
|
||||
}
|
||||
if (Schema::hasColumn('allegati', 'deleted_at')) {
|
||||
$table->dropColumn('deleted_at');
|
||||
}
|
||||
if (Schema::hasColumn('allegati', 'created_at')) {
|
||||
$table->dropTimestamps();
|
||||
}
|
||||
|
||||
// Ripristina il nome originale della colonna se è stata rinominata
|
||||
if (Schema::hasColumn('allegati', 'user_id')) {
|
||||
$table->renameColumn('user_id', 'id_utente_caricamento');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Crea la tabella amministratori moderna con best practice Laravel
|
||||
* e supporto per sistema multi-database.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('amministratori', function (Blueprint $table) {
|
||||
$table->id(); // Chiave primaria standard Laravel
|
||||
|
||||
// Codice alfanumerico unico di 8 caratteri per identificazione
|
||||
$table->string('codice_amministratore', 8)->unique();
|
||||
$table->index('codice_amministratore');
|
||||
|
||||
// Dati amministratore
|
||||
$table->string('ragione_sociale');
|
||||
$table->string('nome')->nullable();
|
||||
$table->string('cognome')->nullable();
|
||||
$table->string('codice_fiscale', 16)->unique();
|
||||
$table->string('partita_iva', 11)->nullable();
|
||||
|
||||
// Contatti
|
||||
$table->string('indirizzo')->nullable();
|
||||
$table->string('cap', 5)->nullable();
|
||||
$table->string('citta')->nullable();
|
||||
$table->string('provincia', 2)->nullable();
|
||||
$table->string('telefono')->nullable();
|
||||
$table->string('cellulare')->nullable();
|
||||
$table->string('email')->unique();
|
||||
$table->string('pec')->nullable();
|
||||
$table->string('sito_web')->nullable();
|
||||
|
||||
// Sistema multi-database e cartelle
|
||||
$table->string('database_name', 8)->nullable(); // Nome DB dedicato (stesso del codice)
|
||||
$table->string('cartella_dati', 255)->nullable(); // Percorso cartella dati
|
||||
$table->boolean('database_attivo')->default(false); // Se ha DB separato
|
||||
$table->string('server_database')->nullable(); // Server hosting DB (per distribuzione)
|
||||
|
||||
// Configurazioni
|
||||
$table->json('configurazioni')->nullable(); // JSON per impostazioni personalizzate
|
||||
$table->decimal('commissione_percentuale', 5, 2)->default(0.00);
|
||||
$table->decimal('costo_fisso_mensile', 8, 2)->default(0.00);
|
||||
|
||||
// Stato e date
|
||||
$table->enum('stato', ['attivo', 'sospeso', 'disattivato'])->default('attivo');
|
||||
$table->date('data_inizio_attivita')->nullable();
|
||||
$table->date('data_scadenza_contratto')->nullable();
|
||||
|
||||
// Laravel standard
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indici per performance
|
||||
$table->index(['stato', 'database_attivo']);
|
||||
$table->index('codice_fiscale');
|
||||
$table->index('email');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('amministratori');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('amministratori', function (Blueprint $table) {
|
||||
$table->softDeletes();
|
||||
|
||||
// Aggiungiamo anche il campo codice se non esiste
|
||||
if (!Schema::hasColumn('amministratori', 'codice')) {
|
||||
$table->string('codice', 8)->unique()->after('id');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('amministratori', function (Blueprint $table) {
|
||||
$table->dropSoftDeletes();
|
||||
|
||||
if (Schema::hasColumn('amministratori', 'codice')) {
|
||||
$table->dropColumn('codice');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
44
netgescon-laravel/Dockerfile
Normal file
44
netgescon-laravel/Dockerfile
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
FROM php:8.2-fpm
|
||||
|
||||
# Installa dipendenze di sistema
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
curl \
|
||||
libpng-dev \
|
||||
libonig-dev \
|
||||
libxml2-dev \
|
||||
zip \
|
||||
unzip \
|
||||
nodejs \
|
||||
npm
|
||||
|
||||
# Pulisce cache
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Installa estensioni PHP
|
||||
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
|
||||
|
||||
# Installa Composer
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# Imposta directory di lavoro
|
||||
WORKDIR /var/www
|
||||
|
||||
# Copia file applicazione
|
||||
COPY . /var/www
|
||||
|
||||
# Installa dipendenze PHP
|
||||
RUN composer install --optimize-autoloader --no-dev
|
||||
|
||||
# Installa dipendenze Node.js
|
||||
RUN npm install && npm run build
|
||||
|
||||
# Imposta permessi
|
||||
RUN chown -R www-data:www-data /var/www \
|
||||
&& chmod -R 755 /var/www/storage \
|
||||
&& chmod -R 755 /var/www/bootstrap/cache
|
||||
|
||||
# Espone porta 9000
|
||||
EXPOSE 9000
|
||||
|
||||
CMD ["php-fpm"]
|
||||
206
netgescon-laravel/app/Console/Commands/CreateAmministratore.php
Normal file
206
netgescon-laravel/app/Console/Commands/CreateAmministratore.php
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\Amministratore;
|
||||
use App\Models\Stabile;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class CreateAmministratore extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*/
|
||||
protected $signature = 'netgescon:create-amministratore
|
||||
{nome : Nome dell\'amministratore}
|
||||
{cognome : Cognome dell\'amministratore}
|
||||
{email : Email dell\'amministratore}
|
||||
{--password= : Password (se non specificata, viene generata)}
|
||||
{--studio= : Nome dello studio}
|
||||
{--piva= : Partita IVA}
|
||||
{--cf= : Codice fiscale}
|
||||
{--telefono= : Telefono}
|
||||
{--indirizzo= : Indirizzo}
|
||||
{--cap= : CAP}
|
||||
{--citta= : Città}
|
||||
{--provincia= : Provincia}
|
||||
{--pec= : Email PEC}
|
||||
{--multi-db : Abilita database dedicato}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*/
|
||||
protected $description = 'Crea un nuovo amministratore con cartelle e permessi';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('🏗️ Creazione nuovo amministratore...');
|
||||
|
||||
// Raccolta dati
|
||||
$nome = $this->argument('nome');
|
||||
$cognome = $this->argument('cognome');
|
||||
$email = $this->argument('email');
|
||||
$password = $this->option('password') ?: $this->generatePassword();
|
||||
|
||||
// Verifica email univoca
|
||||
if (User::where('email', $email)->exists()) {
|
||||
$this->error("❌ Email {$email} già esistente!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. Crea utente
|
||||
$this->info("👤 Creazione utente {$nome} {$cognome}...");
|
||||
$user = User::create([
|
||||
'name' => "{$nome} {$cognome}",
|
||||
'email' => $email,
|
||||
'password' => Hash::make($password),
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
|
||||
// 2. Assegna ruolo amministratore
|
||||
$user->assignRole('amministratore');
|
||||
$this->info("✅ Ruolo 'amministratore' assegnato");
|
||||
|
||||
// 3. Crea record amministratore
|
||||
$this->info("🏢 Creazione record amministratore...");
|
||||
$amministratore = Amministratore::create([
|
||||
'user_id' => $user->id,
|
||||
'nome' => $nome,
|
||||
'cognome' => $cognome,
|
||||
'denominazione_studio' => $this->option('studio') ?: "Studio {$cognome}",
|
||||
'partita_iva' => $this->option('piva') ?: null,
|
||||
'codice_fiscale_studio' => $this->option('cf') ?: null,
|
||||
'telefono_studio' => $this->option('telefono') ?: null,
|
||||
'indirizzo_studio' => $this->option('indirizzo') ?: null,
|
||||
'cap_studio' => $this->option('cap') ?: null,
|
||||
'citta_studio' => $this->option('citta') ?: null,
|
||||
'provincia_studio' => $this->option('provincia') ?: null,
|
||||
'email_studio' => $email,
|
||||
'pec_studio' => $this->option('pec') ?: null,
|
||||
]);
|
||||
|
||||
// 4. Crea struttura cartelle
|
||||
$this->info("📁 Creazione cartelle dati...");
|
||||
$this->createAdminFolders($amministratore);
|
||||
|
||||
// 5. Crea stabile di esempio (opzionale)
|
||||
if ($this->confirm('Vuoi creare uno stabile di esempio?', true)) {
|
||||
$this->createExampleStabile($amministratore);
|
||||
}
|
||||
|
||||
// 6. Sistema multi-database (se richiesto)
|
||||
if ($this->option('multi-db')) {
|
||||
$this->info("🗄️ Configurazione database dedicato...");
|
||||
$this->setupDedicatedDatabase($amministratore);
|
||||
}
|
||||
|
||||
// Output finale
|
||||
$this->info('');
|
||||
$this->info('🎉 Amministratore creato con successo!');
|
||||
$this->table(['Campo', 'Valore'], [
|
||||
['Nome Completo', $amministratore->nome_completo],
|
||||
['Email', $user->email],
|
||||
['Password', $password],
|
||||
['Codice Univoco', $amministratore->codice_univoco],
|
||||
['Studio', $amministratore->denominazione_studio],
|
||||
['Cartelle', "storage/app/amministratori/{$amministratore->codice_univoco}/"],
|
||||
['Multi-DB', $this->option('multi-db') ? 'Abilitato' : 'Condiviso'],
|
||||
]);
|
||||
|
||||
$this->warn('⚠️ IMPORTANTE: Salva la password generata!');
|
||||
|
||||
return 0;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error("❌ Errore durante la creazione: " . $e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera password sicura
|
||||
*/
|
||||
private function generatePassword(): string
|
||||
{
|
||||
return 'Admin' . rand(1000, 9999) . '!';
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea struttura cartelle per amministratore
|
||||
*/
|
||||
private function createAdminFolders(Amministratore $amministratore): void
|
||||
{
|
||||
$basePath = "amministratori/{$amministratore->codice_univoco}";
|
||||
|
||||
$folders = [
|
||||
'documenti/allegati',
|
||||
'documenti/contratti',
|
||||
'documenti/assemblee',
|
||||
'documenti/preventivi',
|
||||
'backup/database',
|
||||
'backup/files',
|
||||
'temp/upload',
|
||||
'temp/processing',
|
||||
'logs',
|
||||
'exports',
|
||||
];
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
Storage::disk('local')->makeDirectory("{$basePath}/{$folder}");
|
||||
$this->line(" 📂 {$folder}");
|
||||
}
|
||||
|
||||
// Crea file README
|
||||
$readme = "# Cartella Amministratore: {$amministratore->nome_completo}\n\n";
|
||||
$readme .= "**Codice**: {$amministratore->codice_univoco}\n";
|
||||
$readme .= "**Creato**: " . now()->format('d/m/Y H:i') . "\n\n";
|
||||
$readme .= "## Struttura Cartelle\n\n";
|
||||
$readme .= "- `documenti/` - Documenti dell'amministratore\n";
|
||||
$readme .= "- `backup/` - Backup automatici\n";
|
||||
$readme .= "- `temp/` - File temporanei\n";
|
||||
$readme .= "- `logs/` - Log specifici\n";
|
||||
$readme .= "- `exports/` - Esportazioni dati\n";
|
||||
|
||||
Storage::disk('local')->put("{$basePath}/README.md", $readme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea stabile di esempio
|
||||
*/
|
||||
private function createExampleStabile(Amministratore $amministratore): void
|
||||
{
|
||||
$denominazione = $this->ask('Nome del condominio', "Condominio {$amministratore->cognome}");
|
||||
|
||||
$stabile = Stabile::create([
|
||||
'amministratore_id' => $amministratore->id,
|
||||
'denominazione' => $denominazione,
|
||||
'indirizzo' => $this->ask('Indirizzo', 'Via Roma 1'),
|
||||
'cap' => $this->ask('CAP', '00100'),
|
||||
'citta' => $this->ask('Città', 'Roma'),
|
||||
'provincia' => $this->ask('Provincia', 'RM'),
|
||||
'codice_fiscale' => strtoupper(substr($denominazione, 0, 3)) . rand(100000, 999999),
|
||||
'stato' => 'attivo',
|
||||
]);
|
||||
|
||||
$this->info("🏢 Stabile creato: {$stabile->denominazione}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura database dedicato (placeholder)
|
||||
*/
|
||||
private function setupDedicatedDatabase(Amministratore $amministratore): void
|
||||
{
|
||||
// TODO: Implementare logica multi-database
|
||||
$dbName = "netgescon_" . strtolower($amministratore->codice_univoco);
|
||||
$this->line(" 🗄️ Database: {$dbName}");
|
||||
$this->warn(" ⚠️ Implementazione multi-DB in development");
|
||||
}
|
||||
}
|
||||
281
netgescon-laravel/app/Console/Commands/ManageDistribution.php
Normal file
281
netgescon-laravel/app/Console/Commands/ManageDistribution.php
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Amministratore;
|
||||
use App\Services\DistributionService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ManageDistribution extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*/
|
||||
protected $signature = 'distribution:manage
|
||||
{action : Action to perform (migrate|status|backup|test)}
|
||||
{--administrator= : Administrator code (8 characters)}
|
||||
{--target-server= : Target server URL for migration}
|
||||
{--all : Apply to all administrators}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*/
|
||||
protected $description = 'Manage multi-server distribution of administrators';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$action = $this->argument('action');
|
||||
|
||||
switch ($action) {
|
||||
case 'migrate':
|
||||
return $this->migrateAdministrator();
|
||||
case 'status':
|
||||
return $this->showDistributionStatus();
|
||||
case 'backup':
|
||||
return $this->backupAdministrator();
|
||||
case 'test':
|
||||
return $this->testDistribution();
|
||||
default:
|
||||
$this->error("Unknown action: {$action}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migra un amministratore verso un altro server
|
||||
*/
|
||||
private function migrateAdministrator()
|
||||
{
|
||||
$adminCode = $this->option('administrator');
|
||||
$targetServer = $this->option('target-server');
|
||||
|
||||
if (!$adminCode) {
|
||||
$adminCode = $this->ask('Administrator code (8 characters)');
|
||||
}
|
||||
|
||||
if (!$targetServer) {
|
||||
$targetServer = $this->ask('Target server URL');
|
||||
}
|
||||
|
||||
if (!$adminCode || !$targetServer) {
|
||||
$this->error('Both administrator code and target server are required');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$amministratore = Amministratore::where('codice_amministratore', $adminCode)->first();
|
||||
|
||||
if (!$amministratore) {
|
||||
$this->error("Administrator {$adminCode} not found");
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->info("Starting migration of administrator {$adminCode} to {$targetServer}");
|
||||
|
||||
// Verifica server target
|
||||
$this->info('Checking target server health...');
|
||||
$healthCheck = DistributionService::checkServerHealth($targetServer);
|
||||
|
||||
if (!$healthCheck['success']) {
|
||||
$this->error("Target server health check failed: {$healthCheck['error']}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->info('Target server is healthy and compatible');
|
||||
|
||||
// Conferma migrazione
|
||||
if (!$this->confirm("Are you sure you want to migrate administrator {$adminCode} to {$targetServer}?")) {
|
||||
$this->info('Migration cancelled');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Esegui migrazione
|
||||
$this->info('Starting migration process...');
|
||||
$result = DistributionService::migrateAdministrator($amministratore, $targetServer);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->info("✅ Migration completed successfully!");
|
||||
$this->info("Administrator {$adminCode} is now accessible at: {$result['new_url']}");
|
||||
} else {
|
||||
$this->error("❌ Migration failed: {$result['error']}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra stato della distribuzione
|
||||
*/
|
||||
private function showDistributionStatus()
|
||||
{
|
||||
$this->info('NetGesCon Multi-Server Distribution Status');
|
||||
$this->info('==========================================');
|
||||
|
||||
$stats = DistributionService::getDistributionStats();
|
||||
|
||||
$this->info("Total Administrators: {$stats['total_administrators']}");
|
||||
$this->info("Local Administrators: {$stats['local_administrators']}");
|
||||
$this->info("Distributed Administrators: {$stats['distributed_administrators']}");
|
||||
|
||||
$this->newLine();
|
||||
$this->info('Server Distribution:');
|
||||
|
||||
if (empty($stats['servers'])) {
|
||||
$this->info(' No distributed servers configured');
|
||||
} else {
|
||||
foreach ($stats['servers'] as $server) {
|
||||
$this->info(" {$server['server']}: {$server['administrators_count']} administrators");
|
||||
}
|
||||
}
|
||||
|
||||
$this->newLine();
|
||||
$this->info('Status Distribution:');
|
||||
foreach ($stats['status_distribution'] as $status => $count) {
|
||||
$this->info(" {$status}: {$count}");
|
||||
}
|
||||
|
||||
// Mostra dettagli amministratori distribuiti
|
||||
$distributedAdmins = Amministratore::whereNotNull('server_database')->get();
|
||||
|
||||
if ($distributedAdmins->isNotEmpty()) {
|
||||
$this->newLine();
|
||||
$this->info('Distributed Administrators Details:');
|
||||
$this->table(
|
||||
['Code', 'Name', 'Server', 'Status', 'Last Backup'],
|
||||
$distributedAdmins->map(function ($admin) {
|
||||
return [
|
||||
$admin->codice_amministratore,
|
||||
$admin->nome_completo,
|
||||
$admin->server_database ?: 'localhost',
|
||||
$admin->stato_sincronizzazione,
|
||||
$admin->ultimo_backup ? $admin->ultimo_backup->format('Y-m-d H:i') : 'Never'
|
||||
];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Esegue backup di un amministratore
|
||||
*/
|
||||
private function backupAdministrator()
|
||||
{
|
||||
$adminCode = $this->option('administrator');
|
||||
$all = $this->option('all');
|
||||
|
||||
if (!$adminCode && !$all) {
|
||||
$adminCode = $this->ask('Administrator code (8 characters) or use --all for all administrators');
|
||||
}
|
||||
|
||||
if ($all) {
|
||||
$this->info('Backing up all administrators...');
|
||||
$administrators = Amministratore::all();
|
||||
} else {
|
||||
$administrators = Amministratore::where('codice_amministratore', $adminCode)->get();
|
||||
|
||||
if ($administrators->isEmpty()) {
|
||||
$this->error("Administrator {$adminCode} not found");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
$successCount = 0;
|
||||
$errorCount = 0;
|
||||
|
||||
foreach ($administrators as $admin) {
|
||||
$this->info("Backing up administrator {$admin->codice_amministratore}...");
|
||||
|
||||
$result = DistributionService::performDistributedBackup($admin);
|
||||
|
||||
if ($result['success']) {
|
||||
$this->info("✅ Backup completed for {$admin->codice_amministratore}");
|
||||
$successCount++;
|
||||
} else {
|
||||
$this->error("❌ Backup failed for {$admin->codice_amministratore}: {$result['error']}");
|
||||
$errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("Backup completed: {$successCount} successful, {$errorCount} errors");
|
||||
return $errorCount > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Testa la funzionalità di distribuzione
|
||||
*/
|
||||
private function testDistribution()
|
||||
{
|
||||
$this->info('Testing distribution functionality...');
|
||||
|
||||
// Test 1: Verifica struttura cartelle
|
||||
$this->info('1. Testing folder structure...');
|
||||
$testAdmin = Amministratore::first();
|
||||
|
||||
if (!$testAdmin) {
|
||||
$this->error('No administrators found for testing');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$archiveInfo = $testAdmin->getArchiveInfo();
|
||||
|
||||
if ($archiveInfo['exists']) {
|
||||
$this->info("✅ Archive exists: {$archiveInfo['path']}");
|
||||
$this->info(" Size: {$archiveInfo['size_formatted']}");
|
||||
$this->info(" Files: {$archiveInfo['files_count']}");
|
||||
} else {
|
||||
$this->warn("⚠️ Archive not found for {$testAdmin->codice_amministratore}");
|
||||
}
|
||||
|
||||
// Test 2: Health check locale
|
||||
$this->info('2. Testing local health check...');
|
||||
$localUrl = config('app.url');
|
||||
$healthCheck = DistributionService::checkServerHealth($localUrl);
|
||||
|
||||
if ($healthCheck['success']) {
|
||||
$this->info("✅ Local server health check passed");
|
||||
} else {
|
||||
$this->error("❌ Local server health check failed: {$healthCheck['error']}");
|
||||
}
|
||||
|
||||
// Test 3: Backup test
|
||||
$this->info('3. Testing backup functionality...');
|
||||
$backupResult = $testAdmin->createDatabaseBackup();
|
||||
|
||||
if ($backupResult['success']) {
|
||||
$this->info("✅ Backup test passed");
|
||||
$this->info(" File: {$backupResult['filename']}");
|
||||
$this->info(" Size: " . number_format($backupResult['size']) . " bytes");
|
||||
} else {
|
||||
$this->error("❌ Backup test failed: {$backupResult['error']}");
|
||||
}
|
||||
|
||||
// Test 4: Migrazione simulata
|
||||
$this->info('4. Testing migration preparation...');
|
||||
$migrationResult = $testAdmin->prepareForMigration();
|
||||
|
||||
if ($migrationResult['success']) {
|
||||
$this->info("✅ Migration preparation test passed");
|
||||
$this->info(" Archive: {$migrationResult['zip_file']}");
|
||||
$this->info(" Size: " . number_format($migrationResult['size']) . " bytes");
|
||||
|
||||
// Cleanup test files
|
||||
if (file_exists($migrationResult['zip_file'])) {
|
||||
unlink($migrationResult['zip_file']);
|
||||
}
|
||||
if (file_exists($migrationResult['metadata_file'])) {
|
||||
unlink($migrationResult['metadata_file']);
|
||||
}
|
||||
} else {
|
||||
$this->error("❌ Migration preparation test failed: {$migrationResult['error']}");
|
||||
}
|
||||
|
||||
$this->info('Distribution testing completed');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
317
netgescon-laravel/app/Console/Commands/PopulateTestData.php
Normal file
317
netgescon-laravel/app/Console/Commands/PopulateTestData.php
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Soggetto;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\Rata;
|
||||
use App\Models\Assemblea;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class PopulateTestData extends Command
|
||||
{
|
||||
protected $signature = 'netgescon:populate-test-data';
|
||||
protected $description = 'Popola il database con dati di test per NetGesCon';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->info('🏢 Popolamento dati di test NetGesCon...');
|
||||
|
||||
// Crea stabili di test
|
||||
$this->createTestStabili();
|
||||
|
||||
// Crea condomini di test
|
||||
$this->createTestCondomini();
|
||||
|
||||
// Crea tickets di test
|
||||
$this->createTestTickets();
|
||||
|
||||
// Crea rate di test
|
||||
$this->createTestRate();
|
||||
|
||||
// Crea assemblee di test
|
||||
$this->createTestAssemblee();
|
||||
|
||||
$this->info('✅ Dati di test creati con successo!');
|
||||
$this->info('📊 Usa /test-sidebar-data per vedere il risultato');
|
||||
}
|
||||
|
||||
private function createTestStabili()
|
||||
{
|
||||
if (Stabile::count() > 0) {
|
||||
$this->info('⏭️ Stabili già presenti, skip...');
|
||||
return;
|
||||
}
|
||||
|
||||
$stabili = [
|
||||
[
|
||||
'nome' => 'Condominio Roma Centro',
|
||||
'indirizzo' => 'Via Roma 123, Roma',
|
||||
'codice_fiscale' => 'STABROM123',
|
||||
'stato' => 'attivo',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'nome' => 'Residenza Milano Nord',
|
||||
'indirizzo' => 'Via Milano 456, Milano',
|
||||
'codice_fiscale' => 'STABMIL456',
|
||||
'stato' => 'attivo',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'nome' => 'Condominio Firenze Sud',
|
||||
'indirizzo' => 'Via Firenze 789, Firenze',
|
||||
'codice_fiscale' => 'STABFIR789',
|
||||
'stato' => 'inattivo',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($stabili as $stabile) {
|
||||
Stabile::create($stabile);
|
||||
}
|
||||
|
||||
$this->info('🏢 Creati 3 stabili di test');
|
||||
}
|
||||
|
||||
private function createTestCondomini()
|
||||
{
|
||||
if (Soggetto::count() > 0) {
|
||||
$this->info('⏭️ Condomini già presenti, skip...');
|
||||
return;
|
||||
}
|
||||
|
||||
$condomini = [
|
||||
[
|
||||
'nome' => 'Mario',
|
||||
'cognome' => 'Rossi',
|
||||
'codice_fiscale' => 'RSSMRA80A01H501Z',
|
||||
'tipo' => 'proprietario',
|
||||
'email' => 'mario.rossi@example.com',
|
||||
'telefono' => '333-1234567',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'nome' => 'Giulia',
|
||||
'cognome' => 'Bianchi',
|
||||
'codice_fiscale' => 'BNCGLI85B15H501Y',
|
||||
'tipo' => 'proprietario',
|
||||
'email' => 'giulia.bianchi@example.com',
|
||||
'telefono' => '333-2345678',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'nome' => 'Luca',
|
||||
'cognome' => 'Verdi',
|
||||
'codice_fiscale' => 'VRDLCU90C20H501X',
|
||||
'tipo' => 'inquilino',
|
||||
'email' => 'luca.verdi@example.com',
|
||||
'telefono' => '333-3456789',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'nome' => 'Anna',
|
||||
'cognome' => 'Neri',
|
||||
'codice_fiscale' => 'NRANNA75D25H501W',
|
||||
'tipo' => 'inquilino',
|
||||
'email' => 'anna.neri@example.com',
|
||||
'telefono' => '333-4567890',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($condomini as $condomino) {
|
||||
Soggetto::create($condomino);
|
||||
}
|
||||
|
||||
$this->info('👥 Creati 4 condomini di test');
|
||||
}
|
||||
|
||||
private function createTestTickets()
|
||||
{
|
||||
if (Ticket::count() > 0) {
|
||||
$this->info('⏭️ Tickets già presenti, skip...');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prendi il primo stabile disponibile
|
||||
$stabile = Stabile::first();
|
||||
if (!$stabile) {
|
||||
$this->error('❌ Nessuno stabile trovato. Crea prima uno stabile.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prendi il primo utente disponibile
|
||||
$user = User::first();
|
||||
if (!$user) {
|
||||
$this->error('❌ Nessun utente trovato. Crea prima un utente.');
|
||||
return;
|
||||
}
|
||||
|
||||
$tickets = [
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'aperto_da_user_id' => $user->id,
|
||||
'titolo' => 'Perdita d\'acqua nel bagno',
|
||||
'descrizione' => 'C\'è una perdita d\'acqua nel bagno del primo piano',
|
||||
'priorita' => 'Alta',
|
||||
'stato' => 'Aperto',
|
||||
'data_apertura' => now(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'aperto_da_user_id' => $user->id,
|
||||
'titolo' => 'Problema ascensore',
|
||||
'descrizione' => 'L\'ascensore si ferma tra il secondo e il terzo piano',
|
||||
'priorita' => 'Alta',
|
||||
'stato' => 'In Lavorazione',
|
||||
'data_apertura' => now(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'aperto_da_user_id' => $user->id,
|
||||
'titolo' => 'Richiesta sostituzione lampadina',
|
||||
'descrizione' => 'La lampadina nell\'androne è bruciata',
|
||||
'priorita' => 'Bassa',
|
||||
'stato' => 'Aperto',
|
||||
'data_apertura' => now(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'aperto_da_user_id' => $user->id,
|
||||
'titolo' => 'Rumore eccessivo',
|
||||
'descrizione' => 'Il vicino del piano di sopra fa troppo rumore',
|
||||
'priorita' => 'Media',
|
||||
'stato' => 'Chiuso',
|
||||
'data_apertura' => now()->subDays(5),
|
||||
'data_chiusura_effettiva' => now(),
|
||||
'created_at' => now()->subDays(2),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($tickets as $ticket) {
|
||||
Ticket::create($ticket);
|
||||
}
|
||||
|
||||
$this->info('🎫 Creati 4 tickets di test');
|
||||
}
|
||||
|
||||
private function createTestRate()
|
||||
{
|
||||
// TODO: Implementare rate con la nuova struttura
|
||||
$this->info('⏭️ Creazione rate temporaneamente disabilitata');
|
||||
return;
|
||||
|
||||
// Prendi il primo stabile disponibile
|
||||
$stabile = Stabile::first();
|
||||
if (!$stabile) {
|
||||
$this->error('❌ Nessuno stabile trovato. Crea prima uno stabile.');
|
||||
return;
|
||||
}
|
||||
|
||||
$rate = [
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'importo' => 250.00,
|
||||
'data_scadenza' => Carbon::now()->subDays(10), // Scaduta
|
||||
'stato' => 'non_pagata',
|
||||
'descrizione' => 'Rata mensile gennaio 2025',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'importo' => 250.00,
|
||||
'data_scadenza' => Carbon::now()->subDays(5), // Scaduta
|
||||
'stato' => 'non_pagata',
|
||||
'descrizione' => 'Rata mensile febbraio 2025',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'importo' => 250.00,
|
||||
'data_scadenza' => Carbon::now()->addDays(20),
|
||||
'stato' => 'non_pagata',
|
||||
'descrizione' => 'Rata mensile marzo 2025',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'importo' => 250.00,
|
||||
'data_scadenza' => Carbon::now()->subDays(30),
|
||||
'data_pagamento' => Carbon::now()->subDays(25),
|
||||
'stato' => 'pagata',
|
||||
'descrizione' => 'Rata mensile dicembre 2024',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($rate as $rata) {
|
||||
Rata::create($rata);
|
||||
}
|
||||
|
||||
$this->info('💰 Create 4 rate di test');
|
||||
}
|
||||
|
||||
private function createTestAssemblee()
|
||||
{
|
||||
// TODO: Implementare assemblee quando la tabella sarà disponibile
|
||||
$this->info('⏭️ Creazione assemblee temporaneamente disabilitata');
|
||||
return;
|
||||
|
||||
// Prendi il primo stabile disponibile
|
||||
$stabile = Stabile::first();
|
||||
if (!$stabile) {
|
||||
$this->error('❌ Nessuno stabile trovato. Crea prima uno stabile.');
|
||||
return;
|
||||
}
|
||||
|
||||
$assemblee = [
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'titolo' => 'Assemblea Ordinaria Gennaio 2025',
|
||||
'data_assemblea' => Carbon::now()->addDays(15),
|
||||
'luogo' => 'Sala condominiale',
|
||||
'stato' => 'programmata',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id,
|
||||
'titolo' => 'Assemblea Straordinaria - Rifacimento tetto',
|
||||
'data_assemblea' => Carbon::now()->addDays(30),
|
||||
'luogo' => 'Sala condominiale',
|
||||
'stato' => 'bozza',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($assemblee as $assemblea) {
|
||||
Assemblea::create($assemblea);
|
||||
}
|
||||
|
||||
$this->info('🏛️ Create 2 assemblee di test');
|
||||
}
|
||||
}
|
||||
82
netgescon-laravel/app/Console/Seeders/AllegatiSeeder.php
Normal file
82
netgescon-laravel/app/Console/Seeders/AllegatiSeeder.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\Allegato;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\User;
|
||||
use App\Models\MovimentoContabile;
|
||||
|
||||
class AllegatiSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seeder per la tabella allegati con dati di test realistici.
|
||||
* Segue le best practice Laravel con chiavi primarie 'id' standard.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Recupera alcuni stabili e utenti esistenti per le relazioni
|
||||
$stabili = Stabile::limit(3)->get();
|
||||
$users = User::limit(2)->get();
|
||||
$movimenti = MovimentoContabile::limit(5)->get();
|
||||
|
||||
$this->command->info("Trovati: {$stabili->count()} stabili, {$users->count()} utenti, {$movimenti->count()} movimenti");
|
||||
|
||||
if ($stabili->isEmpty() || $users->isEmpty()) {
|
||||
$this->command->warn('Assicurati che esistano stabili e utenti prima di eseguire questo seeder.');
|
||||
$this->command->info('Creazione dati di esempio senza relazioni...');
|
||||
}
|
||||
|
||||
$allegatiData = [
|
||||
[
|
||||
'stabile_id' => $stabili->first()?->id,
|
||||
'nome_file_originale' => 'Fattura_Energia_Gennaio_2025.pdf',
|
||||
'nome_file_storage' => 'fattura_energia_jan_2025_' . uniqid() . '.pdf',
|
||||
'percorso_file_storage' => 'allegati/fatture/2025/01/',
|
||||
'tipo_mime' => 'application/pdf',
|
||||
'dimensione_byte' => 245760, // ~240KB
|
||||
'descrizione' => 'Fattura energia elettrica gennaio 2025',
|
||||
'allegabile_type' => MovimentoContabile::class,
|
||||
'allegabile_id' => $movimenti->first()?->id,
|
||||
'user_id' => $users->first()?->id,
|
||||
'tags' => json_encode(['fattura', 'energia', 'utilities']),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabili->first()?->id,
|
||||
'nome_file_originale' => 'Preventivo_Manutenzione_Ascensore.docx',
|
||||
'nome_file_storage' => 'preventivo_ascensore_' . uniqid() . '.docx',
|
||||
'percorso_file_storage' => 'allegati/preventivi/2025/',
|
||||
'tipo_mime' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dimensione_byte' => 89120, // ~87KB
|
||||
'descrizione' => 'Preventivo per manutenzione straordinaria ascensore',
|
||||
'allegabile_type' => MovimentoContabile::class,
|
||||
'allegabile_id' => $movimenti->skip(1)->first()?->id,
|
||||
'user_id' => $users->first()?->id,
|
||||
'tags' => json_encode(['preventivo', 'ascensore', 'manutenzione']),
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabili->get(1)?->id ?? $stabili->first()?->id,
|
||||
'nome_file_originale' => 'Foto_Danni_Facciata.jpg',
|
||||
'nome_file_storage' => 'foto_danni_facciata_' . uniqid() . '.jpg',
|
||||
'percorso_file_storage' => 'allegati/foto/danni/2025/',
|
||||
'tipo_mime' => 'image/jpeg',
|
||||
'dimensione_byte' => 2097152, // ~2MB
|
||||
'descrizione' => 'Fotografia dei danni alla facciata ovest',
|
||||
'allegabile_type' => MovimentoContabile::class,
|
||||
'allegabile_id' => $movimenti->skip(2)->first()?->id,
|
||||
'user_id' => $users->last()?->id,
|
||||
'tags' => json_encode(['foto', 'danni', 'facciata']),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($allegatiData as $data) {
|
||||
// Crea l'allegato sempre, anche se alcune relazioni sono null
|
||||
$allegato = Allegato::create($data);
|
||||
$this->command->info("Creato allegato: {$data['nome_file_originale']} (ID: {$allegato->id}, Codice: {$allegato->codice_allegato})");
|
||||
}
|
||||
|
||||
$this->command->info('Seeder AllegatiSeeder completato con successo!');
|
||||
}
|
||||
}
|
||||
111
netgescon-laravel/app/Console/Seeders/AmministratoriSeeder.php
Normal file
111
netgescon-laravel/app/Console/Seeders/AmministratoriSeeder.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\Amministratore;
|
||||
use App\Models\User;
|
||||
use App\Models\Stabile;
|
||||
|
||||
class AmministratoriSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seeder per amministratori con codici alfanumerici e sistema multi-database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$this->command->info('Creazione amministratori di test...');
|
||||
|
||||
// Amministratore 1 - Con database dedicato
|
||||
$admin1 = Amministratore::create([
|
||||
'ragione_sociale' => 'Studio Amministrativo Rossi & Associati',
|
||||
'nome' => 'Mario',
|
||||
'cognome' => 'Rossi',
|
||||
'codice_fiscale' => 'RSSMRA70A01H501X',
|
||||
'partita_iva' => '12345678901',
|
||||
'email' => 'mario.rossi@studiorossi.it',
|
||||
'telefono' => '06-12345678',
|
||||
'cellulare' => '335-1234567',
|
||||
'indirizzo' => 'Via Roma 123',
|
||||
'cap' => '00100',
|
||||
'citta' => 'Roma',
|
||||
'provincia' => 'RM',
|
||||
'database_attivo' => true,
|
||||
'commissione_percentuale' => 2.50,
|
||||
'costo_fisso_mensile' => 150.00,
|
||||
'stato' => 'attivo',
|
||||
'data_inizio_attivita' => '2024-01-01',
|
||||
]);
|
||||
|
||||
// Amministratore 2 - Database condiviso
|
||||
$admin2 = Amministratore::create([
|
||||
'ragione_sociale' => 'Amministrazioni Bianchi SRL',
|
||||
'nome' => 'Laura',
|
||||
'cognome' => 'Bianchi',
|
||||
'codice_fiscale' => 'BNCLRA80B02H501Y',
|
||||
'partita_iva' => '09876543210',
|
||||
'email' => 'laura.bianchi@ammbianchi.it',
|
||||
'telefono' => '06-87654321',
|
||||
'cellulare' => '339-9876543',
|
||||
'indirizzo' => 'Via Milano 456',
|
||||
'cap' => '00200',
|
||||
'citta' => 'Roma',
|
||||
'provincia' => 'RM',
|
||||
'database_attivo' => false,
|
||||
'commissione_percentuale' => 3.00,
|
||||
'costo_fisso_mensile' => 100.00,
|
||||
'stato' => 'attivo',
|
||||
'data_inizio_attivita' => '2024-06-01',
|
||||
]);
|
||||
|
||||
$this->command->info("Creati amministratori:");
|
||||
$this->command->info("- {$admin1->ragione_sociale} (Codice: {$admin1->codice_amministratore})");
|
||||
$this->command->info("- {$admin2->ragione_sociale} (Codice: {$admin2->codice_amministratore})");
|
||||
|
||||
// Crea stabili di test per i due amministratori
|
||||
$this->createStabiliPerAmministratori($admin1, $admin2);
|
||||
|
||||
$this->command->info('Seeder AmministratoriSeeder completato con successo!');
|
||||
}
|
||||
|
||||
private function createStabiliPerAmministratori($admin1, $admin2)
|
||||
{
|
||||
// Stabili per Amministratore 1
|
||||
Stabile::create([
|
||||
'amministratore_id' => $admin1->id,
|
||||
'denominazione' => 'Condominio Villa Roma',
|
||||
'indirizzo' => 'Via del Corso 100',
|
||||
'cap' => '00186',
|
||||
'citta' => 'Roma',
|
||||
'provincia' => 'RM',
|
||||
'codice_fiscale' => 'VLRM001234567890',
|
||||
'stato' => 'attivo',
|
||||
]);
|
||||
|
||||
Stabile::create([
|
||||
'amministratore_id' => $admin1->id,
|
||||
'denominazione' => 'Condominio Sole Nascente',
|
||||
'indirizzo' => 'Via Nazionale 250',
|
||||
'cap' => '00184',
|
||||
'citta' => 'Roma',
|
||||
'provincia' => 'RM',
|
||||
'codice_fiscale' => 'SLNS001234567891',
|
||||
'stato' => 'attivo',
|
||||
]);
|
||||
|
||||
// Stabili per Amministratore 2
|
||||
Stabile::create([
|
||||
'amministratore_id' => $admin2->id,
|
||||
'denominazione' => 'Condominio Verde Pineta',
|
||||
'indirizzo' => 'Via Tiburtina 500',
|
||||
'cap' => '00159',
|
||||
'citta' => 'Roma',
|
||||
'provincia' => 'RM',
|
||||
'codice_fiscale' => 'VRDP001234567892',
|
||||
'stato' => 'attivo',
|
||||
]);
|
||||
|
||||
$this->command->info("Creati stabili di test per entrambi gli amministratori");
|
||||
}
|
||||
}
|
||||
22
netgescon-laravel/app/Console/Seeders/DatabaseSeeder.php
Normal file
22
netgescon-laravel/app/Console/Seeders/DatabaseSeeder.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Chiama solo il seeder che abbiamo creato.
|
||||
$this->call([
|
||||
// SuperAdminSeeder::class, // Questo seeder è ora inglobato in TestSetupSeeder
|
||||
\App\Console\Seeders\TestSetupSeeder::class, // Chiama il seeder principale di setup
|
||||
\App\Console\Seeders\ImpostazioniSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
56
netgescon-laravel/app/Console/Seeders/ImpostazioniSeeder.php
Normal file
56
netgescon-laravel/app/Console/Seeders/ImpostazioniSeeder.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
namespace App\Console\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ImpostazioniSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
DB::table('impostazioni')->insertOrIgnore([
|
||||
[
|
||||
'chiave' => 'sidebar_bg',
|
||||
'valore' => '#fde047',
|
||||
'descrizione' => 'Colore di sfondo sidebar (giallo)',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_text',
|
||||
'valore' => '#1e293b',
|
||||
'descrizione' => 'Colore testo sidebar',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_accent',
|
||||
'valore' => '#6366f1',
|
||||
'descrizione' => 'Colore accento sidebar (indigo)',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_bg_dark',
|
||||
'valore' => '#23272e',
|
||||
'descrizione' => 'Colore sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_text_dark',
|
||||
'valore' => '#f1f5f9',
|
||||
'descrizione' => 'Colore testo sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_accent_dark',
|
||||
'valore' => '#fbbf24',
|
||||
'descrizione' => 'Colore accento sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Seeders;
|
||||
|
||||
use App\Models\MovimentoContabile;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class MovimentiContabiliSeeder extends Seeder
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
// Recupera uno stabile e un utente per i test
|
||||
$stabile = Stabile::first();
|
||||
$user = User::first();
|
||||
|
||||
if (!$stabile || !$user) {
|
||||
$this->command->error('Mancano Stabili o Utenti. Esegui prima gli altri seeder.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->command->info('Creazione movimenti contabili di test...');
|
||||
|
||||
// Movimenti in Prima Nota
|
||||
$movimentiPrimaNota = [
|
||||
[
|
||||
'stabile_id' => $stabile->id, // Usa 'id' invece di 'id_stabile'
|
||||
'data_registrazione' => now()->subDays(5),
|
||||
'descrizione' => 'Fattura elettrica Enel - Gen 2025',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 156.78,
|
||||
'iva' => 33.92,
|
||||
'importo_netto' => 122.86,
|
||||
'stato_movimento' => 'prima_nota',
|
||||
'numero_documento' => 'ENEL2025001',
|
||||
'protocollo' => 'PROT001/2025',
|
||||
'creato_da' => $user->id,
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id, // Usa 'id' invece di 'id_stabile'
|
||||
'data_registrazione' => now()->subDays(3),
|
||||
'descrizione' => 'Fattura gas Eni - Gen 2025',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 89.45,
|
||||
'iva' => 19.48,
|
||||
'importo_netto' => 69.97,
|
||||
'stato_movimento' => 'prima_nota',
|
||||
'numero_documento' => 'ENI2025001',
|
||||
'protocollo' => 'PROT002/2025',
|
||||
'creato_da' => $user->id,
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id, // Usa 'id' invece di 'id_stabile'
|
||||
'data_registrazione' => now()->subDays(2),
|
||||
'descrizione' => 'Rata condominiale Gennaio 2025',
|
||||
'tipo_movimento' => 'entrata',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 2340.00,
|
||||
'iva' => 0.00,
|
||||
'importo_netto' => 2340.00,
|
||||
'stato_movimento' => 'prima_nota',
|
||||
'protocollo' => 'PROT003/2025',
|
||||
'creato_da' => $user->id,
|
||||
]
|
||||
];
|
||||
|
||||
// Movimenti già Confermati
|
||||
$movimentiConfermati = [
|
||||
[
|
||||
'stabile_id' => $stabile->id, // Usa 'id' invece di 'id_stabile'
|
||||
'data_registrazione' => now()->subDays(10),
|
||||
'descrizione' => 'Pulizia scale - Dicembre 2024',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'ordinario',
|
||||
'importo_totale' => 250.00,
|
||||
'iva' => 55.00,
|
||||
'importo_netto' => 195.00,
|
||||
'stato_movimento' => 'confermato',
|
||||
'data_conferma' => now()->subDays(8),
|
||||
'confermato_da' => $user->id,
|
||||
'numero_documento' => 'PULIZIE001',
|
||||
'protocollo' => 'PROT020/2024',
|
||||
'creato_da' => $user->id,
|
||||
],
|
||||
[
|
||||
'stabile_id' => $stabile->id, // Usa 'id' invece di 'id_stabile'
|
||||
'data_registrazione' => now()->subDays(15),
|
||||
'descrizione' => 'Riparazione ascensore',
|
||||
'tipo_movimento' => 'uscita',
|
||||
'categoria_movimento' => 'straordinario',
|
||||
'importo_totale' => 850.00,
|
||||
'iva' => 187.00,
|
||||
'importo_netto' => 663.00,
|
||||
'stato_movimento' => 'confermato',
|
||||
'data_conferma' => now()->subDays(12),
|
||||
'confermato_da' => $user->id,
|
||||
'numero_documento' => 'ASC2024001',
|
||||
'protocollo' => 'PROT019/2024',
|
||||
'creato_da' => $user->id,
|
||||
]
|
||||
];
|
||||
|
||||
// Crea movimenti in prima nota
|
||||
foreach ($movimentiPrimaNota as $movimento) {
|
||||
MovimentoContabile::create($movimento);
|
||||
}
|
||||
|
||||
// Crea movimenti confermati
|
||||
foreach ($movimentiConfermati as $movimento) {
|
||||
MovimentoContabile::create($movimento);
|
||||
}
|
||||
|
||||
$this->command->info('Creati ' . count($movimentiPrimaNota) . ' movimenti in Prima Nota');
|
||||
$this->command->info('Creati ' . count($movimentiConfermati) . ' movimenti Confermati');
|
||||
$this->command->info('Seeder MovimentiContabili completato!');
|
||||
}
|
||||
}
|
||||
379
netgescon-laravel/app/Console/Seeders/TestSetupSeeder.php
Normal file
379
netgescon-laravel/app/Console/Seeders/TestSetupSeeder.php
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Models\User;
|
||||
use App\Models\Amministratore;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\Soggetto;
|
||||
use App\Models\Proprieta;
|
||||
use App\Models\TabellaMillesimale;
|
||||
use App\Models\DettaglioTabellaMillesimale;
|
||||
use App\Models\PianoContiCondominio;
|
||||
use App\Models\Gestione;
|
||||
use App\Models\Preventivo;
|
||||
use App\Models\VocePreventivo;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
// Assicurati di avere i modelli e le migrazioni corretti prima di eseguire questo seeder.
|
||||
// Questo seeder crea un ambiente di test con un utente Super Admin, un Amministratore, un Condominio e alcune Unità Immobiliari con Soggetti associati.
|
||||
// Assicurati di eseguire questo seeder con il comando `php artisan db:seed --class=TestSetupSeeder` per popolare il database con i dati di test.
|
||||
// Puoi modificare le email e le password per adattarle alle tue esigenze di test.
|
||||
// Assicurati di avere i modelli e le migrazioni corretti prima di eseguire questo seeder.
|
||||
// Questo seeder è utile per testare le funzionalità del tuo gestionale senza dover inserire manualmente i dati ogni volta.
|
||||
// Puoi anche estendere questo seeder per aggiungere ulteriori dati di test come spese, entrate, verbali, ecc.
|
||||
// Assicurati di avere le relazioni corrette nei modelli Soggetto, UnitaImmobiliare e SoggettoUnita per gestire le associazioni tra soggetti e unità immobiliari.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
|
||||
|
||||
class TestSetupSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Pulisce la cache dei permessi
|
||||
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
||||
|
||||
// 1. Crea i ruoli
|
||||
// Usa Spatie\Permission\Models\Role per assegnare i ruoli
|
||||
$superAdminRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'super-admin', 'guard_name' => 'web']);
|
||||
// Ruoli in italiano per la gestione condominiale
|
||||
$amministratoreRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'amministratore', 'guard_name' => 'web']);
|
||||
$collaboratoreRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'collaboratore', 'guard_name' => 'web']);
|
||||
$condominoRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'condomino', 'guard_name' => 'web']);
|
||||
$fornitoreRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'fornitore', 'guard_name' => 'web']);
|
||||
$inquilinoRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'inquilino', 'guard_name' => 'web']);
|
||||
$ospiteRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'ospite', 'guard_name' => 'web']);
|
||||
$serviziRole = \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'servizi', 'guard_name' => 'web']);
|
||||
$this->command->info('Ruoli creati/verificati.');
|
||||
|
||||
// Ruoli di base per sviluppo (rimosso uso di App\Models\Role e campo label)
|
||||
// Tutti i ruoli sono ora gestiti solo tramite Spatie\Permission\Models\Role
|
||||
|
||||
|
||||
// 2. Crea l'utente Super Admin
|
||||
// Rimosso il campo 'role' diretto, verrà assegnato tramite Spatie
|
||||
|
||||
$superAdmin = User::firstOrCreate(
|
||||
['email' => 'superadmin@example.com'],
|
||||
[
|
||||
'name' => 'Super Admin',
|
||||
'password' => Hash::make('password'), // Cambia questa password in produzione!
|
||||
'email_verified_at' => now(),
|
||||
|
||||
]
|
||||
);
|
||||
// Il ruolo 'super-admin' verrà assegnato tramite Spatie
|
||||
$this->command->info('Utente Super Admin creato/aggiornato: ' . $superAdmin->email); // Variabile corretta
|
||||
|
||||
// 2. Crea un Utente Amministratore
|
||||
$adminUser = User::firstOrCreate(
|
||||
['email' => 'admin@example.com'],
|
||||
[
|
||||
'name' => 'Amministratore Test',
|
||||
'password' => Hash::make('password'), // Cambia questa password in produzione!
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
// Il ruolo 'admin' verrà assegnato tramite Spatie
|
||||
$this->command->info('Utente Amministratore creato/aggiornato: ' . $adminUser->email);
|
||||
|
||||
// 3. Crea un Record Amministratore (collegato all'utente admin)
|
||||
$amministratore = Amministratore::firstOrCreate(
|
||||
['user_id' => $adminUser->id],
|
||||
[
|
||||
'nome' => 'Mario',
|
||||
'cognome' => 'Rossi',
|
||||
'denominazione_studio' => 'Studio Rossi Amministrazioni',
|
||||
'partita_iva' => '12345678901',
|
||||
'codice_fiscale_studio' => 'RSSMRA80A01H501K',
|
||||
'indirizzo_studio' => 'Via Roma 10',
|
||||
'cap_studio' => '00100',
|
||||
'citta_studio' => 'Roma',
|
||||
'provincia_studio' => 'RM',
|
||||
'telefono_studio' => '061234567',
|
||||
'email_studio' => 'studio.rossi@example.com',
|
||||
'pec_studio' => 'studio.rossi@pec.it',
|
||||
]
|
||||
);
|
||||
$this->command->info('Record Amministratore creato/aggiornato: ' . $amministratore->nome . ' ' . $amministratore->cognome);
|
||||
|
||||
// 4. Crea un Condominio di Test
|
||||
$stabile = Stabile::firstOrCreate(
|
||||
['denominazione' => 'Stabile Test Via Milano 1'],
|
||||
[
|
||||
'amministratore_id' => $amministratore->id_amministratore,
|
||||
'indirizzo' => 'Via Milano 1',
|
||||
'cap' => '20100',
|
||||
'citta' => 'Milano',
|
||||
'provincia' => 'MI',
|
||||
'codice_fiscale' => 'CNDMLN00001A001A',
|
||||
'note' => 'Condominio di test per lo sviluppo.',
|
||||
'stato' => 'attivo',
|
||||
]
|
||||
);
|
||||
$this->command->info('Stabile di Test creato/aggiornato: ' . $stabile->denominazione);
|
||||
|
||||
// 5. Crea Unità Immobiliari di Test
|
||||
$unita1 = UnitaImmobiliare::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'interno' => '1', 'scala' => 'A', 'fabbricato' => 'Principale'],
|
||||
|
||||
|
||||
[
|
||||
'piano' => '1',
|
||||
'subalterno' => '1',
|
||||
'categoria_catastale' => 'A/3',
|
||||
'superficie' => 80.50,
|
||||
'vani' => 4.5,
|
||||
'indirizzo' => null,
|
||||
'note' => 'Appartamento di test A1',
|
||||
]
|
||||
);
|
||||
$unita2 = UnitaImmobiliare::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'interno' => '2', 'scala' => 'A', 'fabbricato' => 'Principale'],
|
||||
[
|
||||
'piano' => '1',
|
||||
'subalterno' => '2',
|
||||
'categoria_catastale' => 'A/3',
|
||||
'superficie' => 70.00,
|
||||
'vani' => 3.5,
|
||||
'indirizzo' => null,
|
||||
'note' => 'Appartamento di test A2',
|
||||
]
|
||||
);
|
||||
$this->command->info('Unità Immobiliari di Test create.');
|
||||
|
||||
// 6. Crea Soggetti di Test
|
||||
$soggettoProprietario1 = Soggetto::firstOrCreate(['email' => 'proprietario1@example.com'], ['nome' => 'Giuseppe', 'cognome' => 'Verdi', 'tipo' => 'proprietario', 'codice_fiscale' => 'VRDGPP80A01H501A']);
|
||||
$soggettoProprietario2 = Soggetto::firstOrCreate(['email' => 'proprietario2@example.com'], ['nome' => 'Maria', 'cognome' => 'Bianchi', 'tipo' => 'proprietario', 'codice_fiscale' => 'BNCMRA85B02H502B']);
|
||||
$soggettoInquilino = Soggetto::firstOrCreate(['email' => 'inquilino@example.com'], ['nome' => 'Luca', 'cognome' => 'Neri', 'tipo' => 'inquilino', 'codice_fiscale' => 'NRELCA90C03H503C']);
|
||||
$this->command->info('Soggetti di Test creati.');
|
||||
|
||||
// 7. Collega Soggetti alle Unità (Proprieta)
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoProprietario1->id ?? $soggettoProprietario1->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita1->id ?? $unita1->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'proprietario',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2020-01-01'
|
||||
]);
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoProprietario1->id ?? $soggettoProprietario1->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita2->id ?? $unita2->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'nudo_proprietario',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2022-03-01'
|
||||
]);
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoProprietario2->id ?? $soggettoProprietario2->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita2->id ?? $unita2->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'usufruttuario',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2022-03-01'
|
||||
]);
|
||||
Proprieta::firstOrCreate([
|
||||
'soggetto_id' => $soggettoInquilino->id ?? $soggettoInquilino->id_soggetto,
|
||||
'unita_immobiliare_id' => $unita1->id ?? $unita1->id_unita
|
||||
], [
|
||||
'tipo_diritto' => 'inquilino',
|
||||
'percentuale_possesso' => 100.00,
|
||||
'data_inizio' => '2023-06-15'
|
||||
]);
|
||||
$this->command->info('Relazioni Soggetto-Unità create.');
|
||||
|
||||
// 8. Crea una Tabella Millesimale di Test
|
||||
$tabellaA = TabellaMillesimale::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'nome_tabella_millesimale' => 'Tabella A - Proprietà'],
|
||||
['descrizione' => 'Ripartizione spese in base ai millesimi di proprietà generale.']
|
||||
);
|
||||
// Fix: recupera la chiave primaria corretta se non presente
|
||||
if (!$tabellaA->id) {
|
||||
// Prova a ricaricare dal DB se firstOrCreate restituisce un oggetto senza la chiave primaria
|
||||
$tabellaA = TabellaMillesimale::where('stabile_id', $stabile->id)
|
||||
->where('nome_tabella_millesimale', 'Tabella A - Proprietà')
|
||||
->first();
|
||||
}
|
||||
if (!$tabellaA || !$tabellaA->id) {
|
||||
$this->command->error('Errore: la tabella millesimale non è stata creata correttamente!');
|
||||
return;
|
||||
}
|
||||
$this->command->info('Tabella Millesimale di Test creata.');
|
||||
|
||||
// 9. Crea Dettagli Millesimali per le unità
|
||||
DettaglioTabellaMillesimale::firstOrCreate(
|
||||
['tabella_millesimale_id' => $tabellaA->id, 'unita_immobiliare_id' => $unita1->id ?? $unita1->id_unita],
|
||||
['millesimi' => 500.0000]
|
||||
);
|
||||
DettaglioTabellaMillesimale::firstOrCreate(
|
||||
['tabella_millesimale_id' => $tabellaA->id, 'unita_immobiliare_id' => $unita2->id ?? $unita2->id_unita],
|
||||
['millesimi' => 500.0000]
|
||||
);
|
||||
$this->command->info('Dettagli Millesimali creati.');
|
||||
|
||||
// 10. Crea una Gestione di Test
|
||||
$gestione2024 = Gestione::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'anno_gestione' => 2024, 'tipo_gestione' => 'Ord.'],
|
||||
['data_inizio' => '2024-01-01', 'data_fine' => '2024-12-31', 'stato' => 'aperta']
|
||||
);
|
||||
$this->command->info('Gestione di Test creata.');
|
||||
|
||||
// Aggiungiamo anche la gestione 2025
|
||||
$gestione2025 = Gestione::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'anno_gestione' => 2025, 'tipo_gestione' => 'Ord.'],
|
||||
['data_inizio' => '2025-01-01', 'stato' => 'aperta']
|
||||
);
|
||||
$this->command->info('Gestione 2025 creata.');
|
||||
|
||||
// 11. Crea un Piano dei Conti per lo Stabile (esempio base)
|
||||
$contoPulizie = PianoContiCondominio::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'codice' => 'SP.PUL'],
|
||||
['descrizione' => 'Spese di Pulizia Scale', 'tipo_conto' => 'ECONOMICO_COSTO']
|
||||
);
|
||||
$contoAssicurazione = PianoContiCondominio::firstOrCreate(
|
||||
['stabile_id' => $stabile->id, 'codice' => 'SP.ASS'],
|
||||
['descrizione' => 'Assicurazione Fabbricato', 'tipo_conto' => 'ECONOMICO_COSTO']
|
||||
);
|
||||
$this->command->info('Piano dei Conti di Test creato.');
|
||||
|
||||
/*// 12. Crea un Preventivo di Test
|
||||
$preventivo2024 = Preventivo::firstOrCreate(
|
||||
['id_gestione' => $gestione2024->id_gestione],
|
||||
['descrizione' => 'Preventivo Ordinario 2024', 'stato' => 'APPROVATO']
|
||||
);
|
||||
$this->command->info('Preventivo di Test creato.');
|
||||
|
||||
// 13. Crea Voci di Preventivo
|
||||
VocePreventivo::firstOrCreate(['id_preventivo' => $preventivo2024->id_preventivo, 'id_piano_conto_condominio_pc' => $contoPulizie->id_conto_condominio_pc], ['importo_previsto' => 1200.00, 'id_tabella_millesimale_ripartizione' => $tabellaA->id_tabella_millesimale]);
|
||||
VocePreventivo::firstOrCreate(['id_preventivo' => $preventivo2024->id_preventivo, 'id_piano_conto_condominio_pc' => $contoAssicurazione->id_conto_condominio_pc], ['importo_previsto' => 800.00, 'id_tabella_millesimale_ripartizione' => $tabellaA->id_tabella_millesimale]);
|
||||
$this->command->info('Voci di Preventivo create.'); */
|
||||
|
||||
// Creazione Permessi (Esempio)
|
||||
$gestioneCondominiPermission = Permission::firstOrCreate(['name' => 'gestione-condomini']);
|
||||
$visualizzaReportPermission = Permission::firstOrCreate(['name' => 'visualizza-report']);
|
||||
|
||||
Permission::firstOrCreate(['name' => 'view-stabili']);
|
||||
Permission::firstOrCreate(['name' => 'manage-stabili']); // Permesso generico per le azioni CRUD
|
||||
|
||||
|
||||
// Permessi per la gestione utenti (Super Admin)
|
||||
Permission::firstOrCreate(['name' => 'create-users']);
|
||||
Permission::firstOrCreate(['name' => 'view-users']);
|
||||
Permission::firstOrCreate(['name' => 'manage-users']); // Include create, edit, delete, update role
|
||||
Permission::firstOrCreate(['name' => 'impersonate-users']);
|
||||
|
||||
// Permessi per la gestione amministratori (Super Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-amministratori']);
|
||||
Permission::firstOrCreate(['name' => 'manage-amministratori']); // Include create, edit, delete
|
||||
|
||||
// Permessi per la gestione categorie ticket (Super Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-categorie-ticket']);
|
||||
Permission::firstOrCreate(['name' => 'manage-categorie-ticket']); // Include create, edit, delete
|
||||
|
||||
// Permessi per la gestione soggetti (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-soggetti']);
|
||||
Permission::firstOrCreate(['name' => 'manage-soggetti']); // Include create, edit, delete
|
||||
|
||||
// Permessi per la gestione fornitori (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-fornitori']);
|
||||
Permission::firstOrCreate(['name' => 'manage-fornitori']);
|
||||
|
||||
// Permessi per la gestione ticket (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-tickets']);
|
||||
Permission::firstOrCreate(['name' => 'manage-tickets']);
|
||||
|
||||
// Permessi per la gestione unità immobiliari (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-unita-immobiliari']);
|
||||
Permission::firstOrCreate(['name' => 'manage-unita-immobiliari']);
|
||||
|
||||
// Permessi per le impostazioni e API Tokens (Admin)
|
||||
Permission::firstOrCreate(['name' => 'view-impostazioni']);
|
||||
Permission::firstOrCreate(['name' => 'manage-api-tokens']);
|
||||
Permission::firstOrCreate(['name' => 'view-rubrica']);
|
||||
|
||||
|
||||
// Aggiungi qui altri permessi specifici per il tuo progetto
|
||||
|
||||
|
||||
// Assegnazione Permessi ai Ruoli (Esempio)
|
||||
$amministratoreRole = \Spatie\Permission\Models\Role::where('name', 'amministratore')->first();
|
||||
$adminRole = \Spatie\Permission\Models\Role::where('name', 'admin')->first();
|
||||
$superAdminRole = \Spatie\Permission\Models\Role::where('name', 'super-admin')->first();
|
||||
|
||||
$amministratoreRole = \Spatie\Permission\Models\Role::where('name', 'amministratore')->first();
|
||||
if ($amministratoreRole) {
|
||||
$amministratoreRole->givePermissionTo([
|
||||
'visualizza-report',
|
||||
'view-stabili', 'manage-stabili',
|
||||
'view-soggetti', 'manage-soggetti',
|
||||
'view-fornitori', 'manage-fornitori',
|
||||
'view-tickets', 'manage-tickets',
|
||||
'view-unita-immobiliari', 'manage-unita-immobiliari',
|
||||
'view-impostazioni', 'manage-api-tokens', 'view-rubrica',
|
||||
]);
|
||||
} else {
|
||||
$this->command->warn("Ruolo 'amministratore' non trovato: permessi non assegnati.");
|
||||
}
|
||||
|
||||
|
||||
// Assegna i permessi al ruolo 'admin'
|
||||
$adminRole->givePermissionTo([
|
||||
'view-soggetti', 'manage-soggetti',
|
||||
'view-fornitori', 'manage-fornitori',
|
||||
'view-tickets', 'manage-tickets',
|
||||
'view-unita-immobiliari', 'manage-unita-immobiliari',
|
||||
'view-impostazioni', 'manage-api-tokens', 'view-rubrica',
|
||||
]);
|
||||
|
||||
|
||||
// Assegna il ruolo 'amministratore' all'utente di test per permettergli di gestire gli stabili
|
||||
if ($amministratoreRole) {
|
||||
$adminUser->assignRole('amministratore');
|
||||
} else {
|
||||
$this->command->warn("Ruolo 'amministratore' non trovato: non assegnato all'utente di test.");
|
||||
}
|
||||
|
||||
|
||||
// Assegna tutti i permessi al Super Admin
|
||||
$superAdminRole->givePermissionTo(Permission::all());
|
||||
$superAdmin->assignRole('super-admin');
|
||||
|
||||
$this->command->info('Setup di test completato con successo!');
|
||||
}
|
||||
}
|
||||
// Questo seeder crea un ambiente di test con un utente Super Admin, un Amministratore, un Condominio e alcune Unità Immobiliari con Soggetti associati.
|
||||
// Assicurati di eseguire questo seeder con il comando `php artisan db:seed --class=TestSetupSeeder` per popolare il database con i dati di test.
|
||||
// Puoi modificare le email e le password per adattarle alle tue esigenze di test.
|
||||
// Assicurati di avere i modelli e le migrazioni corretti prima di eseguire questo seeder.
|
||||
// Questo seeder è utile per testare le funzionalità del tuo gestionale senza dover inserire manualmente i dati ogni volta.
|
||||
// Puoi anche estendere questo seeder per aggiungere ulteriori dati di test come spese, entrate, verbali, ecc.
|
||||
// Assicurati di avere le relazioni corrette nei modelli Soggetto, UnitaImmobiliare e SoggettoUnita per gestire le associazioni tra soggetti e unità immobiliari.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Assicurati di eseguire il seeder in un ambiente di sviluppo o test, non in produzione, per evitare conflitti con i dati reali.
|
||||
// Ricorda di aggiornare le password e le email in produzione per garantire la sicurezza del tuo gestionale.
|
||||
// Questo seeder è progettato per essere eseguito una sola volta per impostare un ambiente di test iniziale.
|
||||
// Puoi eseguire nuovamente il seeder per ripristinare lo stato di test, ma fai attenzione a non duplicare i dati esistenti.
|
||||
// Se hai bisogno di modificare i dati di test, puoi farlo direttamente nel seeder o creare nuovi seeders per aggiungere ulteriori dati.
|
||||
// Assicurati di avere le dipendenze corrette nel tuo progetto Laravel per eseguire questo seeder senza errori.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Assicurati di eseguire il seeder in un ambiente di sviluppo o test, non in produzione, per evitare conflitti con i dati reali.
|
||||
// Ricorda di aggiornare le password e le email in produzione per garantire la sicurezza del tuo gestionale.
|
||||
// Questo seeder è progettato per essere eseguito una sola volta per impostare un ambiente di test iniziale.
|
||||
// Puoi eseguire nuovamente il seeder per ripristinare lo stato di test, ma fai attenzione a non duplicare i dati esistenti.
|
||||
// Se hai bisogno di modificare i dati di test, puoi farlo direttamente nel seeder o creare nuovi seeders per aggiungere ulteriori dati.
|
||||
// Assicurati di avere le dipendenze corrette nel tuo progetto Laravel per eseguire questo seeder senza errori.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
// Questo seeder è un ottimo punto di partenza per testare le funzionalità del tuo gestionale e garantire che tutto funzioni correttamente.
|
||||
// Puoi anche utilizzare questo seeder come base per creare altri seeders specifici per le tue esigenze di test.
|
||||
252
netgescon-laravel/app/Helpers/DashboardDataHelper.php
Normal file
252
netgescon-laravel/app/Helpers/DashboardDataHelper.php
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Soggetto;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Fornitore;
|
||||
use App\Models\Rata;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\Assemblea;
|
||||
use App\Models\MovimentoContabile;
|
||||
use App\Models\Documento;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DashboardDataHelper
|
||||
{
|
||||
/**
|
||||
* Ottiene dati reali per la dashboard principale
|
||||
*/
|
||||
public static function getDashboardData()
|
||||
{
|
||||
return Cache::remember('dashboard_data', 300, function () {
|
||||
return [
|
||||
'stabili' => self::getStabiliData(),
|
||||
'condomini' => self::getCondominiData(),
|
||||
'contabilita' => self::getContabilitaData(),
|
||||
'tickets' => self::getTicketsData(),
|
||||
'assemblee' => self::getAssembleeData(),
|
||||
'sistema' => self::getSistemaData(),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dati degli stabili con dettagli aggiuntivi
|
||||
*/
|
||||
private static function getStabiliData()
|
||||
{
|
||||
try {
|
||||
$totaleStabili = Stabile::count();
|
||||
$stabiliAttivi = Stabile::where('stato', 'attivo')->count();
|
||||
$unitaTotali = UnitaImmobiliare::count();
|
||||
$unitaOccupate = UnitaImmobiliare::whereHas('proprietari')->count();
|
||||
|
||||
return [
|
||||
'totale' => $totaleStabili,
|
||||
'attivi' => $stabiliAttivi,
|
||||
'inattivi' => $totaleStabili - $stabiliAttivi,
|
||||
'unita_totali' => $unitaTotali,
|
||||
'unita_occupate' => $unitaOccupate,
|
||||
'unita_libere' => $unitaTotali - $unitaOccupate,
|
||||
'percentuale_occupazione' => $unitaTotali > 0 ? round(($unitaOccupate / $unitaTotali) * 100, 1) : 0,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'totale' => 0, 'attivi' => 0, 'inattivi' => 0,
|
||||
'unita_totali' => 0, 'unita_occupate' => 0, 'unita_libere' => 0,
|
||||
'percentuale_occupazione' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dati dei condomini con classificazioni
|
||||
*/
|
||||
private static function getCondominiData()
|
||||
{
|
||||
try {
|
||||
$totaleCondomini = Soggetto::count();
|
||||
$proprietari = Soggetto::where('tipo', 'proprietario')->count();
|
||||
$inquilini = Soggetto::where('tipo', 'inquilino')->count();
|
||||
|
||||
return [
|
||||
'totale' => $totaleCondomini,
|
||||
'proprietari' => $proprietari,
|
||||
'inquilini' => $inquilini,
|
||||
'altri' => $totaleCondomini - $proprietari - $inquilini,
|
||||
'percentuale_proprietari' => $totaleCondomini > 0 ? round(($proprietari / $totaleCondomini) * 100, 1) : 0,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'totale' => 0, 'proprietari' => 0, 'inquilini' => 0, 'altri' => 0,
|
||||
'percentuale_proprietari' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dati della contabilità con trend
|
||||
*/
|
||||
private static function getContabilitaData()
|
||||
{
|
||||
try {
|
||||
$oggi = Carbon::now();
|
||||
$meseScorso = $oggi->copy()->subMonth();
|
||||
|
||||
$rateScadute = Rata::where('data_scadenza', '<', $oggi)
|
||||
->where('stato', '!=', 'pagata')
|
||||
->count();
|
||||
|
||||
$incassiMeseCorrente = Rata::whereMonth('data_pagamento', $oggi->month)
|
||||
->whereYear('data_pagamento', $oggi->year)
|
||||
->where('stato', 'pagata')
|
||||
->sum('importo');
|
||||
|
||||
$incassiMeseScorso = Rata::whereMonth('data_pagamento', $meseScorso->month)
|
||||
->whereYear('data_pagamento', $meseScorso->year)
|
||||
->where('stato', 'pagata')
|
||||
->sum('importo');
|
||||
|
||||
return [
|
||||
'rate_scadute' => $rateScadute,
|
||||
'rate_del_mese' => Rata::whereMonth('data_scadenza', $oggi->month)
|
||||
->whereYear('data_scadenza', $oggi->year)
|
||||
->count(),
|
||||
'incassi_mese_corrente' => $incassiMeseCorrente,
|
||||
'incassi_mese_scorso' => $incassiMeseScorso,
|
||||
'trend_incassi' => $incassiMeseScorso > 0 ?
|
||||
round((($incassiMeseCorrente - $incassiMeseScorso) / $incassiMeseScorso) * 100, 1) : 0,
|
||||
'movimenti_mese' => MovimentoContabile::whereMonth('data_movimento', $oggi->month)
|
||||
->whereYear('data_movimento', $oggi->year)
|
||||
->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'rate_scadute' => 0, 'rate_del_mese' => 0,
|
||||
'incassi_mese_corrente' => 0, 'incassi_mese_scorso' => 0,
|
||||
'trend_incassi' => 0, 'movimenti_mese' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dati dei tickets con priorità e tempi
|
||||
*/
|
||||
private static function getTicketsData()
|
||||
{
|
||||
try {
|
||||
$ticketsAperti = Ticket::where('stato', 'aperto')->count();
|
||||
$ticketsUrgenti = Ticket::where('priorita', 'alta')
|
||||
->where('stato', '!=', 'chiuso')
|
||||
->count();
|
||||
$ticketsInLavorazione = Ticket::where('stato', 'in_lavorazione')->count();
|
||||
$ticketsChiusiOggi = Ticket::where('stato', 'chiuso')
|
||||
->whereDate('updated_at', Carbon::today())
|
||||
->count();
|
||||
|
||||
return [
|
||||
'aperti' => $ticketsAperti,
|
||||
'urgenti' => $ticketsUrgenti,
|
||||
'in_lavorazione' => $ticketsInLavorazione,
|
||||
'chiusi_oggi' => $ticketsChiusiOggi,
|
||||
'totali' => Ticket::count(),
|
||||
'percentuale_risoluzione' => $ticketsAperti + $ticketsInLavorazione > 0 ?
|
||||
round(($ticketsChiusiOggi / ($ticketsAperti + $ticketsInLavorazione + $ticketsChiusiOggi)) * 100, 1) : 100,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'aperti' => 0, 'urgenti' => 0, 'in_lavorazione' => 0,
|
||||
'chiusi_oggi' => 0, 'totali' => 0, 'percentuale_risoluzione' => 100
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dati delle assemblee con calendario
|
||||
*/
|
||||
private static function getAssembleeData()
|
||||
{
|
||||
try {
|
||||
$oggi = Carbon::now();
|
||||
$prossimi30Giorni = $oggi->copy()->addDays(30);
|
||||
|
||||
return [
|
||||
'prossime' => Assemblea::where('data_assemblea', '>', $oggi)->count(),
|
||||
'prossimi_30_giorni' => Assemblea::whereBetween('data_assemblea', [$oggi, $prossimi30Giorni])->count(),
|
||||
'questo_mese' => Assemblea::whereMonth('data_assemblea', $oggi->month)
|
||||
->whereYear('data_assemblea', $oggi->year)
|
||||
->count(),
|
||||
'delibere_da_approvare' => Assemblea::where('stato', 'bozza')->count(),
|
||||
'verbali_da_completare' => Assemblea::where('stato', 'verbale_incompleto')->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'prossime' => 0, 'prossimi_30_giorni' => 0, 'questo_mese' => 0,
|
||||
'delibere_da_approvare' => 0, 'verbali_da_completare' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dati generali del sistema
|
||||
*/
|
||||
private static function getSistemaData()
|
||||
{
|
||||
try {
|
||||
return [
|
||||
'utenti_attivi' => DB::table('users')->where('active', true)->count(),
|
||||
'ultimo_backup' => self::getLastBackupDate(),
|
||||
'spazio_documenti' => self::getDocumentsSpaceUsage(),
|
||||
'uptime' => self::getSystemUptime(),
|
||||
'versione' => config('app.version', '2.1.0'),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'utenti_attivi' => 1,
|
||||
'ultimo_backup' => 'Non disponibile',
|
||||
'spazio_documenti' => 'Non disponibile',
|
||||
'uptime' => 'Non disponibile',
|
||||
'versione' => '2.1.0'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene la data dell'ultimo backup
|
||||
*/
|
||||
private static function getLastBackupDate()
|
||||
{
|
||||
// Implementazione placeholder - sostituire con logica reale
|
||||
return Carbon::now()->subDays(1)->format('d/m/Y H:i');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene l'utilizzo dello spazio per i documenti
|
||||
*/
|
||||
private static function getDocumentsSpaceUsage()
|
||||
{
|
||||
// Implementazione placeholder - sostituire con logica reale
|
||||
return '245 MB utilizzati';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene l'uptime del sistema
|
||||
*/
|
||||
private static function getSystemUptime()
|
||||
{
|
||||
// Implementazione placeholder - sostituire con logica reale
|
||||
return '15 giorni, 8 ore';
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulisce la cache
|
||||
*/
|
||||
public static function clearCache()
|
||||
{
|
||||
Cache::forget('dashboard_data');
|
||||
}
|
||||
}
|
||||
105
netgescon-laravel/app/Helpers/MenuHelper.php
Normal file
105
netgescon-laravel/app/Helpers/MenuHelper.php
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class MenuHelper
|
||||
{
|
||||
/**
|
||||
* Verifica se l'utente può accedere a una specifica sezione del menu
|
||||
*/
|
||||
public static function canUserAccessMenu($menuSection, $userRole = null)
|
||||
{
|
||||
// Se non specificato, prende il ruolo dall'utente autenticato
|
||||
$userRole = $userRole ?? self::getCurrentUserRole();
|
||||
|
||||
// Definizione permessi per ogni ruolo
|
||||
$permissions = [
|
||||
'super_admin' => ['*'], // Accesso completo
|
||||
'admin' => [
|
||||
'dashboard', 'stabili', 'condomini', 'contabilita', 'fiscale',
|
||||
'assemblee', 'risorse-economiche', 'comunicazioni', 'affitti',
|
||||
'pratiche', 'consumi', 'tickets', 'impostazioni', 'utenti'
|
||||
],
|
||||
'amministratore' => [
|
||||
'dashboard', 'stabili', 'condomini', 'contabilita', 'fiscale',
|
||||
'assemblee', 'risorse-economiche', 'comunicazioni', 'affitti',
|
||||
'pratiche', 'consumi', 'tickets'
|
||||
],
|
||||
'collaboratore' => [
|
||||
'dashboard', 'stabili', 'condomini', 'contabilita',
|
||||
'comunicazioni', 'tickets', 'pratiche'
|
||||
],
|
||||
'ragioniere' => [
|
||||
'dashboard', 'contabilita', 'fiscale', 'risorse-economiche',
|
||||
'comunicazioni', 'tickets'
|
||||
],
|
||||
'condomino' => [
|
||||
'dashboard', 'comunicazioni', 'tickets'
|
||||
],
|
||||
'guest' => []
|
||||
];
|
||||
|
||||
// Super admin ha accesso a tutto
|
||||
if ($userRole === 'super_admin') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verifica permessi specifici
|
||||
$userPermissions = $permissions[$userRole] ?? [];
|
||||
return in_array($menuSection, $userPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper per controllare multiple sezioni
|
||||
*/
|
||||
public static function canUserAccessAnyMenu($menuSections, $userRole = null)
|
||||
{
|
||||
if (!is_array($menuSections)) {
|
||||
$menuSections = [$menuSections];
|
||||
}
|
||||
|
||||
foreach ($menuSections as $section) {
|
||||
if (self::canUserAccessMenu($section, $userRole)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene il ruolo utente corrente
|
||||
*/
|
||||
public static function getCurrentUserRole()
|
||||
{
|
||||
if (Auth::check()) {
|
||||
return Auth::user()->role ?? 'amministratore'; // Default per test
|
||||
}
|
||||
return 'guest';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica se l'utente ha un ruolo specifico o superiore
|
||||
*/
|
||||
public static function hasMinimumRole($requiredRole, $userRole = null)
|
||||
{
|
||||
$userRole = $userRole ?? self::getCurrentUserRole();
|
||||
|
||||
$roleHierarchy = [
|
||||
'guest' => 0,
|
||||
'condomino' => 1,
|
||||
'collaboratore' => 2,
|
||||
'ragioniere' => 2,
|
||||
'amministratore' => 3,
|
||||
'admin' => 4,
|
||||
'super_admin' => 5
|
||||
];
|
||||
|
||||
$userLevel = $roleHierarchy[$userRole] ?? 0;
|
||||
$requiredLevel = $roleHierarchy[$requiredRole] ?? 999;
|
||||
|
||||
return $userLevel >= $requiredLevel;
|
||||
}
|
||||
}
|
||||
199
netgescon-laravel/app/Helpers/SidebarStatsHelper.php
Normal file
199
netgescon-laravel/app/Helpers/SidebarStatsHelper.php
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Soggetto;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Fornitore;
|
||||
use App\Models\Rata;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\Assemblea;
|
||||
use App\Models\MovimentoContabile;
|
||||
use App\Models\Documento;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SidebarStatsHelper
|
||||
{
|
||||
/**
|
||||
* Ottiene statistiche per la sidebar con cache
|
||||
*/
|
||||
public static function getStats()
|
||||
{
|
||||
return Cache::remember('sidebar_stats', 300, function () { // Cache per 5 minuti
|
||||
return [
|
||||
'stabili' => self::getStabiliStats(),
|
||||
'condomini' => self::getCondominiStats(),
|
||||
'tickets' => self::getTicketsStats(),
|
||||
'contabilita' => self::getContabilitaStats(),
|
||||
'fornitori' => self::getFornitoriStats(),
|
||||
'assemblee' => self::getAssembleeStats(),
|
||||
'documenti' => self::getDocumentiStats(),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Stabili
|
||||
*/
|
||||
private static function getStabiliStats()
|
||||
{
|
||||
try {
|
||||
$totaleUnita = UnitaImmobiliare::count();
|
||||
$unitaOccupate = UnitaImmobiliare::whereHas('proprietari')->count();
|
||||
|
||||
return [
|
||||
'totale' => Stabile::count(),
|
||||
'attivi' => Stabile::where('stato', 'attivo')->count(),
|
||||
'unita_totali' => $totaleUnita,
|
||||
'unita_libere' => $totaleUnita - $unitaOccupate,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['totale' => 0, 'attivi' => 0, 'unita_totali' => 0, 'unita_libere' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Condomini
|
||||
*/
|
||||
private static function getCondominiStats()
|
||||
{
|
||||
try {
|
||||
return [
|
||||
'totale' => Soggetto::count(),
|
||||
'proprietari' => Soggetto::where('tipo', 'proprietario')->count(),
|
||||
'inquilini' => Soggetto::where('tipo', 'inquilino')->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['totale' => 0, 'proprietari' => 0, 'inquilini' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Tickets
|
||||
*/
|
||||
private static function getTicketsStats()
|
||||
{
|
||||
try {
|
||||
return [
|
||||
'aperti' => Ticket::where('stato', 'aperto')->count(),
|
||||
'urgenti' => Ticket::where('priorita', 'alta')
|
||||
->where('stato', '!=', 'chiuso')
|
||||
->count(),
|
||||
'in_lavorazione' => Ticket::where('stato', 'in_lavorazione')->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['aperti' => 0, 'urgenti' => 0, 'in_lavorazione' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Contabilità
|
||||
*/
|
||||
private static function getContabilitaStats()
|
||||
{
|
||||
try {
|
||||
$oggi = Carbon::now();
|
||||
$meseCorrente = $oggi->format('Y-m');
|
||||
|
||||
return [
|
||||
'rate_scadute' => Rata::where('data_scadenza', '<', $oggi)
|
||||
->where('stato', '!=', 'pagata')
|
||||
->count(),
|
||||
'incassi_mese' => Rata::whereMonth('data_pagamento', $oggi->month)
|
||||
->whereYear('data_pagamento', $oggi->year)
|
||||
->where('stato', 'pagata')
|
||||
->sum('importo'),
|
||||
'movimenti_mese' => MovimentoContabile::whereMonth('data_movimento', $oggi->month)
|
||||
->whereYear('data_movimento', $oggi->year)
|
||||
->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['rate_scadute' => 0, 'incassi_mese' => 0, 'movimenti_mese' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Fornitori
|
||||
*/
|
||||
private static function getFornitoriStats()
|
||||
{
|
||||
try {
|
||||
return [
|
||||
'totale' => Fornitore::count(),
|
||||
'attivi' => Fornitore::where('stato', 'attivo')->count(),
|
||||
'fatture_pending' => 0, // Da implementare quando avremo il modello Fattura
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['totale' => 0, 'attivi' => 0, 'fatture_pending' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Assemblee
|
||||
*/
|
||||
private static function getAssembleeStats()
|
||||
{
|
||||
try {
|
||||
$oggi = Carbon::now();
|
||||
|
||||
return [
|
||||
'prossime' => Assemblea::where('data_assemblea', '>', $oggi)->count(),
|
||||
'questo_mese' => Assemblea::whereMonth('data_assemblea', $oggi->month)
|
||||
->whereYear('data_assemblea', $oggi->year)
|
||||
->count(),
|
||||
'delibere_da_approvare' => Assemblea::where('stato', 'bozza')->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['prossime' => 0, 'questo_mese' => 0, 'delibere_da_approvare' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiche Documenti
|
||||
*/
|
||||
private static function getDocumentiStats()
|
||||
{
|
||||
try {
|
||||
$oggi = Carbon::now();
|
||||
|
||||
return [
|
||||
'totali' => Documento::count(),
|
||||
'caricati_oggi' => Documento::whereDate('created_at', $oggi->toDateString())->count(),
|
||||
'da_revisionare' => Documento::where('stato', 'bozza')->count(),
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return ['totali' => 0, 'caricati_oggi' => 0, 'da_revisionare' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulisce la cache delle statistiche
|
||||
*/
|
||||
public static function clearCache()
|
||||
{
|
||||
Cache::forget('sidebar_stats');
|
||||
}
|
||||
|
||||
/**
|
||||
* Badge per contatori con colori dinamici
|
||||
*/
|
||||
public static function getBadge($count, $type = 'info')
|
||||
{
|
||||
if ($count == 0) return '';
|
||||
|
||||
$colors = [
|
||||
'success' => 'bg-success',
|
||||
'warning' => 'bg-warning text-dark',
|
||||
'danger' => 'bg-danger',
|
||||
'info' => 'bg-info',
|
||||
'primary' => 'bg-primary'
|
||||
];
|
||||
|
||||
$colorClass = $colors[$type] ?? 'bg-secondary';
|
||||
|
||||
return "<span class=\"badge {$colorClass} ms-2\">{$count}</span>";
|
||||
}
|
||||
}
|
||||
271
netgescon-laravel/app/Helpers/ThemeHelper.php
Normal file
271
netgescon-laravel/app/Helpers/ThemeHelper.php
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Models\UserSetting;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ThemeHelper
|
||||
{
|
||||
/**
|
||||
* Colori di default del tema NetGesCon
|
||||
*/
|
||||
const DEFAULT_THEME = [
|
||||
'primary_color' => '#f39c12', // Giallo NetGesCon
|
||||
'secondary_color' => '#3498db', // Blu
|
||||
'success_color' => '#27ae60', // Verde
|
||||
'danger_color' => '#e74c3c', // Rosso
|
||||
'warning_color' => '#f39c12', // Arancione/Giallo
|
||||
'info_color' => '#17a2b8', // Azzurro
|
||||
'light_color' => '#f8f9fa', // Grigio chiaro
|
||||
'dark_color' => '#343a40', // Grigio scuro
|
||||
'sidebar_bg' => '#f39c12', // Sfondo sidebar (giallo)
|
||||
'sidebar_text' => '#ffffff', // Testo sidebar (bianco)
|
||||
'header_bg' => '#2c5aa0', // Sfondo header (blu)
|
||||
'header_text' => '#ffffff', // Testo header (bianco)
|
||||
'theme_mode' => 'light' // Modalità tema (light/dark)
|
||||
];
|
||||
|
||||
/**
|
||||
* Temi predefiniti disponibili
|
||||
*/
|
||||
const PRESET_THEMES = [
|
||||
'netgescon_classic' => [
|
||||
'name' => 'NetGesCon Classico',
|
||||
'description' => 'Schema colori tradizionale NetGesCon',
|
||||
'colors' => self::DEFAULT_THEME
|
||||
],
|
||||
'netgescon_blue' => [
|
||||
'name' => 'NetGesCon Blu',
|
||||
'description' => 'Variante blu professionale',
|
||||
'colors' => [
|
||||
'primary_color' => '#2c5aa0',
|
||||
'secondary_color' => '#f39c12',
|
||||
'success_color' => '#27ae60',
|
||||
'danger_color' => '#e74c3c',
|
||||
'warning_color' => '#f39c12',
|
||||
'info_color' => '#17a2b8',
|
||||
'light_color' => '#f8f9fa',
|
||||
'dark_color' => '#343a40',
|
||||
'sidebar_bg' => '#2c5aa0',
|
||||
'sidebar_text' => '#ffffff',
|
||||
'header_bg' => '#f39c12',
|
||||
'header_text' => '#ffffff',
|
||||
'theme_mode' => 'light'
|
||||
]
|
||||
],
|
||||
'netgescon_green' => [
|
||||
'name' => 'NetGesCon Verde',
|
||||
'description' => 'Variante verde natura',
|
||||
'colors' => [
|
||||
'primary_color' => '#27ae60',
|
||||
'secondary_color' => '#2c5aa0',
|
||||
'success_color' => '#2ecc71',
|
||||
'danger_color' => '#e74c3c',
|
||||
'warning_color' => '#f39c12',
|
||||
'info_color' => '#17a2b8',
|
||||
'light_color' => '#f8f9fa',
|
||||
'dark_color' => '#343a40',
|
||||
'sidebar_bg' => '#27ae60',
|
||||
'sidebar_text' => '#ffffff',
|
||||
'header_bg' => '#2c5aa0',
|
||||
'header_text' => '#ffffff',
|
||||
'theme_mode' => 'light'
|
||||
]
|
||||
],
|
||||
'netgescon_dark' => [
|
||||
'name' => 'NetGesCon Dark',
|
||||
'description' => 'Tema scuro per la sera',
|
||||
'colors' => [
|
||||
'primary_color' => '#f39c12',
|
||||
'secondary_color' => '#6c757d',
|
||||
'success_color' => '#28a745',
|
||||
'danger_color' => '#dc3545',
|
||||
'warning_color' => '#ffc107',
|
||||
'info_color' => '#17a2b8',
|
||||
'light_color' => '#343a40',
|
||||
'dark_color' => '#212529',
|
||||
'sidebar_bg' => '#212529',
|
||||
'sidebar_text' => '#f39c12',
|
||||
'header_bg' => '#343a40',
|
||||
'header_text' => '#f39c12',
|
||||
'theme_mode' => 'dark'
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* Ottiene i colori del tema per l'utente corrente
|
||||
*/
|
||||
public static function getUserTheme($userId = null): array
|
||||
{
|
||||
$userId = $userId ?? Auth::id();
|
||||
|
||||
if (!$userId) {
|
||||
return self::DEFAULT_THEME;
|
||||
}
|
||||
|
||||
$settings = UserSetting::where('user_id', $userId)
|
||||
->whereIn('key', array_keys(self::DEFAULT_THEME))
|
||||
->pluck('value', 'key')
|
||||
->toArray();
|
||||
|
||||
// Merge con i valori di default
|
||||
return array_merge(self::DEFAULT_THEME, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Salva le impostazioni del tema per un utente
|
||||
*/
|
||||
public static function saveUserTheme($userId, array $themeData): bool
|
||||
{
|
||||
try {
|
||||
foreach ($themeData as $key => $value) {
|
||||
if (array_key_exists($key, self::DEFAULT_THEME)) {
|
||||
UserSetting::updateOrCreate(
|
||||
['user_id' => $userId, 'key' => $key],
|
||||
['value' => $value]
|
||||
);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Errore salvataggio tema utente: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applica un tema predefinito a un utente
|
||||
*/
|
||||
public static function applyPresetTheme($userId, string $presetName): bool
|
||||
{
|
||||
if (!isset(self::PRESET_THEMES[$presetName])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::saveUserTheme($userId, self::PRESET_THEMES[$presetName]['colors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera CSS personalizzato per il tema utente
|
||||
*/
|
||||
public static function generateCustomCSS($userId = null): string
|
||||
{
|
||||
$theme = self::getUserTheme($userId);
|
||||
|
||||
return "
|
||||
:root {
|
||||
--netgescon-primary: {$theme['primary_color']};
|
||||
--netgescon-secondary: {$theme['secondary_color']};
|
||||
--netgescon-success: {$theme['success_color']};
|
||||
--netgescon-danger: {$theme['danger_color']};
|
||||
--netgescon-warning: {$theme['warning_color']};
|
||||
--netgescon-info: {$theme['info_color']};
|
||||
--netgescon-light: {$theme['light_color']};
|
||||
--netgescon-dark: {$theme['dark_color']};
|
||||
--netgescon-sidebar-bg: {$theme['sidebar_bg']};
|
||||
--netgescon-sidebar-text: {$theme['sidebar_text']};
|
||||
--netgescon-header-bg: {$theme['header_bg']};
|
||||
--netgescon-header-text: {$theme['header_text']};
|
||||
}
|
||||
|
||||
/* Sidebar personalizzata */
|
||||
.netgescon-sidebar {
|
||||
background-color: var(--netgescon-sidebar-bg) !important;
|
||||
color: var(--netgescon-sidebar-text) !important;
|
||||
}
|
||||
|
||||
.netgescon-sidebar .nav-link {
|
||||
color: var(--netgescon-sidebar-text) !important;
|
||||
}
|
||||
|
||||
.netgescon-sidebar .nav-link:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.netgescon-sidebar .nav-link.active {
|
||||
background-color: rgba(255, 255, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
/* Header personalizzato */
|
||||
.netgescon-header {
|
||||
background-color: var(--netgescon-header-bg) !important;
|
||||
color: var(--netgescon-header-text) !important;
|
||||
}
|
||||
|
||||
/* Pulsanti principali */
|
||||
.btn-primary {
|
||||
background-color: var(--netgescon-primary) !important;
|
||||
border-color: var(--netgescon-primary) !important;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--netgescon-secondary) !important;
|
||||
border-color: var(--netgescon-secondary) !important;
|
||||
}
|
||||
|
||||
/* Badge e alert */
|
||||
.badge-primary {
|
||||
background-color: var(--netgescon-primary) !important;
|
||||
}
|
||||
|
||||
.alert-primary {
|
||||
background-color: var(--netgescon-primary) !important;
|
||||
border-color: var(--netgescon-primary) !important;
|
||||
}
|
||||
|
||||
/* Tema scuro */
|
||||
" . ($theme['theme_mode'] === 'dark' ? "
|
||||
body {
|
||||
background-color: var(--netgescon-dark) !important;
|
||||
color: var(--netgescon-light) !important;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--netgescon-light) !important;
|
||||
border-color: #6c757d !important;
|
||||
}
|
||||
|
||||
.table-dark {
|
||||
--bs-table-bg: var(--netgescon-dark);
|
||||
}
|
||||
" : "") . "
|
||||
";
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottiene tutti i temi predefiniti
|
||||
*/
|
||||
public static function getPresetThemes(): array
|
||||
{
|
||||
return self::PRESET_THEMES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valida un colore esadecimale
|
||||
*/
|
||||
public static function isValidHexColor(string $color): bool
|
||||
{
|
||||
return preg_match('/^#([a-f0-9]{3}){1,2}$/i', $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converte un colore esadecimale in RGB
|
||||
*/
|
||||
public static function hexToRgb(string $hex): array
|
||||
{
|
||||
$hex = str_replace('#', '', $hex);
|
||||
|
||||
if (strlen($hex) == 3) {
|
||||
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
|
||||
}
|
||||
|
||||
return [
|
||||
'r' => hexdec(substr($hex, 0, 2)),
|
||||
'g' => hexdec(substr($hex, 2, 2)),
|
||||
'b' => hexdec(substr($hex, 4, 2))
|
||||
];
|
||||
}
|
||||
}
|
||||
12
netgescon-laravel/app/Helpers/impostazioni.php
Normal file
12
netgescon-laravel/app/Helpers/impostazioni.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
if (!function_exists('impostazione')) {
|
||||
function impostazione($chiave, $default = null) {
|
||||
return Cache::rememberForever('impostazione_' . $chiave, function() use ($chiave, $default) {
|
||||
$val = DB::table('impostazioni')->where('chiave', $chiave)->value('valore');
|
||||
return $val ?? $default;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AllegatoController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.allegati.index', [
|
||||
'title' => 'Allegati',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Allegati' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('admin.allegati.create', [
|
||||
'title' => 'Nuovo Allegato',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Allegati' => route('admin.allegati.index'),
|
||||
'Nuovo Allegato' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// TODO: Implement store logic
|
||||
return redirect()->route('admin.allegati.index')
|
||||
->with('success', 'Allegato creato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
return view('admin.allegati.show', [
|
||||
'title' => 'Dettaglio Allegato',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Allegati' => route('admin.allegati.index'),
|
||||
'Dettaglio' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
return view('admin.allegati.edit', [
|
||||
'title' => 'Modifica Allegato',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Allegati' => route('admin.allegati.index'),
|
||||
'Modifica' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
// TODO: Implement update logic
|
||||
return redirect()->route('admin.allegati.index')
|
||||
->with('success', 'Allegato aggiornato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
// TODO: Implement destroy logic
|
||||
return redirect()->route('admin.allegati.index')
|
||||
->with('success', 'Allegato eliminato con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AnagraficaCondominusController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.anagrafica-condominiale.index', [
|
||||
'title' => 'Anagrafica Condominiale',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Anagrafica Condominiale' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('admin.anagrafica-condominiale.create', [
|
||||
'title' => 'Nuova Anagrafica',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Anagrafica Condominiale' => route('admin.anagrafica-condominiale.index'),
|
||||
'Nuova Anagrafica' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// TODO: Implement store logic
|
||||
return redirect()->route('admin.anagrafica-condominiale.index')
|
||||
->with('success', 'Anagrafica creata con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
return view('admin.anagrafica-condominiale.show', [
|
||||
'title' => 'Dettaglio Anagrafica',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Anagrafica Condominiale' => route('admin.anagrafica-condominiale.index'),
|
||||
'Dettaglio' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
return view('admin.anagrafica-condominiale.edit', [
|
||||
'title' => 'Modifica Anagrafica',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Anagrafica Condominiale' => route('admin.anagrafica-condominiale.index'),
|
||||
'Modifica' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
// TODO: Implement update logic
|
||||
return redirect()->route('admin.anagrafica-condominiale.index')
|
||||
->with('success', 'Anagrafica aggiornata con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
// TODO: Implement destroy logic
|
||||
return redirect()->route('admin.anagrafica-condominiale.index')
|
||||
->with('success', 'Anagrafica eliminata con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ApiTokenController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:manage-api-tokens');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
// Laravel Sanctum non fornisce un modo diretto per listare i token senza Jetstream/Fortify UI.
|
||||
// Solitamente si mostra un form per creare un nuovo token e si visualizza il token *solo una volta* dopo la creazione.
|
||||
// L'utente deve copiarlo e salvarlo.
|
||||
// Si possono elencare i token esistenti (senza mostrare il valore plain-text) per permetterne la revoca.
|
||||
$tokens = $user->tokens; // Collection di PersonalAccessToken
|
||||
|
||||
return view('admin.api-tokens.index', ['tokens' => $tokens]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'token_name' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$user = Auth::user();
|
||||
$tokenName = $request->input('token_name');
|
||||
|
||||
// Puoi definire delle 'abilities' (permessi) per il token se necessario
|
||||
// $newToken = $user->createToken($tokenName, ['import:data']);
|
||||
$newToken = $user->createToken($tokenName);
|
||||
|
||||
// IMPORTANTE: Il plainTextToken è visibile solo qui, subito dopo la creazione.
|
||||
// Dovrai passarlo alla vista e informare l'utente di copiarlo immediatamente.
|
||||
return back()->with('status', 'Token API creato con successo! Copia il token: ' . $newToken->plainTextToken);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, $tokenId)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$user->tokens()->where('id', $tokenId)->delete();
|
||||
return back()->with('status', 'Token API revocato con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,528 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Assemblea;
|
||||
use App\Models\OrdineGiorno;
|
||||
use App\Models\Convocazione;
|
||||
use App\Models\PresenzaAssemblea;
|
||||
use App\Models\Votazione;
|
||||
use App\Models\Verbale;
|
||||
use App\Models\RegistroProtocollo;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Preventivo;
|
||||
use App\Models\TabellaMillesimale;
|
||||
use App\Models\Soggetto;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AssembleaController extends Controller
|
||||
{
|
||||
/**
|
||||
* Dashboard assemblee
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
$assemblee = Assemblea::with(['stabile', 'creatoDa'])
|
||||
->whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})
|
||||
->orderBy('data_prima_convocazione', 'desc')
|
||||
->paginate(15);
|
||||
|
||||
// Statistiche
|
||||
$stats = [
|
||||
'assemblee_programmate' => Assemblea::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->whereIn('stato', ['bozza', 'convocata'])->count(),
|
||||
|
||||
'assemblee_svolte' => Assemblea::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('stato', 'svolta')->count(),
|
||||
|
||||
'convocazioni_inviate' => Convocazione::whereHas('assemblea.stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('data_invio', '>=', now()->subDays(30))->count(),
|
||||
|
||||
'delibere_approvate' => OrdineGiorno::whereHas('assemblea.stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('esito_votazione', 'approvato')->count(),
|
||||
];
|
||||
|
||||
return view('admin.assemblee.index', compact('assemblee', 'stats'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form creazione assemblea
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
$stabili = Stabile::where('amministratore_id', $amministratore_id)->attivi()->get();
|
||||
|
||||
return view('admin.assemblee.create', compact('stabili'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store assemblea
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'stabile_id' => 'required|exists:stabili,id_stabile',
|
||||
'tipo' => 'required|in:ordinaria,straordinaria',
|
||||
'data_prima_convocazione' => 'required|date|after:now',
|
||||
'data_seconda_convocazione' => 'required|date|after:data_prima_convocazione',
|
||||
'luogo' => 'required|string|max:255',
|
||||
'note' => 'nullable|string',
|
||||
'ordine_giorno' => 'required|array|min:1',
|
||||
'ordine_giorno.*.titolo' => 'required|string|max:255',
|
||||
'ordine_giorno.*.descrizione' => 'required|string',
|
||||
'ordine_giorno.*.tipo_voce' => 'required|in:discussione,delibera,spesa,preventivo,altro',
|
||||
'ordine_giorno.*.importo_spesa' => 'nullable|numeric|min:0',
|
||||
'ordine_giorno.*.tabella_millesimale_id' => 'nullable|exists:tabelle_millesimali,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$assemblea = Assemblea::create([
|
||||
'stabile_id' => $request->stabile_id,
|
||||
'tipo' => $request->tipo,
|
||||
'data_prima_convocazione' => $request->data_prima_convocazione,
|
||||
'data_seconda_convocazione' => $request->data_seconda_convocazione,
|
||||
'luogo' => $request->luogo,
|
||||
'note' => $request->note,
|
||||
'stato' => 'bozza',
|
||||
'creato_da_user_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
// Crea ordine del giorno
|
||||
foreach ($request->ordine_giorno as $index => $punto) {
|
||||
OrdineGiorno::create([
|
||||
'assemblea_id' => $assemblea->id,
|
||||
'numero_punto' => $index + 1,
|
||||
'titolo' => $punto['titolo'],
|
||||
'descrizione' => $punto['descrizione'],
|
||||
'tipo_voce' => $punto['tipo_voce'],
|
||||
'importo_spesa' => $punto['importo_spesa'] ?? null,
|
||||
'tabella_millesimale_id' => $punto['tabella_millesimale_id'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return redirect()->route('admin.assemblee.show', $assemblea)
|
||||
->with('success', 'Assemblea creata con successo.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore durante la creazione: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visualizza assemblea
|
||||
*/
|
||||
public function show(Assemblea $assemblea)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$assemblea->load([
|
||||
'stabile',
|
||||
'ordineGiorno.preventivo',
|
||||
'ordineGiorno.tabellaMillesimale',
|
||||
'convocazioni.soggetto',
|
||||
'presenze.soggetto',
|
||||
'verbale',
|
||||
'documenti'
|
||||
]);
|
||||
|
||||
// Calcola statistiche convocazioni
|
||||
$statsConvocazioni = [
|
||||
'totale_inviate' => $assemblea->convocazioni->count(),
|
||||
'consegnate' => $assemblea->convocazioni->where('esito_invio', 'consegnato')->count(),
|
||||
'lette' => $assemblea->convocazioni->where('esito_invio', 'letto')->count(),
|
||||
'conferme_presenza' => $assemblea->convocazioni->where('presenza_confermata', true)->count(),
|
||||
'deleghe' => $assemblea->convocazioni->where('delega_presente', true)->count(),
|
||||
];
|
||||
|
||||
// Calcola quorum se assemblea svolta
|
||||
$quorum = null;
|
||||
if ($assemblea->stato === 'svolta') {
|
||||
$quorum = $assemblea->calcolaQuorum();
|
||||
}
|
||||
|
||||
return view('admin.assemblee.show', compact('assemblea', 'statsConvocazioni', 'quorum'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invia convocazioni
|
||||
*/
|
||||
public function inviaConvocazioni(Request $request, Assemblea $assemblea)
|
||||
{
|
||||
$request->validate([
|
||||
'canali' => 'required|array',
|
||||
'canali.*' => 'in:email,pec,whatsapp,telegram,raccomandata,mano,portiere',
|
||||
]);
|
||||
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
if ($assemblea->stato !== 'bozza') {
|
||||
return back()->withErrors(['error' => 'Le convocazioni possono essere inviate solo per assemblee in bozza.']);
|
||||
}
|
||||
|
||||
try {
|
||||
$convocazioniInviate = $assemblea->inviaConvocazioni($request->canali, Auth::id());
|
||||
|
||||
return back()->with('success', "Inviate {$convocazioniInviate} convocazioni con successo.");
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return back()->withErrors(['error' => 'Errore nell\'invio convocazioni: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestione presenze
|
||||
*/
|
||||
public function presenze(Assemblea $assemblea)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$unitaImmobiliari = $assemblea->stabile->unitaImmobiliari()
|
||||
->with(['proprieta.soggetto'])
|
||||
->get();
|
||||
|
||||
$presenzeEsistenti = $assemblea->presenze()
|
||||
->with(['soggetto', 'unitaImmobiliare'])
|
||||
->get()
|
||||
->keyBy(function($presenza) {
|
||||
return $presenza->soggetto_id . '_' . $presenza->unita_immobiliare_id;
|
||||
});
|
||||
|
||||
return view('admin.assemblee.presenze', compact('assemblea', 'unitaImmobiliari', 'presenzeEsistenti'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registra presenza
|
||||
*/
|
||||
public function registraPresenza(Request $request, Assemblea $assemblea)
|
||||
{
|
||||
$request->validate([
|
||||
'presenze' => 'required|array',
|
||||
'presenze.*.soggetto_id' => 'required|exists:soggetti,id_soggetto',
|
||||
'presenze.*.unita_immobiliare_id' => 'required|exists:unita_immobiliari,id_unita',
|
||||
'presenze.*.tipo_presenza' => 'required|in:presente,delegato,assente',
|
||||
'presenze.*.millesimi_rappresentati' => 'required|numeric|min:0',
|
||||
'presenze.*.delegante_soggetto_id' => 'nullable|exists:soggetti,id_soggetto',
|
||||
]);
|
||||
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Elimina presenze esistenti
|
||||
$assemblea->presenze()->delete();
|
||||
|
||||
// Registra nuove presenze
|
||||
foreach ($request->presenze as $presenzaData) {
|
||||
if ($presenzaData['tipo_presenza'] !== 'assente') {
|
||||
PresenzaAssemblea::create([
|
||||
'assemblea_id' => $assemblea->id,
|
||||
'soggetto_id' => $presenzaData['soggetto_id'],
|
||||
'unita_immobiliare_id' => $presenzaData['unita_immobiliare_id'],
|
||||
'tipo_presenza' => $presenzaData['tipo_presenza'],
|
||||
'millesimi_rappresentati' => $presenzaData['millesimi_rappresentati'],
|
||||
'delegante_soggetto_id' => $presenzaData['delegante_soggetto_id'] ?? null,
|
||||
'ora_arrivo' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Aggiorna stato assemblea
|
||||
$assemblea->update(['stato' => 'svolta', 'data_svolgimento' => now()]);
|
||||
|
||||
DB::commit();
|
||||
return back()->with('success', 'Presenze registrate con successo.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore nella registrazione presenze: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestione votazioni
|
||||
*/
|
||||
public function votazioni(Assemblea $assemblea, OrdineGiorno $ordineGiorno)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
if ($assemblea->stato !== 'svolta') {
|
||||
return back()->withErrors(['error' => 'Le votazioni possono essere gestite solo per assemblee svolte.']);
|
||||
}
|
||||
|
||||
$presenze = $assemblea->presenze()->with(['soggetto', 'unitaImmobiliare'])->get();
|
||||
$votazioniEsistenti = $ordineGiorno->votazioni()
|
||||
->get()
|
||||
->keyBy(function($voto) {
|
||||
return $voto->soggetto_id . '_' . $voto->unita_immobiliare_id;
|
||||
});
|
||||
|
||||
return view('admin.assemblee.votazioni', compact('assemblea', 'ordineGiorno', 'presenze', 'votazioniEsistenti'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registra votazioni
|
||||
*/
|
||||
public function registraVotazioni(Request $request, Assemblea $assemblea, OrdineGiorno $ordineGiorno)
|
||||
{
|
||||
$request->validate([
|
||||
'voti' => 'required|array',
|
||||
'voti.*.soggetto_id' => 'required|exists:soggetti,id_soggetto',
|
||||
'voti.*.unita_immobiliare_id' => 'required|exists:unita_immobiliari,id_unita',
|
||||
'voti.*.voto' => 'required|in:favorevole,contrario,astenuto,non_votante',
|
||||
'voti.*.millesimi_voto' => 'required|numeric|min:0',
|
||||
]);
|
||||
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Elimina votazioni esistenti
|
||||
$ordineGiorno->votazioni()->delete();
|
||||
|
||||
// Registra nuovi voti
|
||||
foreach ($request->voti as $votoData) {
|
||||
if ($votoData['voto'] !== 'non_votante') {
|
||||
Votazione::create([
|
||||
'ordine_giorno_id' => $ordineGiorno->id,
|
||||
'soggetto_id' => $votoData['soggetto_id'],
|
||||
'unita_immobiliare_id' => $votoData['unita_immobiliare_id'],
|
||||
'voto' => $votoData['voto'],
|
||||
'millesimi_voto' => $votoData['millesimi_voto'],
|
||||
'data_voto' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Calcola risultato
|
||||
$risultato = $ordineGiorno->calcolaRisultato();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return back()->with('success', 'Votazioni registrate. Esito: ' . $risultato['esito']);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore nella registrazione voti: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gestione verbale
|
||||
*/
|
||||
public function verbale(Assemblea $assemblea)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$assemblea->load(['ordineGiorno.delibera', 'presenze.soggetto']);
|
||||
$verbale = $assemblea->verbale;
|
||||
|
||||
return view('admin.assemblee.verbale', compact('assemblea', 'verbale'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store/Update verbale
|
||||
*/
|
||||
public function storeVerbale(Request $request, Assemblea $assemblea)
|
||||
{
|
||||
$request->validate([
|
||||
'testo_verbale' => 'required|string',
|
||||
'allegati.*' => 'nullable|file|max:10240',
|
||||
]);
|
||||
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
try {
|
||||
$numeroVerbale = $this->generaNumeroVerbale($assemblea);
|
||||
|
||||
// Gestione allegati
|
||||
$allegati = [];
|
||||
if ($request->hasFile('allegati')) {
|
||||
foreach ($request->file('allegati') as $file) {
|
||||
$path = $file->store('verbali/allegati', 'public');
|
||||
$allegati[] = [
|
||||
'nome' => $file->getClientOriginalName(),
|
||||
'path' => $path,
|
||||
'size' => $file->getSize(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$verbale = Verbale::updateOrCreate(
|
||||
['assemblea_id' => $assemblea->id],
|
||||
[
|
||||
'numero_verbale' => $numeroVerbale,
|
||||
'testo_verbale' => $request->testo_verbale,
|
||||
'allegati' => $allegati,
|
||||
'data_redazione' => now(),
|
||||
'redatto_da_user_id' => Auth::id(),
|
||||
'stato' => 'definitivo',
|
||||
]
|
||||
);
|
||||
|
||||
return back()->with('success', 'Verbale salvato con successo.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return back()->withErrors(['error' => 'Errore nel salvataggio verbale: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invia verbale ai condomini
|
||||
*/
|
||||
public function inviaVerbale(Request $request, Assemblea $assemblea)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($assemblea->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$verbale = $assemblea->verbale;
|
||||
if (!$verbale) {
|
||||
return back()->withErrors(['error' => 'Nessun verbale da inviare.']);
|
||||
}
|
||||
|
||||
try {
|
||||
// Invia verbale a tutti i condomini
|
||||
$inviiRiusciti = $this->inviaVerbaleCondomini($assemblea, $verbale);
|
||||
|
||||
$verbale->update([
|
||||
'inviato_condomini' => true,
|
||||
'data_invio_condomini' => now(),
|
||||
'stato' => 'inviato',
|
||||
]);
|
||||
|
||||
return back()->with('success', "Verbale inviato a {$inviiRiusciti} condomini.");
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return back()->withErrors(['error' => 'Errore nell\'invio verbale: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registro protocollo
|
||||
*/
|
||||
public function registroProtocollo(Request $request)
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
$query = RegistroProtocollo::with(['assemblea.stabile', 'soggettoDestinatario', 'creatoDa'])
|
||||
->whereHas('assemblea.stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
});
|
||||
|
||||
// Filtri
|
||||
if ($request->filled('tipo_comunicazione')) {
|
||||
$query->where('tipo_comunicazione', $request->tipo_comunicazione);
|
||||
}
|
||||
|
||||
if ($request->filled('data_da')) {
|
||||
$query->where('data_invio', '>=', $request->data_da);
|
||||
}
|
||||
|
||||
if ($request->filled('data_a')) {
|
||||
$query->where('data_invio', '<=', $request->data_a);
|
||||
}
|
||||
|
||||
$comunicazioni = $query->orderBy('data_invio', 'desc')->paginate(20);
|
||||
|
||||
return view('admin.assemblee.registro-protocollo', compact('comunicazioni'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera numero verbale
|
||||
*/
|
||||
private function generaNumeroVerbale(Assemblea $assemblea)
|
||||
{
|
||||
$anno = $assemblea->data_prima_convocazione->year;
|
||||
$ultimoVerbale = Verbale::whereHas('assemblea', function($q) use ($anno) {
|
||||
$q->whereYear('data_prima_convocazione', $anno);
|
||||
})->orderBy('numero_verbale', 'desc')->first();
|
||||
|
||||
if ($ultimoVerbale) {
|
||||
$numero = intval(substr($ultimoVerbale->numero_verbale, -3)) + 1;
|
||||
} else {
|
||||
$numero = 1;
|
||||
}
|
||||
|
||||
return 'VERB/' . $anno . '/' . str_pad($numero, 3, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invia verbale ai condomini
|
||||
*/
|
||||
private function inviaVerbaleCondomini(Assemblea $assemblea, Verbale $verbale)
|
||||
{
|
||||
$unitaImmobiliari = $assemblea->stabile->unitaImmobiliari()->with('proprieta.soggetto')->get();
|
||||
$inviiRiusciti = 0;
|
||||
|
||||
foreach ($unitaImmobiliari as $unita) {
|
||||
foreach ($unita->proprieta as $proprieta) {
|
||||
$soggetto = $proprieta->soggetto;
|
||||
|
||||
if ($soggetto->email) {
|
||||
// Simula invio email
|
||||
$numeroProtocollo = RegistroProtocollo::generaNumeroProtocollo();
|
||||
|
||||
RegistroProtocollo::create([
|
||||
'numero_protocollo' => $numeroProtocollo,
|
||||
'tipo_comunicazione' => 'verbale',
|
||||
'assemblea_id' => $assemblea->id,
|
||||
'soggetto_destinatario_id' => $soggetto->id_soggetto,
|
||||
'oggetto' => "Verbale Assemblea {$assemblea->tipo} del {$assemblea->data_prima_convocazione->format('d/m/Y')}",
|
||||
'contenuto' => $verbale->testo_verbale,
|
||||
'canale' => 'email',
|
||||
'data_invio' => now(),
|
||||
'esito' => 'inviato',
|
||||
'creato_da_user_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
$inviiRiusciti++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $inviiRiusciti;
|
||||
}
|
||||
}
|
||||
118
netgescon-laravel/app/Http/Controllers/Admin/BancaController.php
Normal file
118
netgescon-laravel/app/Http/Controllers/Admin/BancaController.php
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Banca;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class BancaController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$banche = Banca::with(['movimentiBancari'])
|
||||
->orderBy('denominazione')
|
||||
->paginate(15);
|
||||
|
||||
return view('admin.banche.index', compact('banche'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('admin.banche.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'denominazione' => 'required|string|max:255',
|
||||
'codice_abi' => 'nullable|string|max:10',
|
||||
'codice_cab' => 'nullable|string|max:10',
|
||||
'iban' => 'nullable|string|max:34',
|
||||
'indirizzo' => 'nullable|string',
|
||||
'telefono' => 'nullable|string|max:20',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'note' => 'nullable|string',
|
||||
'attivo' => 'boolean',
|
||||
]);
|
||||
|
||||
$banca = Banca::create($validated);
|
||||
|
||||
return redirect()
|
||||
->route('admin.banche.index')
|
||||
->with('success', 'Banca creata con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Banca $banca)
|
||||
{
|
||||
$banca->load(['movimentiBancari' => function($query) {
|
||||
$query->orderBy('data_operazione', 'desc')->limit(10);
|
||||
}]);
|
||||
|
||||
return view('admin.banche.show', compact('banca'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Banca $banca)
|
||||
{
|
||||
return view('admin.banche.edit', compact('banca'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Banca $banca)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'denominazione' => 'required|string|max:255',
|
||||
'codice_abi' => 'nullable|string|max:10',
|
||||
'codice_cab' => 'nullable|string|max:10',
|
||||
'iban' => 'nullable|string|max:34',
|
||||
'indirizzo' => 'nullable|string',
|
||||
'telefono' => 'nullable|string|max:20',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'note' => 'nullable|string',
|
||||
'attivo' => 'boolean',
|
||||
]);
|
||||
|
||||
$banca->update($validated);
|
||||
|
||||
return redirect()
|
||||
->route('admin.banche.index')
|
||||
->with('success', 'Banca aggiornata con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Banca $banca)
|
||||
{
|
||||
// Check if bank has any movements before deleting
|
||||
if ($banca->movimentiBancari()->count() > 0) {
|
||||
return redirect()
|
||||
->route('admin.banche.index')
|
||||
->with('error', 'Impossibile eliminare la banca: sono presenti movimenti associati.');
|
||||
}
|
||||
|
||||
$banca->delete();
|
||||
|
||||
return redirect()
|
||||
->route('admin.banche.index')
|
||||
->with('success', 'Banca eliminata con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Bilancio;
|
||||
use App\Models\ScritturaBilancio;
|
||||
use App\Models\Conguaglio;
|
||||
use App\Models\Quadratura;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Gestione;
|
||||
use App\Models\PianoConto;
|
||||
use App\Models\MovimentoContabile;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class BilancioController extends Controller
|
||||
{
|
||||
/**
|
||||
* Dashboard bilanci
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
$bilanci = Bilancio::with(['stabile', 'gestione', 'approvatoDa'])
|
||||
->whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})
|
||||
->orderBy('anno_esercizio', 'desc')
|
||||
->orderBy('created_at', 'desc')
|
||||
->paginate(15);
|
||||
|
||||
// Statistiche
|
||||
$stats = [
|
||||
'bilanci_aperti' => Bilancio::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->whereIn('stato', ['bozza', 'provvisorio'])->count(),
|
||||
|
||||
'bilanci_approvati' => Bilancio::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('stato', 'approvato')->count(),
|
||||
|
||||
'conguagli_da_pagare' => Conguaglio::whereHas('bilancio.stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('stato', 'calcolato')->count(),
|
||||
|
||||
'totale_avanzi' => Bilancio::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('risultato_gestione', '>', 0)->sum('risultato_gestione'),
|
||||
];
|
||||
|
||||
return view('admin.bilanci.index', compact('bilanci', 'stats'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form creazione bilancio
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
$stabili = Stabile::where('amministratore_id', $amministratore_id)->attivi()->get();
|
||||
|
||||
return view('admin.bilanci.create', compact('stabili'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store bilancio
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'stabile_id' => 'required|exists:stabili,id_stabile',
|
||||
'gestione_id' => 'required|exists:gestioni,id_gestione',
|
||||
'anno_esercizio' => 'required|integer|min:2020|max:2030',
|
||||
'data_inizio_esercizio' => 'required|date',
|
||||
'data_fine_esercizio' => 'required|date|after:data_inizio_esercizio',
|
||||
'tipo_gestione' => 'required|in:ordinaria,riscaldamento,straordinaria,acqua,altro',
|
||||
'descrizione' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$bilancio = Bilancio::create([
|
||||
'stabile_id' => $request->stabile_id,
|
||||
'gestione_id' => $request->gestione_id,
|
||||
'anno_esercizio' => $request->anno_esercizio,
|
||||
'data_inizio_esercizio' => $request->data_inizio_esercizio,
|
||||
'data_fine_esercizio' => $request->data_fine_esercizio,
|
||||
'tipo_gestione' => $request->tipo_gestione,
|
||||
'descrizione' => $request->descrizione,
|
||||
'stato' => 'bozza',
|
||||
'versione' => 1,
|
||||
]);
|
||||
|
||||
// Importa movimenti contabili del periodo
|
||||
$this->importaMovimentiContabili($bilancio);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return redirect()->route('admin.bilanci.show', $bilancio)
|
||||
->with('success', 'Bilancio creato con successo.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore durante la creazione: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visualizza bilancio
|
||||
*/
|
||||
public function show(Bilancio $bilancio)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($bilancio->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$bilancio->load([
|
||||
'stabile',
|
||||
'gestione',
|
||||
'scritture.dettagli.conto',
|
||||
'conguagli.unitaImmobiliare',
|
||||
'quadrature',
|
||||
'rimborsiAssicurativi'
|
||||
]);
|
||||
|
||||
// Calcola totali aggiornati
|
||||
$bilancio->calcolaTotali();
|
||||
|
||||
return view('admin.bilanci.show', compact('bilancio'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Importa movimenti contabili nel bilancio
|
||||
*/
|
||||
private function importaMovimentiContabili(Bilancio $bilancio)
|
||||
{
|
||||
$movimenti = MovimentoContabile::where('stabile_id', $bilancio->stabile_id)
|
||||
->where('gestione_id', $bilancio->gestione_id)
|
||||
->whereBetween('data_registrazione', [
|
||||
$bilancio->data_inizio_esercizio,
|
||||
$bilancio->data_fine_esercizio
|
||||
])
|
||||
->with('dettagli')
|
||||
->get();
|
||||
|
||||
foreach ($movimenti as $movimento) {
|
||||
$this->creaScritturaDaMovimento($bilancio, $movimento);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea scrittura bilancio da movimento contabile
|
||||
*/
|
||||
private function creaScritturaDaMovimento(Bilancio $bilancio, MovimentoContabile $movimento)
|
||||
{
|
||||
$scrittura = ScritturaBilancio::create([
|
||||
'bilancio_id' => $bilancio->id,
|
||||
'numero_scrittura' => $this->generaNumeroScrittura($bilancio),
|
||||
'data_scrittura' => $movimento->data_registrazione,
|
||||
'descrizione' => $movimento->descrizione,
|
||||
'tipo_scrittura' => 'gestione',
|
||||
'importo_totale' => $movimento->importo_totale,
|
||||
'movimento_contabile_id' => $movimento->id,
|
||||
'creato_da_user_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
// Crea dettagli in partita doppia
|
||||
foreach ($movimento->dettagli as $dettaglio) {
|
||||
$scrittura->dettagli()->create([
|
||||
'conto_id' => $dettaglio->conto_id ?? $this->getContoDefault($movimento->tipo_movimento),
|
||||
'importo_dare' => $dettaglio->importo_dare,
|
||||
'importo_avere' => $dettaglio->importo_avere,
|
||||
'descrizione_dettaglio' => $dettaglio->descrizione,
|
||||
]);
|
||||
}
|
||||
|
||||
return $scrittura;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcola conguagli
|
||||
*/
|
||||
public function calcolaConguagli(Bilancio $bilancio)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($bilancio->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$bilancio->calcolaConguagli();
|
||||
|
||||
DB::commit();
|
||||
return back()->with('success', 'Conguagli calcolati con successo.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore nel calcolo conguagli: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera rate conguaglio
|
||||
*/
|
||||
public function generaRateConguaglio(Request $request, Bilancio $bilancio)
|
||||
{
|
||||
$request->validate([
|
||||
'conguaglio_ids' => 'required|array',
|
||||
'numero_rate' => 'required|integer|min:1|max:12',
|
||||
'data_inizio' => 'required|date',
|
||||
]);
|
||||
|
||||
// Verifica accesso
|
||||
if ($bilancio->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$dataInizio = Carbon::parse($request->data_inizio);
|
||||
$rateGenerate = 0;
|
||||
|
||||
foreach ($request->conguaglio_ids as $conguaglioId) {
|
||||
$conguaglio = Conguaglio::findOrFail($conguaglioId);
|
||||
|
||||
if ($conguaglio->bilancio_id !== $bilancio->id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rate = $conguaglio->generaRate($request->numero_rate, $dataInizio, Auth::id());
|
||||
$rateGenerate += $rate->count();
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
return back()->with('success', "Generate {$rateGenerate} rate di conguaglio.");
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore nella generazione rate: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quadratura bilancio
|
||||
*/
|
||||
public function quadratura(Request $request, Bilancio $bilancio)
|
||||
{
|
||||
$request->validate([
|
||||
'data_quadratura' => 'required|date',
|
||||
'saldo_banca_effettivo' => 'required|numeric',
|
||||
]);
|
||||
|
||||
// Verifica accesso
|
||||
if ($bilancio->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
// Calcola saldo contabile
|
||||
$saldoContabile = $this->calcolaSaldoContabile($bilancio, $request->data_quadratura);
|
||||
|
||||
// Calcola totali crediti/debiti
|
||||
$totaleCrediti = $bilancio->conguagli()->where('tipo_conguaglio', 'a_credito')->sum('conguaglio_dovuto');
|
||||
$totaleDebiti = $bilancio->conguagli()->where('tipo_conguaglio', 'a_debito')->sum('conguaglio_dovuto');
|
||||
|
||||
// Calcola rate
|
||||
$totaleRateEmesse = $this->calcolaTotaleRateEmesse($bilancio);
|
||||
$totaleRateIncassate = $this->calcolaTotaleRateIncassate($bilancio);
|
||||
|
||||
$differenza = $request->saldo_banca_effettivo - $saldoContabile;
|
||||
|
||||
$quadratura = Quadratura::create([
|
||||
'bilancio_id' => $bilancio->id,
|
||||
'data_quadratura' => $request->data_quadratura,
|
||||
'saldo_banca_effettivo' => $request->saldo_banca_effettivo,
|
||||
'saldo_contabile_calcolato' => $saldoContabile,
|
||||
'differenza' => $differenza,
|
||||
'totale_crediti_condomini' => $totaleCrediti,
|
||||
'totale_debiti_condomini' => $totaleDebiti,
|
||||
'totale_rate_emesse' => $totaleRateEmesse,
|
||||
'totale_rate_incassate' => $totaleRateIncassate,
|
||||
'quadratura_ok' => abs($differenza) < 0.01,
|
||||
'verificato_da_user_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
return back()->with('success', 'Quadratura eseguita con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Chiusura esercizio
|
||||
*/
|
||||
public function chiusuraEsercizio(Request $request, Bilancio $bilancio)
|
||||
{
|
||||
$request->validate([
|
||||
'motivo_chiusura' => 'required|string',
|
||||
]);
|
||||
|
||||
// Verifica accesso e stato
|
||||
if ($bilancio->stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
if ($bilancio->stato !== 'approvato') {
|
||||
return back()->withErrors(['error' => 'Il bilancio deve essere approvato prima della chiusura.']);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Genera scritture di chiusura
|
||||
$bilancio->generaScritture_ChiusuraEsercizio(Auth::id());
|
||||
|
||||
// Aggiorna stato bilancio
|
||||
$bilancio->update([
|
||||
'stato' => 'chiuso',
|
||||
'data_chiusura' => now(),
|
||||
'chiuso_da_user_id' => Auth::id(),
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
return back()->with('success', 'Esercizio chiuso con successo.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore nella chiusura: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcola saldo contabile alla data
|
||||
*/
|
||||
private function calcolaSaldoContabile(Bilancio $bilancio, $data)
|
||||
{
|
||||
// Implementazione calcolo saldo contabile
|
||||
return $bilancio->totale_entrate - $bilancio->totale_uscite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcola totale rate emesse
|
||||
*/
|
||||
private function calcolaTotaleRateEmesse(Bilancio $bilancio)
|
||||
{
|
||||
// Implementazione calcolo rate emesse
|
||||
return 0; // Placeholder
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcola totale rate incassate
|
||||
*/
|
||||
private function calcolaTotaleRateIncassate(Bilancio $bilancio)
|
||||
{
|
||||
// Implementazione calcolo rate incassate
|
||||
return 0; // Placeholder
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera numero scrittura
|
||||
*/
|
||||
private function generaNumeroScrittura(Bilancio $bilancio)
|
||||
{
|
||||
$ultimaScrittura = ScritturaBilancio::where('bilancio_id', $bilancio->id)
|
||||
->orderBy('numero_scrittura', 'desc')
|
||||
->first();
|
||||
|
||||
if ($ultimaScrittura) {
|
||||
$numero = intval(substr($ultimaScrittura->numero_scrittura, -4)) + 1;
|
||||
} else {
|
||||
$numero = 1;
|
||||
}
|
||||
|
||||
return 'SCR/' . $bilancio->anno_esercizio . '/' . str_pad($numero, 4, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get conto default per tipo movimento
|
||||
*/
|
||||
private function getContoDefault($tipoMovimento)
|
||||
{
|
||||
// Implementazione per ottenere conto default
|
||||
return 1; // Placeholder
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\MovimentoContabile;
|
||||
use App\Models\Gestione;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Fornitore;
|
||||
use App\Models\VoceSpesa;
|
||||
use App\Models\TabellaMillesimale;
|
||||
use App\Models\Documento;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ContabilitaController extends Controller
|
||||
{
|
||||
/**
|
||||
* Dashboard contabilità
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
// Statistiche generali
|
||||
$stats = [
|
||||
'movimenti_mese' => MovimentoContabile::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->whereMonth('data_registrazione', now()->month)->count(),
|
||||
|
||||
'importo_entrate_mese' => MovimentoContabile::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('tipo_movimento', 'entrata')
|
||||
->whereMonth('data_registrazione', now()->month)
|
||||
->sum('importo_totale'),
|
||||
|
||||
'importo_uscite_mese' => MovimentoContabile::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('tipo_movimento', 'uscita')
|
||||
->whereMonth('data_registrazione', now()->month)
|
||||
->sum('importo_totale'),
|
||||
];
|
||||
|
||||
// Ultimi movimenti
|
||||
$ultimiMovimenti = MovimentoContabile::with(['stabile', 'gestione', 'fornitore'])
|
||||
->whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(10)
|
||||
->get();
|
||||
|
||||
return view('admin.contabilita.index', compact('stats', 'ultimiMovimenti'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista movimenti contabili
|
||||
*/
|
||||
public function movimenti(Request $request)
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
$query = MovimentoContabile::with(['stabile', 'gestione', 'fornitore'])
|
||||
->whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
});
|
||||
|
||||
// Filtri
|
||||
if ($request->filled('stabile_id')) {
|
||||
$query->where('stabile_id', $request->stabile_id);
|
||||
}
|
||||
|
||||
if ($request->filled('gestione_id')) {
|
||||
$query->where('gestione_id', $request->gestione_id);
|
||||
}
|
||||
|
||||
if ($request->filled('tipo_movimento')) {
|
||||
$query->where('tipo_movimento', $request->tipo_movimento);
|
||||
}
|
||||
|
||||
if ($request->filled('data_da')) {
|
||||
$query->where('data_registrazione', '>=', $request->data_da);
|
||||
}
|
||||
|
||||
if ($request->filled('data_a')) {
|
||||
$query->where('data_registrazione', '<=', $request->data_a);
|
||||
}
|
||||
|
||||
$movimenti = $query->orderBy('data_registrazione', 'desc')->paginate(20);
|
||||
|
||||
// Dati per i filtri
|
||||
$stabili = Stabile::where('amministratore_id', $amministratore_id)->get();
|
||||
$gestioni = Gestione::whereIn('stabile_id', $stabili->pluck('id_stabile'))->get();
|
||||
|
||||
return view('admin.contabilita.movimenti', compact('movimenti', 'stabili', 'gestioni'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form registrazione movimento
|
||||
*/
|
||||
public function registrazione()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
$stabili = Stabile::where('amministratore_id', $amministratore_id)->attivi()->get();
|
||||
$fornitori = Fornitore::where('amministratore_id', $amministratore_id)->get();
|
||||
|
||||
return view('admin.contabilita.registrazione', compact('stabili', 'fornitori'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store registrazione movimento
|
||||
*/
|
||||
public function storeRegistrazione(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'stabile_id' => 'required|exists:stabili,id_stabile',
|
||||
'gestione_id' => 'required|exists:gestioni,id_gestione',
|
||||
'tipo_movimento' => 'required|in:entrata,uscita',
|
||||
'data_documento' => 'required|date',
|
||||
'numero_documento' => 'required|string|max:50',
|
||||
'descrizione' => 'required|string|max:255',
|
||||
'importo_totale' => 'required|numeric|min:0',
|
||||
'fornitore_id' => 'nullable|exists:fornitori,id_fornitore',
|
||||
'ritenuta_acconto' => 'nullable|numeric|min:0',
|
||||
'dettagli' => 'required|array|min:1',
|
||||
'dettagli.*.voce_spesa_id' => 'required|exists:voci_spesa,id',
|
||||
'dettagli.*.importo' => 'required|numeric|min:0',
|
||||
'dettagli.*.tabella_millesimale_id' => 'nullable|exists:tabelle_millesimali,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// Genera protocollo univoco
|
||||
$protocollo = $this->generaProtocollo($request->stabile_id);
|
||||
|
||||
// Crea movimento principale
|
||||
$movimento = MovimentoContabile::create([
|
||||
'stabile_id' => $request->stabile_id,
|
||||
'gestione_id' => $request->gestione_id,
|
||||
'fornitore_id' => $request->fornitore_id,
|
||||
'protocollo' => $protocollo,
|
||||
'data_registrazione' => now(),
|
||||
'data_documento' => $request->data_documento,
|
||||
'numero_documento' => $request->numero_documento,
|
||||
'descrizione' => $request->descrizione,
|
||||
'tipo_movimento' => $request->tipo_movimento,
|
||||
'importo_totale' => $request->importo_totale,
|
||||
'ritenuta_acconto' => $request->ritenuta_acconto ?? 0,
|
||||
'importo_netto' => $request->importo_totale - ($request->ritenuta_acconto ?? 0),
|
||||
'stato' => 'registrato',
|
||||
]);
|
||||
|
||||
// Crea dettagli movimento (partita doppia)
|
||||
foreach ($request->dettagli as $dettaglio) {
|
||||
$movimento->dettagli()->create([
|
||||
'voce_spesa_id' => $dettaglio['voce_spesa_id'],
|
||||
'tabella_millesimale_id' => $dettaglio['tabella_millesimale_id'] ?? null,
|
||||
'descrizione' => $dettaglio['descrizione'] ?? '',
|
||||
'importo_dare' => $request->tipo_movimento === 'uscita' ? $dettaglio['importo'] : 0,
|
||||
'importo_avere' => $request->tipo_movimento === 'entrata' ? $dettaglio['importo'] : 0,
|
||||
]);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return redirect()->route('admin.contabilita.movimenti')
|
||||
->with('success', 'Movimento registrato con successo. Protocollo: ' . $protocollo);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error' => 'Errore durante la registrazione: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import da XML (Fattura Elettronica)
|
||||
*/
|
||||
public function importXml(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'xml_file' => 'required|file|mimes:xml|max:2048',
|
||||
'stabile_id' => 'required|exists:stabili,id_stabile',
|
||||
]);
|
||||
|
||||
try {
|
||||
$xmlContent = file_get_contents($request->file('xml_file')->path());
|
||||
$xml = simplexml_load_string($xmlContent);
|
||||
|
||||
// Parsing XML fattura elettronica
|
||||
$fatturaData = $this->parseXmlFattura($xml);
|
||||
|
||||
// Salva documento
|
||||
$documento = Documento::create([
|
||||
'documentable_type' => Stabile::class,
|
||||
'documentable_id' => $request->stabile_id,
|
||||
'nome_file' => $request->file('xml_file')->getClientOriginalName(),
|
||||
'path_file' => $request->file('xml_file')->store('documenti/xml'),
|
||||
'tipo_documento' => 'fattura_elettronica',
|
||||
'xml_data' => $fatturaData,
|
||||
'mime_type' => 'application/xml',
|
||||
'dimensione_file' => $request->file('xml_file')->getSize(),
|
||||
]);
|
||||
|
||||
return view('admin.contabilita.import-xml-review', compact('fatturaData', 'documento'));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return back()->withErrors(['error' => 'Errore durante l\'importazione XML: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera protocollo univoco
|
||||
*/
|
||||
private function generaProtocollo($stabile_id)
|
||||
{
|
||||
$anno = date('Y');
|
||||
$ultimoProtocollo = MovimentoContabile::where('stabile_id', $stabile_id)
|
||||
->whereYear('data_registrazione', $anno)
|
||||
->max('protocollo');
|
||||
|
||||
if ($ultimoProtocollo) {
|
||||
$numero = intval(substr($ultimoProtocollo, -4)) + 1;
|
||||
} else {
|
||||
$numero = 1;
|
||||
}
|
||||
|
||||
return $stabile_id . '/' . $anno . '/' . str_pad($numero, 4, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse XML Fattura Elettronica
|
||||
*/
|
||||
private function parseXmlFattura($xml)
|
||||
{
|
||||
$ns = $xml->getNamespaces(true);
|
||||
$xml->registerXPathNamespace('fe', $ns['']);
|
||||
|
||||
// Dati generali fattura
|
||||
$datiGenerali = [
|
||||
'numero' => (string) $xml->xpath('//DatiGeneraliDocumento/Numero')[0] ?? '',
|
||||
'data' => (string) $xml->xpath('//DatiGeneraliDocumento/Data')[0] ?? '',
|
||||
'importo_totale' => (float) $xml->xpath('//DatiGeneraliDocumento/ImportoTotaleDocumento')[0] ?? 0,
|
||||
];
|
||||
|
||||
// Dati fornitore
|
||||
$fornitore = [
|
||||
'denominazione' => (string) $xml->xpath('//CedentePrestatore//Denominazione')[0] ?? '',
|
||||
'partita_iva' => (string) $xml->xpath('//CedentePrestatore//IdFiscaleIVA/IdCodice')[0] ?? '',
|
||||
'codice_fiscale' => (string) $xml->xpath('//CedentePrestatore//CodiceFiscale')[0] ?? '',
|
||||
];
|
||||
|
||||
// Righe fattura
|
||||
$righe = [];
|
||||
$dettaglioLinee = $xml->xpath('//DettaglioLinee');
|
||||
foreach ($dettaglioLinee as $linea) {
|
||||
$righe[] = [
|
||||
'descrizione' => (string) $linea->Descrizione ?? '',
|
||||
'quantita' => (float) $linea->Quantita ?? 1,
|
||||
'prezzo_unitario' => (float) $linea->PrezzoUnitario ?? 0,
|
||||
'importo_totale' => (float) $linea->PrezzoTotale ?? 0,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'dati_generali' => $datiGenerali,
|
||||
'fornitore' => $fornitore,
|
||||
'righe' => $righe,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContrattoLocazioneController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.contratti-locazione.index', [
|
||||
'title' => 'Contratti Locazione',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Contratti Locazione' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('admin.contratti-locazione.create', [
|
||||
'title' => 'Nuovo Contratto Locazione',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Contratti Locazione' => route('admin.contratti-locazione.index'),
|
||||
'Nuovo Contratto' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// TODO: Implement store logic
|
||||
return redirect()->route('admin.contratti-locazione.index')
|
||||
->with('success', 'Contratto locazione creato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
return view('admin.contratti-locazione.show', [
|
||||
'title' => 'Dettaglio Contratto Locazione',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Contratti Locazione' => route('admin.contratti-locazione.index'),
|
||||
'Dettaglio' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
return view('admin.contratti-locazione.edit', [
|
||||
'title' => 'Modifica Contratto Locazione',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Contratti Locazione' => route('admin.contratti-locazione.index'),
|
||||
'Modifica' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
// TODO: Implement update logic
|
||||
return redirect()->route('admin.contratti-locazione.index')
|
||||
->with('success', 'Contratto locazione aggiornato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
// TODO: Implement destroy logic
|
||||
return redirect()->route('admin.contratti-locazione.index')
|
||||
->with('success', 'Contratto locazione eliminato con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Rata;
|
||||
use App\Models\Documento;
|
||||
use App\Models\MovimentoContabile;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
// Ottieni i dati reali dalle statistiche
|
||||
$statsController = new DashboardStatsController();
|
||||
$statsResponse = $statsController->getStats();
|
||||
$stats = $statsResponse->getData(true);
|
||||
|
||||
// Ottieni l'ID dell'amministratore in modo sicuro
|
||||
$user = Auth::user();
|
||||
$amministratore_id = null;
|
||||
|
||||
if ($user && $user->amministratore) {
|
||||
$amministratore_id = $user->amministratore->id; // Usa 'id' invece di 'id_amministratore'
|
||||
}
|
||||
|
||||
// Se l'utente non ha un amministratore associato, mostra vista vuota
|
||||
if (!$amministratore_id) {
|
||||
return view('admin.dashboard', [
|
||||
'stats' => $stats,
|
||||
'ticketsAperti' => collect(),
|
||||
'scadenzeImminenti' => collect(),
|
||||
'ultimiDocumenti' => collect(),
|
||||
'ultimiMovimenti' => collect(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Statistiche principali
|
||||
$stats = [
|
||||
'stabili_gestiti' => Stabile::where('amministratore_id', $amministratore_id)->count(),
|
||||
'stabili_attivi' => Stabile::where('amministratore_id', $amministratore_id)->where('stato', 'attivo')->count(),
|
||||
'ticket_aperti' => Ticket::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->whereIn('stato', ['Aperto', 'Preso in Carico', 'In Lavorazione'])->count(),
|
||||
'ticket_urgenti' => Ticket::whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->where('priorita', 'Urgente')->whereIn('stato', ['Aperto', 'Preso in Carico'])->count(),
|
||||
];
|
||||
|
||||
// Ticket aperti da lavorare
|
||||
$ticketsAperti = Ticket::with(['stabile', 'categoriaTicket'])
|
||||
->whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})
|
||||
->whereIn('stato', ['Aperto', 'Preso in Carico', 'In Lavorazione'])
|
||||
->orderBy('priorita', 'desc')
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
// Scadenze imminenti (prossimi 30 giorni)
|
||||
$scadenzeImminenti = collect(); // Placeholder per quando implementeremo le rate
|
||||
|
||||
// Ultimi documenti caricati
|
||||
$ultimiDocumenti = Documento::with('documentable')
|
||||
->whereHasMorph('documentable', [Stabile::class], function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
// Movimenti contabili recenti
|
||||
$ultimiMovimenti = MovimentoContabile::with(['stabile', 'fornitore'])
|
||||
->whereHas('stabile', function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return view('admin.dashboard', compact(
|
||||
'stats',
|
||||
'ticketsAperti',
|
||||
'scadenzeImminenti',
|
||||
'ultimiDocumenti',
|
||||
'ultimiMovimenti'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DashboardStatsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Ottiene le statistiche per la dashboard
|
||||
*/
|
||||
public function getStats()
|
||||
{
|
||||
try {
|
||||
// Statistiche base (con fallback se le tabelle non esistono)
|
||||
$stats = [
|
||||
'stabili_totali' => $this->getStabiliCount(),
|
||||
'condomini_totali' => $this->getCondominiCount(),
|
||||
'tickets_aperti' => $this->getTicketsApertiCount(),
|
||||
'fatture_mese' => $this->getFattureMeseSum(),
|
||||
'notifiche_recenti' => $this->getNotificheRecenti(),
|
||||
'ultimi_tickets' => $this->getUltimiTickets()
|
||||
];
|
||||
|
||||
return response()->json($stats);
|
||||
} catch (\Exception $e) {
|
||||
// Se ci sono errori, restituiamo dati mock
|
||||
return response()->json([
|
||||
'stabili_totali' => 12,
|
||||
'condomini_totali' => 248,
|
||||
'tickets_aperti' => 7,
|
||||
'fatture_mese' => 15420.00,
|
||||
'notifiche_recenti' => [
|
||||
['tipo' => 'warning', 'messaggio' => 'Scadenza rata - Condominio Roma'],
|
||||
['tipo' => 'info', 'messaggio' => 'Nuovo ticket supporto #1234'],
|
||||
['tipo' => 'success', 'messaggio' => 'Fattura #2024-001 pagata']
|
||||
],
|
||||
'ultimi_tickets' => [
|
||||
['id' => '#1234', 'descrizione' => 'Problema ascensore', 'stato' => 'Aperto'],
|
||||
['id' => '#1233', 'descrizione' => 'Perdita idrica', 'stato' => 'Urgente'],
|
||||
['id' => '#1232', 'descrizione' => 'Richiesta info', 'stato' => 'Risolto']
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getStabiliCount()
|
||||
{
|
||||
try {
|
||||
if (DB::getSchemaBuilder()->hasTable('stabili')) {
|
||||
return DB::table('stabili')->count();
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
return 12; // fallback
|
||||
}
|
||||
|
||||
private function getCondominiCount()
|
||||
{
|
||||
try {
|
||||
if (DB::getSchemaBuilder()->hasTable('soggetti')) {
|
||||
return DB::table('soggetti')->where('tipo', 'condomino')->count();
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
return 248; // fallback
|
||||
}
|
||||
|
||||
private function getTicketsApertiCount()
|
||||
{
|
||||
try {
|
||||
if (DB::getSchemaBuilder()->hasTable('tickets')) {
|
||||
return DB::table('tickets')->where('stato', 'aperto')->count();
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
return 7; // fallback
|
||||
}
|
||||
|
||||
private function getFattureMeseSum()
|
||||
{
|
||||
try {
|
||||
if (DB::getSchemaBuilder()->hasTable('fatture')) {
|
||||
return DB::table('fatture')
|
||||
->whereMonth('created_at', now()->month)
|
||||
->whereYear('created_at', now()->year)
|
||||
->sum('importo') ?? 0;
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
return 15420.00; // fallback
|
||||
}
|
||||
|
||||
private function getNotificheRecenti()
|
||||
{
|
||||
// Per ora restituiamo dati mock, poi implementeremo una tabella notifiche
|
||||
return [
|
||||
['tipo' => 'warning', 'messaggio' => 'Scadenza rata - Condominio Roma'],
|
||||
['tipo' => 'info', 'messaggio' => 'Nuovo ticket supporto #1234'],
|
||||
['tipo' => 'success', 'messaggio' => 'Fattura #2024-001 pagata']
|
||||
];
|
||||
}
|
||||
|
||||
private function getUltimiTickets()
|
||||
{
|
||||
try {
|
||||
if (DB::getSchemaBuilder()->hasTable('tickets')) {
|
||||
return DB::table('tickets')
|
||||
->select('id', 'oggetto as descrizione', 'stato')
|
||||
->orderBy('created_at', 'desc')
|
||||
->limit(3)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
return [
|
||||
['id' => '#1234', 'descrizione' => 'Problema ascensore', 'stato' => 'Aperto'],
|
||||
['id' => '#1233', 'descrizione' => 'Perdita idrica', 'stato' => 'Urgente'],
|
||||
['id' => '#1232', 'descrizione' => 'Richiesta info', 'stato' => 'Risolto']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DirittoRealeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.diritti-reali.index', [
|
||||
'title' => 'Diritti Reali',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Diritti Reali' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('admin.diritti-reali.create', [
|
||||
'title' => 'Nuovo Diritto Reale',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Diritti Reali' => route('admin.diritti-reali.index'),
|
||||
'Nuovo Diritto' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// TODO: Implement store logic
|
||||
return redirect()->route('admin.diritti-reali.index')
|
||||
->with('success', 'Diritto reale creato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
return view('admin.diritti-reali.show', [
|
||||
'title' => 'Dettaglio Diritto Reale',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Diritti Reali' => route('admin.diritti-reali.index'),
|
||||
'Dettaglio' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
return view('admin.diritti-reali.edit', [
|
||||
'title' => 'Modifica Diritto Reale',
|
||||
'breadcrumb' => [
|
||||
'Dashboard' => route('admin.dashboard'),
|
||||
'Diritti Reali' => route('admin.diritti-reali.index'),
|
||||
'Modifica' => ''
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
// TODO: Implement update logic
|
||||
return redirect()->route('admin.diritti-reali.index')
|
||||
->with('success', 'Diritto reale aggiornato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
// TODO: Implement destroy logic
|
||||
return redirect()->route('admin.diritti-reali.index')
|
||||
->with('success', 'Diritto reale eliminato con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\DocumentoStabile;
|
||||
use App\Models\Stabile;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use ZipArchive;
|
||||
|
||||
class DocumentiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Carica nuovi documenti per uno stabile
|
||||
*/
|
||||
public function store(Request $request, Stabile $stabile)
|
||||
{
|
||||
$request->validate([
|
||||
'documenti.*' => 'required|file|max:10240|mimes:pdf,doc,docx,xls,xlsx,jpg,jpeg,png,gif',
|
||||
'categoria_documento' => 'required|string|in:' . implode(',', array_keys(DocumentoStabile::categorie()))
|
||||
]);
|
||||
|
||||
$documentiCaricati = [];
|
||||
$errori = [];
|
||||
|
||||
if ($request->hasFile('documenti')) {
|
||||
foreach ($request->file('documenti') as $file) {
|
||||
try {
|
||||
// Genera nome unico per il file
|
||||
$nomeOriginale = $file->getClientOriginalName();
|
||||
$estensione = $file->getClientOriginalExtension();
|
||||
$nomeFile = Str::slug(pathinfo($nomeOriginale, PATHINFO_FILENAME)) . '_' . time() . '.' . $estensione;
|
||||
|
||||
// Percorso di salvataggio: documenti/stabili/{stabile_id}/
|
||||
$percorso = "documenti/stabili/{$stabile->id}";
|
||||
$percorsoCompleto = $file->storeAs($percorso, $nomeFile, 'public');
|
||||
|
||||
// Crea record nel database
|
||||
$documento = DocumentoStabile::create([
|
||||
'stabile_id' => $stabile->id,
|
||||
'nome_file' => $nomeFile,
|
||||
'nome_originale' => $nomeOriginale,
|
||||
'percorso_file' => $percorsoCompleto,
|
||||
'categoria' => $request->categoria_documento,
|
||||
'tipo_mime' => $file->getMimeType(),
|
||||
'dimensione' => $file->getSize(),
|
||||
'descrizione' => $request->descrizione_documento,
|
||||
'data_scadenza' => $request->data_scadenza_documento,
|
||||
'tags' => $request->tags_documento,
|
||||
'pubblico' => $request->has('pubblico_documento'),
|
||||
'caricato_da' => Auth::id()
|
||||
]);
|
||||
|
||||
$documentiCaricati[] = $documento;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errori[] = "Errore nel caricamento di {$nomeOriginale}: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($documentiCaricati) > 0) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => count($documentiCaricati) . ' documento/i caricato/i con successo',
|
||||
'documenti' => $documentiCaricati,
|
||||
'errori' => $errori
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Nessun documento caricato',
|
||||
'errori' => $errori
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista documenti di uno stabile
|
||||
*/
|
||||
public function index(Stabile $stabile)
|
||||
{
|
||||
$documenti = $stabile->documenti()
|
||||
->with('caricatore')
|
||||
->orderBy('created_at', 'desc')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'documenti' => $documenti
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download di un documento
|
||||
*/
|
||||
public function download(DocumentoStabile $documento)
|
||||
{
|
||||
if (!$documento->fileEsiste()) {
|
||||
abort(404, 'File non trovato');
|
||||
}
|
||||
|
||||
// Incrementa contatore download
|
||||
$documento->incrementaDownload();
|
||||
|
||||
return Storage::disk('public')->download(
|
||||
$documento->percorso_file,
|
||||
$documento->nome_originale
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visualizza un documento nel browser
|
||||
*/
|
||||
public function view(DocumentoStabile $documento)
|
||||
{
|
||||
if (!$documento->fileEsiste()) {
|
||||
abort(404, 'File non trovato');
|
||||
}
|
||||
|
||||
// Incrementa contatore accessi
|
||||
$documento->update(['ultimo_accesso' => now()]);
|
||||
|
||||
$path = Storage::disk('public')->path($documento->percorso_file);
|
||||
|
||||
return response()->file($path, [
|
||||
'Content-Type' => $documento->tipo_mime,
|
||||
'Content-Disposition' => 'inline; filename="' . $documento->nome_originale . '"'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Elimina un documento
|
||||
*/
|
||||
public function destroy(DocumentoStabile $documento)
|
||||
{
|
||||
try {
|
||||
$documento->delete(); // Il boot() del model si occuperà di eliminare il file fisico
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Documento eliminato con successo'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Errore nell\'eliminazione del documento: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download multiplo di documenti
|
||||
*/
|
||||
public function downloadMultiple(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'documento_ids' => 'required|array',
|
||||
'documento_ids.*' => 'exists:documenti_stabili,id'
|
||||
]);
|
||||
|
||||
$documenti = DocumentoStabile::whereIn('id', $request->documento_ids)->get();
|
||||
|
||||
if ($documenti->isEmpty()) {
|
||||
return response()->json(['success' => false, 'message' => 'Nessun documento trovato'], 404);
|
||||
}
|
||||
|
||||
// Crea un file ZIP temporaneo
|
||||
$zipFileName = 'documenti_' . time() . '.zip';
|
||||
$zipPath = storage_path('app/temp/' . $zipFileName);
|
||||
|
||||
// Assicurati che la directory temp esista
|
||||
if (!file_exists(dirname($zipPath))) {
|
||||
mkdir(dirname($zipPath), 0755, true);
|
||||
}
|
||||
|
||||
$zip = new ZipArchive;
|
||||
if ($zip->open($zipPath, ZipArchive::CREATE) === TRUE) {
|
||||
foreach ($documenti as $documento) {
|
||||
if ($documento->fileEsiste()) {
|
||||
$filePath = Storage::disk('public')->path($documento->percorso_file);
|
||||
$zip->addFile($filePath, $documento->nome_originale);
|
||||
$documento->incrementaDownload();
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
|
||||
return response()->download($zipPath, $zipFileName)->deleteFileAfterSend(true);
|
||||
}
|
||||
|
||||
return response()->json(['success' => false, 'message' => 'Errore nella creazione dell\'archivio'], 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminazione multipla di documenti
|
||||
*/
|
||||
public function deleteMultiple(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'documento_ids' => 'required|array',
|
||||
'documento_ids.*' => 'exists:documenti_stabili,id'
|
||||
]);
|
||||
|
||||
try {
|
||||
$documenti = DocumentoStabile::whereIn('id', $request->documento_ids)->get();
|
||||
$deletedCount = 0;
|
||||
|
||||
foreach ($documenti as $documento) {
|
||||
$documento->delete();
|
||||
$deletedCount++;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "{$deletedCount} documento/i eliminato/i con successo",
|
||||
'deleted_count' => $deletedCount
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Errore nell\'eliminazione dei documenti: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stampa elenco documenti
|
||||
*/
|
||||
public function printList(Stabile $stabile)
|
||||
{
|
||||
$documenti = $stabile->documenti()
|
||||
->with('caricatore')
|
||||
->orderBy('categoria')
|
||||
->orderBy('created_at', 'desc')
|
||||
->get()
|
||||
->groupBy('categoria');
|
||||
|
||||
return view('admin.documenti.print-list', compact('stabile', 'documenti'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggiorna i metadati di un documento
|
||||
*/
|
||||
public function updateMetadata(Request $request, DocumentoStabile $documento)
|
||||
{
|
||||
$request->validate([
|
||||
'categoria' => 'required|string|in:' . implode(',', array_keys(DocumentoStabile::categorie())),
|
||||
'descrizione' => 'nullable|string|max:1000',
|
||||
'data_scadenza' => 'nullable|date',
|
||||
'tags' => 'nullable|string',
|
||||
'pubblico' => 'boolean'
|
||||
]);
|
||||
|
||||
$documento->update($request->only([
|
||||
'categoria', 'descrizione', 'data_scadenza', 'tags', 'pubblico'
|
||||
]));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Metadati documento aggiornati con successo',
|
||||
'documento' => $documento->fresh()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ricerca documenti
|
||||
*/
|
||||
public function search(Request $request, Stabile $stabile)
|
||||
{
|
||||
$query = $stabile->documenti();
|
||||
|
||||
if ($request->filled('categoria')) {
|
||||
$query->where('categoria', $request->categoria);
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where(function($q) use ($search) {
|
||||
$q->where('nome_originale', 'like', "%{$search}%")
|
||||
->orWhere('descrizione', 'like', "%{$search}%")
|
||||
->orWhere('tags', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->filled('scadenza')) {
|
||||
switch ($request->scadenza) {
|
||||
case 'scaduti':
|
||||
$query->scaduti();
|
||||
break;
|
||||
case 'in_scadenza':
|
||||
$query->inScadenza(30);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$documenti = $query->with('caricatore')
|
||||
->orderBy('created_at', 'desc')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'documenti' => $documenti
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Documento;
|
||||
use App\Models\Stabile;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class DocumentoController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
|
||||
$query = Documento::with('documentable')
|
||||
->whereHasMorph('documentable', [Stabile::class], function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
});
|
||||
|
||||
// Filtri
|
||||
if ($request->filled('tipo_documento')) {
|
||||
$query->where('tipo_documento', $request->tipo_documento);
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$query->where(function($q) use ($request) {
|
||||
$q->where('nome_file', 'like', '%' . $request->search . '%')
|
||||
->orWhere('descrizione', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
}
|
||||
|
||||
$documenti = $query->orderBy('created_at', 'desc')->paginate(20);
|
||||
|
||||
// Tipi documento per filtro
|
||||
$tipiDocumento = Documento::whereHasMorph('documentable', [Stabile::class], function($q) use ($amministratore_id) {
|
||||
$q->where('amministratore_id', $amministratore_id);
|
||||
})->distinct()->pluck('tipo_documento')->filter();
|
||||
|
||||
return view('admin.documenti.index', compact('documenti', 'tipiDocumento'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
||||
$stabili = Stabile::where('amministratore_id', $amministratore_id)->attivi()->get();
|
||||
|
||||
return view('admin.documenti.create', compact('stabili'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'documentable_type' => 'required|string',
|
||||
'documentable_id' => 'required|integer',
|
||||
'file' => 'required|file|max:10240', // 10MB max
|
||||
'tipo_documento' => 'required|string|max:100',
|
||||
'descrizione' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$file = $request->file('file');
|
||||
$path = $file->store('documenti', 'public');
|
||||
|
||||
Documento::create([
|
||||
'documentable_type' => $request->documentable_type,
|
||||
'documentable_id' => $request->documentable_id,
|
||||
'nome_file' => $file->getClientOriginalName(),
|
||||
'path_file' => $path,
|
||||
'tipo_documento' => $request->tipo_documento,
|
||||
'descrizione' => $request->descrizione,
|
||||
'mime_type' => $file->getMimeType(),
|
||||
'dimensione_file' => $file->getSize(),
|
||||
'hash_file' => hash_file('sha256', $file->path()),
|
||||
]);
|
||||
|
||||
return redirect()->route('admin.documenti.index')
|
||||
->with('success', 'Documento caricato con successo.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Documento $documento)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($documento->documentable_type === Stabile::class) {
|
||||
$stabile = $documento->documentable;
|
||||
if ($stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
return view('admin.documenti.show', compact('documento'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Download del documento
|
||||
*/
|
||||
public function download(Documento $documento)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($documento->documentable_type === Stabile::class) {
|
||||
$stabile = $documento->documentable;
|
||||
if ($stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Storage::disk('public')->exists($documento->path_file)) {
|
||||
abort(404, 'File non trovato');
|
||||
}
|
||||
|
||||
return Storage::disk('public')->download($documento->path_file, $documento->nome_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Documento $documento)
|
||||
{
|
||||
// Verifica accesso
|
||||
if ($documento->documentable_type === Stabile::class) {
|
||||
$stabile = $documento->documentable;
|
||||
if ($stabile->amministratore_id !== Auth::user()->amministratore->id_amministratore ?? null) {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
// Elimina il file fisico
|
||||
if (Storage::disk('public')->exists($documento->path_file)) {
|
||||
Storage::disk('public')->delete($documento->path_file);
|
||||
}
|
||||
|
||||
$documento->delete();
|
||||
|
||||
return redirect()->route('admin.documenti.index')
|
||||
->with('success', 'Documento eliminato con successo.');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class FileManagerController extends Controller
|
||||
{
|
||||
/**
|
||||
* Mostra la gestione file dell'amministratore
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
// Verifica che l'utente sia un amministratore
|
||||
if (!$user->hasRole('amministratore') || !$user->amministratore) {
|
||||
abort(403, 'Accesso non autorizzato');
|
||||
}
|
||||
|
||||
$amministratore = $user->amministratore;
|
||||
$basePath = $amministratore->getFolderPath();
|
||||
|
||||
// Ottieni struttura cartelle
|
||||
$folders = $this->getFolderStructure($basePath);
|
||||
|
||||
// Statistiche utilizzo spazio
|
||||
$stats = $this->calculateStorageStats($basePath);
|
||||
|
||||
return view('admin.file-manager.index', compact('amministratore', 'folders', 'stats'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostra contenuto di una cartella specifica
|
||||
*/
|
||||
public function folder(Request $request, $folder = '')
|
||||
{
|
||||
$user = Auth::user();
|
||||
$amministratore = $user->amministratore;
|
||||
$basePath = $amministratore->getFolderPath();
|
||||
|
||||
// Sanitizza il path per sicurezza
|
||||
$safePath = $this->sanitizePath($folder);
|
||||
$fullPath = $basePath . '/' . $safePath;
|
||||
|
||||
// Verifica che la cartella esista
|
||||
if (!Storage::disk('local')->exists($fullPath)) {
|
||||
abort(404, 'Cartella non trovata');
|
||||
}
|
||||
|
||||
// Ottieni contenuto cartella
|
||||
$files = Storage::disk('local')->files($fullPath);
|
||||
$directories = Storage::disk('local')->directories($fullPath);
|
||||
|
||||
// Formatta per la vista
|
||||
$formattedFiles = collect($files)->map(function ($file) {
|
||||
return [
|
||||
'name' => basename($file),
|
||||
'path' => $file,
|
||||
'size' => Storage::disk('local')->size($file),
|
||||
'modified' => Storage::disk('local')->lastModified($file),
|
||||
'type' => $this->getFileType($file),
|
||||
];
|
||||
});
|
||||
|
||||
$formattedDirs = collect($directories)->map(function ($dir) {
|
||||
return [
|
||||
'name' => basename($dir),
|
||||
'path' => $dir,
|
||||
'type' => 'folder',
|
||||
];
|
||||
});
|
||||
|
||||
return view('admin.file-manager.folder', compact(
|
||||
'amministratore',
|
||||
'formattedFiles',
|
||||
'formattedDirs',
|
||||
'safePath',
|
||||
'fullPath'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file nella cartella dell'amministratore
|
||||
*/
|
||||
public function upload(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'file' => 'required|file|max:10240', // Max 10MB
|
||||
'folder' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$user = Auth::user();
|
||||
$amministratore = $user->amministratore;
|
||||
$basePath = $amministratore->getFolderPath();
|
||||
|
||||
$folder = $this->sanitizePath($request->folder ?? 'documenti/allegati');
|
||||
$uploadPath = $basePath . '/' . $folder;
|
||||
|
||||
// Upload file
|
||||
$file = $request->file('file');
|
||||
$filename = time() . '_' . $file->getClientOriginalName();
|
||||
|
||||
$file->storeAs($uploadPath, $filename, 'local');
|
||||
|
||||
return redirect()->back()->with('success', "File {$filename} caricato con successo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Download file dall'archivio amministratore
|
||||
*/
|
||||
public function download($filePath)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$amministratore = $user->amministratore;
|
||||
$basePath = $amministratore->getFolderPath();
|
||||
|
||||
$safePath = $this->sanitizePath($filePath);
|
||||
$fullPath = $basePath . '/' . $safePath;
|
||||
|
||||
// Verifica che il file esista e appartenga all'amministratore
|
||||
if (!Storage::disk('local')->exists($fullPath)) {
|
||||
abort(404, 'File non trovato');
|
||||
}
|
||||
|
||||
return response()->download(storage_path("app/{$fullPath}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottieni struttura cartelle
|
||||
*/
|
||||
private function getFolderStructure($basePath): array
|
||||
{
|
||||
$structure = [
|
||||
'documenti' => [
|
||||
'allegati' => [],
|
||||
'contratti' => [],
|
||||
'assemblee' => [],
|
||||
'preventivi' => [],
|
||||
],
|
||||
'backup' => [
|
||||
'database' => [],
|
||||
'files' => [],
|
||||
],
|
||||
'exports' => [],
|
||||
'logs' => [],
|
||||
];
|
||||
|
||||
foreach ($structure as $folder => $subfolders) {
|
||||
if (is_array($subfolders)) {
|
||||
foreach ($subfolders as $subfolder => $content) {
|
||||
$path = "{$basePath}/{$folder}/{$subfolder}";
|
||||
$structure[$folder][$subfolder] = $this->getFolderInfo($path);
|
||||
}
|
||||
} else {
|
||||
$path = "{$basePath}/{$folder}";
|
||||
$structure[$folder] = $this->getFolderInfo($path);
|
||||
}
|
||||
}
|
||||
|
||||
return $structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottieni info cartella
|
||||
*/
|
||||
private function getFolderInfo($path): array
|
||||
{
|
||||
if (!Storage::disk('local')->exists($path)) {
|
||||
return ['files' => 0, 'size' => 0];
|
||||
}
|
||||
|
||||
$files = Storage::disk('local')->allFiles($path);
|
||||
$totalSize = 0;
|
||||
|
||||
foreach ($files as $file) {
|
||||
$totalSize += Storage::disk('local')->size($file);
|
||||
}
|
||||
|
||||
return [
|
||||
'files' => count($files),
|
||||
'size' => $totalSize,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcola statistiche storage
|
||||
*/
|
||||
private function calculateStorageStats($basePath): array
|
||||
{
|
||||
$allFiles = Storage::disk('local')->allFiles($basePath);
|
||||
$totalSize = 0;
|
||||
$fileTypes = [];
|
||||
|
||||
foreach ($allFiles as $file) {
|
||||
$size = Storage::disk('local')->size($file);
|
||||
$totalSize += $size;
|
||||
|
||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||
$fileTypes[$ext] = ($fileTypes[$ext] ?? 0) + 1;
|
||||
}
|
||||
|
||||
return [
|
||||
'total_files' => count($allFiles),
|
||||
'total_size' => $totalSize,
|
||||
'file_types' => $fileTypes,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizza path per sicurezza
|
||||
*/
|
||||
private function sanitizePath($path): string
|
||||
{
|
||||
// Rimuovi caratteri pericolosi
|
||||
$path = str_replace(['../', '../', '..\\'], '', $path);
|
||||
$path = trim($path, '/\\');
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ottieni tipo file
|
||||
*/
|
||||
private function getFileType($file): string
|
||||
{
|
||||
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||
|
||||
$types = [
|
||||
'pdf' => 'document',
|
||||
'doc' => 'document', 'docx' => 'document',
|
||||
'xls' => 'spreadsheet', 'xlsx' => 'spreadsheet',
|
||||
'jpg' => 'image', 'jpeg' => 'image', 'png' => 'image', 'gif' => 'image',
|
||||
'zip' => 'archive', 'rar' => 'archive', '7z' => 'archive',
|
||||
];
|
||||
|
||||
return $types[$ext] ?? 'file';
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user