Files
L-Ami-Fiduciaire/app/Http/Controllers/ClientController.php

338 lines
10 KiB
PHP
Raw Normal View History

<?php
namespace App\Http\Controllers;
use App\Concerns\HasWorkspaceScope;
use App\Enums\ClientStatus;
use App\Enums\LegalForm;
use App\Enums\WorkspaceUserRole;
use App\Http\Requests\StoreClientRequest;
use App\Http\Requests\UpdateClientRequest;
use App\Models\Client;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;
class ClientController extends Controller
{
use HasWorkspaceScope;
protected function legalFormLabels(): array
{
$labels = [
'sarl' => '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');
}
}