Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +01:00
|
|
|
<?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;
|
Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +01:00
|
|
|
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;
|
Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +01:00
|
|
|
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;
|
Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +01:00
|
|
|
use Symfony\Component\Routing\Attribute\Route;
|
|
|
|
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
|
|
|
|
|
|
|
|
|
#[IsGranted('ROLE_USER')]
|
|
|
|
|
class AccountController extends AbstractController
|
|
|
|
|
{
|
|
|
|
|
#[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
|
Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +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
|
|
|
/** @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())) {
|
2026-03-20 00:05:17 +01:00
|
|
|
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
|
2026-03-20 00:05:17 +01:00
|
|
|
} // @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,
|
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')));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$em->flush();
|
|
|
|
|
|
|
|
|
|
$this->addFlash('success', 'Parametres mis a jour.');
|
|
|
|
|
|
|
|
|
|
return $this->redirectToRoute('app_account', ['tab' => 'settings']);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 00:05:17 +01:00
|
|
|
/** @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');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 00:05:17 +01:00
|
|
|
/** @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,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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']);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 00:05:17 +01:00
|
|
|
/** @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']);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 00:05:17 +01:00
|
|
|
/** @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 application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +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
|
|
|
|
2026-03-20 00:05:17 +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"',
|
|
|
|
|
]);
|
|
|
|
|
}
|
Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +01:00
|
|
|
}
|