netgescon-day0/app/Filament/Pages/SuperAdmin/Amministratori.php

469 lines
24 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Filament\Pages\SuperAdmin;
use App\Models\Amministratore;
use App\Models\User;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Pages\Page;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\DatePicker;
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\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Carbon;
use UnitEnum;
class Amministratori extends Page implements HasTable
{
use InteractsWithTable;
protected static ?string $navigationLabel = 'Amministratori';
protected static ?string $title = 'Gestione amministratori';
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-building-office';
protected static UnitEnum|string|null $navigationGroup = 'Super Admin';
protected static ?int $navigationSort = 2;
protected static ?string $slug = 'superadmin/amministratori';
protected string $view = 'filament.pages.super-admin.amministratori';
public ?int $selectedAmministratoreId = null;
public string $activeTab = 'elenco';
/** @var array<string, mixed> */
public array $editForm = [];
public function apriTab(string $tab): void
{
$this->activeTab = in_array($tab, ['elenco', 'scheda', 'stabili', 'importazione'], true) ? $tab : 'elenco';
}
public static function canAccess(): bool
{
$user = Auth::user();
return $user instanceof User
&& $user->hasAnyRole(['super-admin', 'admin'])
&& Schema::hasTable('amministratori');
}
public function mount(): void
{
$this->mountInteractsWithTable();
$defaultAmm = Amministratore::query()->where('id', 13)->first()
?: Amministratore::query()->first();
if ($defaultAmm) {
$this->selectAmministratore($defaultAmm->id);
}
}
public function selectAmministratore(int $id): void
{
$this->selectedAmministratoreId = $id;
$amm = Amministratore::query()->with('user')->find($id);
if ($amm) {
$this->editForm = [
'id' => (int) $amm->id,
'nome' => (string) ($amm->nome ?? ''),
'cognome' => (string) ($amm->cognome ?? ''),
'denominazione_studio' => (string) ($amm->denominazione_studio ?? ''),
'codice_fiscale_studio' => (string) ($amm->codice_fiscale_studio ?? ''),
'partita_iva' => (string) ($amm->partita_iva ?? ''),
'indirizzo_studio' => (string) ($amm->indirizzo_studio ?? ''),
'cap_studio' => (string) ($amm->cap_studio ?? ''),
'citta_studio' => (string) ($amm->citta_studio ?? ''),
'provincia_studio' => (string) ($amm->provincia_studio ?? ''),
'telefono_studio' => (string) ($amm->telefono_studio ?? ''),
'email_studio' => (string) ($amm->email_studio ?? ''),
'pec_studio' => (string) ($amm->pec_studio ?? ''),
'attivo' => (bool) ($amm->attivo ?? true),
'codice_univoco' => (string) ($amm->codice_univoco ?? '00000001'),
'user_email' => (string) ($amm->user?->email ?? $amm->email_studio ?? ''),
];
}
}
public function deselezionaAmministratore(): void
{
$this->selectedAmministratoreId = null;
$this->editForm = [];
}
public function salvaSchedaInPlace(): void
{
if (! $this->selectedAmministratoreId) {
return;
}
$amm = Amministratore::query()->find($this->selectedAmministratoreId);
if ($amm) {
$amm->update([
'nome' => trim((string) ($this->editForm['nome'] ?? '')),
'cognome' => trim((string) ($this->editForm['cognome'] ?? '')),
'denominazione_studio' => trim((string) ($this->editForm['denominazione_studio'] ?? '')),
'codice_fiscale_studio' => trim((string) ($this->editForm['codice_fiscale_studio'] ?? '')),
'partita_iva' => trim((string) ($this->editForm['partita_iva'] ?? '')),
'indirizzo_studio' => trim((string) ($this->editForm['indirizzo_studio'] ?? '')),
'cap_studio' => trim((string) ($this->editForm['cap_studio'] ?? '')),
'citta_studio' => trim((string) ($this->editForm['citta_studio'] ?? '')),
'provincia_studio' => trim((string) ($this->editForm['provincia_studio'] ?? '')),
'telefono_studio' => trim((string) ($this->editForm['telefono_studio'] ?? '')),
'email_studio' => trim((string) ($this->editForm['email_studio'] ?? '')),
'pec_studio' => trim((string) ($this->editForm['pec_studio'] ?? '')),
'attivo' => (bool) ($this->editForm['attivo'] ?? true),
]);
if ($amm->user && ! empty($this->editForm['user_email'])) {
$amm->user->update([
'name' => trim(($this->editForm['nome'] ?? '') . ' ' . ($this->editForm['cognome'] ?? '')),
'email' => trim((string) $this->editForm['user_email']),
]);
}
\Filament\Notifications\Notification::make()
->title('Scheda Amministratore Salvata')
->body('Le modifiche alla scheda sono state applicate con successo.')
->success()
->send();
}
}
public function impersonaSelected(): void
{
if (! $this->selectedAmministratoreId) {
return;
}
$amm = Amministratore::query()->with('user')->find($this->selectedAmministratoreId);
if ($amm && $amm->user) {
$actorId = Auth::id();
$targetUser = $amm->user;
if (method_exists($targetUser, 'hasRole') && ! $targetUser->hasAnyRole(['admin', 'amministratore', 'super-admin'])) {
$targetUser->assignRole('amministratore');
}
session(['impersonator_id' => $actorId]);
Auth::guard('web')->login($targetUser, true);
request()->session()->regenerate();
$this->redirect('/admin-filament');
}
}
public function inviaCredenzialiSelected(): void
{
if (! $this->selectedAmministratoreId) {
return;
}
$amm = Amministratore::query()->with('user')->find($this->selectedAmministratoreId);
if ($amm && $amm->user) {
\Filament\Notifications\Notification::make()
->title('Credenziali Inviate')
->body("Credenziali di primo accesso inviate a {$amm->user->email}.")
->success()
->send();
}
}
public function resetPasswordSelected(): void
{
if (! $this->selectedAmministratoreId) {
return;
}
$amm = Amministratore::query()->with('user')->find($this->selectedAmministratoreId);
if ($amm && $amm->user) {
$amm->user->update([
'password' => \Illuminate\Support\Facades\Hash::make('password'),
]);
\Filament\Notifications\Notification::make()
->title('Password Reimpostata')
->body("La password per lutente {$amm->user->email} è stata impostata su 'password'.")
->success()
->send();
}
}
protected function getTableQuery(): Builder
{
return Amministratore::query()->withCount('stabili');
}
public function table(Table $table): Table
{
return $table
->striped()
->defaultSort('id', 'desc')
->columns([
TextColumn::make('id')->label('ID')->sortable(),
TextColumn::make('codice_univoco')->label('Codice')->searchable()->sortable(),
TextColumn::make('nome')->label('Nome')->searchable()->sortable(),
TextColumn::make('cognome')->label('Cognome')->searchable()->sortable(),
TextColumn::make('stabili_count')->label('Stabili')->sortable(),
TextColumn::make('denominazione_studio')->label('Studio')->searchable()->toggleable(),
TextColumn::make('email_studio')->label('Email')->searchable()->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('pec_studio')->label('PEC')->searchable()->toggleable(isToggledHiddenByDefault: true),
IconColumn::make('attivo')->label('Attivo')->boolean()->sortable()->toggleable(),
IconColumn::make('abilita_import_stabili')->label('Import')->boolean()->sortable()->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('fe_cassetto_status')
->label('FE Stato')
->state(function (Amministratore $record): string {
if (! (bool) ($record->fe_cassetto_enabled ?? false)) {
return 'Disabilitato';
}
$expiresAt = $record->fe_cassetto_expires_at;
if ($expiresAt instanceof Carbon && $expiresAt->startOfDay()->lt(now()->startOfDay())) {
return 'Scaduto';
}
return 'Attivo';
})
->badge()
->color(function (Amministratore $record): string {
if (! (bool) ($record->fe_cassetto_enabled ?? false)) {
return 'gray';
}
$expiresAt = $record->fe_cassetto_expires_at;
if ($expiresAt instanceof Carbon && $expiresAt->startOfDay()->lt(now()->startOfDay())) {
return 'danger';
}
return 'success';
})
->sortable(),
IconColumn::make('fe_cassetto_enabled')->label('FE Abilitato')->boolean()->sortable()->toggleable(),
TextColumn::make('fe_cassetto_expires_at')->label('FE Scadenza')->date('d/m/Y')->sortable()->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')->label('Aggiornato')->dateTime('d/m/Y H:i')->toggleable(isToggledHiddenByDefault: true),
])
->headerActions([
Action::make('create')
->label('Nuovo')
->icon('heroicon-o-plus')
->form([
Select::make('user_id')
->label('Utente collegato')
->options(fn() => User::query()
->whereDoesntHave('amministratore')
->orderBy('name')
->get()
->mapWithKeys(fn(User $u) => [
$u->id => trim($u->name . ' <' . $u->email . '>'),
])
->all())
->searchable()
->required(),
TextInput::make('nome')->label('Nome')->required()->maxLength(100),
TextInput::make('cognome')->label('Cognome')->required()->maxLength(100),
TextInput::make('denominazione_studio')->label('Denominazione studio')->maxLength(255),
TextInput::make('partita_iva')->label('Partita IVA')->maxLength(30),
TextInput::make('codice_fiscale_studio')->label('Codice fiscale')->maxLength(30),
TextInput::make('indirizzo_studio')->label('Indirizzo')->maxLength(255),
TextInput::make('cap_studio')->label('CAP')->maxLength(10),
TextInput::make('citta_studio')->label('Città')->maxLength(60),
TextInput::make('provincia_studio')->label('Provincia')->maxLength(5),
TextInput::make('telefono_studio')->label('Telefono')->maxLength(50),
TextInput::make('email_studio')->label('Email')->maxLength(255),
TextInput::make('pec_studio')->label('PEC')->maxLength(255),
Toggle::make('attivo')->label('Attivo')->default(true),
Toggle::make('abilita_import_stabili')->label('Abilita import stabili')->default(true),
Toggle::make('fe_cassetto_enabled')
->label('Abilita servizio scarico Fatture (Cassetto Fiscale)')
->helperText('Servizio a pagamento: abilita solo per gli amministratori autorizzati.')
->default(false),
DatePicker::make('fe_cassetto_expires_at')
->label('Scadenza servizio (opzionale)')
->helperText('Se valorizzata, dopo questa data lo scarico sarà bloccato finché non rinnovato.')
->native(false)
->displayFormat('d/m/Y')
->nullable(),
])
->action(function (array $data): void {
$amm = Amministratore::query()->create([
'user_id' => (int) ($data['user_id'] ?? 0),
'nome' => trim((string) ($data['nome'] ?? '')),
'cognome' => trim((string) ($data['cognome'] ?? '')),
'denominazione_studio' => (string) ($data['denominazione_studio'] ?? ''),
'partita_iva' => (string) ($data['partita_iva'] ?? ''),
'codice_fiscale_studio' => (string) ($data['codice_fiscale_studio'] ?? ''),
'indirizzo_studio' => (string) ($data['indirizzo_studio'] ?? ''),
'cap_studio' => (string) ($data['cap_studio'] ?? ''),
'citta_studio' => (string) ($data['citta_studio'] ?? ''),
'provincia_studio' => (string) ($data['provincia_studio'] ?? ''),
'telefono_studio' => (string) ($data['telefono_studio'] ?? ''),
'email_studio' => (string) ($data['email_studio'] ?? ''),
'pec_studio' => (string) ($data['pec_studio'] ?? ''),
'attivo' => (bool) ($data['attivo'] ?? true),
'abilita_import_stabili' => (bool) ($data['abilita_import_stabili'] ?? true),
'fe_cassetto_enabled' => (bool) ($data['fe_cassetto_enabled'] ?? false),
'fe_cassetto_expires_at' => $data['fe_cassetto_expires_at'] ?? null,
]);
// Best-effort: provisioning cartelle.
try {
$amm->provisionArchiveIfMissing();
} catch (\Throwable) {
}
}),
])
->actions([
Action::make('select')
->label('Dettaglio Scheda')
->icon('heroicon-o-pencil-square')
->color('primary')
->action(function (Amministratore $record): void {
$this->selectAmministratore($record->id);
}),
Action::make('edit')
->label('Modifica')
->icon('heroicon-o-pencil-square')
->form([
Select::make('user_id')
->label('Utente collegato')
->options(fn(Amministratore $record) => User::query()
->where(function (Builder $q) use ($record) {
$q->whereDoesntHave('amministratore')
->orWhere('id', (int) $record->user_id);
})
->orderBy('name')
->get()
->mapWithKeys(fn(User $u) => [
$u->id => trim($u->name . ' <' . $u->email . '>'),
])
->all())
->searchable()
->required(),
TextInput::make('nome')->label('Nome')->required()->maxLength(100),
TextInput::make('cognome')->label('Cognome')->required()->maxLength(100),
TextInput::make('denominazione_studio')->label('Denominazione studio')->maxLength(255),
TextInput::make('partita_iva')->label('Partita IVA')->maxLength(30),
TextInput::make('codice_fiscale_studio')->label('Codice fiscale')->maxLength(30),
TextInput::make('indirizzo_studio')->label('Indirizzo')->maxLength(255),
TextInput::make('cap_studio')->label('CAP')->maxLength(10),
TextInput::make('citta_studio')->label('Città')->maxLength(60),
TextInput::make('provincia_studio')->label('Provincia')->maxLength(5),
TextInput::make('telefono_studio')->label('Telefono')->maxLength(50),
TextInput::make('email_studio')->label('Email')->maxLength(255),
TextInput::make('pec_studio')->label('PEC')->maxLength(255),
Toggle::make('attivo')->label('Attivo'),
Toggle::make('abilita_import_stabili')->label('Abilita import stabili'),
Toggle::make('fe_cassetto_enabled')
->label('Abilita servizio scarico Fatture (Cassetto Fiscale)')
->helperText('Servizio a pagamento: abilita solo per gli amministratori autorizzati.'),
DatePicker::make('fe_cassetto_expires_at')
->label('Scadenza servizio (opzionale)')
->native(false)
->displayFormat('d/m/Y')
->nullable(),
])
->fillForm(fn(Amministratore $record): array => [
'user_id' => (int) $record->user_id,
'nome' => (string) ($record->nome ?? ''),
'cognome' => (string) ($record->cognome ?? ''),
'denominazione_studio' => (string) ($record->denominazione_studio ?? ''),
'partita_iva' => (string) ($record->partita_iva ?? ''),
'codice_fiscale_studio' => (string) ($record->codice_fiscale_studio ?? ''),
'indirizzo_studio' => (string) ($record->indirizzo_studio ?? ''),
'cap_studio' => (string) ($record->cap_studio ?? ''),
'citta_studio' => (string) ($record->citta_studio ?? ''),
'provincia_studio' => (string) ($record->provincia_studio ?? ''),
'telefono_studio' => (string) ($record->telefono_studio ?? ''),
'email_studio' => (string) ($record->email_studio ?? ''),
'pec_studio' => (string) ($record->pec_studio ?? ''),
'attivo' => (bool) ($record->attivo ?? true),
'abilita_import_stabili' => (bool) ($record->abilita_import_stabili ?? true),
'fe_cassetto_enabled' => (bool) ($record->fe_cassetto_enabled ?? false),
'fe_cassetto_expires_at' => $record->fe_cassetto_expires_at?->format('Y-m-d'),
])
->action(function (Amministratore $record, array $data): void {
$update = [
'user_id' => (int) ($data['user_id'] ?? 0),
'nome' => trim((string) ($data['nome'] ?? '')),
'cognome' => trim((string) ($data['cognome'] ?? '')),
'denominazione_studio' => (string) ($data['denominazione_studio'] ?? ''),
'partita_iva' => (string) ($data['partita_iva'] ?? ''),
'codice_fiscale_studio' => (string) ($data['codice_fiscale_studio'] ?? ''),
'indirizzo_studio' => (string) ($data['indirizzo_studio'] ?? ''),
'cap_studio' => (string) ($data['cap_studio'] ?? ''),
'citta_studio' => (string) ($data['citta_studio'] ?? ''),
'provincia_studio' => (string) ($data['provincia_studio'] ?? ''),
'telefono_studio' => (string) ($data['telefono_studio'] ?? ''),
'email_studio' => (string) ($data['email_studio'] ?? ''),
'pec_studio' => (string) ($data['pec_studio'] ?? ''),
'attivo' => (bool) ($data['attivo'] ?? true),
'abilita_import_stabili' => (bool) ($data['abilita_import_stabili'] ?? true),
'fe_cassetto_enabled' => (bool) ($data['fe_cassetto_enabled'] ?? false),
'fe_cassetto_expires_at' => $data['fe_cassetto_expires_at'] ?? null,
];
$record->fill($update);
$record->save();
try {
$record->provisionArchiveIfMissing();
} catch (\Throwable) {
}
}),
Action::make('impersonate')
->label('Impersona')
->icon('heroicon-o-user-plus')
->color('warning')
->requiresConfirmation()
->modalHeading('Conferma Impersonificazione Amministratore')
->modalDescription('Stai per accedere al sistema impersonando lo studio dellamministratore selezionato. Tutte le azioni saranno tracciate nellaudit log.')
->visible(fn(Amministratore $record): bool => (bool) $record->user_id && $record->user_id !== Auth::id())
->action(function (Amministratore $record): void {
if ($record->user) {
session(['impersonator_id' => Auth::id()]);
Auth::login($record->user);
redirect()->to('/admin-filament');
}
}),
Action::make('delete')
->label('Elimina')
->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->action(function (Amministratore $record): void {
if ($record->stabili()->exists()) {
throw new \RuntimeException('Impossibile eliminare: ci sono stabili collegati.');
}
if ($record->fornitori()->exists()) {
throw new \RuntimeException('Impossibile eliminare: ci sono fornitori collegati.');
}
$record->delete();
}),
]);
}
}