836 lines
41 KiB
PHP
836 lines
41 KiB
PHP
<?php
|
|
namespace App\Filament\Pages\Gescon;
|
|
|
|
use App\Filament\Pages\Condomini\CruscottoStabile;
|
|
use App\Models\Amministratore;
|
|
use App\Models\Palazzina;
|
|
use App\Models\Persona;
|
|
use App\Models\PersonaUnitaRelazione;
|
|
use App\Models\PianoContiCondominio;
|
|
use App\Models\Stabile;
|
|
use App\Models\StabileAmministratoreTransfer;
|
|
use App\Models\UnitaImmobiliare;
|
|
use App\Models\User;
|
|
use App\Services\GesconImport\EssentialImportService;
|
|
use App\Services\Stabili\StabileTransferService;
|
|
use App\Support\StabileContext;
|
|
use BackedEnum;
|
|
use Filament\Actions\Action;
|
|
use Filament\Forms\Components\Checkbox;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\Textarea;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Pages\Page;
|
|
use Filament\Tables\Columns\IconColumn;
|
|
use Filament\Tables\Columns\TextColumn;
|
|
use Filament\Tables\Concerns\InteractsWithTable;
|
|
use Filament\Tables\Contracts\HasTable;
|
|
use Filament\Tables\Table;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Schema as SchemaFacade;
|
|
use Illuminate\Support\Str;
|
|
use UnitEnum;
|
|
|
|
class StabiliArchivio extends Page implements HasTable
|
|
{
|
|
use InteractsWithTable;
|
|
|
|
protected static ?string $navigationLabel = 'Elenco stabili';
|
|
|
|
protected static ?string $title = 'Elenco stabili';
|
|
|
|
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-building-office';
|
|
|
|
protected static UnitEnum|string|null $navigationGroup = 'Stabile';
|
|
|
|
protected static ?int $navigationSort = 11;
|
|
|
|
protected static ?string $slug = 'gescon/anagrafica/stabili';
|
|
|
|
protected string $view = 'filament.pages.gescon.table';
|
|
|
|
public static function canAccess(): bool
|
|
{
|
|
$user = Auth::user();
|
|
return $user instanceof User
|
|
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']);
|
|
}
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->mountInteractsWithTable();
|
|
}
|
|
|
|
protected function getTableQuery(): Builder
|
|
{
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return Stabile::query()->whereRaw('1 = 0');
|
|
}
|
|
|
|
if ($user->hasAnyRole(['super-admin'])) {
|
|
return Stabile::query();
|
|
}
|
|
|
|
$amm = $user->amministratore;
|
|
if ($amm) {
|
|
return Stabile::query()->where('amministratore_id', $amm->id);
|
|
}
|
|
|
|
$allowedIds = StabileContext::accessibleStabili($user)
|
|
->pluck('id')
|
|
->map(fn($v) => (int) $v)
|
|
->values();
|
|
|
|
if ($allowedIds->isEmpty()) {
|
|
return Stabile::query()->whereRaw('1 = 0');
|
|
}
|
|
|
|
return Stabile::query()->whereIn('id', $allowedIds);
|
|
}
|
|
|
|
public function table(Table $table): Table
|
|
{
|
|
return $table
|
|
->striped()
|
|
->defaultSort('denominazione')
|
|
->headerActions([
|
|
Action::make('sync_all_gescon')
|
|
->label('Sync GESCON (tutti)')
|
|
->icon('heroicon-o-arrow-path')
|
|
->visible(function (): bool {
|
|
$user = Auth::user();
|
|
return $user instanceof User && $user->can('gescon-import.execute');
|
|
})
|
|
->form([
|
|
TextInput::make('path')
|
|
->label('Percorso archivio GESCON')
|
|
->helperText('Cartella base che contiene /<codice_stabile>/... e /dbc/Stabili.mdb')
|
|
->default('/mnt/gescon-archives/gescon')
|
|
->maxLength(500),
|
|
TextInput::make('anno')
|
|
->label('Anno gestione (opzionale)')
|
|
->helperText('Inserisci un anno (es. 2025) o "all" per tutte le cartelle.'),
|
|
Checkbox::make('dry')->label('Dry-run (solo simulazione)')->default(false),
|
|
Checkbox::make('with_unita')->label('Includi unità immobiliari')->default(false),
|
|
Checkbox::make('with_soggetti')->label('Includi anagrafiche (soggetti)')->default(false),
|
|
Checkbox::make('with_diritti')->label('Includi diritti (proprietà/inquilini)')->default(false),
|
|
Checkbox::make('with_millesimi')->label('Includi tabelle millesimali')->default(false),
|
|
Checkbox::make('with_voci')->label('Includi voci (piano dei conti / voci spesa)')->default(false),
|
|
Checkbox::make('with_gestioni')->label('Includi gestioni')->default(false),
|
|
Checkbox::make('with_banche')->label('Includi banche')->default(false),
|
|
])
|
|
->requiresConfirmation()
|
|
->action(function (array $data): void {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return;
|
|
}
|
|
|
|
$amm = $user->amministratore;
|
|
if (! $amm) {
|
|
Notification::make()
|
|
->title('Amministratore non associato')
|
|
->body('Impossibile eseguire sync senza amministratore associato all\'utente.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$options = [
|
|
'path' => (string) ($data['path'] ?? '/mnt/gescon-archives/gescon'),
|
|
'anno' => isset($data['anno']) && trim((string) $data['anno']) !== '' ? trim((string) $data['anno']) : null,
|
|
'with_unita' => (bool) ($data['with_unita'] ?? false),
|
|
'with_soggetti' => (bool) ($data['with_soggetti'] ?? false),
|
|
'with_diritti' => (bool) ($data['with_diritti'] ?? false),
|
|
'with_millesimi' => (bool) ($data['with_millesimi'] ?? false),
|
|
'with_voci' => (bool) ($data['with_voci'] ?? false),
|
|
'with_gestioni' => (bool) ($data['with_gestioni'] ?? false),
|
|
'with_banche' => (bool) ($data['with_banche'] ?? false),
|
|
'dry' => (bool) ($data['dry'] ?? false),
|
|
];
|
|
|
|
$query = $this->getTableQuery();
|
|
$stabili = $query->get();
|
|
$svc = new EssentialImportService();
|
|
foreach ($stabili as $record) {
|
|
$legacyCode = trim((string) ($record->codice_stabile ?? ''));
|
|
if ($legacyCode === '') {
|
|
$legacyCode = trim((string) ($record->codice_interno ?? ''));
|
|
}
|
|
if ($legacyCode === '') {
|
|
continue;
|
|
}
|
|
$svc->syncStabile($amm, $legacyCode, $options);
|
|
}
|
|
|
|
Notification::make()
|
|
->title('Sync completato')
|
|
->body('Sincronizzati tutti gli stabili visibili.')
|
|
->success()
|
|
->send();
|
|
}),
|
|
Action::make('crea_stabile')
|
|
->label('Crea stabile')
|
|
->icon('heroicon-o-plus')
|
|
->visible(function (): bool {
|
|
$user = Auth::user();
|
|
return $user instanceof User
|
|
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore']);
|
|
})
|
|
->form([
|
|
TextInput::make('codice_stabile')
|
|
->label('Codice stabile (cartella legacy)')
|
|
->helperText('Esempio: 0021. Serve per collegare la cartella in /mnt/gescon-archives/gescon')
|
|
->required()
|
|
->maxLength(20),
|
|
TextInput::make('denominazione')
|
|
->label('Denominazione')
|
|
->required()
|
|
->maxLength(255),
|
|
TextInput::make('indirizzo')
|
|
->label('Indirizzo')
|
|
->maxLength(255),
|
|
TextInput::make('cap')
|
|
->label('CAP')
|
|
->maxLength(10),
|
|
TextInput::make('citta')
|
|
->label('Città')
|
|
->maxLength(100),
|
|
TextInput::make('provincia')
|
|
->label('Provincia')
|
|
->maxLength(5),
|
|
Checkbox::make('entra_subito')
|
|
->label('Entra subito nello stabile')
|
|
->default(true),
|
|
])
|
|
->action(function (array $data): void {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
Notification::make()->title('Utente non valido')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$amm = $user->amministratore;
|
|
if (! $amm) {
|
|
$amm = Amministratore::query()->orderBy('id')->first();
|
|
}
|
|
if (! $amm) {
|
|
Notification::make()
|
|
->title('Nessun amministratore disponibile')
|
|
->body('Serve almeno un record in tabella amministratori per creare uno stabile.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$codice = trim((string) ($data['codice_stabile'] ?? ''));
|
|
if ($codice === '') {
|
|
Notification::make()->title('Codice mancante')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
if (Stabile::query()->where('codice_stabile', $codice)->exists()) {
|
|
Notification::make()
|
|
->title('Codice già presente')
|
|
->body('Esiste già uno stabile con codice ' . $codice)
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$stabile = Stabile::query()->create([
|
|
'amministratore_id' => $amm->id,
|
|
'codice_stabile' => $codice,
|
|
'denominazione' => (string) ($data['denominazione'] ?? $codice),
|
|
'indirizzo' => (string) ($data['indirizzo'] ?? ''),
|
|
'cap' => (string) ($data['cap'] ?? ''),
|
|
'citta' => (string) ($data['citta'] ?? ''),
|
|
'provincia' => (string) ($data['provincia'] ?? ''),
|
|
'stato' => 'attivo',
|
|
'attivo' => true,
|
|
]);
|
|
|
|
Notification::make()
|
|
->title('Stabile creato')
|
|
->body('Codice: ' . $codice)
|
|
->success()
|
|
->send();
|
|
|
|
StabileContext::setActiveStabileId($user, (int) $stabile->id);
|
|
|
|
if (! empty($data['entra_subito'])) {
|
|
$this->redirect(\App\Filament\Pages\Condomini\CruscottoStabile::getUrl(panel: 'admin-filament'));
|
|
}
|
|
}),
|
|
|
|
Action::make('crea_demo')
|
|
->label('Crea stabile demo')
|
|
->icon('heroicon-o-sparkles')
|
|
->visible(function (): bool {
|
|
$user = Auth::user();
|
|
return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin']);
|
|
})
|
|
->form([
|
|
TextInput::make('denominazione')
|
|
->label('Denominazione')
|
|
->default('Condominio Demo')
|
|
->required(),
|
|
Checkbox::make('entra_subito')
|
|
->label('Entra subito nello stabile')
|
|
->default(true),
|
|
])
|
|
->requiresConfirmation()
|
|
->action(function (array $data): void {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
Notification::make()->title('Utente non valido')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$amm = $user->amministratore;
|
|
if (! $amm) {
|
|
$amm = Amministratore::query()->orderBy('id')->first();
|
|
}
|
|
if (! $amm) {
|
|
Notification::make()
|
|
->title('Nessun amministratore disponibile')
|
|
->body('Serve almeno un record in tabella amministratori per creare uno stabile.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$codice = 'DEMO' . Str::upper(Str::random(4));
|
|
while (Stabile::query()->where('codice_stabile', $codice)->exists()) {
|
|
$codice = 'DEMO' . Str::upper(Str::random(4));
|
|
}
|
|
|
|
$stabile = Stabile::query()->create([
|
|
'amministratore_id' => $amm->id,
|
|
'codice_stabile' => $codice,
|
|
'denominazione' => (string) ($data['denominazione'] ?? 'Condominio Demo'),
|
|
'indirizzo' => 'Via Demo 1',
|
|
'cap' => '00000',
|
|
'citta' => 'Demo',
|
|
'provincia' => 'RM',
|
|
'stato' => 'attivo',
|
|
'attivo' => true,
|
|
]);
|
|
|
|
$palazzina = Palazzina::query()->create([
|
|
'stabile_id' => $stabile->id,
|
|
'codice_palazzina' => 'A',
|
|
'denominazione' => 'Palazzina A',
|
|
'numero_scale' => 1,
|
|
'numero_piani_fuori_terra' => 3,
|
|
'numero_piani_interrati' => 0,
|
|
'ha_piano_terra' => true,
|
|
'appartamenti_per_piano' => 2,
|
|
'attiva' => true,
|
|
'created_by' => $user->id,
|
|
]);
|
|
|
|
$unita = UnitaImmobiliare::query()->create([
|
|
'stabile_id' => $stabile->id,
|
|
'palazzina_id' => $palazzina->id,
|
|
'codice_unita' => 'A-1-0-01',
|
|
'palazzina' => 'A',
|
|
'scala' => '1',
|
|
'piano' => 0,
|
|
'interno' => '01',
|
|
'denominazione' => 'Unità Demo',
|
|
'tipo_unita' => 'appartamento',
|
|
'attiva' => true,
|
|
'unita_demo' => true,
|
|
'created_by' => $user->id,
|
|
]);
|
|
|
|
$persona = Persona::query()->create([
|
|
'tipologia' => 'fisica',
|
|
'cognome' => 'Demo',
|
|
'nome' => 'Condomino',
|
|
'codice_fiscale' => null,
|
|
'telefono_principale' => null,
|
|
'email_principale' => null,
|
|
'attivo' => true,
|
|
]);
|
|
|
|
PersonaUnitaRelazione::query()->create([
|
|
'persona_id' => $persona->id,
|
|
'unita_id' => $unita->id,
|
|
'tipo_relazione' => 'proprietario',
|
|
'quota_relazione' => 100,
|
|
'attivo' => true,
|
|
'riceve_comunicazioni' => true,
|
|
'riceve_convocazioni' => true,
|
|
'vota_assemblea' => true,
|
|
]);
|
|
|
|
Notification::make()
|
|
->title('Stabile demo creato')
|
|
->body('Codice: ' . $codice)
|
|
->success()
|
|
->send();
|
|
|
|
StabileContext::setActiveStabileId($user, (int) $stabile->id);
|
|
|
|
if (! empty($data['entra_subito'])) {
|
|
$this->redirect(CruscottoStabile::getUrl(panel: 'admin-filament'));
|
|
}
|
|
}),
|
|
])
|
|
->columns([
|
|
TextColumn::make('codice_stabile')
|
|
->label('Codice stabile')
|
|
->searchable()
|
|
->sortable()
|
|
->toggleable(),
|
|
|
|
TextColumn::make('cod_stabile')
|
|
->label('Codice mnemonico')
|
|
->searchable()
|
|
->sortable()
|
|
->toggleable(),
|
|
|
|
TextColumn::make('denominazione')
|
|
->label('Denominazione')
|
|
->searchable()
|
|
->sortable()
|
|
->wrap(),
|
|
|
|
TextColumn::make('amministratore_corrente')
|
|
->label('Amministratore')
|
|
->getStateUsing(function (Stabile $record): string {
|
|
$amministratore = $record->amministratore;
|
|
if (! $amministratore instanceof Amministratore) {
|
|
return '-';
|
|
}
|
|
|
|
$label = trim((string) ($amministratore->denominazione_studio ?: $amministratore->nome_completo));
|
|
if ($label === '') {
|
|
$label = 'Amministratore';
|
|
}
|
|
|
|
return $label . ' (ID ' . (int) $amministratore->id . ')';
|
|
})
|
|
->searchable(false)
|
|
->toggleable()
|
|
->wrap(),
|
|
|
|
TextColumn::make('indirizzo_completo')
|
|
->label('Indirizzo')
|
|
->toggleable()
|
|
->wrap(),
|
|
|
|
TextColumn::make('stato')
|
|
->label('Stato')
|
|
->sortable()
|
|
->toggleable(),
|
|
|
|
IconColumn::make('attivo')
|
|
->label('Attivo')
|
|
->boolean()
|
|
->toggleable(),
|
|
|
|
TextColumn::make('updated_at')
|
|
->label('Aggiornato')
|
|
->dateTime('d/m/Y H:i')
|
|
->sortable()
|
|
->toggleable(),
|
|
])
|
|
->actions([
|
|
Action::make('scheda')
|
|
->label('Scheda')
|
|
->icon('heroicon-o-identification')
|
|
->url(fn(Stabile $record) => StabileScheda::getUrl([
|
|
'record' => (int) $record->id,
|
|
], panel: 'admin-filament')),
|
|
|
|
Action::make('modifica')
|
|
->label('Modifica')
|
|
->icon('heroicon-o-pencil-square')
|
|
->visible(function (Stabile $record): bool {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return false;
|
|
}
|
|
|
|
if ($user->hasAnyRole(['super-admin', 'admin'])) {
|
|
return true;
|
|
}
|
|
|
|
// Amministratore: può modificare solo i propri.
|
|
$ammId = (int) ($user->amministratore?->id ?? 0);
|
|
return $ammId > 0 && (int) ($record->amministratore_id ?? 0) === $ammId;
|
|
})
|
|
->form([
|
|
TextInput::make('codice_stabile')
|
|
->label('Codice stabile (legacy)')
|
|
->helperText('Codice cartella GESCON (es. 0021).')
|
|
->required()
|
|
->maxLength(20),
|
|
TextInput::make('cod_stabile')
|
|
->label('Codice operatore (mnemonico)')
|
|
->helperText('Codice breve mostrato in Filament (es. 148).')
|
|
->maxLength(20),
|
|
TextInput::make('denominazione')->label('Denominazione')->required()->maxLength(255),
|
|
TextInput::make('indirizzo')->label('Indirizzo')->maxLength(255),
|
|
TextInput::make('cap')->label('CAP')->maxLength(10),
|
|
TextInput::make('citta')->label('Città')->maxLength(100),
|
|
TextInput::make('provincia')->label('Provincia')->maxLength(5),
|
|
Select::make('stato')
|
|
->label('Stato')
|
|
->options([
|
|
'attivo' => 'Attivo',
|
|
'inattivo' => 'Inattivo',
|
|
])
|
|
->default('attivo')
|
|
->required(),
|
|
Checkbox::make('attivo')->label('Attivo')->default(true),
|
|
])
|
|
->fillForm(fn(Stabile $record): array=> [
|
|
'codice_stabile' => (string) ($record->codice_stabile ?? ''),
|
|
'cod_stabile' => (string) ($record->cod_stabile ?? ''),
|
|
'denominazione' => (string) ($record->denominazione ?? ''),
|
|
'indirizzo' => (string) ($record->indirizzo ?? ''),
|
|
'cap' => (string) ($record->cap ?? ''),
|
|
'citta' => (string) ($record->citta ?? ''),
|
|
'provincia' => (string) ($record->provincia ?? ''),
|
|
'stato' => (string) ($record->stato ?? 'attivo'),
|
|
'attivo' => (bool) ($record->attivo ?? true),
|
|
])
|
|
->action(function (Stabile $record, array $data): void {
|
|
$codice = trim((string) ($data['codice_stabile'] ?? ''));
|
|
if ($codice === '') {
|
|
Notification::make()->title('Codice mancante')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$codOperatore = trim((string) ($data['cod_stabile'] ?? ''));
|
|
$codOperatore = $codOperatore !== '' ? $codOperatore : null;
|
|
|
|
$dupe = Stabile::query()
|
|
->where('codice_stabile', $codice)
|
|
->whereKeyNot((int) $record->id)
|
|
->exists();
|
|
if ($dupe) {
|
|
Notification::make()->title('Codice già presente')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$record->fill([
|
|
'codice_stabile' => $codice,
|
|
'cod_stabile' => $codOperatore,
|
|
'denominazione' => (string) ($data['denominazione'] ?? $codice),
|
|
'indirizzo' => (string) ($data['indirizzo'] ?? ''),
|
|
'cap' => (string) ($data['cap'] ?? ''),
|
|
'citta' => (string) ($data['citta'] ?? ''),
|
|
'provincia' => (string) ($data['provincia'] ?? ''),
|
|
'stato' => (string) ($data['stato'] ?? 'attivo'),
|
|
'attivo' => (bool) ($data['attivo'] ?? true),
|
|
]);
|
|
$record->save();
|
|
|
|
Notification::make()->title('Stabile aggiornato')->success()->send();
|
|
}),
|
|
|
|
Action::make('piano_conti_standard')
|
|
->label('Piano conti standard')
|
|
->icon('heroicon-o-clipboard-document-list')
|
|
->requiresConfirmation()
|
|
->action(function (Stabile $record): void {
|
|
if (! SchemaFacade::hasTable('piano_conti_condominio')) {
|
|
Notification::make()->title('Tabella piano conti non disponibile')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
$exists = PianoContiCondominio::query()
|
|
->where('stabile_id', $record->id)
|
|
->exists();
|
|
|
|
if ($exists) {
|
|
Notification::make()->title('Piano conti già presente')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
$standard = [
|
|
['codice' => 'SP.AMM', 'descrizione' => 'Spese di amministrazione', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.PUL', 'descrizione' => 'Spese pulizia e igiene', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.ILL', 'descrizione' => 'Spese illuminazione', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.ACQ', 'descrizione' => 'Spese acqua', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.RIS', 'descrizione' => 'Spese riscaldamento', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.ASC', 'descrizione' => 'Spese ascensore', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.ASS', 'descrizione' => 'Assicurazione fabbricato', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
['codice' => 'SP.MAN', 'descrizione' => 'Manutenzione ordinaria', 'tipo_conto' => 'ECONOMICO_COSTO'],
|
|
];
|
|
|
|
foreach ($standard as $row) {
|
|
PianoContiCondominio::firstOrCreate(
|
|
['stabile_id' => $record->id, 'codice' => $row['codice']],
|
|
['descrizione' => $row['descrizione'], 'tipo_conto' => $row['tipo_conto']]
|
|
);
|
|
}
|
|
|
|
Notification::make()->title('Piano conti standard creato')->success()->send();
|
|
}),
|
|
|
|
Action::make('trasferisci')
|
|
->label('Cambia amministratore')
|
|
->icon('heroicon-o-arrow-right-circle')
|
|
->visible(function (): bool {
|
|
$user = Auth::user();
|
|
return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin']);
|
|
})
|
|
->form([
|
|
Select::make('to_amministratore_id')
|
|
->label('Nuovo amministratore')
|
|
->options(function (): array {
|
|
return Amministratore::query()
|
|
->orderBy('id')
|
|
->get()
|
|
->mapWithKeys(function (Amministratore $a): array {
|
|
$label = trim((string) ($a->denominazione_studio ?: $a->nome_completo));
|
|
if ($label === '') {
|
|
$label = 'Amministratore';
|
|
}
|
|
$code = (string) ($a->codice_univoco ?: $a->codice_amministratore ?: '');
|
|
$suffix = $code !== '' ? (' [' . $code . ']') : '';
|
|
return [$a->id => $label . $suffix . ' (ID ' . $a->id . ')'];
|
|
})
|
|
->all();
|
|
})
|
|
->searchable()
|
|
->required(),
|
|
Textarea::make('reason')
|
|
->label('Motivazione')
|
|
->helperText('Traccia il motivo del passaggio: riallineamento, presa in carico interna, correzione operativa, ecc.')
|
|
->rows(3)
|
|
->required()
|
|
->maxLength(5000),
|
|
Checkbox::make('also_rubrica')
|
|
->label('Aggiorna anche Rubrica collegata (se presente)')
|
|
->default(true),
|
|
])
|
|
->requiresConfirmation()
|
|
->action(function (Stabile $record, array $data): void {
|
|
$user = Auth::user();
|
|
$toId = (int) ($data['to_amministratore_id'] ?? 0);
|
|
if ($toId <= 0) {
|
|
Notification::make()->title('Amministratore non valido')->danger()->send();
|
|
return;
|
|
}
|
|
if ((int) ($record->amministratore_id ?? 0) === $toId) {
|
|
Notification::make()->title('Nessuna modifica')->body('Stabile già assegnato a questo amministratore.')->warning()->send();
|
|
return;
|
|
}
|
|
|
|
$dest = Amministratore::query()->find($toId);
|
|
if (! $dest) {
|
|
Notification::make()->title('Amministratore non trovato')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$transfer = app(StabileTransferService::class)->transfer(
|
|
stabile: $record,
|
|
destination: $dest,
|
|
actor: $user instanceof User ? $user : null,
|
|
alsoRubrica: (bool) ($data['also_rubrica'] ?? true),
|
|
reason: trim((string) ($data['reason'] ?? '')),
|
|
source: 'portal-superadmin',
|
|
ipAddress: request()->ip(),
|
|
meta: [
|
|
'panel' => 'admin-filament',
|
|
'action' => 'stabili-archivio-trasferisci',
|
|
],
|
|
);
|
|
|
|
Notification::make()
|
|
->title('Trasferimento completato')
|
|
->body('Nuovo amministratore: ' . ($dest->codice_univoco ?: ('ID ' . $dest->id)) . ' · storico #' . (int) $transfer->id)
|
|
->success()
|
|
->send();
|
|
}),
|
|
|
|
Action::make('storico_trasferimenti')
|
|
->label('Storico passaggi')
|
|
->icon('heroicon-o-clock')
|
|
->visible(function (): bool {
|
|
$user = Auth::user();
|
|
return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin']);
|
|
})
|
|
->modalHeading('Storico passaggi amministratore')
|
|
->modalSubmitAction(false)
|
|
->modalCancelActionLabel('Chiudi')
|
|
->modalContent(function (Stabile $record): View {
|
|
$transfers = StabileAmministratoreTransfer::query()
|
|
->with(['fromAmministratore', 'toAmministratore', 'changedByUser'])
|
|
->where('stabile_id', (int) $record->id)
|
|
->latest('id')
|
|
->limit(25)
|
|
->get();
|
|
|
|
return view('filament.pages.gescon.partials.stabile-transfer-history', [
|
|
'stabile' => $record,
|
|
'transfers' => $transfers,
|
|
]);
|
|
}),
|
|
|
|
Action::make('entra')
|
|
->label('Entra')
|
|
->icon('heroicon-o-arrow-right')
|
|
->action(function (Stabile $record): void {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return;
|
|
}
|
|
if (! StabileContext::setActiveStabileId($user, (int) $record->id)) {
|
|
Notification::make()->title('Accesso negato')->danger()->send();
|
|
return;
|
|
}
|
|
$this->redirect(CruscottoStabile::getUrl(panel: 'admin-filament'));
|
|
}),
|
|
|
|
Action::make('sync_gescon')
|
|
->label('Sync GESCON')
|
|
->icon('heroicon-o-arrow-path')
|
|
->visible(function (): bool {
|
|
$user = Auth::user();
|
|
return $user instanceof User && $user->can('gescon-import.execute');
|
|
})
|
|
->form([
|
|
TextInput::make('path')
|
|
->label('Percorso archivio GESCON')
|
|
->helperText('Cartella base che contiene /<codice_stabile>/... e /dbc/Stabili.mdb')
|
|
->default('/mnt/gescon-archives/gescon')
|
|
->maxLength(500),
|
|
TextInput::make('anno')
|
|
->label('Anno gestione (opzionale)')
|
|
->helperText('Inserisci un anno (es. 2025) o "all" per tutte le cartelle.'),
|
|
Checkbox::make('dry')->label('Dry-run (solo simulazione)')->default(false),
|
|
Checkbox::make('with_unita')->label('Includi unità immobiliari')->default(false),
|
|
Checkbox::make('with_soggetti')->label('Includi anagrafiche (soggetti)')->default(false),
|
|
Checkbox::make('with_diritti')->label('Includi diritti (proprietà/inquilini)')->default(false),
|
|
Checkbox::make('with_millesimi')->label('Includi tabelle millesimali')->default(false),
|
|
Checkbox::make('with_voci')->label('Includi voci (piano dei conti / voci spesa)')->default(false),
|
|
Checkbox::make('with_gestioni')->label('Includi gestioni')->default(false),
|
|
Checkbox::make('with_banche')->label('Includi banche')->default(false),
|
|
])
|
|
->requiresConfirmation()
|
|
->action(function (Stabile $record, array $data): void {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
Notification::make()->title('Utente non valido')->danger()->send();
|
|
return;
|
|
}
|
|
|
|
$amm = $user->amministratore;
|
|
if (! $amm) {
|
|
Notification::make()
|
|
->title('Amministratore non associato')
|
|
->body('Impossibile eseguire sync senza amministratore associato all\'utente.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$legacyCode = trim((string) ($record->codice_stabile ?? ''));
|
|
if ($legacyCode === '') {
|
|
$legacyCode = trim((string) ($record->codice_interno ?? ''));
|
|
}
|
|
if ($legacyCode === '') {
|
|
Notification::make()
|
|
->title('Codice legacy mancante')
|
|
->body('Lo stabile non ha codice_stabile/codice_interno: non so quale cartella GESCON usare.')
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$svc = new EssentialImportService();
|
|
$res = $svc->syncStabile($amm, $legacyCode, [
|
|
'path' => (string) ($data['path'] ?? '/mnt/gescon-archives/gescon'),
|
|
'anno' => isset($data['anno']) && trim((string) $data['anno']) !== '' ? trim((string) $data['anno']) : null,
|
|
'with_unita' => (bool) ($data['with_unita'] ?? false),
|
|
'with_soggetti' => (bool) ($data['with_soggetti'] ?? false),
|
|
'with_diritti' => (bool) ($data['with_diritti'] ?? false),
|
|
'with_millesimi' => (bool) ($data['with_millesimi'] ?? false),
|
|
'with_voci' => (bool) ($data['with_voci'] ?? false),
|
|
'with_gestioni' => (bool) ($data['with_gestioni'] ?? false),
|
|
'with_banche' => (bool) ($data['with_banche'] ?? false),
|
|
'dry' => (bool) ($data['dry'] ?? false),
|
|
]);
|
|
|
|
$title = ($res['changed'] ?? false)
|
|
? 'Sync completato'
|
|
: 'Nessuna variazione (hash invariato)';
|
|
|
|
Notification::make()
|
|
->title($title)
|
|
->body('Stabile: ' . $legacyCode)
|
|
->success()
|
|
->send();
|
|
}),
|
|
|
|
Action::make('elimina')
|
|
->label('Elimina')
|
|
->icon('heroicon-o-trash')
|
|
->color('danger')
|
|
->visible(function (Stabile $record): bool {
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
return false;
|
|
}
|
|
|
|
if ($user->hasAnyRole(['super-admin', 'admin'])) {
|
|
return true;
|
|
}
|
|
|
|
// Amministratore: può eliminare solo i propri, e solo se non ci sono dipendenze.
|
|
$ammId = (int) ($user->amministratore?->id ?? 0);
|
|
return $ammId > 0 && (int) ($record->amministratore_id ?? 0) === $ammId;
|
|
})
|
|
->requiresConfirmation()
|
|
->action(function (Stabile $record): void {
|
|
$checks = [
|
|
'Palazzine' => fn() => $record->palazzine()->exists(),
|
|
'Unità immobiliari' => fn() => $record->unitaImmobiliari()->exists(),
|
|
'Tabelle millesimali' => fn() => $record->tabelleMillesimali()->exists(),
|
|
'Voci spesa' => fn() => $record->vociSpesa()->exists(),
|
|
'Gestioni contabili' => fn() => $record->gestioniContabili()->exists(),
|
|
'Gestioni condominiali' => fn() => $record->gestioniCondominiali()->exists(),
|
|
'Documenti collegati' => fn() => $record->documentiCollegati()->exists(),
|
|
'Dati bancari' => fn() => $record->datiBancari()->exists(),
|
|
'Tickets' => fn() => $record->tickets()->exists(),
|
|
];
|
|
|
|
$blocked = [];
|
|
foreach ($checks as $label => $fn) {
|
|
try {
|
|
if ($fn()) {
|
|
$blocked[] = $label;
|
|
}
|
|
} catch (\Throwable) {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
if (! empty($blocked)) {
|
|
Notification::make()
|
|
->title('Eliminazione bloccata')
|
|
->body('Lo stabile ha dati collegati: ' . implode(', ', $blocked))
|
|
->danger()
|
|
->send();
|
|
return;
|
|
}
|
|
|
|
$record->delete();
|
|
Notification::make()->title('Stabile eliminato')->success()->send();
|
|
}),
|
|
]);
|
|
}
|
|
}
|