Skip to content

Instantly share code, notes, and snippets.

@bummzack
Last active September 18, 2019 16:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bummzack/e90a0cc4c65a681747c57db2f47da88e to your computer and use it in GitHub Desktop.
Save bummzack/e90a0cc4c65a681747c57db2f47da88e to your computer and use it in GitHub Desktop.
Stripe Payments with Stripe Checkout (JS) and SilverStripe 4 + SilverShop
---
Name: shop
After:
- '#mysite'
---
SilverShop\Page\CheckoutPageController:
extensions:
- Bummzack\Shop\Extensions\CheckoutPageExtension
# Change this to a different config if you're not using a single-page-checkout
SilverStripe\Core\Injector\Injector:
SilverShop\Checkout\SinglePageCheckoutComponentConfig:
class: Bummzack\Shop\Checkout\Config
// This requires jQuery and https://checkout.stripe.com/checkout.js
(function ($) {
$(function () {
// ----------------------------------------------------------------------
// Stripe JS integration
// ----------------------------------------------------------------------
var applyStripeConfig = function (elem) {
var config = elem.data("config");
if (!config) {
return;
}
var form = $('#' + config.formID);
var settings = $.extend({}, config.config, {
token: function (token) {
if (token && token.id && form.length) {
form.find('input[name=' + config.tokenField + ']').val(token.id);
form.submit();
}
}
});
var handler = StripeCheckout.configure(settings);
form.on("submit", function (evt) {
if (!form[0].checkValidity || !form[0].checkValidity()) {
evt.preventDefault();
return;
}
var data = form.serializeArray().reduce(function(m,o){
m[o.name] = o.value;
return m;
}, {});
if (!(config.methodField in data && data[config.methodField] === 'Stripe') || !(config.tokenField in data)) {
return;
}
if (!data[config.tokenField]) {
evt.preventDefault();
handler.open($.extend({}, config.popup, {
email: form.find('input.email:first').val()
}));
return;
}
$("body").addClass("ajax-loading");
});
};
// Delay to ensure checkout.js has been loaded and parsed
window.setTimeout(function () {
applyStripeConfig($("#StripeConfig"));
}, 100);
});
})(jQuery);
---
Name: payment
---
SilverStripe\Omnipay\Model\Payment:
allowed_gateways:
- Stripe
SilverStripe\Omnipay\GatewayInfo:
Stripe:
use_authorize: false
can_refund: multiple
parameters:
apiKey: 'stripe_api_key'
publishableKey: 'stripe_publishable_key'
testMode: true
<?php
namespace Bummzack\Shop\Checkout;
use SilverShop\Checkout\CheckoutComponentConfig;
use SilverShop\Checkout\Component\Notes;
use SilverShop\Checkout\Component\Terms;
use SilverShop\Model\Order;
class Config extends CheckoutComponentConfig
{
public function __construct(Order $order)
{
parent::__construct($order);
$this->addComponent(ShippingAddress::create());
$this->addComponent(BillingAddress::create());
$this->addComponent(StripeJsPayment::create());
$this->addComponent(Notes::create());
$this->addComponent(Terms::create());
}
}
<?php
namespace Bummzack\Shop\Checkout;
use SilverShop\Checkout\Component\Payment;
use SilverShop\Extension\ShopConfigExtension;
use SilverShop\Model\Order;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\OptionsetField;
use SilverStripe\i18n\i18n;
use SilverStripe\Omnipay\GatewayInfo;
use SilverStripe\ORM\ValidationException;
use SilverStripe\ORM\ValidationResult;
use SilverStripe\SiteConfig\SiteConfig;
/**
* Custom payment checkout component that integrates stripe JS payment form.
*/
class StripeJsPayment extends Payment
{
/**
* Get form fields for manipulating the current order,
* according to the responsibility of this component.
*
* @param Order $order
* @param Form $form
*
* @return FieldList
*/
public function getFormFields(Order $order, Form $form = null)
{
$fields = parent::getFormFields($order);
$params = GatewayInfo::getParameters('Stripe');
$jsConfig = [
'formID' => $form ? $form->getHTMLID() : 'PaymentForm_OrderForm',
'tokenField' => $this->name() . '_token',
'methodField' => $this->name() . '_PaymentMethod',
'config' => [
'key' => isset($params['publishableKey']) ? $params['publishableKey'] : '',
'currency' => ShopConfigExtension::get_site_currency(),
'locale' => i18n::getData()->langFromLocale(i18n::get_locale())
],
'popup' => [
'name' => SiteConfig::current_site_config()->Title,
'amount' => $order->GrandTotal() * 100
]
];
$fields->push(HiddenField::create('token', '', ''));
$fields->push(LiteralField::create('_stripeConfig', sprintf(
'<span id="StripeConfig" data-config=\'%s\'></span>',
json_encode($jsConfig)
)));
return $fields;
}
public function getRequiredFields(Order $order)
{
return ['PaymentMethod'];
}
public function providesPaymentData()
{
return true;
}
public function validateData(Order $order, array $data)
{
parent::validateData($order, $data);
$result = ValidationResult::create();
// In case of "Stripe", the token must also be present
if (($data['PaymentMethod'] === 'Stripe' && empty($data['token']))) {
$result->addError(
_t('SilverShop\Checkout\Component\Payment.NoPaymentMethod', "Payment method not provided"),
"PaymentMethod"
);
throw new ValidationException($result);
}
return true;
}
}
<?php
namespace Bummzack\Shop\Extensions;
use SilverStripe\Core\Extension;
use SilverStripe\Forms\Form;
use SilverStripe\View\Requirements;
class CheckoutPageExtension extends Extension
{
public function updateOrderForm(Form $form)
{
// Load the stripe JS
Requirements::javascript('https://checkout.stripe.com/checkout.js', [
'async' => true, 'defer' => true
]);
// Load the own checkout file
Requirements::javascript('js_checkout.js', ['defer' => true]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment