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

463 lines
18 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\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 $nome = '';
public string $cognome = '';
public string $email = '';
public string $telefono = '';
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();
}
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])],
'nome' => ['nullable', 'string', 'max:100'],
'cognome' => ['nullable', 'string', 'max:100'],
'email' => ['nullable', 'email', 'max:255'],
'telefono' => ['nullable', 'string', 'max:50'],
'note' => ['nullable', 'string', 'max:2000'],
'createUserAccess' => ['nullable', 'boolean'],
'accessPassword' => ['nullable', 'string', 'min:8', 'max:100'],
'fornitoreEsternoId' => ['nullable', 'integer'],
]);
$tipo = (string) $validated['collaboratoreTipo'];
if ($tipo === FornitoreDipendente::TIPO_INTERNO && trim((string) ($validated['nome'] ?? '')) === '') {
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')
: trim((string) $validated['nome']);
$dipendente->cognome = $tipo === FornitoreDipendente::TIPO_FORNITORE_ESTERNO
? 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;
}
$dipendente->save();
$this->resetForm();
$this->refreshRows();
$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,
'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->nome = '';
$this->cognome = '';
$this->email = '';
$this->telefono = '';
$this->collaboratoreTipo = FornitoreDipendente::TIPO_INTERNO;
$this->fornitoreSearch = '';
$this->fornitoreEsternoId = null;
$this->note = '';
$this->createUserAccess = false;
$this->accessPassword = '';
$this->refreshFornitoreOptions();
}
}