Files
e-ticket/src/Controller/AccountController.php

393 lines
15 KiB
PHP
Raw Normal View History

<?php
namespace App\Controller;
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
use App\Entity\Payout;
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
use App\Entity\User;
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
use App\Service\MailerService;
use App\Service\PayoutPdfService;
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
use App\Service\StripeService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[IsGranted('ROLE_USER')]
class AccountController extends AbstractController
{
private const BREADCRUMB_HOME = ['name' => 'Accueil', 'url' => '/'];
private const BREADCRUMB_ACCOUNT = ['name' => 'Mon compte', 'url' => '/mon-compte'];
#[Route('/mon-compte', name: 'app_account')]
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
public function index(Request $request, StripeService $stripeService, EntityManagerInterface $em): Response
{
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
/** @var User $user */
$user = $this->getUser();
$isOrganizer = $this->isGranted('ROLE_ORGANIZER');
$defaultTab = $isOrganizer ? 'events' : 'tickets';
$tab = $request->query->getString('tab', $defaultTab);
if ($isOrganizer && $user->getStripeAccountId() && (!$user->isStripeChargesEnabled() || !$user->isStripePayoutsEnabled())) {
try { // @codeCoverageIgnoreStart
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
$account = $stripeService->getClient()->accounts->retrieve($user->getStripeAccountId());
$user->setStripeChargesEnabled((bool) $account->charges_enabled);
$user->setStripePayoutsEnabled((bool) $account->payouts_enabled);
$em->flush();
} catch (\Throwable) {
// Stripe API unavailable, keep current status
} // @codeCoverageIgnoreEnd
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
}
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
$payouts = [];
$subAccounts = [];
if ($isOrganizer) {
$payouts = $em->getRepository(Payout::class)->findBy(
['organizer' => $user],
['createdAt' => 'DESC'],
);
$subAccounts = $em->getRepository(User::class)->findBy(
['parentOrganizer' => $user],
['createdAt' => 'DESC'],
);
}
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
return $this->render('account/index.html.twig', [
'tab' => $tab,
'isOrganizer' => $isOrganizer,
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
'payouts' => $payouts,
'subAccounts' => $subAccounts,
Add organizer pages, SEO breadcrumbs, Open Graph, homepage redesign, and infrastructure updates - Add public organizers list page (/organisateurs) with neo-brutalist card grid, social icons, and logo display - Add organizer detail page (/organisateur/{id}-{slug}) with company info, SIRET, email, address, social links, and events placeholder - Add slug-based URLs with 301 redirect on wrong slug, getSlug() method on User entity - Add "Voir les evenements" button on organizer cards linking to detail page - Add JSON-LD BreadcrumbList to all 17 pages that were missing breadcrumbs (login, forgot_password, register_success, email_verified, legal/*, attestation/*, account/*) - Add Open Graph meta tags (og:title, og:description, og:image, og:type, og:locale, og:site_name) in base.html.twig with automatic inheritance from title/description blocks - Add og:image with organizer logo on detail page - Update sitemap: add /organisateurs to sitemap-main, generate organizer detail URLs in sitemap-orgas with logo images - Update navbar to highlight "Organisateurs" on detail pages - Redesign homepage with hero section, marquee, stats counters, how-it-works, and CTA sections - Add Tailwind v4 @source "../templates" directive to app.scss and admin.scss - Migrate Flysystem from S3 to local storage (uploads/events, uploads/logos) - Update Liip Imagine config with FormatExtensionResolver for webp conversion - Add User entity social fields (website, facebook, instagram, twitter, tiktok), logo upload (Vich), __serialize/__unserialize for session safety - Add account page settings tab with profile, logo upload, and social media for organizers - Add Stripe Connect status display and sub-account management in account page - Delete WebpExtensionSubscriber (replaced by FormatExtensionResolver) - Add migration for social fields and logo columns - Add deploy.yml chmod tasks for uploads directories - Add HomeController tests (detail success, wrong slug redirect, 404 cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:44:31 +01:00
'breadcrumbs' => [
self::BREADCRUMB_HOME,
self::BREADCRUMB_ACCOUNT,
Add organizer pages, SEO breadcrumbs, Open Graph, homepage redesign, and infrastructure updates - Add public organizers list page (/organisateurs) with neo-brutalist card grid, social icons, and logo display - Add organizer detail page (/organisateur/{id}-{slug}) with company info, SIRET, email, address, social links, and events placeholder - Add slug-based URLs with 301 redirect on wrong slug, getSlug() method on User entity - Add "Voir les evenements" button on organizer cards linking to detail page - Add JSON-LD BreadcrumbList to all 17 pages that were missing breadcrumbs (login, forgot_password, register_success, email_verified, legal/*, attestation/*, account/*) - Add Open Graph meta tags (og:title, og:description, og:image, og:type, og:locale, og:site_name) in base.html.twig with automatic inheritance from title/description blocks - Add og:image with organizer logo on detail page - Update sitemap: add /organisateurs to sitemap-main, generate organizer detail URLs in sitemap-orgas with logo images - Update navbar to highlight "Organisateurs" on detail pages - Redesign homepage with hero section, marquee, stats counters, how-it-works, and CTA sections - Add Tailwind v4 @source "../templates" directive to app.scss and admin.scss - Migrate Flysystem from S3 to local storage (uploads/events, uploads/logos) - Update Liip Imagine config with FormatExtensionResolver for webp conversion - Add User entity social fields (website, facebook, instagram, twitter, tiktok), logo upload (Vich), __serialize/__unserialize for session safety - Add account page settings tab with profile, logo upload, and social media for organizers - Add Stripe Connect status display and sub-account management in account page - Delete WebpExtensionSubscriber (replaced by FormatExtensionResolver) - Add migration for social fields and logo columns - Add deploy.yml chmod tasks for uploads directories - Add HomeController tests (detail success, wrong slug redirect, 404 cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:44:31 +01:00
],
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
]);
}
#[Route('/mon-compte/parametres', name: 'app_account_settings', methods: ['POST'])]
public function settings(Request $request, EntityManagerInterface $em): Response
{
/** @var User $user */
$user = $this->getUser();
$isOrganizer = $this->isGranted('ROLE_ORGANIZER');
if (!$isOrganizer) {
$user->setFirstName(trim($request->request->getString('first_name')));
$user->setLastName(trim($request->request->getString('last_name')));
}
$user->setEmail(trim($request->request->getString('email')));
$user->setPhone(trim($request->request->getString('phone')));
if (!$isOrganizer) {
$user->setAddress(trim($request->request->getString('address')));
$user->setPostalCode(trim($request->request->getString('postal_code')));
$user->setCity(trim($request->request->getString('city')));
}
Add organizer pages, SEO breadcrumbs, Open Graph, homepage redesign, and infrastructure updates - Add public organizers list page (/organisateurs) with neo-brutalist card grid, social icons, and logo display - Add organizer detail page (/organisateur/{id}-{slug}) with company info, SIRET, email, address, social links, and events placeholder - Add slug-based URLs with 301 redirect on wrong slug, getSlug() method on User entity - Add "Voir les evenements" button on organizer cards linking to detail page - Add JSON-LD BreadcrumbList to all 17 pages that were missing breadcrumbs (login, forgot_password, register_success, email_verified, legal/*, attestation/*, account/*) - Add Open Graph meta tags (og:title, og:description, og:image, og:type, og:locale, og:site_name) in base.html.twig with automatic inheritance from title/description blocks - Add og:image with organizer logo on detail page - Update sitemap: add /organisateurs to sitemap-main, generate organizer detail URLs in sitemap-orgas with logo images - Update navbar to highlight "Organisateurs" on detail pages - Redesign homepage with hero section, marquee, stats counters, how-it-works, and CTA sections - Add Tailwind v4 @source "../templates" directive to app.scss and admin.scss - Migrate Flysystem from S3 to local storage (uploads/events, uploads/logos) - Update Liip Imagine config with FormatExtensionResolver for webp conversion - Add User entity social fields (website, facebook, instagram, twitter, tiktok), logo upload (Vich), __serialize/__unserialize for session safety - Add account page settings tab with profile, logo upload, and social media for organizers - Add Stripe Connect status display and sub-account management in account page - Delete WebpExtensionSubscriber (replaced by FormatExtensionResolver) - Add migration for social fields and logo columns - Add deploy.yml chmod tasks for uploads directories - Add HomeController tests (detail success, wrong slug redirect, 404 cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:44:31 +01:00
if ($isOrganizer) {
$user->setWebsite(trim($request->request->getString('website')));
$user->setFacebook(trim($request->request->getString('facebook')));
$user->setInstagram(trim($request->request->getString('instagram')));
$user->setTwitter(trim($request->request->getString('twitter')));
$user->setTiktok(trim($request->request->getString('tiktok')));
$logoFile = $request->files->get('logo');
if ($logoFile) {
$user->setLogoFile($logoFile);
}
}
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
$em->flush();
$this->addFlash('success', 'Parametres mis a jour.');
return $this->redirectToRoute('app_account', ['tab' => 'settings']);
}
/** @codeCoverageIgnore Requires live Stripe API */
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
#[Route('/mon-compte/stripe-connect', name: 'app_account_stripe_connect')]
public function stripeConnect(StripeService $stripeService, EntityManagerInterface $em): Response
{
/** @var User $user */
$user = $this->getUser();
if (!$this->isGranted('ROLE_ORGANIZER')) {
return $this->redirectToRoute('app_account');
}
try {
if (!$user->getStripeAccountId()) {
$accountId = $stripeService->createAccountConnect($user);
$user->setStripeAccountId($accountId);
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
$user->setStripeStatus('started');
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
$em->flush();
}
$link = $stripeService->createAccountLink($user->getStripeAccountId());
return $this->redirect($link);
} catch (\Throwable $e) {
$this->addFlash('error', 'Erreur lors de la connexion a Stripe : '.$e->getMessage());
return $this->redirectToRoute('app_account');
}
}
/** @codeCoverageIgnore Requires live Stripe API */
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
#[Route('/mon-compte/stripe-cancel', name: 'app_account_stripe_cancel', methods: ['POST'])]
public function stripeCancel(StripeService $stripeService, EntityManagerInterface $em): Response
{
/** @var User $user */
$user = $this->getUser();
if ($this->isGranted('ROLE_ORGANIZER') && $user->getStripeAccountId()) {
try {
$stripeService->deleteAccount($user->getStripeAccountId());
} catch (\Throwable) {
// Account may already be deleted on Stripe side
}
$user->setStripeAccountId(null);
$user->setStripeChargesEnabled(false);
$user->setStripePayoutsEnabled(false);
$em->flush();
$this->addFlash('success', 'Compte Stripe cloture.');
}
return $this->redirectToRoute('app_account');
}
#[Route('/stripe/connect/return', name: 'app_stripe_connect_return')]
public function stripeConnectReturn(): Response
{
$this->addFlash('success', 'Configuration Stripe terminee.');
return $this->redirectToRoute('app_account');
}
#[Route('/stripe/connect/refresh', name: 'app_stripe_connect_refresh')]
public function stripeConnectRefresh(): Response
{
return $this->redirectToRoute('app_account_stripe_connect');
}
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
#[Route('/mon-compte/sous-compte/creer', name: 'app_account_create_subaccount', methods: ['POST'])]
public function createSubAccount(Request $request, EntityManagerInterface $em, UserPasswordHasherInterface $passwordHasher, MailerService $mailerService): Response
{
/** @var User $user */
$user = $this->getUser();
if (!$this->isGranted('ROLE_ORGANIZER')) {
return $this->redirectToRoute('app_account');
}
$plainPassword = bin2hex(random_bytes(8));
$subAccount = new User();
$subAccount->setFirstName(trim($request->request->getString('first_name')));
$subAccount->setLastName(trim($request->request->getString('last_name')));
$subAccount->setEmail(trim($request->request->getString('email')));
$subAccount->setPassword($passwordHasher->hashPassword($subAccount, $plainPassword));
$subAccount->setIsVerified(true);
$subAccount->setEmailVerifiedAt(new \DateTimeImmutable());
$subAccount->setParentOrganizer($user);
$permissions = $request->request->all('permissions');
$subAccount->setSubAccountPermissions($permissions);
$em->persist($subAccount);
$em->flush();
$mailerService->sendEmail(
to: $subAccount->getEmail(),
subject: 'Votre sous-compte E-Ticket a ete cree',
content: $this->renderView('email/subaccount_created.html.twig', [
'firstName' => $subAccount->getFirstName(),
'organizerName' => $user->getCompanyName() ?? $user->getFirstName().' '.$user->getLastName(),
'email' => $subAccount->getEmail(),
'password' => $plainPassword,
'permissions' => $permissions,
]),
withUnsubscribe: false,
);
$this->addFlash('success', sprintf('Sous-compte %s %s cree.', $subAccount->getFirstName(), $subAccount->getLastName()));
return $this->redirectToRoute('app_account', ['tab' => 'subaccounts']);
}
#[Route('/mon-compte/sous-compte/{id}', name: 'app_account_edit_subaccount_page', methods: ['GET'])]
public function editSubAccountPage(User $subAccount): Response
{
/** @var User $user */
$user = $this->getUser();
if ($subAccount->getParentOrganizer()?->getId() !== $user->getId()) {
throw $this->createAccessDeniedException();
}
return $this->render('account/edit_subaccount.html.twig', [
'subAccount' => $subAccount,
Add organizer pages, SEO breadcrumbs, Open Graph, homepage redesign, and infrastructure updates - Add public organizers list page (/organisateurs) with neo-brutalist card grid, social icons, and logo display - Add organizer detail page (/organisateur/{id}-{slug}) with company info, SIRET, email, address, social links, and events placeholder - Add slug-based URLs with 301 redirect on wrong slug, getSlug() method on User entity - Add "Voir les evenements" button on organizer cards linking to detail page - Add JSON-LD BreadcrumbList to all 17 pages that were missing breadcrumbs (login, forgot_password, register_success, email_verified, legal/*, attestation/*, account/*) - Add Open Graph meta tags (og:title, og:description, og:image, og:type, og:locale, og:site_name) in base.html.twig with automatic inheritance from title/description blocks - Add og:image with organizer logo on detail page - Update sitemap: add /organisateurs to sitemap-main, generate organizer detail URLs in sitemap-orgas with logo images - Update navbar to highlight "Organisateurs" on detail pages - Redesign homepage with hero section, marquee, stats counters, how-it-works, and CTA sections - Add Tailwind v4 @source "../templates" directive to app.scss and admin.scss - Migrate Flysystem from S3 to local storage (uploads/events, uploads/logos) - Update Liip Imagine config with FormatExtensionResolver for webp conversion - Add User entity social fields (website, facebook, instagram, twitter, tiktok), logo upload (Vich), __serialize/__unserialize for session safety - Add account page settings tab with profile, logo upload, and social media for organizers - Add Stripe Connect status display and sub-account management in account page - Delete WebpExtensionSubscriber (replaced by FormatExtensionResolver) - Add migration for social fields and logo columns - Add deploy.yml chmod tasks for uploads directories - Add HomeController tests (detail success, wrong slug redirect, 404 cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:44:31 +01:00
'breadcrumbs' => [
self::BREADCRUMB_HOME,
self::BREADCRUMB_ACCOUNT,
['name' => 'Sous-compte', 'url' => self::BREADCRUMB_ACCOUNT['url'].'/sous-compte/'.$subAccount->getId()],
Add organizer pages, SEO breadcrumbs, Open Graph, homepage redesign, and infrastructure updates - Add public organizers list page (/organisateurs) with neo-brutalist card grid, social icons, and logo display - Add organizer detail page (/organisateur/{id}-{slug}) with company info, SIRET, email, address, social links, and events placeholder - Add slug-based URLs with 301 redirect on wrong slug, getSlug() method on User entity - Add "Voir les evenements" button on organizer cards linking to detail page - Add JSON-LD BreadcrumbList to all 17 pages that were missing breadcrumbs (login, forgot_password, register_success, email_verified, legal/*, attestation/*, account/*) - Add Open Graph meta tags (og:title, og:description, og:image, og:type, og:locale, og:site_name) in base.html.twig with automatic inheritance from title/description blocks - Add og:image with organizer logo on detail page - Update sitemap: add /organisateurs to sitemap-main, generate organizer detail URLs in sitemap-orgas with logo images - Update navbar to highlight "Organisateurs" on detail pages - Redesign homepage with hero section, marquee, stats counters, how-it-works, and CTA sections - Add Tailwind v4 @source "../templates" directive to app.scss and admin.scss - Migrate Flysystem from S3 to local storage (uploads/events, uploads/logos) - Update Liip Imagine config with FormatExtensionResolver for webp conversion - Add User entity social fields (website, facebook, instagram, twitter, tiktok), logo upload (Vich), __serialize/__unserialize for session safety - Add account page settings tab with profile, logo upload, and social media for organizers - Add Stripe Connect status display and sub-account management in account page - Delete WebpExtensionSubscriber (replaced by FormatExtensionResolver) - Add migration for social fields and logo columns - Add deploy.yml chmod tasks for uploads directories - Add HomeController tests (detail success, wrong slug redirect, 404 cases) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:44:31 +01:00
],
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
]);
}
#[Route('/mon-compte/sous-compte/{id}/modifier', name: 'app_account_edit_subaccount', methods: ['POST'])]
public function editSubAccount(User $subAccount, Request $request, EntityManagerInterface $em): Response
{
/** @var User $user */
$user = $this->getUser();
if ($subAccount->getParentOrganizer()?->getId() !== $user->getId()) {
throw $this->createAccessDeniedException();
}
$permissions = $request->request->all('permissions');
$subAccount->setSubAccountPermissions($permissions);
$subAccount->setFirstName(trim($request->request->getString('first_name')));
$subAccount->setLastName(trim($request->request->getString('last_name')));
$subAccount->setEmail(trim($request->request->getString('email')));
$em->flush();
$this->addFlash('success', sprintf('Sous-compte %s %s mis a jour.', $subAccount->getFirstName(), $subAccount->getLastName()));
return $this->redirectToRoute('app_account', ['tab' => 'subaccounts']);
}
#[Route('/mon-compte/sous-compte/{id}/supprimer', name: 'app_account_delete_subaccount', methods: ['POST'])]
public function deleteSubAccount(User $subAccount, EntityManagerInterface $em): Response
{
/** @var User $user */
$user = $this->getUser();
if ($subAccount->getParentOrganizer()?->getId() !== $user->getId()) {
throw $this->createAccessDeniedException();
}
$name = sprintf('%s %s', $subAccount->getFirstName(), $subAccount->getLastName());
$em->remove($subAccount);
$em->flush();
$this->addFlash('success', sprintf('Sous-compte %s supprime.', $name));
return $this->redirectToRoute('app_account', ['tab' => 'subaccounts']);
}
#[Route('/mon-compte/evenement/creer', name: 'app_account_create_event', methods: ['GET', 'POST'])]
public function createEvent(Request $request, EntityManagerInterface $em): Response
{
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
/** @var User $user */
$user = $this->getUser();
if ($request->isMethod('POST')) {
$event = new \App\Entity\Event();
$event->setAccount($user);
$event->setTitle(trim($request->request->getString('title')));
$event->setDescription(trim($request->request->getString('description')) ?: null);
$event->setStartAt(new \DateTimeImmutable($request->request->getString('start_at')));
$event->setEndAt(new \DateTimeImmutable($request->request->getString('end_at')));
$event->setAddress(trim($request->request->getString('address')));
$event->setZipcode(trim($request->request->getString('zipcode')));
$event->setCity(trim($request->request->getString('city')));
$pictureFile = $request->files->get('event_main_picture');
if ($pictureFile) {
$event->setEventMainPictureFile($pictureFile);
}
$em->persist($event);
$em->flush();
$this->addFlash('success', 'Evenement cree avec succes.');
return $this->redirectToRoute('app_account', ['tab' => 'events']);
}
return $this->render('account/create_event.html.twig', [
'breadcrumbs' => [
self::BREADCRUMB_HOME,
self::BREADCRUMB_ACCOUNT,
['name' => 'Creer un evenement', 'url' => '/mon-compte/evenement/creer'],
],
]);
}
/** @codeCoverageIgnore Test helper, not used in production */
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
#[Route('/mon-compte/test-payout', name: 'app_account_test_payout', methods: ['POST'])]
public function testPayout(EntityManagerInterface $em): Response
{
/** @var User $user */
$user = $this->getUser();
if (!$this->isGranted('ROLE_ORGANIZER') || !$user->getStripeAccountId()) {
return $this->redirectToRoute('app_account');
}
$payout = new Payout();
$payout->setOrganizer($user);
$payout->setStripePayoutId('po_test_'.bin2hex(random_bytes(8)));
$payout->setStatus('paid');
$payout->setAmount(random_int(1000, 50000));
$payout->setCurrency('eur');
$payout->setDestination('ba_test_bank');
$payout->setStripeAccountId($user->getStripeAccountId());
$payout->setArrivalDate(new \DateTimeImmutable('+2 days'));
$em->persist($payout);
$em->flush();
$this->addFlash('success', sprintf('Payout test cree : %s (%.2f EUR)', $payout->getStripePayoutId(), $payout->getAmountDecimal()));
return $this->redirectToRoute('app_account', ['tab' => 'payouts']);
}
/** @codeCoverageIgnore Requires live Stripe API */
Refactor Stripe integration: single Connect webhook, account pages, cleanup Stripe webhook: - Single webhook endpoint /stripe/webhook for Connect + payment events - v2 Connect events configured manually in Stripe Dashboard (not via API) - account.updated syncs charges_enabled/payouts_enabled via API retrieve - Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault) Account page (/mon-compte): - Buyer tabs: Billets, Achats, Factures, Parametres - Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs - Stripe Connect status banner: setup required, pending verification, active, refused - Stripe Connect onboarding: create account, complete verification (GET links) - Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard) - Cancel/close Stripe account: deletes via API + resets local fields - Stripe required message on events/subaccounts/payouts tabs when not active - Settings: organizer fields locked (name, address), email/phone editable - Return/refresh routes for Stripe Connect onboarding flow - Error handling with flash messages on all Stripe operations - Auto-sync Stripe status on /mon-compte visit StripeService cleanup: - Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir - Add deleteAccount method - Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink Security: - Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist - Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
#[Route('/mon-compte/stripe-dashboard', name: 'app_account_stripe_dashboard')]
public function stripeDashboard(StripeService $stripeService): Response
{
/** @var User $user */
$user = $this->getUser();
if (!$this->isGranted('ROLE_ORGANIZER') || !$user->getStripeAccountId()) {
return $this->redirectToRoute('app_account');
}
try {
$link = $stripeService->createLoginLink($user->getStripeAccountId());
return $this->redirect($link);
} catch (\Throwable $e) {
$this->addFlash('error', 'Erreur Stripe : '.$e->getMessage());
return $this->redirectToRoute('app_account');
}
}
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
/** @codeCoverageIgnore Generates PDF with dompdf */
Add payouts, PDF attestations, sub-accounts, and webhook improvements Payout system: - Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate) - Webhook handles payout.created/updated/paid/failed/canceled with email notification - Payout list in /mon-compte virements tab with status badges - PDF attestation on paid payouts with email attachment PDF attestation: - dompdf with DejaVu Sans font, yellow-orange gradient background - Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks - QR code linking to /attestation/check/{payoutId} for authenticity verification - Public verification page: shows payout details if valid, error if altered - Legal disclaimer and CGV reference - Button visible only when status is paid, opens in new tab Sub-accounts: - Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User - Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations) - Create sub-account with random password, send email with credentials - Edit page with name/email/permissions checkboxes - Delete with confirmation - hasPermission() helper method Account improvements: - Block entire page for unapproved organizers with validation pending message - Display stripeStatus in Stripe Connect banners - Remove test payout button Webhook v2 Connect events: - v2.core.account.created/updated/closed → update stripeStatus - capability_status_updated → sync charges/payouts enabled from capabilities - PayoutPdfService for reusable PDF generation Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
#[Route('/mon-compte/payout/{id}/attestation', name: 'app_account_payout_pdf')]
public function payoutPdf(Payout $payout, PayoutPdfService $pdfService): Response
{
/** @var User $user */
$user = $this->getUser();
if ($payout->getOrganizer()->getId() !== $user->getId()) {
throw $this->createAccessDeniedException();
}
return new Response($pdfService->generate($payout), 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="attestation_'.$payout->getStripePayoutId().'.pdf"',
]);
}
}