453 lines
23 KiB
PHP
Executable File
453 lines
23 KiB
PHP
Executable File
<?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;
|
||
|
||
/** @var array<string, mixed> */
|
||
public array $editForm = [];
|
||
|
||
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) {
|
||
session(['impersonator_id' => Auth::id()]);
|
||
Auth::login($amm->user);
|
||
$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 l’utente {$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 dell’amministratore selezionato. Tutte le azioni saranno tracciate nell’audit 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();
|
||
}),
|
||
]);
|
||
}
|
||
}
|