Add audit trail: AuditLog entity, AuditService, admin logs page

- AuditLog entity: action, entityType, entityId, data (JSON), performedBy, ipAddress
- AuditService: logs actions with current user and IP
- Audit on: order_created, order_paid, order_cancelled, order_refunded
- Admin /admin/logs: paginated table with action badges, details, user, IP
- Navigation link 'Logs' in admin header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-03-22 20:48:10 +01:00
parent 6ae9b1c7ff
commit 66ac2379ec
12 changed files with 350 additions and 6 deletions

View File

@@ -11,6 +11,7 @@ use App\Entity\Category;
use App\Entity\Event;
use App\Entity\Payout;
use App\Entity\User;
use App\Service\AuditService;
use App\Service\BilletOrderService;
use App\Service\EventIndexService;
use App\Service\MailerService;
@@ -817,7 +818,7 @@ class AccountController extends AbstractController
}
#[Route('/mon-compte/evenement/{id}/commande/{orderId}/annuler', name: 'app_account_event_cancel_order', methods: ['POST'])]
public function cancelOrder(Event $event, int $orderId, EntityManagerInterface $em): Response
public function cancelOrder(Event $event, int $orderId, EntityManagerInterface $em, AuditService $audit): Response
{
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
@@ -841,6 +842,11 @@ class AccountController extends AbstractController
$em->flush();
$audit->log('order_cancelled', 'BilletBuyer', $order->getId(), [
'orderNumber' => $order->getOrderNumber(),
'event' => $event->getTitle(),
]);
$this->addFlash('success', 'Commande '.$order->getOrderNumber().' annulee.');
return $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId(), 'tab' => 'stats']);
@@ -850,7 +856,7 @@ class AccountController extends AbstractController
* @codeCoverageIgnore Requires live Stripe API
*/
#[Route('/mon-compte/evenement/{id}/commande/{orderId}/rembourser', name: 'app_account_event_refund_order', methods: ['POST'])]
public function refundOrder(Event $event, int $orderId, EntityManagerInterface $em, StripeService $stripeService): Response
public function refundOrder(Event $event, int $orderId, EntityManagerInterface $em, StripeService $stripeService, AuditService $audit): Response
{
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
@@ -884,6 +890,12 @@ class AccountController extends AbstractController
$em->flush();
$audit->log('order_refunded', 'BilletBuyer', $order->getId(), [
'orderNumber' => $order->getOrderNumber(),
'event' => $event->getTitle(),
'totalHT' => $order->getTotalHTDecimal(),
]);
$this->addFlash('success', 'Commande '.$order->getOrderNumber().' remboursee.');
return $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId(), 'tab' => 'stats']);