<div class="container">
<div class="row">
<div class="col-12">
<div id="PaymentStatus"></div>
</div>
<div class="col-12">
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Pagar con Apple Pay</h5>
<div id="ckoApplePay" class="apple-pay-button apple-pay-button-text-plain" lang=es>
</div>
<p><small>Este ejemplo se ejecuta dentro de un iframe y Apple no lo permite. Para ver el comportamiento completo <a href="https://codepen.io/pen/debug/VwXBQyp">visite este enlace.</a></small></p>
<p style="display:none" id="ckoApplePayError">Su navegador o equipo no soporta Apple Pay.</p>
</div>
</div>
</div>
</div>
</div>
.apple-pay-button {
width: 250px;
height: 40px;
display: inline-block;
appearance: pay-button;
cursor: pointer;
}
.apple-pay-button-with-text>* {
display: none;
}
.apple-pay-button-black-with-text {
pay-button-style: black;
}
.apple-pay-button-white-with-text {
pay-button-style: white;
}
.apple-pay-button-white-with-line-with-text {
pay-button-style: white-outline;
}
.apple-pay-button-text-book {
pay-button-type: book;
}
.apple-pay-button-text-buy {
pay-button-type: buy;
}
.apple-pay-button-text-check-out {
pay-button-type: check-out;
}
.apple-pay-button-text-donate {
pay-button-type: donate;
}
/* For mobile devices */
@media only screen and (max-width: 600px) {
.apple-pay-button {
width: 90%;
height: 50px;
}
}
var applePayUiController = (function () {
var DOMStrings = {
appleButton: 'ckoApplePay',
errorMessage: 'ckoApplePayError'
}
return {
DOMStrings,
displayApplePayButton: function () {
document.getElementById(DOMStrings.appleButton).style.display = 'block'
},
hideApplePayButton: function () {
document.getElementById(DOMStrings.appleButton).style.display = 'none'
},
displayErrorMessage: function () {
document.getElementById(DOMStrings.errorMessage).style.display = 'block'
}
}
})()
var applePayController = (function (uiController) {
// BEGIN SIPAY CUSTOMIZE
var BACKEND_URL_VALIDATE_SESSION = 'https://enpr4mevu14qbjf.m.pipedream.net'
var BACKEND_URL_PAY = 'https://enl6ugm0xqdbbf3.m.pipedream.net'
// END SIPAY CUSTOMIZE
var request_id = ''
// High level configuration options.
// BEGIN SIPAY CUSTOMIZE
var config = {
payments: {
acceptedCardSchemes: ['amex', 'masterCard', 'maestro', 'visa', 'mada']
},
shop: {
product_price: 10.0,
shop_name: 'Tienda Demo',
shop_localisation: {
currencyCode: 'EUR',
countryCode: 'ES'
}
},
shipping: {
ES_region: [
{
label: 'Free Shipping',
amount: '0.00',
detail: 'Arrives in 3-5 days',
identifier: 'freeShipping'
},
{
label: 'Express Shipping',
amount: '5.00',
detail: 'Arrives in 1-2 days',
identifier: 'expressShipping'
}
],
WORLDWIDE_region: [
{
label: 'Worldwide Standard Shipping',
amount: '10.00',
detail: 'Arrives in 5-8 days',
identifier: 'worldwideShipping'
}
]
}
}
// END SIPAY CUSTOMIZE
/**
* Checks if Apple Pay is possible in the current environment.
* @return {boolean} Boolean to check if Apple Pay is possible
*/
var _applePayAvailable = function () {
return window.ApplePaySession && ApplePaySession.canMakePayments()
}
/**
* Starts the Apple Pay session using a configuration
*/
var _startApplePaySession = function (config) {
var applePaySession = new ApplePaySession(6, config)
_handleApplePayEvents(applePaySession)
applePaySession.begin()
}
/**
* This method cals your backend server with the Apple Pay validation URL.
* On the backend, a POST request will be done to this URL with the Apple Pay certificates
* and the outcome will be returned
*
* @param {string} appleUrl The Apple Pay validation URL generated by Apple
* @param {function} callback Callback function used to return the server call outcome
*
* @return {object} The session payload
*
*/
var _validateApplePaySession = function (appleUrl, callback) {
// I'm using AXIOS to do a POST request to the backend but any HTTP client can be used
const message = {
// BEGIN SIPAY CUSTOMIZE
// 'url': appleUrl, <- LIVE
'url': 'https://apple-pay-gateway-cert.apple.com/paymentservices/paymentSession', // <- SANDBOX
'domain': window.location.host, // Web domain
'title': 'Sale'
// END SIPAY CUSTOMIZE
}
axios
.post(
BACKEND_URL_VALIDATE_SESSION,
message,
{
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Max-Age': '1000'
}
}
)
.then(function (response) {
callback(response.data.payload)
request_id = response.data.payload.request_id
})
}
/**
* This method returns the available payment methods for a certain region. You can add
* your business logic here to determine the shipping methods you need.
*
* @param {string} 2 Letter ISO of the region
*
* @return {Array} An array of shipping methods
*
*/
var _getAvailableShippingMethods = function (region) {
// return the shipping methods available based on region
if (region === 'ES') {
return { methods: config.shipping.ES_region }
} else {
return { methods: config.shipping.WORLDWIDE_region }
}
}
var _calculateTotal = function (subtotal, shipping) {
return (parseFloat(subtotal) + parseFloat(shipping)).toFixed(2)
}
// here we talk to our backend to send the Apple Pay Payload and return the transaction outcome
var _performTransaction = function (details, callback) {
// I'm using AXIOS to do a POST request to the backend but any HTTP client can be used
axios
.post(
BACKEND_URL_PAY,
{
token: details.token,
request_id: request_id,
// customerEmail: details.shippingContact.emailAddress,
// billingDetails: details.billingContact,
// shippingDetails: details.shippingContact
},
{
headers: { 'Access-Control-Allow-Origin': '*' }
}
)
.then(function (response) {
console.log(response);
callback(response.data)
})
}
/**
* This is the main method of the script, since here we handle all the Apple Pay
* events. Here you are able to populate your shipping methods, react to shipping methods
* changes, and many other interaction that the user has with the Apple Pay pup-up.
*
* @param {object} Apple Pay Session (the one generate on the button click)
*
*/
var _handleApplePayEvents = function (appleSession) {
// This is the first event that Apple triggers. Here you need to validate the
// Apple Pay Session from your Back-End
appleSession.onvalidatemerchant = function (event) {
_validateApplePaySession(event.validationURL, function (merchantSession) {
appleSession.completeMerchantValidation(merchantSession)
})
}
// This method is triggered before populating the shipping methods. This is the
// perfect place inject your shipping methods
appleSession.onshippingcontactselected = function (event) {
// populate with the availbale shipping methods for the region (Apple will tell you the region).
// while the full address will only be available to you after the user confirms tha payment
var shipping = _getAvailableShippingMethods(
config.shop.shop_localisation.countryCode
)
// Update total and line items based on the shipping methods
var newTotal = {
type: 'final',
label: config.shop.shop_name,
amount: _calculateTotal(
config.shop.product_price,
shipping.methods[0].amount
)
}
var newLineItems = [
{
type: 'final',
label: 'Subtotal',
amount: config.shop.product_price
},
{
type: 'final',
label: shipping.methods[0].label,
amount: shipping.methods[0].amount
}
]
appleSession.completeShippingContactSelection(
ApplePaySession.STATUS_SUCCESS,
shipping.methods,
newTotal,
newLineItems
)
}
// This method is triggered when a user select one of the shipping options.
// Here you generally want to keep track of the transaction amount
appleSession.onshippingmethodselected = function (event) {
var newTotal = {
type: 'final',
label: config.shop.shop_name,
amount: _calculateTotal(
config.shop.product_price,
event.shippingMethod.amount
)
}
var newLineItems = [
{
type: 'final',
label: 'Subtotal',
amount: config.shop.product_price
},
{
type: 'final',
label: event.shippingMethod.label,
amount: event.shippingMethod.amount
}
]
appleSession.completeShippingMethodSelection(
ApplePaySession.STATUS_SUCCESS,
newTotal,
newLineItems
)
}
// This method is the most important method. It gets triggered after the user has
// confirmed the transaction with the Touch ID or Face ID. Besides getting all the
// details about the customer (email, address ...) you also get the Apple Pay payload
// needed to perform a payment.
appleSession.onpaymentauthorized = function (event) {
_performTransaction(event.payment, function (outcome) {
console.log('### BEGIN outcome ###')
console.log(outcome);
console.log('*** END outcome ***')
const paymentStatusElement = document.getElementById('PaymentStatus');
if (outcome.payload.code == 0) {
appleSession.completePayment(ApplePaySession.STATUS_SUCCESS)
// BEGIN SIPAY CUSTOMIZE
paymentStatusElement.innerHTML = '<img src="images/ok.png" /><p><h1>¡PAGO REALIZADO CON ÉXITO!</h1></p>';
uiController.hideApplePayButton()
console.log('Authorization Succesful');
// END SIPAY CUSTOMIZE
} else {
appleSession.completePayment(ApplePaySession.STATUS_FAILURE)
// BEGIN SIPAY CUSTOMIZE
paymentStatusElement.innerHTML = '<img src="images/ko.png" /><p><h1>¡PAGO FALLIDO!</h1></p>';
uiController.hideApplePayButton()
console.log('Authorization Fail');
// END SIPAY CUSTOMIZE
}
})
}
}
/**
* Sets a onClick listen on the Apple Pay button. When clicked it will
* begin the Apple Pay session with your configuration
*/
var _setButtonClickListener = function () {
document
.getElementById(uiController.DOMStrings.appleButton)
.addEventListener('click', function () {
_startApplePaySession({
currencyCode: config.shop.shop_localisation.currencyCode,
countryCode: config.shop.shop_localisation.countryCode,
merchantCapabilities: [
'supports3DS',
'supportsEMV',
'supportsCredit',
'supportsDebit'
],
supportedNetworks: config.payments.acceptedCardSchemes,
shippingType: 'shipping',
requiredBillingContactFields: [
// 'postalAddress',
// 'name',
// 'phone',
// 'email'
],
requiredShippingContactFields: [
// 'postalAddress',
// 'name',
// 'phone',
// 'email'
],
applicationData: 'aG9sYSBwcm9iYW5kbyBjdXN0b20gZmllbGQ=',
total: {
label: config.shop.shop_name,
amount: config.shop.product_price,
type: 'final'
}
})
})
}
return {
init: function () {
// If Apple Pay is available show the button otherwise show the error
if (_applePayAvailable()) {
// Notice we are using the functions from our UI controller
uiController.displayApplePayButton()
} else {
uiController.hideApplePayButton()
uiController.displayErrorMessage()
}
// Set the onClick listener on the Apple Pay button
_setButtonClickListener()
}
}
})(applePayUiController) // passing the UI controller
// Initialise the Apple Pay controller and let the magic happen
applePayController.init()