463 lines
18 KiB
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();
|
|
}
|
|
}
|