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>
190 lines
5.7 KiB
PHP
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,
|
|
];
|
|
}
|
|
}
|