Files
e-ticket/src/Service/StripeService.php
Serreau Jovann c207fd31b1 Add app:stripe:sync command to sync Stripe status for all organizers
Fetches charges_enabled and payouts_enabled from Stripe API for each
organizer with a connected account and updates the local database.
Also adds retrieveAccountStatus() to StripeService for testability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:56:11 +01:00

190 lines
5.7 KiB
PHP

<?php
namespace App\Service;
use App\Entity\Billet;
use App\Entity\User;
use Stripe\Event;
use Stripe\Exception\SignatureVerificationException;
use Stripe\StripeClient;
use Stripe\Webhook;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class StripeService
{
private StripeClient $stripe;
public function __construct(
#[Autowire(env: 'STRIPE_SK')] private string $stripeSecret,
#[Autowire(env: 'STRIPE_WEBHOOK_SECRET')] private string $webhookSecret,
#[Autowire(env: 'STRIPE_WEBHOOK_SECRET_CONNECT')] private string $webhookSecretConnect,
#[Autowire(env: 'OUTSIDE_URL')] private string $outsideUrl,
) {
$this->stripe = new StripeClient($this->stripeSecret);
}
public function verifyWebhookSignature(string $payload, string $signature): ?Event
{
try {
return Webhook::constructEvent($payload, $signature, $this->webhookSecret);
} catch (SignatureVerificationException) {
return null;
}
}
public function verifyConnectWebhookSignature(string $payload, string $signature): ?Event
{
try {
return Webhook::constructEvent($payload, $signature, $this->webhookSecretConnect);
} catch (SignatureVerificationException) {
return null;
}
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function deleteAccount(string $accountId): void
{
$this->stripe->accounts->delete($accountId);
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function createAccountConnect(User $user): string
{
$account = $this->stripe->accounts->create([
'type' => 'express',
'country' => 'FR',
'email' => $user->getEmail(),
'capabilities' => [
'card_payments' => ['requested' => true],
'transfers' => ['requested' => true],
],
'business_type' => \in_array('ROLE_ORGANIZER', $user->getRoles(), true) ? 'company' : 'individual',
'business_profile' => [
'name' => $user->getCompanyName(),
'url' => $this->outsideUrl,
],
]);
return $account->id;
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function createAccountLink(string $accountId): string
{
$link = $this->stripe->accountLinks->create([
'account' => $accountId,
'refresh_url' => $this->outsideUrl.'/stripe/connect/refresh',
'return_url' => $this->outsideUrl.'/stripe/connect/return',
'type' => 'account_onboarding',
]);
return $link->url;
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function createLoginLink(string $accountId): string
{
$link = $this->stripe->accounts->createLoginLink($accountId);
return $link->url;
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function createProduct(Billet $billet, string $connectedAccountId): string
{
$product = $this->stripe->products->create([
'name' => $billet->getName(),
'description' => $billet->getDescription(),
'default_price_data' => [
'currency' => 'eur',
'unit_amount' => $billet->getPriceHT(),
],
], ['stripe_account' => $connectedAccountId]);
return $product->id;
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function updateProduct(Billet $billet, string $connectedAccountId): void
{
$this->stripe->products->update($billet->getStripeProductId(), [
'name' => $billet->getName(),
'description' => $billet->getDescription(),
], ['stripe_account' => $connectedAccountId]);
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function deleteProduct(string $productId, string $connectedAccountId): void
{
$this->stripe->products->update($productId, [
'active' => false,
], ['stripe_account' => $connectedAccountId]);
}
/**
* @codeCoverageIgnore Requires live Stripe API
*/
public function createBillingCheckoutSession(User $user): string
{
$session = $this->stripe->checkout->sessions->create([
'mode' => 'subscription',
'customer_email' => $user->getEmail(),
'line_items' => [[
'price_data' => [
'currency' => 'eur',
'unit_amount' => $user->getBillingAmount(),
'recurring' => ['interval' => 'month'],
'product_data' => [
'name' => 'Abonnement E-Ticket',
],
],
'quantity' => 1,
]],
'metadata' => [
'user_id' => (string) $user->getId(),
],
'success_url' => $this->outsideUrl.'/mon-compte/abonnement/succes',
'cancel_url' => $this->outsideUrl.'/mon-compte',
]);
return $session->url;
}
/**
* @codeCoverageIgnore Simple getter
*/
public function getClient(): StripeClient
{
return $this->stripe;
}
/**
* @codeCoverageIgnore Requires live Stripe API
*
* @return array{charges_enabled: bool, payouts_enabled: bool}
*/
public function retrieveAccountStatus(string $accountId): array
{
$account = $this->stripe->accounts->retrieve($accountId);
return [
'charges_enabled' => (bool) $account->charges_enabled,
'payouts_enabled' => (bool) $account->payouts_enabled,
];
}
}