Last active
September 18, 2019 16:04
-
-
Save bummzack/e90a0cc4c65a681747c57db2f47da88e to your computer and use it in GitHub Desktop.
Stripe Payments with Stripe Checkout (JS) and SilverStripe 4 + SilverShop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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