Skip to content

Commit

Permalink
Support Afterpay through Stripe
Browse files Browse the repository at this point in the history
  • Loading branch information
joshbmarshall committed Mar 29, 2022
1 parent 6c2c052 commit b9b7024
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 14 deletions.
71 changes: 66 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,21 @@ $payum = (new PayumBuilder)
'factory' => 'stripe_elements',
'publishable_key' => 'Your Public Key',
'secret_key' => 'Your Private Key',
'img_url' => 'https://path/to/logo/image.jpg',
])

->addGateway('stripe_afterpay', [
'factory' => 'stripe_afterpay',
'publishable_key' => 'Your Public Key',
'secret_key' => 'Your Private Key',
'img_url' => 'https://path/to/logo/image.jpg',
])

->getPayum()
;
```

### Request payment
### Request card payment

```php
<?php
Expand All @@ -51,7 +59,7 @@ $payment->setCurrencyCode($currency);
$payment->setTotalAmount(100); // Total cents
$payment->setDescription(substr($description, 0, 45));
$payment->setDetails([
'local' => [
'local' => [
'email' => $email, // Used for the customer to be able to save payment details
],
]);
Expand All @@ -63,6 +71,59 @@ header("Location: " . $url);
die();
```

### Request Afterpay payment

Afterpay requires more information about the customer to process the payment

```php
<?php

use Payum\Core\Request\Capture;

$storage = $payum->getStorage(\Payum\Core\Model\Payment::class);
$request = [
'invoice_id' => 100,
];

$payment = $storage->create();
$payment->setNumber(uniqid());
$payment->setCurrencyCode($currency);
$payment->setTotalAmount(100); // Total cents
$payment->setDescription(substr($description, 0, 45));
$payment->setDetails([
'local' => [
'email' => $email, // Used for the customer to be able to save payment details
],
'shipping' => [
'name' => 'Firstname Lastname',
'address' => [
'line1' => 'Address Line 1',
'city' => 'Address City',
'state' => 'Address State',
'country' => 'Address Country',
'postal_code' => 'Address Postal Code',
],
],
'billing' => [
'name' => trim($shopper['first_name'] . ' ' . $shopper['last_name']),
'email' => $shopper['email'],
'address' => [
'line1' => 'Address Line 1',
'city' => 'Address City',
'state' => 'Address State',
'country' => 'Address Country',
'postal_code' => 'Address Postal Code',
],
],
]);
$storage->setInternalDetails($payment, $request);

$captureToken = $payum->getTokenFactory()->createCaptureToken('stripe_afterpay', $payment, 'done.php');
$url = $captureToken->getTargetUrl();
header("Location: " . $url);
die();
```

### Check it worked

```php
Expand All @@ -80,11 +141,11 @@ $gateway->execute($status = new GetHumanStatus($model));

// using shortcut
if ($status->isNew() || $status->isCaptured() || $status->isAuthorized()) {
// success
// success
} elseif ($status->isPending()) {
// most likely success, but you have to wait for a push notification.
// most likely success, but you have to wait for a push notification.
} elseif ($status->isFailed() || $status->isCanceled()) {
// the payment has failed or user canceled it.
// the payment has failed or user canceled it.
}
```

Expand Down
33 changes: 25 additions & 8 deletions src/Action/ObtainNonceAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ class ObtainNonceAction implements ActionInterface, GatewayAwareInterface {
* @var string
*/
protected $templateName;
protected $use_afterpay;

/**
* @param string $templateName
*/
public function __construct(string $templateName) {
public function __construct(string $templateName, bool $use_afterpay) {
$this->templateName = $templateName;
$this->use_afterpay = $use_afterpay;
}

/**
Expand All @@ -41,31 +43,46 @@ public function execute($request) {
if ($model['card']) {
throw new LogicException('The token has already been set.');
}
$uri = \League\Uri\Http::createFromServer($_SERVER);

$getHttpRequest = new GetHttpRequest();
$this->gateway->execute($getHttpRequest);
if ($getHttpRequest->method == 'POST' && isset($getHttpRequest->request['payment_intent'])) {
// Received payment intent information from Stripe
if (isset($getHttpRequest->request['payment_intent'])) {
$model['nonce'] = $getHttpRequest->request['payment_intent'];
return;
}

$model['stripePaymentIntent'] = \Stripe\PaymentIntent::create([
$afterPayDetails = [];
if ($this->use_afterpay) { // Afterpay order
$afterPayDetails = [
'confirm' => true,
'payment_method_types' => ['afterpay_clearpay'],
'shipping' => $model['shipping'],
'payment_method_data' => [
'type' => 'afterpay_clearpay',
'billing_details' => $model['billing'],
],
'return_url' => $uri->withPath('')->withFragment('')->withQuery('')->__toString() . $getHttpRequest->uri,
];
}
$paymentIntentData = array_merge([
'amount' => round($model['amount'] * pow(10, $model['currencyDigits'])),
'payment_method_types' => $model['payment_method_types'] ?? ['card'],
'currency' => $model['currency'],
'metadata' => ['integration_check' => 'accept_a_payment'],
'statement_descriptor' => $model['statement_descriptor_suffix'],
'description' => $model['description'],
'automatic_payment_methods' => [
'enabled' => 'true',
],
]);
], $afterPayDetails);

$model['stripePaymentIntent'] = \Stripe\PaymentIntent::create($paymentIntentData);
$this->gateway->execute($renderTemplate = new RenderTemplate($this->templateName, array(
'amount' => $model['currencySymbol'] . ' ' . number_format($model['amount'], $model['currencyDigits']),
'client_secret' => $model['stripePaymentIntent']->client_secret,
'publishable_key' => $model['publishable_key'],
'actionUrl' => $getHttpRequest->uri,
'imgUrl' => $model['img_url'],
'use_afterpay' => $this->use_afterpay ? "true" : "false",
'billing' => $model['billing'] ?? [],
)));

throw new HttpResponse($renderTemplate->getResult());
Expand Down
27 changes: 27 additions & 0 deletions src/Resources/views/Action/obtain_nonce.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,33 @@
// prompt the user to enter authentication details without leaving your page.
var payWithCard = function(stripe) {
loading(true);
// Afterpay?
if ({{ use_afterpay }}) {
stripe.confirmAfterpayClearpayPayment(
'{{ client_secret }}',
{
payment_method: {
billing_details: {
email: "{{ billing.email }}",
name: "{{ billing.name }}", // Double quotes less likely to be in a name
address: {
line1: "{{ billing.address.line1 }}",
city: "{{ billing.address.city }}",
state: "{{ billing.address.state }}",
country: "{{ billing.address.country }}",
postal_code: "{{ billing.address.postal_code }}",
},
},
},
return_url: window.location.href,
}
).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
}
});
return
}
stripe
.confirmPayment({
elements,
Expand Down
3 changes: 2 additions & 1 deletion src/StripeElementsGatewayFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected function populateConfig(ArrayObject $config)
'payum.action.status' => new StatusAction(),
'payum.action.convert_payment' => new ConvertPaymentAction(),
'payum.action.obtain_nonce' => function (ArrayObject $config) {
return new ObtainNonceAction($config['payum.template.obtain_nonce']);
return new ObtainNonceAction($config['payum.template.obtain_nonce'], $config['type'] == 'stripe_afterpay');
},
]);

Expand All @@ -44,6 +44,7 @@ protected function populateConfig(ArrayObject $config)
return new Api((array) $config, $config['payum.http_client'], $config['httplug.message_factory']);
};
}
$config['use_afterpay'] = $config['type'] == 'stripe_afterpay';
$payumPaths = $config['payum.paths'];
$payumPaths['PayumStripeElements'] = __DIR__ . '/Resources/views';
$config['payum.paths'] = $payumPaths;
Expand Down

0 comments on commit b9b7024

Please sign in to comment.