1024 lines
43 KiB
PHP
1024 lines
43 KiB
PHP
<?php
|
|
namespace App\Filament\Pages\Gescon;
|
|
|
|
use App\Models\Fornitore;
|
|
use App\Models\RubricaContattoCanale;
|
|
use App\Models\RubricaRuolo;
|
|
use App\Models\RubricaUniversale;
|
|
use App\Models\Stabile;
|
|
use App\Models\Titolo;
|
|
use App\Models\UnitaImmobiliare;
|
|
use App\Models\User;
|
|
use App\Support\StabileContext;
|
|
use Filament\Actions\Action;
|
|
use Filament\Forms\Components\DatePicker;
|
|
use Filament\Forms\Components\Hidden;
|
|
use Filament\Forms\Components\Repeater;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Forms\Components\Toggle;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Pages\Page;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class RubricaUniversaleScheda extends Page
|
|
{
|
|
protected static ?string $title = 'Scheda anagrafica (Rubrica)';
|
|
|
|
protected static ?string $slug = 'gescon/anagrafica/rubrica/{record}';
|
|
|
|
protected static bool $shouldRegisterNavigation = false;
|
|
|
|
protected string $view = 'filament.pages.gescon.rubrica-universale-scheda';
|
|
|
|
public RubricaUniversale $rubrica;
|
|
|
|
/** @var array<int, array<string, mixed>> */
|
|
public array $fornitori = [];
|
|
|
|
/** @var array<int, array<string, mixed>> */
|
|
public array $stabili = [];
|
|
|
|
/** @var array<int, array<string, mixed>> */
|
|
public array $contattiPrincipali = [];
|
|
|
|
/** @var array<int, array<string, mixed>> */
|
|
public array $ruoliAttivi = [];
|
|
|
|
/** @var array<int, array<string, mixed>> */
|
|
public array $cronistoriaRuoli = [];
|
|
|
|
public int $adminId = 0;
|
|
|
|
public ?int $prevRecordId = null;
|
|
|
|
public ?int $nextRecordId = null;
|
|
|
|
public int $navPerPage = 25;
|
|
|
|
public int $navPage = 1;
|
|
|
|
public int $navPages = 1;
|
|
|
|
/** @var array<int, int> */
|
|
public array $adminStabileIds = [];
|
|
|
|
public bool $isInlineEditing = false;
|
|
|
|
/** @var array<string,mixed> */
|
|
public array $inlineForm = [];
|
|
|
|
public function mount(int | string $record): void
|
|
{
|
|
$user = Auth::user();
|
|
if (! $user instanceof User) {
|
|
abort(403);
|
|
}
|
|
|
|
if (! $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore'])) {
|
|
abort(403);
|
|
}
|
|
|
|
$this->rubrica = RubricaUniversale::query()->findOrFail((int) $record);
|
|
|
|
$activeStabile = StabileContext::getActiveStabile($user);
|
|
$adminId = (int) ($activeStabile?->amministratore_id ?: 0);
|
|
$this->adminId = $adminId;
|
|
|
|
$stabiliAdminIds = [];
|
|
if (! $user->hasRole('super-admin') && $adminId > 0) {
|
|
$stabiliAdminIds = Stabile::query()
|
|
->where('amministratore_id', $adminId)
|
|
->pluck('id')
|
|
->map(fn($id) => (int) $id)
|
|
->all();
|
|
}
|
|
|
|
$this->adminStabileIds = $stabiliAdminIds;
|
|
|
|
$this->initArchivioNavigation();
|
|
|
|
$this->fornitori = Fornitore::query()
|
|
->where('amministratore_id', $adminId)
|
|
->where('rubrica_id', (int) $this->rubrica->id)
|
|
->orderBy('ragione_sociale')
|
|
->limit(50)
|
|
->get(['id', 'codice_univoco', 'ragione_sociale', 'partita_iva', 'codice_fiscale'])
|
|
->map(fn(Fornitore $f) => [
|
|
'id' => (int) $f->id,
|
|
'codice' => (string) ($f->codice_univoco ?? ''),
|
|
'nome' => (string) ($f->ragione_sociale ?: trim((string) ($f->cognome ?? '') . ' ' . (string) ($f->nome ?? ''))),
|
|
'piva' => (string) ($f->partita_iva ?? ''),
|
|
'cf' => (string) ($f->codice_fiscale ?? ''),
|
|
])
|
|
->all();
|
|
|
|
$ruoliQuery = RubricaRuolo::query()
|
|
->with(['stabile', 'unitaImmobiliare.stabile'])
|
|
->where('rubrica_id', (int) $this->rubrica->id);
|
|
|
|
if (! $user->hasRole('super-admin') && ! empty($stabiliAdminIds)) {
|
|
$ruoliQuery->where(function ($q) use ($stabiliAdminIds) {
|
|
$q->whereNull('stabile_id')
|
|
->orWhereIn('stabile_id', $stabiliAdminIds);
|
|
});
|
|
}
|
|
|
|
$ruoli = $ruoliQuery
|
|
->orderByDesc('is_attivo')
|
|
->orderByDesc('is_preferito')
|
|
->orderByDesc('data_inizio')
|
|
->orderByDesc('id')
|
|
->limit(200)
|
|
->get();
|
|
|
|
$labels = self::getRuoliLabels();
|
|
|
|
$this->ruoliAttivi = $ruoli
|
|
->filter(fn(RubricaRuolo $r) => (bool) $r->is_attivo)
|
|
->map(function (RubricaRuolo $r) use ($labels) {
|
|
$stabile = $r->stabile ?: $r->unitaImmobiliare?->stabile;
|
|
$ruoloKey = (string) ($r->ruolo_standard ?? 'altro');
|
|
$ruoloLabel = (string) ($labels[$ruoloKey] ?? $ruoloKey);
|
|
if (! empty($r->ruolo_custom)) {
|
|
$ruoloLabel .= ' (' . (string) $r->ruolo_custom . ')';
|
|
}
|
|
|
|
return [
|
|
'ruolo' => $ruoloLabel,
|
|
'stabile_codice' => (string) ($stabile?->codice_operatore ?? $stabile?->codice_stabile ?? ''),
|
|
'stabile_nome' => (string) ($stabile?->denominazione ?? ''),
|
|
'unita_id' => (int) ($r->unitaImmobiliare?->id ?? 0),
|
|
'unita_codice' => (string) ($r->unitaImmobiliare?->codice_unita ?? ''),
|
|
'unita_nome' => (string) ($r->unitaImmobiliare?->denominazione ?? ''),
|
|
'preferito' => (bool) ($r->is_preferito ?? false),
|
|
];
|
|
})
|
|
->values()
|
|
->all();
|
|
|
|
$this->cronistoriaRuoli = $ruoli
|
|
->map(function (RubricaRuolo $r) use ($labels) {
|
|
$stabile = $r->stabile ?: $r->unitaImmobiliare?->stabile;
|
|
$unita = $r->unitaImmobiliare;
|
|
|
|
$ruoloKey = (string) ($r->ruolo_standard ?? 'altro');
|
|
$ruoloLabel = (string) ($labels[$ruoloKey] ?? $ruoloKey);
|
|
if (! empty($r->ruolo_custom)) {
|
|
$ruoloLabel .= ' (' . (string) $r->ruolo_custom . ')';
|
|
}
|
|
|
|
return [
|
|
'ruolo' => $ruoloLabel,
|
|
'data_inizio' => optional($r->data_inizio)->format('d/m/Y'),
|
|
'data_fine' => $r->data_fine ? optional($r->data_fine)->format('d/m/Y') : null,
|
|
'attivo' => (bool) ($r->is_attivo ?? true),
|
|
'preferito' => (bool) ($r->is_preferito ?? false),
|
|
'stabile_codice' => (string) ($stabile?->codice_operatore ?? $stabile?->codice_stabile ?? ''),
|
|
'stabile_nome' => (string) ($stabile?->denominazione ?? ''),
|
|
'unita_id' => (int) ($unita?->id ?? 0),
|
|
'unita_codice' => (string) ($unita?->codice_unita ?? ''),
|
|
'unita_nome' => (string) ($unita?->denominazione ?? ''),
|
|
];
|
|
})
|
|
->all();
|
|
|
|
// Collegamenti stabili: includi sia stabili con rubrica_id diretto sia stabili legati tramite ruoli.
|
|
$stabiliIds = [];
|
|
foreach ($ruoli as $r) {
|
|
$sid = (int) ($r->stabile_id ?? 0);
|
|
if ($sid <= 0) {
|
|
$sid = (int) ($r->unitaImmobiliare?->stabile_id ?? 0);
|
|
}
|
|
if ($sid > 0) {
|
|
$stabiliIds[] = $sid;
|
|
}
|
|
}
|
|
$stabiliIds = array_values(array_unique($stabiliIds));
|
|
|
|
$stabiliQuery = Stabile::query()->where('amministratore_id', $adminId);
|
|
if (! empty($stabiliIds)) {
|
|
$stabiliQuery->where(function (Builder $q) use ($stabiliIds): void {
|
|
$q->whereIn('id', $stabiliIds)
|
|
->orWhere('rubrica_id', (int) $this->rubrica->id);
|
|
});
|
|
} else {
|
|
$stabiliQuery->where('rubrica_id', (int) $this->rubrica->id);
|
|
}
|
|
|
|
$this->stabili = $stabiliQuery
|
|
->orderBy('codice_stabile')
|
|
->limit(100)
|
|
->get(['id', 'codice_stabile', 'cod_stabile', 'denominazione', 'codice_fiscale'])
|
|
->map(fn(Stabile $s) => [
|
|
'id' => (int) $s->id,
|
|
'codice' => (string) ($s->codice_operatore ?? $s->codice_stabile ?? ''),
|
|
'nome' => (string) ($s->denominazione ?? ''),
|
|
'cf' => (string) ($s->codice_fiscale ?? ''),
|
|
])
|
|
->all();
|
|
|
|
// Contatti principali (per mostrarli velocemente nella scheda): prende canali principali + fallback ai campi telefono/email.
|
|
$principali = RubricaContattoCanale::query()
|
|
->where('rubrica_id', (int) $this->rubrica->id)
|
|
->orderByDesc('is_principale')
|
|
->orderByDesc('data_inizio')
|
|
->orderByDesc('id')
|
|
->limit(20)
|
|
->get();
|
|
|
|
$this->contattiPrincipali = $principali
|
|
->map(fn(RubricaContattoCanale $c) => [
|
|
'tipo' => (string) ($c->tipo ?? 'altro'),
|
|
'etichetta' => (string) ($c->etichetta ?? ''),
|
|
'valore' => (string) ($c->valore ?? ''),
|
|
'principale' => (bool) ($c->is_principale ?? false),
|
|
])
|
|
->all();
|
|
|
|
$this->fillInlineForm();
|
|
}
|
|
|
|
public function startInlineEdit(): void
|
|
{
|
|
$this->fillInlineForm();
|
|
$this->isInlineEditing = true;
|
|
}
|
|
|
|
public function cancelInlineEdit(): void
|
|
{
|
|
$this->fillInlineForm();
|
|
$this->isInlineEditing = false;
|
|
}
|
|
|
|
public function saveInlineEdit(): void
|
|
{
|
|
$data = validator($this->inlineForm, [
|
|
'nome' => ['nullable', 'string', 'max:255'],
|
|
'cognome' => ['nullable', 'string', 'max:255'],
|
|
'ragione_sociale' => ['nullable', 'string', 'max:255'],
|
|
'tipo_contatto' => ['nullable', 'string', 'max:120'],
|
|
'categoria' => ['nullable', 'string', 'max:120'],
|
|
'codice_fiscale' => ['nullable', 'string', 'max:32'],
|
|
'partita_iva' => ['nullable', 'string', 'max:32'],
|
|
'email' => ['nullable', 'string', 'max:255'],
|
|
'pec' => ['nullable', 'string', 'max:255'],
|
|
'telefono_ufficio' => ['nullable', 'string', 'max:64'],
|
|
'telefono_cellulare' => ['nullable', 'string', 'max:64'],
|
|
'telefono_casa' => ['nullable', 'string', 'max:64'],
|
|
'indirizzo_completo' => ['nullable', 'string', 'max:255'],
|
|
'tipo_utenza_call' => ['nullable', 'string', 'max:120'],
|
|
'riferimento_stabile' => ['nullable', 'string', 'max:255'],
|
|
'riferimento_unita' => ['nullable', 'string', 'max:255'],
|
|
'note' => ['nullable', 'string', 'max:5000'],
|
|
'note_segreteria' => ['nullable', 'string', 'max:5000'],
|
|
])->validate();
|
|
|
|
$this->rubrica->fill([
|
|
'nome' => $this->cleanNullable($data['nome'] ?? null),
|
|
'cognome' => $this->cleanNullable($data['cognome'] ?? null),
|
|
'ragione_sociale' => $this->cleanNullable($data['ragione_sociale'] ?? null),
|
|
'tipo_contatto' => $this->cleanNullable($data['tipo_contatto'] ?? null),
|
|
'categoria' => $this->cleanNullable($data['categoria'] ?? null),
|
|
'codice_fiscale' => $this->cleanNullable($data['codice_fiscale'] ?? null),
|
|
'partita_iva' => $this->cleanNullable($data['partita_iva'] ?? null),
|
|
'email' => $this->cleanNullable($data['email'] ?? null),
|
|
'pec' => $this->cleanNullable($data['pec'] ?? null),
|
|
'telefono_ufficio' => $this->cleanNullable($data['telefono_ufficio'] ?? null),
|
|
'telefono_cellulare' => $this->cleanNullable($data['telefono_cellulare'] ?? null),
|
|
'telefono_casa' => $this->cleanNullable($data['telefono_casa'] ?? null),
|
|
'indirizzo_completo' => $this->cleanNullable($data['indirizzo_completo'] ?? null),
|
|
'tipo_utenza_call' => $this->cleanNullable($data['tipo_utenza_call'] ?? null),
|
|
'riferimento_stabile' => $this->cleanNullable($data['riferimento_stabile'] ?? null),
|
|
'riferimento_unita' => $this->cleanNullable($data['riferimento_unita'] ?? null),
|
|
'note' => $this->cleanNullable($data['note'] ?? null),
|
|
'note_segreteria' => $this->cleanNullable($data['note_segreteria'] ?? null),
|
|
'data_ultima_modifica' => now()->toDateString(),
|
|
'modificato_da' => Auth::id(),
|
|
]);
|
|
|
|
$this->rubrica->save();
|
|
|
|
$this->mount((int) $this->rubrica->id);
|
|
$this->isInlineEditing = false;
|
|
|
|
Notification::make()
|
|
->title('Contatto aggiornato')
|
|
->success()
|
|
->send();
|
|
}
|
|
|
|
private function initArchivioNavigation(): void
|
|
{
|
|
$pp = (int) request()->query('pp', 25);
|
|
if ($pp <= 0) {
|
|
$pp = 25;
|
|
}
|
|
if (! in_array($pp, [10, 25, 50, 100], true)) {
|
|
$pp = 25;
|
|
}
|
|
|
|
$this->navPerPage = $pp;
|
|
|
|
if ($this->adminId <= 0) {
|
|
$this->prevRecordId = null;
|
|
$this->nextRecordId = null;
|
|
$this->navPage = 1;
|
|
$this->navPages = 1;
|
|
return;
|
|
}
|
|
|
|
$base = RubricaUniversale::query()->where('amministratore_id', $this->adminId);
|
|
|
|
$total = (clone $base)->count();
|
|
$this->navPages = max(1, (int) ceil($total / $this->navPerPage));
|
|
|
|
$before = (clone $base)
|
|
->where($this->whereBeforeCurrent())
|
|
->count();
|
|
$position = $before + 1;
|
|
$this->navPage = max(1, (int) ceil($position / $this->navPerPage));
|
|
|
|
$this->prevRecordId = (clone $base)
|
|
->where($this->whereBeforeCurrent())
|
|
->tap(fn(Builder $q) => $this->applySort($q, 'desc'))
|
|
->value('id');
|
|
|
|
$this->nextRecordId = (clone $base)
|
|
->where($this->whereAfterCurrent())
|
|
->tap(fn(Builder $q) => $this->applySort($q, 'asc'))
|
|
->value('id');
|
|
}
|
|
|
|
private function applySort(Builder $query, string $direction): void
|
|
{
|
|
$dir = strtolower($direction) === 'desc' ? 'DESC' : 'ASC';
|
|
|
|
$query
|
|
->orderByRaw("COALESCE(ragione_sociale, '') {$dir}")
|
|
->orderByRaw("COALESCE(cognome, '') {$dir}")
|
|
->orderByRaw("COALESCE(nome, '') {$dir}")
|
|
->orderBy('id', $dir);
|
|
}
|
|
|
|
private function whereBeforeCurrent(): \Closure
|
|
{
|
|
$ragione = (string) ($this->rubrica->ragione_sociale ?? '');
|
|
$cognome = (string) ($this->rubrica->cognome ?? '');
|
|
$nome = (string) ($this->rubrica->nome ?? '');
|
|
$id = (int) $this->rubrica->id;
|
|
|
|
return function (Builder $q) use ($ragione, $cognome, $nome, $id): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') < ?", [$ragione])
|
|
->orWhere(function (Builder $q) use ($ragione, $cognome): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') = ?", [$ragione])
|
|
->whereRaw("COALESCE(cognome, '') < ?", [$cognome]);
|
|
})
|
|
->orWhere(function (Builder $q) use ($ragione, $cognome, $nome): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') = ?", [$ragione])
|
|
->whereRaw("COALESCE(cognome, '') = ?", [$cognome])
|
|
->whereRaw("COALESCE(nome, '') < ?", [$nome]);
|
|
})
|
|
->orWhere(function (Builder $q) use ($ragione, $cognome, $nome, $id): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') = ?", [$ragione])
|
|
->whereRaw("COALESCE(cognome, '') = ?", [$cognome])
|
|
->whereRaw("COALESCE(nome, '') = ?", [$nome])
|
|
->where('id', '<', $id);
|
|
});
|
|
};
|
|
}
|
|
|
|
private function whereAfterCurrent(): \Closure
|
|
{
|
|
$ragione = (string) ($this->rubrica->ragione_sociale ?? '');
|
|
$cognome = (string) ($this->rubrica->cognome ?? '');
|
|
$nome = (string) ($this->rubrica->nome ?? '');
|
|
$id = (int) $this->rubrica->id;
|
|
|
|
return function (Builder $q) use ($ragione, $cognome, $nome, $id): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') > ?", [$ragione])
|
|
->orWhere(function (Builder $q) use ($ragione, $cognome): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') = ?", [$ragione])
|
|
->whereRaw("COALESCE(cognome, '') > ?", [$cognome]);
|
|
})
|
|
->orWhere(function (Builder $q) use ($ragione, $cognome, $nome): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') = ?", [$ragione])
|
|
->whereRaw("COALESCE(cognome, '') = ?", [$cognome])
|
|
->whereRaw("COALESCE(nome, '') > ?", [$nome]);
|
|
})
|
|
->orWhere(function (Builder $q) use ($ragione, $cognome, $nome, $id): void {
|
|
$q->whereRaw("COALESCE(ragione_sociale, '') = ?", [$ragione])
|
|
->whereRaw("COALESCE(cognome, '') = ?", [$cognome])
|
|
->whereRaw("COALESCE(nome, '') = ?", [$nome])
|
|
->where('id', '>', $id);
|
|
});
|
|
};
|
|
}
|
|
|
|
public function getPrevUrl(): ?string
|
|
{
|
|
if (! $this->prevRecordId) {
|
|
return null;
|
|
}
|
|
return self::getUrl(['record' => $this->prevRecordId], panel: 'admin-filament')
|
|
. '?pp=' . $this->navPerPage;
|
|
}
|
|
|
|
public function getNextUrl(): ?string
|
|
{
|
|
if (! $this->nextRecordId) {
|
|
return null;
|
|
}
|
|
return self::getUrl(['record' => $this->nextRecordId], panel: 'admin-filament')
|
|
. '?pp=' . $this->navPerPage;
|
|
}
|
|
|
|
public function getPrevPageUrl(): ?string
|
|
{
|
|
$target = $this->navPage - 1;
|
|
if ($target < 1) {
|
|
return null;
|
|
}
|
|
return $this->getPageUrl($target);
|
|
}
|
|
|
|
public function getNextPageUrl(): ?string
|
|
{
|
|
$target = $this->navPage + 1;
|
|
if ($target > $this->navPages) {
|
|
return null;
|
|
}
|
|
return $this->getPageUrl($target);
|
|
}
|
|
|
|
public function getPageUrl(int $page): ?string
|
|
{
|
|
if ($this->adminId <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$page = max(1, min($page, $this->navPages));
|
|
$offset = ($page - 1) * $this->navPerPage;
|
|
|
|
$base = RubricaUniversale::query()
|
|
->where('amministratore_id', $this->adminId);
|
|
|
|
$this->applySort($base, 'asc');
|
|
$id = (int) ($base->skip($offset)->take(1)->value('id') ?? 0);
|
|
if ($id <= 0) {
|
|
return null;
|
|
}
|
|
|
|
return self::getUrl(['record' => $id], panel: 'admin-filament')
|
|
. '?pp=' . $this->navPerPage;
|
|
}
|
|
|
|
public function getPerPageUrl(int $perPage): string
|
|
{
|
|
if (! in_array($perPage, [10, 25, 50, 100], true)) {
|
|
$perPage = 25;
|
|
}
|
|
|
|
return self::getUrl(['record' => (int) $this->rubrica->id], panel: 'admin-filament')
|
|
. '?pp=' . $perPage;
|
|
}
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Action::make('titolo')
|
|
->label('Titolo')
|
|
->icon('heroicon-o-tag')
|
|
->form([
|
|
Select::make('titolo_id')
|
|
->label('Titolo')
|
|
->native(false)
|
|
->searchable()
|
|
->options(fn() => $this->getTitoliOptions()),
|
|
])
|
|
->fillForm(fn(): array=> [
|
|
'titolo_id' => $this->rubrica->titolo_id ? (int) $this->rubrica->titolo_id : null,
|
|
])
|
|
->action(function (array $data): void {
|
|
$titoloId = isset($data['titolo_id']) && is_numeric($data['titolo_id'])
|
|
? (int) $data['titolo_id']
|
|
: null;
|
|
|
|
$this->rubrica->titolo_id = $titoloId;
|
|
$this->rubrica->data_ultima_modifica = now()->toDateString();
|
|
$this->rubrica->modificato_da = Auth::id();
|
|
$this->rubrica->save();
|
|
|
|
$this->mount((int) $this->rubrica->id);
|
|
|
|
Notification::make()
|
|
->title('Titolo aggiornato')
|
|
->success()
|
|
->send();
|
|
}),
|
|
Action::make('contatti')
|
|
->label('Contatti')
|
|
->icon('heroicon-o-phone')
|
|
->action(function (): void {
|
|
$this->startInlineEdit();
|
|
}),
|
|
|
|
Action::make('contatti_avanzati')
|
|
->label('Contatti avanzati')
|
|
->icon('heroicon-o-rectangle-stack')
|
|
->modalWidth('7xl')
|
|
->form([
|
|
Repeater::make('canali')
|
|
->label('Contatti aggiuntivi')
|
|
->defaultItems(0)
|
|
->reorderable(true)
|
|
->schema([
|
|
Hidden::make('id'),
|
|
|
|
Select::make('tipo')
|
|
->label('Tipo')
|
|
->options([
|
|
'telefono' => 'Telefono',
|
|
'cellulare' => 'Cellulare',
|
|
'email' => 'Email',
|
|
'pec' => 'PEC',
|
|
'fax' => 'Fax',
|
|
'sito_web' => 'Sito web',
|
|
'altro' => 'Altro',
|
|
])
|
|
->native(false)
|
|
->required()
|
|
->columnSpan(2),
|
|
|
|
TextInput::make('etichetta')
|
|
->label('Etichetta')
|
|
->maxLength(50)
|
|
->columnSpan(2),
|
|
|
|
TextInput::make('valore')
|
|
->label('Valore')
|
|
->required()
|
|
->maxLength(255)
|
|
->columnSpan(4),
|
|
|
|
Toggle::make('is_principale')
|
|
->label('Principale')
|
|
->default(false)
|
|
->columnSpan(2),
|
|
|
|
Select::make('stabile_id')
|
|
->label('Stabile (opzionale)')
|
|
->native(false)
|
|
->searchable()
|
|
->options(fn() => $this->getStabiliOptions())
|
|
->reactive()
|
|
->afterStateUpdated(fn($set) => $set('unita_immobiliare_id', null))
|
|
->columnSpan(3),
|
|
|
|
Select::make('unita_immobiliare_id')
|
|
->label('Unità (opzionale)')
|
|
->native(false)
|
|
->searchable()
|
|
->options(fn($get) => $this->getUnitaOptions($get('stabile_id')))
|
|
->columnSpan(3),
|
|
|
|
DatePicker::make('data_inizio')
|
|
->label('Data inizio')
|
|
->columnSpan(2),
|
|
|
|
DatePicker::make('data_fine')
|
|
->label('Data fine')
|
|
->columnSpan(2),
|
|
|
|
TextInput::make('note')
|
|
->label('Note')
|
|
->maxLength(255)
|
|
->columnSpan(12),
|
|
])
|
|
->columns(12),
|
|
])
|
|
->fillForm(function (): array {
|
|
$canali = RubricaContattoCanale::query()
|
|
->where('rubrica_id', (int) $this->rubrica->id)
|
|
->orderByDesc('is_principale')
|
|
->orderByDesc('data_inizio')
|
|
->orderByDesc('id')
|
|
->limit(200)
|
|
->get();
|
|
|
|
return [
|
|
'canali' => $canali->map(fn(RubricaContattoCanale $c) => [
|
|
'id' => (int) $c->id,
|
|
'tipo' => (string) ($c->tipo ?? 'altro'),
|
|
'etichetta' => (string) ($c->etichetta ?? ''),
|
|
'valore' => (string) ($c->valore ?? ''),
|
|
'is_principale' => (bool) ($c->is_principale ?? false),
|
|
'stabile_id' => $c->stabile_id ? (int) $c->stabile_id : null,
|
|
'unita_immobiliare_id' => $c->unita_immobiliare_id ? (int) $c->unita_immobiliare_id : null,
|
|
'data_inizio' => $c->data_inizio?->format('Y-m-d'),
|
|
'data_fine' => $c->data_fine?->format('Y-m-d'),
|
|
'note' => (string) (($c->meta['note'] ?? null) ?: ''),
|
|
])->all(),
|
|
];
|
|
})
|
|
->action(function (array $data): void {
|
|
/** @var array<int, array<string, mixed>> $rows */
|
|
$rows = $data['canali'] ?? [];
|
|
$rows = is_array($rows) ? array_values($rows) : [];
|
|
|
|
DB::transaction(function () use ($rows): void {
|
|
$keepIds = [];
|
|
|
|
foreach ($rows as $row) {
|
|
$id = (int) ($row['id'] ?? 0);
|
|
$tipo = (string) ($row['tipo'] ?? 'altro');
|
|
if ($tipo === '') {
|
|
$tipo = 'altro';
|
|
}
|
|
|
|
$attrs = [
|
|
'rubrica_id' => (int) $this->rubrica->id,
|
|
'tipo' => $tipo,
|
|
'etichetta' => ! empty($row['etichetta']) ? (string) $row['etichetta'] : null,
|
|
'valore' => ! empty($row['valore']) ? (string) $row['valore'] : null,
|
|
'is_principale' => (bool) ($row['is_principale'] ?? false),
|
|
'stabile_id' => ! empty($row['stabile_id']) ? (int) $row['stabile_id'] : null,
|
|
'unita_immobiliare_id' => ! empty($row['unita_immobiliare_id']) ? (int) $row['unita_immobiliare_id'] : null,
|
|
'data_inizio' => $row['data_inizio'] ?? null,
|
|
'data_fine' => $row['data_fine'] ?? null,
|
|
'meta' => [
|
|
'note' => ! empty($row['note']) ? (string) $row['note'] : null,
|
|
],
|
|
];
|
|
|
|
if ($id > 0) {
|
|
$existing = RubricaContattoCanale::query()
|
|
->where('id', $id)
|
|
->where('rubrica_id', (int) $this->rubrica->id)
|
|
->first();
|
|
|
|
if ($existing) {
|
|
$existing->fill($attrs);
|
|
$existing->save();
|
|
$keepIds[] = (int) $existing->id;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$created = RubricaContattoCanale::query()->create($attrs);
|
|
$keepIds[] = (int) $created->id;
|
|
}
|
|
|
|
$deleteQuery = RubricaContattoCanale::query()->where('rubrica_id', (int) $this->rubrica->id);
|
|
if (! empty($keepIds)) {
|
|
$deleteQuery->whereNotIn('id', $keepIds);
|
|
}
|
|
$deleteQuery->delete();
|
|
});
|
|
|
|
$this->mount((int) $this->rubrica->id);
|
|
|
|
Notification::make()
|
|
->title('Contatti aggiornati')
|
|
->success()
|
|
->send();
|
|
}),
|
|
|
|
Action::make('riferimenti_chiamata')
|
|
->label('Riferimenti chiamata')
|
|
->icon('heroicon-o-phone-arrow-up-right')
|
|
->form([
|
|
Select::make('tipo_utenza_call')
|
|
->label('Profilo chiamante')
|
|
->native(false)
|
|
->options([
|
|
'condomino' => 'Condomino',
|
|
'inquilino' => 'Inquilino',
|
|
'fornitore' => 'Fornitore',
|
|
'amministratore' => 'Amministratore',
|
|
'altro' => 'Altro',
|
|
]),
|
|
TextInput::make('riferimento_stabile')
|
|
->label('Riferimento stabile')
|
|
->maxLength(255),
|
|
TextInput::make('riferimento_unita')
|
|
->label('Riferimento unità')
|
|
->maxLength(255),
|
|
TextInput::make('note_segreteria')
|
|
->label('Note segreteria')
|
|
->maxLength(2000),
|
|
])
|
|
->fillForm(fn(): array=> [
|
|
'tipo_utenza_call' => $this->rubrica->tipo_utenza_call,
|
|
'riferimento_stabile' => $this->rubrica->riferimento_stabile,
|
|
'riferimento_unita' => $this->rubrica->riferimento_unita,
|
|
'note_segreteria' => $this->rubrica->note_segreteria,
|
|
])
|
|
->action(function (array $data): void {
|
|
$this->rubrica->tipo_utenza_call = ! empty($data['tipo_utenza_call']) ? (string) $data['tipo_utenza_call'] : null;
|
|
$this->rubrica->riferimento_stabile = ! empty($data['riferimento_stabile']) ? (string) $data['riferimento_stabile'] : null;
|
|
$this->rubrica->riferimento_unita = ! empty($data['riferimento_unita']) ? (string) $data['riferimento_unita'] : null;
|
|
$this->rubrica->note_segreteria = ! empty($data['note_segreteria']) ? (string) $data['note_segreteria'] : null;
|
|
$this->rubrica->data_ultima_modifica = now()->toDateString();
|
|
$this->rubrica->modificato_da = Auth::id();
|
|
$this->rubrica->save();
|
|
|
|
$this->mount((int) $this->rubrica->id);
|
|
|
|
Notification::make()
|
|
->title('Riferimenti chiamata aggiornati')
|
|
->success()
|
|
->send();
|
|
}),
|
|
|
|
Action::make('ruoli_legami')
|
|
->label('Ruoli / legami')
|
|
->icon('heroicon-o-link')
|
|
->modalWidth('7xl')
|
|
->form([
|
|
Repeater::make('ruoli')
|
|
->label('Ruoli e legami')
|
|
->defaultItems(0)
|
|
->reorderable(true)
|
|
->schema([
|
|
Hidden::make('id'),
|
|
|
|
Select::make('ruolo_standard')
|
|
->label('Ruolo')
|
|
->options(self::getRuoliLabels())
|
|
->required()
|
|
->native(false)
|
|
->default('altro')
|
|
->columnSpan(2),
|
|
|
|
TextInput::make('ruolo_custom')
|
|
->label('Ruolo custom')
|
|
->maxLength(255)
|
|
->columnSpan(2),
|
|
|
|
Select::make('stabile_id')
|
|
->label('Stabile')
|
|
->native(false)
|
|
->searchable()
|
|
->options(fn() => $this->getStabiliOptions())
|
|
->reactive()
|
|
->afterStateUpdated(fn($set) => $set('unita_immobiliare_id', null))
|
|
->columnSpan(3),
|
|
|
|
Select::make('unita_immobiliare_id')
|
|
->label('Unità')
|
|
->native(false)
|
|
->searchable()
|
|
->options(fn($get) => $this->getUnitaOptions($get('stabile_id')))
|
|
->columnSpan(3),
|
|
|
|
DatePicker::make('data_inizio')
|
|
->label('Data inizio')
|
|
->columnSpan(2),
|
|
|
|
DatePicker::make('data_fine')
|
|
->label('Data fine')
|
|
->columnSpan(2),
|
|
|
|
Toggle::make('is_preferito')
|
|
->label('Preferito')
|
|
->default(false)
|
|
->columnSpan(2),
|
|
|
|
Toggle::make('is_attivo')
|
|
->label('Attivo')
|
|
->default(true)
|
|
->columnSpan(2),
|
|
])
|
|
->columns(12),
|
|
])
|
|
->fillForm(function (): array {
|
|
$ruoli = RubricaRuolo::query()
|
|
->where('rubrica_id', (int) $this->rubrica->id)
|
|
->orderByDesc('is_attivo')
|
|
->orderByDesc('is_preferito')
|
|
->orderByDesc('data_inizio')
|
|
->orderByDesc('id')
|
|
->limit(200)
|
|
->get();
|
|
|
|
return [
|
|
'ruoli' => $ruoli->map(fn(RubricaRuolo $r) => [
|
|
'id' => (int) $r->id,
|
|
'ruolo_standard' => (string) ($r->ruolo_standard ?? 'altro'),
|
|
'ruolo_custom' => (string) ($r->ruolo_custom ?? ''),
|
|
'stabile_id' => $r->stabile_id ? (int) $r->stabile_id : null,
|
|
'unita_immobiliare_id' => $r->unita_immobiliare_id ? (int) $r->unita_immobiliare_id : null,
|
|
'data_inizio' => $r->data_inizio?->format('Y-m-d'),
|
|
'data_fine' => $r->data_fine?->format('Y-m-d'),
|
|
'is_preferito' => (bool) ($r->is_preferito ?? false),
|
|
'is_attivo' => (bool) ($r->is_attivo ?? true),
|
|
])->all(),
|
|
];
|
|
})
|
|
->action(function (array $data): void {
|
|
/** @var array<int, array<string, mixed>> $rows */
|
|
$rows = $data['ruoli'] ?? [];
|
|
$rows = is_array($rows) ? array_values($rows) : [];
|
|
|
|
DB::transaction(function () use ($rows): void {
|
|
$keepIds = [];
|
|
|
|
foreach ($rows as $row) {
|
|
$id = (int) ($row['id'] ?? 0);
|
|
$ruoloStandard = (string) ($row['ruolo_standard'] ?? 'altro');
|
|
|
|
$attrs = [
|
|
'rubrica_id' => (int) $this->rubrica->id,
|
|
'ruolo_standard' => $ruoloStandard ?: 'altro',
|
|
'ruolo_custom' => ! empty($row['ruolo_custom']) ? (string) $row['ruolo_custom'] : null,
|
|
'stabile_id' => ! empty($row['stabile_id']) ? (int) $row['stabile_id'] : null,
|
|
'unita_immobiliare_id' => ! empty($row['unita_immobiliare_id']) ? (int) $row['unita_immobiliare_id'] : null,
|
|
'data_inizio' => $row['data_inizio'] ?? null,
|
|
'data_fine' => $row['data_fine'] ?? null,
|
|
'is_preferito' => (bool) ($row['is_preferito'] ?? false),
|
|
'is_attivo' => (bool) ($row['is_attivo'] ?? true),
|
|
];
|
|
|
|
if ($id > 0) {
|
|
$existing = RubricaRuolo::query()
|
|
->where('id', $id)
|
|
->where('rubrica_id', (int) $this->rubrica->id)
|
|
->first();
|
|
|
|
if ($existing) {
|
|
$existing->fill($attrs);
|
|
$existing->save();
|
|
$keepIds[] = (int) $existing->id;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$created = RubricaRuolo::query()->create($attrs);
|
|
$keepIds[] = (int) $created->id;
|
|
}
|
|
|
|
$deleteQuery = RubricaRuolo::query()->where('rubrica_id', (int) $this->rubrica->id);
|
|
if (! empty($keepIds)) {
|
|
$deleteQuery->whereNotIn('id', $keepIds);
|
|
}
|
|
$deleteQuery->delete();
|
|
});
|
|
|
|
$this->mount((int) $this->rubrica->id);
|
|
|
|
Notification::make()
|
|
->title('Ruoli / legami aggiornati')
|
|
->success()
|
|
->send();
|
|
}),
|
|
|
|
Action::make('torna')
|
|
->label('Torna')
|
|
->icon('heroicon-o-arrow-left')
|
|
->url(fn() => AnagraficaUnica::getUrl(panel: 'admin-filament')),
|
|
];
|
|
}
|
|
|
|
private function fillInlineForm(): void
|
|
{
|
|
$this->inlineForm = [
|
|
'nome' => (string) ($this->rubrica->nome ?? ''),
|
|
'cognome' => (string) ($this->rubrica->cognome ?? ''),
|
|
'ragione_sociale' => (string) ($this->rubrica->ragione_sociale ?? ''),
|
|
'tipo_contatto' => (string) ($this->rubrica->tipo_contatto ?? ''),
|
|
'categoria' => (string) ($this->rubrica->categoria ?? ''),
|
|
'codice_fiscale' => (string) ($this->rubrica->codice_fiscale ?? ''),
|
|
'partita_iva' => (string) ($this->rubrica->partita_iva ?? ''),
|
|
'email' => (string) ($this->rubrica->email ?? ''),
|
|
'pec' => (string) ($this->rubrica->pec ?? ''),
|
|
'telefono_ufficio' => (string) ($this->rubrica->telefono_ufficio ?? ''),
|
|
'telefono_cellulare' => (string) ($this->rubrica->telefono_cellulare ?? ''),
|
|
'telefono_casa' => (string) ($this->rubrica->telefono_casa ?? ''),
|
|
'indirizzo_completo' => (string) ($this->rubrica->indirizzo_completo ?? ''),
|
|
'tipo_utenza_call' => (string) ($this->rubrica->tipo_utenza_call ?? ''),
|
|
'riferimento_stabile' => (string) ($this->rubrica->riferimento_stabile ?? ''),
|
|
'riferimento_unita' => (string) ($this->rubrica->riferimento_unita ?? ''),
|
|
'note' => (string) ($this->rubrica->note ?? ''),
|
|
'note_segreteria' => (string) ($this->rubrica->note_segreteria ?? ''),
|
|
];
|
|
}
|
|
|
|
private function cleanNullable(mixed $value): mixed
|
|
{
|
|
if (! is_string($value)) {
|
|
return $value;
|
|
}
|
|
|
|
$trim = trim($value);
|
|
|
|
return $trim === '' ? null : $trim;
|
|
}
|
|
|
|
public function getUrlUnita(?int $unitaId): ?string
|
|
{
|
|
if (! $unitaId) {
|
|
return null;
|
|
}
|
|
|
|
if (! class_exists(\App\Filament\Pages\UnitaImmobiliarePage::class)) {
|
|
return null;
|
|
}
|
|
|
|
return \App\Filament\Pages\UnitaImmobiliarePage::getUrl(panel: 'admin-filament')
|
|
. '?unita_id=' . (int) $unitaId
|
|
. '&back=' . urlencode((string) request()->getRequestUri());
|
|
}
|
|
|
|
/** @return array<string, string> */
|
|
protected static function getRuoliLabels(): array
|
|
{
|
|
return [
|
|
'super_admin' => 'Super admin',
|
|
'amministratore' => 'Amministratore',
|
|
'condomino' => 'Condomino',
|
|
'inquilino' => 'Inquilino',
|
|
'fornitore' => 'Fornitore',
|
|
'manutentore' => 'Manutentore',
|
|
'banca' => 'Banca',
|
|
'assicurazione' => 'Assicurazione',
|
|
'collaboratore' => 'Collaboratore',
|
|
'tester' => 'Tester',
|
|
'ospite' => 'Ospite',
|
|
'altro' => 'Altro',
|
|
];
|
|
}
|
|
|
|
/** @return array<int, string> */
|
|
protected function getStabiliOptions(): array
|
|
{
|
|
$query = Stabile::query();
|
|
|
|
$user = Auth::user();
|
|
$isSuperAdmin = $user instanceof User && method_exists($user, 'hasRole')
|
|
? (bool) $user->hasRole('super-admin')
|
|
: false;
|
|
|
|
if (! $isSuperAdmin && $this->adminId > 0) {
|
|
$query->where('amministratore_id', $this->adminId);
|
|
}
|
|
|
|
return $query
|
|
->orderBy('codice_stabile')
|
|
->limit(200)
|
|
->get(['id', 'codice_stabile', 'denominazione'])
|
|
->mapWithKeys(fn(Stabile $s) => [
|
|
(int) $s->id => trim((string) ($s->codice_operatore ?? $s->codice_stabile ?? '') . ' - ' . (string) ($s->denominazione ?? 'Stabile')),
|
|
])
|
|
->all();
|
|
}
|
|
|
|
/** @return array<int, string> */
|
|
protected function getTitoliOptions(): array
|
|
{
|
|
if (! Schema::hasTable('titoli')) {
|
|
return [];
|
|
}
|
|
|
|
return Titolo::query()
|
|
->orderBy('ordine')
|
|
->orderBy('nome')
|
|
->get(['id', 'nome', 'sigla'])
|
|
->mapWithKeys(fn(Titolo $t) => [
|
|
(int) $t->id => trim((string) ($t->sigla ?: $t->nome)),
|
|
])
|
|
->all();
|
|
}
|
|
|
|
/** @return array<int, string> */
|
|
protected function getUnitaOptions($stabileId): array
|
|
{
|
|
$stabileId = (int) ($stabileId ?? 0);
|
|
if ($stabileId <= 0) {
|
|
return [];
|
|
}
|
|
|
|
$query = UnitaImmobiliare::query()->where('stabile_id', $stabileId);
|
|
|
|
return $query
|
|
->orderBy('palazzina_id')
|
|
->orderBy('scala')
|
|
->orderBy('piano')
|
|
->orderBy('interno')
|
|
->orderBy('id')
|
|
->limit(1000)
|
|
->get(['id', 'codice_unita', 'denominazione', 'scala', 'piano', 'interno'])
|
|
->mapWithKeys(function (UnitaImmobiliare $u) {
|
|
$codice = $u->codice_unita ?: ('ID ' . $u->id);
|
|
$nome = $u->denominazione ?: 'Unità';
|
|
$pos = trim('Scala ' . ($u->scala ?? '-') . ' · Piano ' . ($u->piano ?? '-') . ' · Int. ' . ($u->interno ?? '-'));
|
|
|
|
return [(int) $u->id => trim($codice . ' — ' . $nome . ' (' . $pos . ')')];
|
|
})
|
|
->all();
|
|
}
|
|
}
|