Changeset View
Changeset View
Standalone View
Standalone View
src/app/Providers/Payment/Stripe.php
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | public function createMandate(Wallet $wallet, array $payment): ?array | ||||
]; | ]; | ||||
// Note: Stripe does not allow to set amount for 'setup' operation | // Note: Stripe does not allow to set amount for 'setup' operation | ||||
// We'll dispatch WalletCharge job when we receive a webhook request | // We'll dispatch WalletCharge job when we receive a webhook request | ||||
$session = StripeAPI\Checkout\Session::create($request); | $session = StripeAPI\Checkout\Session::create($request); | ||||
$payment['amount'] = 0; | $payment['amount'] = 0; | ||||
$payment['currency_amount'] = 0; | |||||
$payment['id'] = $session->setup_intent; | $payment['id'] = $session->setup_intent; | ||||
$payment['type'] = self::TYPE_MANDATE; | $payment['type'] = self::TYPE_MANDATE; | ||||
$this->storePayment($payment, $wallet->id); | $this->storePayment($payment, $wallet->id); | ||||
return [ | return [ | ||||
'id' => $session->id, | 'id' => $session->id, | ||||
]; | ]; | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | class Stripe extends \App\Providers\PaymentProvider | ||||
{ | { | ||||
if ($payment['type'] == self::TYPE_RECURRING) { | if ($payment['type'] == self::TYPE_RECURRING) { | ||||
return $this->paymentRecurring($wallet, $payment); | return $this->paymentRecurring($wallet, $payment); | ||||
} | } | ||||
// Register the user in Stripe, if not yet done | // Register the user in Stripe, if not yet done | ||||
$customer_id = self::stripeCustomerId($wallet, true); | $customer_id = self::stripeCustomerId($wallet, true); | ||||
$amount = $this->exchange($payment['amount'], $wallet->currency, $payment['currency']); | |||||
$payment['currency_amount'] = $amount; | |||||
$request = [ | $request = [ | ||||
'customer' => $customer_id, | 'customer' => $customer_id, | ||||
'cancel_url' => Utils::serviceUrl('/wallet'), // required | 'cancel_url' => Utils::serviceUrl('/wallet'), // required | ||||
'success_url' => Utils::serviceUrl('/wallet'), // required | 'success_url' => Utils::serviceUrl('/wallet'), // required | ||||
'payment_method_types' => ['card'], // required | 'payment_method_types' => ['card'], // required | ||||
'locale' => 'en', | 'locale' => 'en', | ||||
'line_items' => [ | 'line_items' => [ | ||||
[ | [ | ||||
'name' => $payment['description'], | 'name' => $payment['description'], | ||||
'amount' => $payment['amount'], | 'amount' => $amount, | ||||
'currency' => \strtolower($payment['currency']), | 'currency' => \strtolower($payment['currency']), | ||||
'quantity' => 1, | 'quantity' => 1, | ||||
] | ] | ||||
] | ] | ||||
]; | ]; | ||||
$session = StripeAPI\Checkout\Session::create($request); | $session = StripeAPI\Checkout\Session::create($request); | ||||
Show All 20 Lines | class Stripe extends \App\Providers\PaymentProvider | ||||
{ | { | ||||
// Check if there's a valid mandate | // Check if there's a valid mandate | ||||
$mandate = self::stripeMandate($wallet); | $mandate = self::stripeMandate($wallet); | ||||
if (empty($mandate)) { | if (empty($mandate)) { | ||||
return null; | return null; | ||||
} | } | ||||
$amount = $this->exchange($payment['amount'], $wallet->currency, $payment['currency']); | |||||
$payment['currency_amount'] = $amount; | |||||
$request = [ | $request = [ | ||||
'amount' => $payment['amount'], | 'amount' => $amount, | ||||
'currency' => \strtolower($payment['currency']), | 'currency' => \strtolower($payment['currency']), | ||||
'description' => $payment['description'], | 'description' => $payment['description'], | ||||
'receipt_email' => $wallet->owner->email, | 'receipt_email' => $wallet->owner->email, | ||||
'customer' => $mandate->customer, | 'customer' => $mandate->customer, | ||||
'payment_method' => $mandate->payment_method, | 'payment_method' => $mandate->payment_method, | ||||
'off_session' => true, | 'off_session' => true, | ||||
'confirm' => true, | 'confirm' => true, | ||||
]; | ]; | ||||
Show All 26 Lines | public function webhook(): int | ||||
// Parse and validate the input | // Parse and validate the input | ||||
try { | try { | ||||
$event = StripeAPI\Webhook::constructEvent( | $event = StripeAPI\Webhook::constructEvent( | ||||
$payload, | $payload, | ||||
$sig_header, | $sig_header, | ||||
\config('services.stripe.webhook_secret') | \config('services.stripe.webhook_secret') | ||||
); | ); | ||||
} catch (\Exception $e) { | } catch (\Exception $e) { | ||||
\Log::error("Invalid payload: " . $e->getMessage()); | |||||
// Invalid payload | // Invalid payload | ||||
return 400; | return 400; | ||||
} | } | ||||
switch ($event->type) { | switch ($event->type) { | ||||
case StripeAPI\Event::PAYMENT_INTENT_CANCELED: | case StripeAPI\Event::PAYMENT_INTENT_CANCELED: | ||||
case StripeAPI\Event::PAYMENT_INTENT_PAYMENT_FAILED: | case StripeAPI\Event::PAYMENT_INTENT_PAYMENT_FAILED: | ||||
case StripeAPI\Event::PAYMENT_INTENT_SUCCEEDED: | case StripeAPI\Event::PAYMENT_INTENT_SUCCEEDED: | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | protected static function paymentMethod($details, $default = ''): string | ||||
'%s (**** **** **** %s)', | '%s (**** **** **** %s)', | ||||
\ucfirst($details->card->brand) ?: 'Card', | \ucfirst($details->card->brand) ?: 'Card', | ||||
$details->card->last4 | $details->card->last4 | ||||
); | ); | ||||
} | } | ||||
return $default; | return $default; | ||||
} | } | ||||
/** | |||||
* List supported payment methods. | |||||
* | |||||
* @param string $type The payment type for which we require a method (oneoff/recurring). | |||||
* | |||||
* @return array Array of array with available payment methods: | |||||
* - id: id of the method | |||||
* - name: User readable name of the payment method | |||||
* - minimumAmount: Minimum amount to be charged in cents | |||||
* - currency: Currency used for the method | |||||
* - exchangeRate: The projected exchange rate (actual rate is determined during payment) | |||||
* - icon: An icon (icon name) representing the method | |||||
*/ | |||||
public function providerPaymentMethods($type): array | |||||
{ | |||||
//TODO get this from the stripe API? | |||||
$availableMethods = []; | |||||
switch ($type) { | |||||
case self::TYPE_ONEOFF: | |||||
$availableMethods = [ | |||||
self::METHOD_CREDITCARD => [ | |||||
'id' => self::METHOD_CREDITCARD, | |||||
'name' => "Credit Card", | |||||
'minimumAmount' => self::MIN_AMOUNT, | |||||
'currency' => 'CHF', | |||||
'exchangeRate' => 1.0 | |||||
], | |||||
self::METHOD_PAYPAL => [ | |||||
'id' => self::METHOD_PAYPAL, | |||||
'name' => "PayPal", | |||||
'minimumAmount' => self::MIN_AMOUNT, | |||||
'currency' => 'CHF', | |||||
'exchangeRate' => 1.0 | |||||
] | |||||
]; | |||||
break; | |||||
case self::TYPE_RECURRING: | |||||
$availableMethods = [ | |||||
self::METHOD_CREDITCARD => [ | |||||
'id' => self::METHOD_CREDITCARD, | |||||
'name' => "Credit Card", | |||||
'minimumAmount' => self::MIN_AMOUNT, // Converted to cents, | |||||
'currency' => 'CHF', | |||||
'exchangeRate' => 1.0 | |||||
] | |||||
]; | |||||
break; | |||||
} | |||||
return $availableMethods; | |||||
} | |||||
/** | |||||
* Get a payment. | |||||
* | |||||
* @param string $paymentId Payment identifier | |||||
* | |||||
* @return array Payment information: | |||||
* - id: Payment identifier | |||||
* - status: Payment status | |||||
* - isCancelable: The payment can be canceled | |||||
* - checkoutUrl: The checkout url to complete the payment or null if none | |||||
*/ | |||||
public function getPayment($paymentId): array | |||||
{ | |||||
\Log::info("Stripe::getPayment does not yet retrieve a checkoutUrl."); | |||||
$payment = StripeAPI\PaymentIntent::retrieve($paymentId); | |||||
return [ | |||||
'id' => $payment->id, | |||||
'status' => $payment->status, | |||||
machniak: I know we do not use Stripe right now, but if we ever wanted to switch to it how do we know… | |||||
'isCancelable' => false, | |||||
'checkoutUrl' => null | |||||
]; | |||||
} | |||||
} | } |
I know we do not use Stripe right now, but if we ever wanted to switch to it how do we know that this needs to be implemented first?