Intégration fonctionnalites V1
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\PaymentTransaction;
|
||||
use App\Models\User;
|
||||
use Stripe\Exception\SignatureVerificationException;
|
||||
use Stripe\PaymentIntent;
|
||||
use Stripe\Stripe;
|
||||
use Stripe\Webhook;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class StripePaymentService
|
||||
{
|
||||
private bool $configured = false;
|
||||
|
||||
private function ensureConfigured(): void
|
||||
{
|
||||
if ($this->configured) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! class_exists(Stripe::class)) {
|
||||
throw new \RuntimeException(
|
||||
'SDK Stripe manquant. Exécutez : composer require stripe/stripe-php',
|
||||
);
|
||||
}
|
||||
|
||||
Stripe::setApiKey(config('services.stripe.secret'));
|
||||
$this->configured = true;
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return class_exists(Stripe::class)
|
||||
&& filled(config('services.stripe.secret'))
|
||||
&& filled(config('services.stripe.key'));
|
||||
}
|
||||
|
||||
public function publishableKey(): string
|
||||
{
|
||||
return (string) config('services.stripe.key');
|
||||
}
|
||||
|
||||
public function createPaymentIntent(
|
||||
User $user,
|
||||
PaymentTransaction $payment,
|
||||
float $amount,
|
||||
): PaymentIntent {
|
||||
$this->ensureConfigured();
|
||||
|
||||
return PaymentIntent::create([
|
||||
'amount' => (int) round($amount * 100),
|
||||
'currency' => strtolower($payment->currency),
|
||||
'metadata' => [
|
||||
'payment_uuid' => $payment->uuid,
|
||||
'user_id' => (string) $user->id,
|
||||
'idempotency_key' => $payment->idempotency_key,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function retrievePaymentIntent(string $paymentIntentId): PaymentIntent
|
||||
{
|
||||
$this->ensureConfigured();
|
||||
|
||||
return PaymentIntent::retrieve($paymentIntentId, [
|
||||
'expand' => ['payment_method'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function summarizePaymentIntent(PaymentIntent $intent): array
|
||||
{
|
||||
$summary = [
|
||||
'payment_intent_id' => $intent->id,
|
||||
'status' => $intent->status,
|
||||
'amount' => $intent->amount / 100,
|
||||
'currency' => strtoupper($intent->currency),
|
||||
];
|
||||
|
||||
$paymentMethod = $intent->payment_method;
|
||||
if (is_object($paymentMethod)) {
|
||||
$summary['payment_method_type'] = $paymentMethod->type ?? null;
|
||||
|
||||
if (isset($paymentMethod->card)) {
|
||||
$summary['card_brand'] = $paymentMethod->card->brand ?? null;
|
||||
$summary['card_last4'] = $paymentMethod->card->last4 ?? null;
|
||||
$summary['card_exp_month'] = $paymentMethod->card->exp_month ?? null;
|
||||
$summary['card_exp_year'] = $paymentMethod->card->exp_year ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
public function isPaymentSucceeded(PaymentIntent $paymentIntent): bool
|
||||
{
|
||||
return $paymentIntent->status === 'succeeded';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{provider_payment_id: string, status: string, payload: array<string, mixed>}
|
||||
*/
|
||||
public function parseWebhook(string $payload, string $signature): array
|
||||
{
|
||||
$this->ensureConfigured();
|
||||
|
||||
$secret = config('services.stripe.webhook_secret');
|
||||
|
||||
if (blank($secret)) {
|
||||
throw new \RuntimeException('Webhook Stripe non configuré.');
|
||||
}
|
||||
|
||||
try {
|
||||
$event = Webhook::constructEvent($payload, $signature, $secret);
|
||||
} catch (UnexpectedValueException|SignatureVerificationException $e) {
|
||||
throw new \InvalidArgumentException('Signature webhook Stripe invalide.', 0, $e);
|
||||
}
|
||||
|
||||
$type = $event->type;
|
||||
$object = $event->data->object;
|
||||
|
||||
if (! in_array($type, [
|
||||
'payment_intent.succeeded',
|
||||
'payment_intent.payment_failed',
|
||||
'payment_intent.canceled',
|
||||
], true)) {
|
||||
return [
|
||||
'provider_payment_id' => $object->id ?? '',
|
||||
'status' => 'ignored',
|
||||
'payload' => $event->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
$status = match ($type) {
|
||||
'payment_intent.succeeded' => 'succeeded',
|
||||
'payment_intent.payment_failed' => 'failed',
|
||||
'payment_intent.canceled' => 'cancelled',
|
||||
default => 'ignored',
|
||||
};
|
||||
|
||||
return [
|
||||
'provider_payment_id' => $object->id,
|
||||
'status' => $status,
|
||||
'payload' => $event->toArray(),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user