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 */ 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} */ 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(), ]; } }