> */ public array $rows = []; /** @var array> */ public array $fornitoreOptions = []; /** @var array> */ public array $fornitoreMatches = []; 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->fornitoreMatches = []; $this->createUserAccess = false; } $this->refreshFornitoreOptions(); } public function updatedFornitoreSearch(): void { $this->refreshFornitoreOptions(); } public function selezionaFornitoreEsterno(int $fornitoreId): void { $match = collect($this->fornitoreMatches)->firstWhere('id', $fornitoreId); if (! is_array($match)) { $fornitore = $this->resolveFornitoreEsterno($fornitoreId); if (! $fornitore instanceof Fornitore) { return; } $match = $this->mapFornitoreOption($fornitore); } $this->fornitoreEsternoId = (int) $match['id']; $this->fornitoreSearch = (string) $match['label']; $this->fornitoreMatches = []; } public function resetFornitoreEsternoSelection(): void { $this->fornitoreEsternoId = null; $this->fornitoreSearch = ''; $this->fornitoreMatches = []; $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 = []; $this->fornitoreMatches = []; 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', 'note']) ->map(fn(Fornitore $fornitore) => $this->mapFornitoreOption($fornitore)) ->all(); $this->fornitoreMatches = $this->fornitoreOptions; if ($this->fornitoreEsternoId && ! collect($this->fornitoreMatches)->contains('id', $this->fornitoreEsternoId)) { $selected = $this->resolveFornitoreEsterno((int) $this->fornitoreEsternoId); if ($selected instanceof Fornitore) { array_unshift($this->fornitoreMatches, $this->mapFornitoreOption($selected)); $this->fornitoreMatches = array_slice($this->fornitoreMatches, 0, 20); } } } 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->fornitoreMatches = []; $this->note = ''; $this->createUserAccess = false; $this->accessPassword = ''; $this->refreshFornitoreOptions(); } /** * @return array */ protected function mapFornitoreOption(Fornitore $fornitore): array { return [ 'id' => (int) $fornitore->id, 'label' => $this->getFornitoreLabel($fornitore), 'meta' => trim(collect([ $fornitore->email, $fornitore->telefono ?: $fornitore->cellulare, $fornitore->tags, ])->filter()->implode(' ยท ')), 'note' => Str::limit(trim((string) ($fornitore->note ?? '')), 120), ]; } 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; } }