329 lines
13 KiB
PHP
329 lines
13 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Http\Controllers;
|
||
|
|
|
||
|
|
use App\Enums\FolderPriority;
|
||
|
|
use App\Enums\FolderStatus;
|
||
|
|
use App\Enums\FolderType;
|
||
|
|
use App\Http\Requests\StoreFolderRequest;
|
||
|
|
use App\Http\Requests\UpdateFolderRequest;
|
||
|
|
use App\Models\Client;
|
||
|
|
use App\Models\Folder;
|
||
|
|
use App\Models\MediaDownload;
|
||
|
|
use App\Models\Workspace;
|
||
|
|
use Illuminate\Http\RedirectResponse;
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
use Inertia\Inertia;
|
||
|
|
use Inertia\Response;
|
||
|
|
|
||
|
|
class FolderController extends Controller
|
||
|
|
{
|
||
|
|
protected function folderTypeLabels(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
FolderType::VAT => 'TVA',
|
||
|
|
FolderType::VatMonthly => 'TVA mensuelle',
|
||
|
|
FolderType::VatQuarterly => 'TVA trimestrielle',
|
||
|
|
FolderType::CorporateTax => 'IS',
|
||
|
|
FolderType::IncomeTax => 'IR',
|
||
|
|
FolderType::CNSS => 'CNSS',
|
||
|
|
FolderType::AnnualBalance => 'Bilan',
|
||
|
|
FolderType::Other => 'Autre',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function folderStatusLabels(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
FolderStatus::Draft => 'Brouillon',
|
||
|
|
FolderStatus::WaitingDocuments => 'En attente documents',
|
||
|
|
FolderStatus::DocumentsReceived => 'Documents reçus',
|
||
|
|
FolderStatus::Processing => 'En cours de traitement',
|
||
|
|
FolderStatus::AdditionalDocumentsRequested => 'Pièces complémentaires demandées',
|
||
|
|
FolderStatus::WaitingClientValidation => 'En attente validation client',
|
||
|
|
FolderStatus::Validated => 'Validé',
|
||
|
|
FolderStatus::Closed => 'Clôturé',
|
||
|
|
FolderStatus::Cancelled => 'Annulé',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function folderPriorityLabels(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
FolderPriority::Low => 'Basse',
|
||
|
|
FolderPriority::Medium => 'Normale',
|
||
|
|
FolderPriority::High => 'Haute',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function currentWorkspace(Request $request): Workspace
|
||
|
|
{
|
||
|
|
$workspaceId = $request->session()->get('current_workspace_id');
|
||
|
|
|
||
|
|
return Workspace::query()->findOrFail($workspaceId);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Display a listing of the folders.
|
||
|
|
*/
|
||
|
|
public function index(Request $request): Response
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
|
||
|
|
$perPage = min(max((int) $request->input('per_page', 10), 10), 100);
|
||
|
|
|
||
|
|
$folders = $workspace->folders()
|
||
|
|
->with(['client', 'assignee'])
|
||
|
|
->latest()
|
||
|
|
->paginate($perPage)
|
||
|
|
->through(fn (Folder $folder) => [
|
||
|
|
'id' => $folder->id,
|
||
|
|
'title' => $folder->title,
|
||
|
|
'type' => $folder->type->value,
|
||
|
|
'client_name' => $folder->client->company_name,
|
||
|
|
'status' => $folder->status->value,
|
||
|
|
'due_date' => $folder->due_date?->format('Y-m-d'),
|
||
|
|
'showUrl' => route('folders.show', $folder),
|
||
|
|
'editUrl' => route('folders.edit', $folder),
|
||
|
|
'destroyUrl' => route('folders.destroy', $folder),
|
||
|
|
]);
|
||
|
|
|
||
|
|
return Inertia::render('folders/Index', [
|
||
|
|
'folders' => $folders,
|
||
|
|
'createUrl' => route('folders.create'),
|
||
|
|
'workspaceName' => $workspace->name,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Show the form for creating a new folder.
|
||
|
|
*/
|
||
|
|
public function create(Request $request): Response
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
$initialClientId = $request->integer('client_id', 0) ?: null;
|
||
|
|
|
||
|
|
return Inertia::render('folders/Create', [
|
||
|
|
'indexUrl' => route('folders.index'),
|
||
|
|
'storeUrl' => route('folders.store'),
|
||
|
|
'initialClientId' => $initialClientId,
|
||
|
|
'folderTypeLabels' => $this->folderTypeLabels(),
|
||
|
|
'folderStatusLabels' => $this->folderStatusLabels(),
|
||
|
|
'folderPriorityLabels' => $this->folderPriorityLabels(),
|
||
|
|
'clients' => $workspace->clients()->orderBy('company_name')->get(['id', 'company_name'])->map(fn (Client $c) => [
|
||
|
|
'id' => $c->id,
|
||
|
|
'company_name' => $c->company_name,
|
||
|
|
])->values()->all(),
|
||
|
|
'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 folder in storage.
|
||
|
|
*/
|
||
|
|
public function store(StoreFolderRequest $request): RedirectResponse
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
$data = $request->validated();
|
||
|
|
$data['workspace_id'] = $workspace->id;
|
||
|
|
$data['created_by'] = $request->user()?->id;
|
||
|
|
$data['status'] = $data['status'] ?? FolderStatus::Draft->value;
|
||
|
|
|
||
|
|
Folder::query()->create($data);
|
||
|
|
|
||
|
|
return to_route('folders.index');
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Display the specified folder.
|
||
|
|
*/
|
||
|
|
public function show(Request $request, Folder $folder): Response
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
$this->authorizeFolder($workspace, $folder);
|
||
|
|
|
||
|
|
$folder->load(['client', 'creator', 'assignee', 'messages' => fn ($q) => $q->with(['senderUser', 'senderClient'])->latest()]);
|
||
|
|
|
||
|
|
$allMedia = $folder->getMedia('documents');
|
||
|
|
$downloadedMediaIds = MediaDownload::query()
|
||
|
|
->where('user_id', $request->user()->id)
|
||
|
|
->whereIn('media_id', $allMedia->pluck('id'))
|
||
|
|
->pluck('media_id')
|
||
|
|
->all();
|
||
|
|
|
||
|
|
$messages = $folder->messages->map(function ($m) use ($folder, $allMedia, $downloadedMediaIds) {
|
||
|
|
$attachments = $allMedia
|
||
|
|
->filter(fn ($media) => $media->getCustomProperty('message_id') === $m->id)
|
||
|
|
->map(fn ($media) => [
|
||
|
|
'id' => $media->id,
|
||
|
|
'file_name' => $media->file_name,
|
||
|
|
'mime_type' => $media->mime_type,
|
||
|
|
'size' => $media->human_readable_size,
|
||
|
|
'downloadUrl' => route('folders.media.download', ['folder' => $folder, 'mediaId' => $media->id]),
|
||
|
|
'is_downloaded' => in_array($media->id, $downloadedMediaIds),
|
||
|
|
])
|
||
|
|
->values()
|
||
|
|
->all();
|
||
|
|
|
||
|
|
$confirmationStatus = null;
|
||
|
|
if ($m->type->value === 'confirmation') {
|
||
|
|
$confirmationStatus = $folder->refused_at ? 'refused' : ($folder->validated_at ? 'confirmed' : 'pending');
|
||
|
|
}
|
||
|
|
|
||
|
|
return [
|
||
|
|
'id' => $m->id,
|
||
|
|
'type' => $m->type->value,
|
||
|
|
'body' => $m->body,
|
||
|
|
'sent_by_type' => $m->sent_by_type->value,
|
||
|
|
'sender_name' => $m->sender_name,
|
||
|
|
'created_at' => $m->created_at->format('Y-m-d H:i'),
|
||
|
|
'attachments' => $attachments,
|
||
|
|
'confirmation_status' => $confirmationStatus,
|
||
|
|
];
|
||
|
|
})->values()->all();
|
||
|
|
|
||
|
|
$documents = $allMedia->map(fn ($m) => [
|
||
|
|
'id' => $m->id,
|
||
|
|
'name' => $m->name,
|
||
|
|
'file_name' => $m->file_name,
|
||
|
|
'size' => $m->human_readable_size,
|
||
|
|
'created_at' => $m->created_at->format('d/m/Y H:i'),
|
||
|
|
'uploaded_by' => $m->getCustomProperty('uploaded_by_type') === 'user' ? 'Comptable' : 'Client',
|
||
|
|
'downloadUrl' => route('folders.media.download', ['folder' => $folder, 'mediaId' => $m->id]),
|
||
|
|
'is_downloaded' => in_array($m->id, $downloadedMediaIds),
|
||
|
|
])->values()->all();
|
||
|
|
|
||
|
|
return Inertia::render('folders/Show', [
|
||
|
|
'folder' => [
|
||
|
|
'id' => $folder->id,
|
||
|
|
'title' => $folder->title,
|
||
|
|
'type' => $folder->type->value,
|
||
|
|
'client_id' => $folder->client_id,
|
||
|
|
'client_name' => $folder->client->company_name,
|
||
|
|
'period_year' => $folder->period_year,
|
||
|
|
'period_month' => $folder->period_month,
|
||
|
|
'period_quarter' => $folder->period_quarter,
|
||
|
|
'due_date' => $folder->due_date?->format('Y-m-d'),
|
||
|
|
'status' => $folder->status->value,
|
||
|
|
'priority' => $folder->priority?->value,
|
||
|
|
'assigned_to' => $folder->assigned_to,
|
||
|
|
'assignee_name' => $folder->assignee?->name,
|
||
|
|
'validated_at' => $folder->validated_at?->format('Y-m-d H:i'),
|
||
|
|
'closed_at' => $folder->closed_at?->format('Y-m-d H:i'),
|
||
|
|
'notes_internal' => $folder->notes_internal,
|
||
|
|
'notes_client' => $folder->notes_client,
|
||
|
|
'created_at' => $folder->created_at?->format('Y-m-d H:i'),
|
||
|
|
],
|
||
|
|
'messages' => $messages,
|
||
|
|
'documents' => $documents,
|
||
|
|
'messagesStoreUrl' => route('folders.messages.store', $folder),
|
||
|
|
'mediaStoreUrl' => route('folders.media.store', $folder),
|
||
|
|
'messageTypeLabels' => [
|
||
|
|
'invite' => 'Invitation',
|
||
|
|
'situation' => 'Situation',
|
||
|
|
'file_request' => 'Demande de pièces',
|
||
|
|
'confirmation' => 'Demande de validation',
|
||
|
|
'text' => 'Message',
|
||
|
|
],
|
||
|
|
'indexUrl' => route('folders.index'),
|
||
|
|
'editUrl' => route('folders.edit', $folder),
|
||
|
|
'workspaceUsers' => $workspace->users()->orderBy('users.name')
|
||
|
|
->select('users.id', 'users.name', 'users.email')
|
||
|
|
->get()->map(fn ($u) => ['id' => $u->id, 'name' => $u->name])
|
||
|
|
->values()->all(),
|
||
|
|
'mentionStoreUrl' => route('folders.mentions.store', $folder),
|
||
|
|
'canMention' => in_array(
|
||
|
|
$workspace->users()->where('users.id', $request->user()->id)->first()?->pivot?->role?->value,
|
||
|
|
['owner', 'manager']
|
||
|
|
),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Show the form for editing the specified folder.
|
||
|
|
*/
|
||
|
|
public function edit(Request $request, Folder $folder): Response
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
$this->authorizeFolder($workspace, $folder);
|
||
|
|
|
||
|
|
return Inertia::render('folders/Edit', [
|
||
|
|
'folder' => [
|
||
|
|
'id' => $folder->id,
|
||
|
|
'title' => $folder->title,
|
||
|
|
'type' => $folder->type->value,
|
||
|
|
'client_id' => $folder->client_id,
|
||
|
|
'period_year' => $folder->period_year,
|
||
|
|
'period_month' => $folder->period_month,
|
||
|
|
'period_quarter' => $folder->period_quarter,
|
||
|
|
'due_date' => $folder->due_date?->format('Y-m-d'),
|
||
|
|
'status' => $folder->status->value,
|
||
|
|
'priority' => $folder->priority?->value,
|
||
|
|
'assigned_to' => $folder->assigned_to,
|
||
|
|
'notes_internal' => $folder->notes_internal,
|
||
|
|
'notes_client' => $folder->notes_client,
|
||
|
|
'created_at' => $folder->created_at?->format('Y-m-d H:i'),
|
||
|
|
],
|
||
|
|
'indexUrl' => route('folders.index'),
|
||
|
|
'updateUrl' => route('folders.update', $folder),
|
||
|
|
'folderTypeLabels' => $this->folderTypeLabels(),
|
||
|
|
'folderStatusLabels' => $this->folderStatusLabels(),
|
||
|
|
'folderPriorityLabels' => $this->folderPriorityLabels(),
|
||
|
|
'clients' => $workspace->clients()->orderBy('company_name')->get(['id', 'company_name'])->map(fn (Client $c) => [
|
||
|
|
'id' => $c->id,
|
||
|
|
'company_name' => $c->company_name,
|
||
|
|
])->values()->all(),
|
||
|
|
'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 folder in storage.
|
||
|
|
*/
|
||
|
|
public function update(UpdateFolderRequest $request, Folder $folder): RedirectResponse
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
$this->authorizeFolder($workspace, $folder);
|
||
|
|
|
||
|
|
$folder->update($request->validated());
|
||
|
|
|
||
|
|
return to_route('folders.index');
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove the specified folder from storage.
|
||
|
|
*/
|
||
|
|
public function destroy(Request $request, Folder $folder): RedirectResponse
|
||
|
|
{
|
||
|
|
$workspace = $this->currentWorkspace($request);
|
||
|
|
$this->authorizeFolder($workspace, $folder);
|
||
|
|
|
||
|
|
$folder->delete();
|
||
|
|
|
||
|
|
return to_route('folders.index');
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function authorizeFolder(Workspace $workspace, Folder $folder): void
|
||
|
|
{
|
||
|
|
if ($folder->workspace_id !== $workspace->id) {
|
||
|
|
abort(404);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|