session()->get('current_workspace_id'); return Workspace::query()->findOrFail($workspaceId); } /** * Store a newly created message. */ public function store(StoreDeclarationMessageRequest $request, Declaration $declaration): RedirectResponse { $workspace = $this->currentWorkspace($request); if ($declaration->workspace_id !== $workspace->id) { abort(404); } $user = $request->user(); $type = MessageType::fromValue($request->input('type')); $body = $request->input('body'); $invitation = $type->is(MessageType::Invite) ? $this->createInvitation($declaration) : $this->getOrCreateInvitation($declaration); $metadata = ['invitation_id' => $invitation->id]; $message = $declaration->messages()->create([ 'type' => $type, 'body' => $body, 'sent_by_type' => ActorType::User, 'sent_by_id' => $user->id, 'metadata' => $metadata, ]); $mediaIds = []; if ($request->hasFile('files')) { foreach ($request->file('files') as $file) { $media = $declaration->addMedia($file) ->withCustomProperties([ 'message_id' => $message->id, 'uploaded_by_type' => ActorType::User, 'uploaded_by_id' => $user->id, ]) ->toMediaCollection('documents'); $mediaIds[] = $media->id; } $message->update(['metadata' => array_merge($metadata, ['media_ids' => $mediaIds])]); } $this->updateDeclarationStatusAndConfirmation($declaration, $type, $mediaIds); $emailSent = $this->sendEmailForMessage($declaration, $invitation, $message, $body, $type); $flashMessage = $emailSent ? 'Message envoyé.' : 'Message enregistré, mais l\'email du client n\'est pas configuré.'; return back()->with('flash', ['type' => 'success', 'message' => $flashMessage]); } protected function createInvitation(Declaration $declaration): DeclarationInvitation { $declaration->load('client.primaryContact'); return $declaration->invitations()->create([ 'email' => $declaration->client->primary_contact_email, 'expires_at' => Carbon::now()->addDays(7), ]); } protected function getOrCreateInvitation(Declaration $declaration): DeclarationInvitation { $invitation = $declaration->invitations() ->where('expires_at', '>', now()) ->latest() ->first(); if ($invitation) { return $invitation; } return $this->createInvitation($declaration); } /** * @param array $mediaIds */ protected function updateDeclarationStatusAndConfirmation(Declaration $declaration, MessageType $type, array $mediaIds): void { // Transition through en_cours first if declaration is still in created status, // since created → en_attente_client is not a valid direct transition. if ($declaration->status->is(DeclarationStatus::Created)) { $declaration->update(['status' => DeclarationStatus::EnCours]); $declaration->refresh(); } match ($type->value) { 'invite' => $declaration->update(['status' => DeclarationStatus::EnAttenteClient]), 'situation', 'file_request' => $declaration->update(['status' => DeclarationStatus::EnAttenteClient]), 'confirmation' => $declaration->update([ 'status' => DeclarationStatus::EnAttenteClient, 'confirmation_requested_at' => now(), 'confirmation_media_id' => $mediaIds[0] ?? null, ]), default => null, }; } protected function sendEmailForMessage(Declaration $declaration, DeclarationInvitation $invitation, Message $message, string $body, MessageType $type): bool { $declaration->load('client.primaryContact'); $clientEmail = $declaration->client->primary_contact_email; if (empty($clientEmail)) { \Illuminate\Support\Facades\Log::warning("No primary contact email for client #{$declaration->client_id}, skipping email."); return false; } match ($type->value) { 'invite' => Mail::to($clientEmail)->send(new DeclarationInviteMail($declaration, $invitation)), 'situation' => Mail::to($clientEmail)->send(new DeclarationSituationMail($declaration, $invitation, $body)), 'file_request' => Mail::to($clientEmail)->send(new DeclarationFileRequestMail($declaration, $invitation, $body)), 'confirmation' => Mail::to($clientEmail)->send(new DeclarationConfirmationMail($declaration, $invitation, $body)), 'text' => Mail::to($clientEmail)->send(new DeclarationTextMessageMail($declaration, $body, $invitation->token)), default => null, }; return true; } }