'SARL', 'sa' => 'SA', 'snc' => 'SNC', 'scs' => 'SCS', 'eurl' => 'EURL', 'sel' => 'SEL', 'auto_entrepreneur' => 'Auto-entrepreneur', 'entreprise_individuelle' => 'Entreprise individuelle', 'other' => 'Autre', ]; return array_intersect_key($labels, array_flip(LegalForm::getValues())); } protected function clientStatusLabels(): array { return [ ClientStatus::Active => 'Actif', ClientStatus::Inactive => 'Inactif', ClientStatus::Suspended => 'Suspendu', ]; } protected function serializeContacts(Client $client): array { return $client->contacts->map(fn ($c) => [ 'id' => $c->id, 'full_name' => $c->full_name, 'job_title' => $c->job_title, 'email' => $c->email, 'phone' => $c->phone, 'is_principal' => $c->is_principal, ])->all(); } protected function isWorker(): bool { return auth()->user()->currentWorkspaceUser()->role->is(WorkspaceUserRole::Worker); } /** * Display a listing of the clients. */ public function index(Request $request): Response { $workspace = $this->currentWorkspace(); $user = auth()->user(); $isWorker = $this->isWorker(); $perPage = min(max((int) $request->input('per_page', 10), 10), 100); $query = $workspace->clients(); if ($isWorker) { $query->whereHas('declarations', fn ($q) => $q->where('assigned_to', $user->id)); } $clients = $query ->latest() ->paginate($perPage) ->through(fn (Client $client) => [ 'id' => $client->id, 'company_name' => $client->company_name, 'legal_form' => $client->legal_form->value, 'ice' => $client->ice, 'status' => $client->status?->value, 'showUrl' => route('clients.show', $client), 'editUrl' => route('clients.edit', $client), 'destroyUrl' => route('clients.destroy', $client), ]); return Inertia::render('clients/Index', [ 'clients' => $clients, 'createUrl' => route('clients.create'), 'workspaceName' => $workspace->name, 'canCreate' => ! $isWorker, 'canEdit' => ! $isWorker, 'canDelete' => ! $isWorker, ]); } /** * Show the form for creating a new client. */ public function create(Request $request): Response { if ($this->isWorker()) { abort(404); } $workspace = $this->currentWorkspace(); return Inertia::render('clients/Create', [ 'indexUrl' => route('clients.index'), 'storeUrl' => route('clients.store'), 'legalForms' => $this->legalFormLabels(), 'clientStatusLabels' => $this->clientStatusLabels(), 'workspaceUsers' => $workspace->users()->orderBy('users.name')->select('users.id', 'users.name', 'users.email')->get()->map(fn ($u) => [ 'id' => $u->id, 'name' => $u->name, 'email' => $u->email, ])->values()->all(), ]); } /** * Store a newly created client in storage. */ public function store(StoreClientRequest $request): RedirectResponse { if ($this->isWorker()) { abort(404); } $workspace = $this->currentWorkspace(); $data = $request->validated(); $contacts = $data['contacts']; unset($data['contacts']); $data['workspace_id'] = $workspace->id; $client = Client::query()->create($data); foreach ($contacts as $contact) { $client->contacts()->create($contact); } return to_route('clients.index'); } /** * Display the specified client. */ public function show(Request $request, Client $client): Response { $this->authorizeWorkspaceAccess($client); $isWorker = $this->isWorker(); $user = auth()->user(); if ($isWorker) { $hasAssignedDeclarations = $client->declarations() ->where('assigned_to', $user->id) ->exists(); if (! $hasAssignedDeclarations) { abort(404); } } $client->load(['internalResponsible', 'contacts']); $declarationsQuery = $client->declarations(); if ($isWorker) { $declarationsQuery->where('assigned_to', $user->id); } $declarations = (clone $declarationsQuery) ->with(['assignee']) ->latest() ->limit(50) ->get() ->map(fn ($f) => [ 'id' => $f->id, 'title' => $f->title, 'type' => $f->type->value, 'status' => $f->status->value, 'due_date' => $f->due_date?->format('Y-m-d'), 'created_at' => $f->created_at->format('Y-m-d'), 'showUrl' => route('declarations.show', $f), ]) ->values() ->all(); $allDeclarations = (clone $declarationsQuery)->get(); $stats = [ 'total' => $allDeclarations->count(), 'by_status' => $allDeclarations->groupBy(fn ($f) => $f->status->value) ->map->count() ->all(), 'by_type' => $allDeclarations->groupBy(fn ($f) => $f->type->value) ->map->count() ->all(), ]; return Inertia::render('clients/Show', [ 'client' => [ 'id' => $client->id, 'company_name' => $client->company_name, 'legal_form' => $client->legal_form->value, 'ice' => $client->ice, 'fiscal_id' => $client->fiscal_id, 'rc' => $client->rc, 'cnss' => $client->cnss, 'patente' => $client->patente, 'contacts' => $this->serializeContacts($client), 'internal_responsible_id' => $client->internal_responsible_id, 'internal_responsible_name' => $client->internalResponsible?->name, 'status' => $client->status?->value, 'internal_notes' => $client->internal_notes, ], 'declarations' => $declarations, 'stats' => $stats, 'indexUrl' => route('clients.index'), 'editUrl' => route('clients.edit', $client), 'createDeclarationUrl' => route('declarations.create', ['client_id' => $client->id]), 'canEdit' => ! $isWorker, 'canDelete' => ! $isWorker, ]); } /** * Show the form for editing the specified client. */ public function edit(Request $request, Client $client): Response { if ($this->isWorker()) { abort(404); } $this->authorizeWorkspaceAccess($client); $workspace = $this->currentWorkspace(); $client->load('contacts'); return Inertia::render('clients/Edit', [ 'client' => [ 'id' => $client->id, 'company_name' => $client->company_name, 'legal_form' => $client->legal_form->value, 'ice' => $client->ice, 'fiscal_id' => $client->fiscal_id, 'rc' => $client->rc, 'cnss' => $client->cnss, 'patente' => $client->patente, 'contacts' => $this->serializeContacts($client), 'internal_responsible_id' => $client->internal_responsible_id, 'status' => $client->status?->value, 'internal_notes' => $client->internal_notes, ], 'indexUrl' => route('clients.index'), 'updateUrl' => route('clients.update', $client), 'legalForms' => $this->legalFormLabels(), 'clientStatusLabels' => $this->clientStatusLabels(), 'workspaceUsers' => $workspace->users()->orderBy('users.name')->select('users.id', 'users.name', 'users.email')->get()->map(fn ($u) => [ 'id' => $u->id, 'name' => $u->name, 'email' => $u->email, ])->values()->all(), ]); } /** * Update the specified client in storage. */ public function update(UpdateClientRequest $request, Client $client): RedirectResponse { if ($this->isWorker()) { abort(404); } $this->authorizeWorkspaceAccess($client); $data = $request->validated(); $contacts = $data['contacts']; unset($data['contacts']); DB::transaction(function () use ($client, $data, $contacts) { $client->update($data); $submittedIds = collect($contacts) ->pluck('id') ->filter() ->all(); $client->contacts() ->whereNotIn('id', $submittedIds) ->get() ->each ->delete(); foreach ($contacts as $contactData) { if (! empty($contactData['id'])) { $client->contacts() ->where('id', $contactData['id']) ->first() ?->update($contactData); } else { $client->contacts()->create($contactData); } } }); return to_route('clients.index'); } /** * Remove the specified client from storage. */ public function destroy(Request $request, Client $client): RedirectResponse { if ($this->isWorker()) { abort(404); } $this->authorizeWorkspaceAccess($client); $client->delete(); return to_route('clients.index'); } }