netgescon-day0/app/Filament/Pages/Fornitore/Collaboratori.php

602 lines
24 KiB
PHP

<?php
namespace App\Filament\Pages\Fornitore;
use App\Filament\Pages\Fornitore\Concerns\ResolvesOperatoreContext;
use App\Models\Fornitore;
use App\Models\FornitoreDipendente;
use App\Models\RubricaUniversale;
use App\Models\User;
use BackedEnum;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use UnitEnum;
class Collaboratori extends Page
{
use ResolvesOperatoreContext;
protected static ?string $navigationLabel = 'Collaboratori';
protected static ?string $title = 'Collaboratori fornitore';
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-users';
protected static UnitEnum|string|null $navigationGroup = 'Fornitore';
protected static ?int $navigationSort = 2;
protected static ?string $slug = 'fornitore/collaboratori';
protected string $view = 'filament.pages.fornitore.collaboratori';
public ?Fornitore $fornitore = null;
public bool $missingAdminContext = false;
public string $activeTab = 'nuovo';
public string $nome = '';
public string $cognome = '';
public string $tipoContatto = 'persona_fisica';
public string $ragioneSociale = '';
public string $codiceFiscale = '';
public string $partitaIva = '';
public string $pec = '';
public string $sesso = '';
public string $dataNascita = '';
public string $luogoNascita = '';
public string $provinciaNascita = '';
public string $email = '';
public string $telefono = '';
public string $indirizzo = '';
public string $civico = '';
public string $cap = '';
public string $citta = '';
public string $provincia = '';
public string $nazione = 'Italia';
public string $collaboratoreTipo = FornitoreDipendente::TIPO_INTERNO;
public string $fornitoreSearch = '';
public ?int $fornitoreEsternoId = null;
public string $note = '';
public bool $createUserAccess = false;
public string $accessPassword = '';
public ?string $lastGeneratedPassword = null;
/** @var array<int, array<string, mixed>> */
public array $rows = [];
/** @var array<int, array<string, mixed>> */
public array $fornitoreOptions = [];
public static function canAccess(): bool
{
$user = Auth::user();
return $user instanceof User
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'fornitore']);
}
public function mount(): void
{
[$fornitore] = $this->resolveOperatoreContext(allowAdminWithoutSupplier: true);
if (! $fornitore instanceof Fornitore) {
$this->missingAdminContext = true;
return;
}
$this->fornitore = $fornitore;
$this->refreshFornitoreOptions();
$this->refreshRows();
$this->activeTab = $this->rows !== [] ? 'elenco' : 'nuovo';
}
public function updatedCollaboratoreTipo(): void
{
if ($this->collaboratoreTipo !== FornitoreDipendente::TIPO_FORNITORE_ESTERNO) {
$this->fornitoreEsternoId = null;
$this->fornitoreSearch = '';
$this->createUserAccess = false;
}
$this->refreshFornitoreOptions();
}
public function updatedFornitoreSearch(): void
{
$this->refreshFornitoreOptions();
}
public function createCollaboratore(): void
{
if (! $this->fornitore instanceof Fornitore) {
return;
}
$validated = $this->validate([
'collaboratoreTipo' => ['required', 'string', 'in:' . implode(',', [FornitoreDipendente::TIPO_INTERNO, FornitoreDipendente::TIPO_FORNITORE_ESTERNO])],
'tipoContatto' => ['nullable', 'string', 'in:persona_fisica,persona_giuridica'],
'nome' => ['nullable', 'string', 'max:100'],
'cognome' => ['nullable', 'string', 'max:100'],
'ragioneSociale' => ['nullable', 'string', 'max:255'],
'codiceFiscale' => ['nullable', 'string', 'max:50'],
'partitaIva' => ['nullable', 'string', 'max:50'],
'pec' => ['nullable', 'string', 'max:255'],
'sesso' => ['nullable', 'string', 'max:20'],
'dataNascita' => ['nullable', 'date'],
'luogoNascita' => ['nullable', 'string', 'max:255'],
'provinciaNascita' => ['nullable', 'string', 'max:10'],
'email' => ['nullable', 'email', 'max:255'],
'telefono' => ['nullable', 'string', 'max:50'],
'indirizzo' => ['nullable', 'string', 'max:255'],
'civico' => ['nullable', 'string', 'max:20'],
'cap' => ['nullable', 'string', 'max:20'],
'citta' => ['nullable', 'string', 'max:255'],
'provincia' => ['nullable', 'string', 'max:10'],
'nazione' => ['nullable', 'string', 'max:100'],
'note' => ['nullable', 'string', 'max:2000'],
'createUserAccess' => ['nullable', 'boolean'],
'accessPassword' => ['nullable', 'string', 'min:8', 'max:100'],
'fornitoreEsternoId' => ['nullable', 'integer'],
]);
$tipo = (string) $validated['collaboratoreTipo'];
$tipoContatto = (string) ($validated['tipoContatto'] ?? 'persona_fisica');
if ($tipo === FornitoreDipendente::TIPO_INTERNO) {
$hasPersonalName = trim((string) ($validated['nome'] ?? '')) !== '';
$hasCompanyName = trim((string) ($validated['ragioneSociale'] ?? '')) !== '';
if ($tipoContatto === 'persona_giuridica' && ! $hasCompanyName) {
Notification::make()->title('Inserisci la ragione sociale del collaboratore')->warning()->send();
return;
}
if ($tipoContatto !== 'persona_giuridica' && ! $hasPersonalName) {
Notification::make()->title('Inserisci il nome del collaboratore')->warning()->send();
return;
}
}
$fornitoreEsterno = null;
if ($tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO) {
$fornitoreEsterno = $this->resolveFornitoreEsterno((int) ($validated['fornitoreEsternoId'] ?? 0));
if (! $fornitoreEsterno instanceof Fornitore) {
Notification::make()->title('Seleziona un altro fornitore come collaboratore')->warning()->send();
return;
}
if ((int) $fornitoreEsterno->id === (int) $this->fornitore->id) {
Notification::make()->title('Il fornitore principale non puo essere aggiunto come subfornitore')->warning()->send();
return;
}
}
$email = $tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO
? trim((string) ($fornitoreEsterno?->email ?? ''))
: trim((string) ($validated['email'] ?? ''));
if ($email !== '') {
$existsQuery = FornitoreDipendente::query()
->where('fornitore_id', (int) $this->fornitore->id)
->whereRaw('LOWER(email) = ?', [mb_strtolower($email)]);
if ($tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO && $fornitoreEsterno instanceof Fornitore) {
$existsQuery->orWhere('fornitore_esterno_id', (int) $fornitoreEsterno->id);
}
$exists = $existsQuery->exists();
if ($exists) {
Notification::make()->title('Esiste gia un collaboratore con questa email')->warning()->send();
return;
}
}
$dipendente = new FornitoreDipendente();
$dipendente->fornitore_id = (int) $this->fornitore->id;
$dipendente->fornitore_esterno_id = $fornitoreEsterno?->id;
$dipendente->rubrica_id = $fornitoreEsterno?->rubrica_id;
$dipendente->tipo_collaboratore = $tipo;
$dipendente->nome = $tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO
? (string) ($fornitoreEsterno?->ragione_sociale ?: $fornitoreEsterno?->nome ?: 'Subfornitore')
: ($tipoContatto === 'persona_giuridica'
? trim((string) ($validated['ragioneSociale'] ?? ''))
: trim((string) $validated['nome']));
$dipendente->cognome = $tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO || $tipoContatto === 'persona_giuridica'
? null
: (trim((string) ($validated['cognome'] ?? '')) ?: null);
$dipendente->email = $email !== '' ? $email : null;
$dipendente->telefono = $tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO
? (trim((string) ($fornitoreEsterno?->telefono ?: $fornitoreEsterno?->cellulare ?: '')) ?: null)
: (trim((string) ($validated['telefono'] ?? '')) ?: null);
$dipendente->note = trim((string) ($validated['note'] ?? '')) ?: null;
$dipendente->attivo = true;
$dipendente->created_by_user_id = Auth::id();
$dipendente->updated_by_user_id = Auth::id();
$createdPassword = null;
$plainPassword = trim((string) ($validated['accessPassword'] ?? ''));
if ($tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO && $fornitoreEsterno instanceof Fornitore) {
$linkedUser = User::query()->whereRaw('LOWER(email) = ?', [mb_strtolower((string) ($fornitoreEsterno->email ?? ''))])->first();
if ($linkedUser instanceof User) {
$dipendente->user_id = (int) $linkedUser->id;
}
}
if ($tipo === FornitoreDipendente::TIPO_INTERNO && (bool) ($validated['createUserAccess'] ?? false) && $email !== '') {
$user = User::query()->whereRaw('LOWER(email) = ?', [mb_strtolower($email)])->first();
if (! $user instanceof User) {
$createdPassword = $plainPassword !== '' ? $plainPassword : Str::random(12);
$user = User::query()->create([
'name' => trim($dipendente->nome . ' ' . ($dipendente->cognome ?? '')),
'email' => $email,
'password' => Hash::make($createdPassword),
'email_verified_at' => now(),
'is_active' => true,
]);
} elseif ($plainPassword !== '') {
$user->password = Hash::make($plainPassword);
$user->save();
$createdPassword = $plainPassword;
}
$user->assignRole('fornitore');
$dipendente->user_id = (int) $user->id;
}
if ($tipo === FornitoreDipendente::TIPO_INTERNO) {
$dipendente->rubrica_id = $this->upsertRubricaInterna($validated, $dipendente);
}
$dipendente->save();
$this->resetForm();
$this->refreshRows();
$this->activeTab = 'elenco';
$notification = Notification::make()->title('Collaboratore salvato')->success();
if ($createdPassword !== null && $email !== '') {
$this->lastGeneratedPassword = $createdPassword;
$notification->body('Accesso creato per ' . $email . '. Password temporanea: ' . $createdPassword);
}
$notification->send();
}
public function abilitaAccesso(int $dipendenteId): void
{
if (! $this->fornitore instanceof Fornitore) {
return;
}
$dipendente = FornitoreDipendente::query()
->where('fornitore_id', (int) $this->fornitore->id)
->find($dipendenteId);
if (! $dipendente instanceof FornitoreDipendente) {
Notification::make()->title('Collaboratore non trovato')->danger()->send();
return;
}
if ((string) $dipendente->tipo_collaboratore === FornitoreDipendente::TIPO_FORNITORE_ESTERNO) {
Notification::make()->title('Per un altro fornitore si usa il suo accesso gia esistente')->warning()->send();
return;
}
$email = trim((string) ($dipendente->email ?? ''));
if ($email === '') {
Notification::make()->title('Email collaboratore mancante')->warning()->send();
return;
}
$targetUser = User::query()->whereRaw('LOWER(email) = ?', [mb_strtolower($email)])->first();
$created = false;
if (! $targetUser instanceof User) {
$newPassword = Str::random(12);
$targetUser = User::query()->create([
'name' => trim((string) ($dipendente->nome_completo ?: 'Utente fornitore')),
'email' => $email,
'password' => Hash::make($newPassword),
'email_verified_at' => now(),
'is_active' => true,
]);
$this->lastGeneratedPassword = $newPassword;
$created = true;
}
$targetUser->assignRole('fornitore');
$dipendente->user_id = (int) $targetUser->id;
$dipendente->attivo = true;
$dipendente->updated_by_user_id = Auth::id();
$dipendente->save();
$this->refreshRows();
Notification::make()
->title('Accesso collaboratore abilitato')
->body($created
? 'Nuova password temporanea: ' . ($this->lastGeneratedPassword ?? '(non disponibile)')
: 'Accesso collegato ad utente esistente.')
->success()
->send();
}
public function resetPasswordDipendenteUser(int $userId): void
{
if (! $this->fornitore instanceof Fornitore) {
return;
}
$dipendente = FornitoreDipendente::query()
->where('fornitore_id', (int) $this->fornitore->id)
->where('user_id', $userId)
->first();
if (! $dipendente instanceof FornitoreDipendente) {
Notification::make()->title('Utente non collegato a questo fornitore')->danger()->send();
return;
}
$target = User::query()->find($userId);
if (! $target instanceof User) {
Notification::make()->title('Utente non trovato')->danger()->send();
return;
}
$newPassword = Str::random(12);
$target->password = Hash::make($newPassword);
$target->save();
$this->lastGeneratedPassword = $newPassword;
Notification::make()
->title('Password collaboratore resettata')
->body('Nuova password temporanea: ' . $newPassword)
->success()
->send();
}
public function toggleDipendenteAttivo(int $dipendenteId): void
{
if (! $this->fornitore instanceof Fornitore) {
return;
}
$dipendente = FornitoreDipendente::query()
->where('fornitore_id', (int) $this->fornitore->id)
->find($dipendenteId);
if (! $dipendente instanceof FornitoreDipendente) {
Notification::make()->title('Collaboratore non trovato')->danger()->send();
return;
}
$dipendente->attivo = ! (bool) $dipendente->attivo;
$dipendente->updated_by_user_id = Auth::id();
$dipendente->save();
$this->refreshRows();
Notification::make()->title('Stato collaboratore aggiornato')->success()->send();
}
public function getTicketsUrl(): string
{
if ($this->fornitore instanceof Fornitore) {
return TicketOperativi::getUrl(['fornitore' => (int) $this->fornitore->id], panel: 'admin-filament');
}
return TicketOperativi::getUrl(panel: 'admin-filament');
}
public function getContabilitaUrl(): string
{
if ($this->fornitore instanceof Fornitore) {
return Contabilita::getUrl(['fornitore' => (int) $this->fornitore->id], panel: 'admin-filament');
}
return Contabilita::getUrl(panel: 'admin-filament');
}
protected function refreshRows(): void
{
if (! $this->fornitore instanceof Fornitore) {
$this->rows = [];
return;
}
$this->rows = FornitoreDipendente::query()
->with(['user', 'fornitoreEsterno'])
->where('fornitore_id', (int) $this->fornitore->id)
->orderBy('attivo', 'desc')
->orderBy('tipo_collaboratore')
->orderBy('cognome')
->orderBy('nome')
->get()
->map(fn(FornitoreDipendente $dipendente) => [
'id' => (int) $dipendente->id,
'nome' => (string) $dipendente->nome_completo,
'email' => (string) ($dipendente->email ?? ''),
'telefono' => (string) ($dipendente->telefono ?? ''),
'note' => (string) ($dipendente->note ?? ''),
'attivo' => (bool) $dipendente->attivo,
'user_id' => $dipendente->user_id ? (int) $dipendente->user_id : null,
'rubrica_id' => $dipendente->rubrica_id ? (int) $dipendente->rubrica_id : null,
'tipo' => (string) $dipendente->tipo_collaboratore,
'tipo_label' => (string) $dipendente->tipo_label,
'fornitore_esterno_nome' => (string) ($dipendente->fornitoreEsterno?->ragione_sociale ?: trim((string) (($dipendente->fornitoreEsterno?->nome ?? '') . ' ' . ($dipendente->fornitoreEsterno?->cognome ?? '')))),
])
->all();
}
protected function refreshFornitoreOptions(): void
{
if (! $this->fornitore instanceof Fornitore || $this->collaboratoreTipo !== FornitoreDipendente::TIPO_FORNITORE_ESTERNO) {
$this->fornitoreOptions = [];
return;
}
$search = trim($this->fornitoreSearch);
$this->fornitoreOptions = Fornitore::query()
->whereKeyNot((int) $this->fornitore->id)
->when(
$search !== '',
function (Builder $query) use ($search): void {
$query->where(function (Builder $builder) use ($search): void {
$builder->where('ragione_sociale', 'like', '%' . $search . '%')
->orWhere('nome', 'like', '%' . $search . '%')
->orWhere('cognome', 'like', '%' . $search . '%')
->orWhere('email', 'like', '%' . $search . '%')
->orWhere('telefono', 'like', '%' . $search . '%')
->orWhere('cellulare', 'like', '%' . $search . '%')
->orWhere('tags', 'like', '%' . $search . '%');
});
}
)
->orderByRaw('CASE WHEN amministratore_id = ? THEN 0 ELSE 1 END', [(int) ($this->fornitore->amministratore_id ?? 0)])
->orderByRaw('COALESCE(ragione_sociale, nome, cognome)')
->limit(20)
->get(['id', 'ragione_sociale', 'nome', 'cognome', 'email', 'telefono', 'cellulare', 'tags'])
->map(fn(Fornitore $fornitore) => [
'id' => (int) $fornitore->id,
'label' => $this->getFornitoreLabel($fornitore),
'meta' => trim(collect([
$fornitore->email,
$fornitore->telefono ?: $fornitore->cellulare,
$fornitore->tags,
])->filter()->implode(' · ')),
])
->all();
}
protected function resolveFornitoreEsterno(int $fornitoreId): ?Fornitore
{
if ($fornitoreId <= 0) {
return null;
}
return Fornitore::query()->find($fornitoreId);
}
protected function resetForm(): void
{
$this->tipoContatto = 'persona_fisica';
$this->nome = '';
$this->cognome = '';
$this->ragioneSociale = '';
$this->codiceFiscale = '';
$this->partitaIva = '';
$this->pec = '';
$this->sesso = '';
$this->dataNascita = '';
$this->luogoNascita = '';
$this->provinciaNascita = '';
$this->email = '';
$this->telefono = '';
$this->indirizzo = '';
$this->civico = '';
$this->cap = '';
$this->citta = '';
$this->provincia = '';
$this->nazione = 'Italia';
$this->collaboratoreTipo = FornitoreDipendente::TIPO_INTERNO;
$this->fornitoreSearch = '';
$this->fornitoreEsternoId = null;
$this->note = '';
$this->createUserAccess = false;
$this->accessPassword = '';
$this->refreshFornitoreOptions();
}
protected function upsertRubricaInterna(array $validated, FornitoreDipendente $dipendente): int
{
$email = trim((string) ($validated['email'] ?? ''));
$rubrica = null;
if ($email !== '') {
$rubrica = RubricaUniversale::query()
->whereRaw('LOWER(email) = ?', [mb_strtolower($email)])
->where('categoria', 'fornitore')
->orderByDesc('id')
->first();
}
if (! $rubrica instanceof RubricaUniversale) {
$rubrica = new RubricaUniversale();
$rubrica->data_inserimento = now()->toDateString();
$rubrica->creato_da = Auth::id();
}
$tipoContatto = (string) ($validated['tipoContatto'] ?? 'persona_fisica');
$telefono = trim((string) ($validated['telefono'] ?? ''));
$ragioneSociale = trim((string) ($validated['ragioneSociale'] ?? ''));
$rubrica->titolo_id = null;
$rubrica->nome = $tipoContatto === 'persona_giuridica' ? null : (trim((string) ($validated['nome'] ?? '')) ?: null);
$rubrica->cognome = $tipoContatto === 'persona_giuridica' ? null : (trim((string) ($validated['cognome'] ?? '')) ?: null);
$rubrica->ragione_sociale = $tipoContatto === 'persona_giuridica' ? ($ragioneSociale ?: null) : null;
$rubrica->tipo_contatto = $tipoContatto;
$rubrica->codice_fiscale = trim((string) ($validated['codiceFiscale'] ?? '')) ?: null;
$rubrica->partita_iva = trim((string) ($validated['partitaIva'] ?? '')) ?: null;
$rubrica->sesso = trim((string) ($validated['sesso'] ?? '')) ?: null;
$rubrica->data_nascita = trim((string) ($validated['dataNascita'] ?? '')) ?: null;
$rubrica->luogo_nascita = trim((string) ($validated['luogoNascita'] ?? '')) ?: null;
$rubrica->provincia_nascita = trim((string) ($validated['provinciaNascita'] ?? '')) ?: null;
$rubrica->indirizzo = trim((string) ($validated['indirizzo'] ?? '')) ?: null;
$rubrica->civico = trim((string) ($validated['civico'] ?? '')) ?: null;
$rubrica->cap = trim((string) ($validated['cap'] ?? '')) ?: null;
$rubrica->citta = trim((string) ($validated['citta'] ?? '')) ?: null;
$rubrica->provincia = trim((string) ($validated['provincia'] ?? '')) ?: null;
$rubrica->nazione = trim((string) ($validated['nazione'] ?? '')) ?: 'Italia';
$rubrica->telefono_ufficio = $tipoContatto === 'persona_giuridica' ? ($telefono ?: null) : null;
$rubrica->telefono_cellulare = $telefono ?: null;
$rubrica->email = $email !== '' ? $email : null;
$rubrica->pec = trim((string) ($validated['pec'] ?? '')) ?: null;
$rubrica->note = trim((string) ($validated['note'] ?? '')) ?: null;
$rubrica->categoria = 'fornitore';
$rubrica->stato = 'attivo';
$rubrica->data_ultima_modifica = now()->toDateString();
$rubrica->modificato_da = Auth::id();
$rubrica->save();
$dipendente->rubrica_id = (int) $rubrica->id;
return (int) $rubrica->id;
}
}