- Fix togglePermission() to always include all permission keys with false defaults - Add migration to backfill null/empty Manager permissions with config defaults - Rename nudge UI text from "Relance" to "Notification"/"Notifier" across 8 files - Fix select-all checkbox and show checkboxes on all declaration rows - Remove en_attente_client status restriction from BulkNotificationController Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
105 lines
3.7 KiB
PHP
105 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Concerns\HasWorkspaceScope;
|
|
use App\Http\Requests\BulkNotifyRequest;
|
|
use App\Mail\DeclarationFileRequestMail;
|
|
use App\Models\Declaration;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
class BulkNotificationController extends Controller
|
|
{
|
|
use HasWorkspaceScope;
|
|
|
|
public function store(BulkNotifyRequest $request): RedirectResponse
|
|
{
|
|
$workspace = $this->currentWorkspace();
|
|
$user = $request->user();
|
|
$workspaceUser = $user->currentWorkspaceUser();
|
|
|
|
$declarations = Declaration::where('workspace_id', $workspace->id)
|
|
->forUser($user, $workspaceUser)
|
|
->whereIn('id', $request->validated('declaration_ids'))
|
|
->with('client')
|
|
->get()
|
|
->filter(fn (Declaration $d) => $d->client !== null);
|
|
|
|
if ($declarations->isEmpty()) {
|
|
return back()->with('flash', [
|
|
'type' => 'warning',
|
|
'message' => 'Aucune déclaration éligible trouvée.',
|
|
]);
|
|
}
|
|
|
|
// DB transaction for invitation creation/update, collect mail data for queuing after commit
|
|
$mailJobs = DB::transaction(function () use ($declarations) {
|
|
$jobs = [];
|
|
|
|
foreach ($declarations as $declaration) {
|
|
$clientEmail = $declaration->client->contact_email;
|
|
|
|
$invitation = $declaration->invitations()
|
|
->whereNull('used_at')
|
|
->latest()
|
|
->first();
|
|
|
|
if ($invitation && $invitation->isValid()) {
|
|
if ($invitation->email !== $clientEmail) {
|
|
$invitation->update(['email' => $clientEmail]);
|
|
$invitation->refresh();
|
|
}
|
|
} elseif ($invitation && ! $invitation->isValid()) {
|
|
$invitation->update([
|
|
'email' => $clientEmail,
|
|
'expires_at' => now()->addDays(30),
|
|
]);
|
|
$invitation->refresh();
|
|
} else {
|
|
$invitation = $declaration->invitations()->create([
|
|
'email' => $clientEmail,
|
|
'expires_at' => now()->addDays(30),
|
|
]);
|
|
}
|
|
|
|
$body = 'Nous vous invitons à déposer les documents complémentaires pour votre déclaration "'
|
|
. $declaration->title . '".';
|
|
|
|
$jobs[] = [
|
|
'email' => $declaration->client->contact_email,
|
|
'mailable' => new DeclarationFileRequestMail($declaration, $invitation, $body),
|
|
];
|
|
}
|
|
|
|
return $jobs;
|
|
});
|
|
|
|
// Queue emails outside transaction (Redis is not transactional with MySQL)
|
|
foreach ($mailJobs as $job) {
|
|
Mail::to($job['email'])->queue($job['mailable']);
|
|
}
|
|
|
|
activity()
|
|
->performedOn($workspace)
|
|
->causedBy($user)
|
|
->withProperties([
|
|
'count' => $declarations->count(),
|
|
'declaration_ids' => $declarations->pluck('id')->all(),
|
|
])
|
|
->log('bulk_client_notification');
|
|
|
|
// Invalidate notification caches for workspace users
|
|
$workspace->users->each(function ($wsUser) use ($workspace) {
|
|
Cache::forget("user:{$wsUser->id}:workspace:{$workspace->id}:unread_notifications");
|
|
});
|
|
|
|
return back()->with('flash', [
|
|
'type' => 'success',
|
|
'message' => $declarations->count() . ' notifications envoyées',
|
|
]);
|
|
}
|
|
}
|