Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TR-92: add 3DS #6

Open
wants to merge 39 commits into
base: add-gift-support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6e83199
TR-92: add 3DS
apetrovici Mar 29, 2021
c077afb
TR-92: updates
apetrovici Mar 29, 2021
96917a1
TR-92: 3ds requests updates
apetrovici Mar 30, 2021
9885a79
TR-92: config access token permissions update
apetrovici Mar 30, 2021
1996e0c
TR-92: fix comma
apetrovici Mar 30, 2021
3d8dfa9
Merge branch 'add-gift-support' into feature/tr-92-gpapi-integration-3ds
apetrovici Mar 30, 2021
6a47514
TR-92: update 3ds js lib
apetrovici Mar 30, 2021
e97115c
TR-92: remove unused namespace
apetrovici Mar 30, 2021
8d94d9a
TR-92: handle 3DS1
apetrovici Mar 31, 2021
c7e34a7
TR-92: update endpoints
apetrovici Mar 31, 2021
cf47953
TR-92: update endpoints
apetrovici Mar 31, 2021
5452152
TR-92: updated 3ds lib to handle 3DS1
apetrovici Mar 31, 2021
d97c54e
TR-92: remove wc notices removal
apetrovici Mar 31, 2021
665f524
TR-92: gateway config updates
apetrovici Apr 1, 2021
8a92e9b
TR-92: hosted fields style changes
apetrovici Apr 1, 2021
c21358e
TR-92: add namespace
apetrovici Apr 2, 2021
b827d51
TR-92: add capture action only for authorize
apetrovici Apr 5, 2021
32a024f
TR-92: disable add payment method if admin option not set to allow
apetrovici Apr 5, 2021
7533e79
TR-92: updates styles and errors
apetrovici Apr 5, 2021
bf249bf
TR-92: bug fix toggle buttons only when gateway selected
apetrovici Apr 5, 2021
2eb3508
TR-92: bug fix
apetrovici Apr 5, 2021
73c3fa9
TR-92: display error thrown by init auth
apetrovici Apr 5, 2021
1bdbd17
TR-92: update 3ds requests
apetrovici Apr 6, 2021
f16251b
TR-92: block form on place order submit
apetrovici Apr 7, 2021
b7c044d
TR-92: format refund amount
apetrovici Apr 7, 2021
036054f
TR-92: fix bug
apetrovici Apr 7, 2021
76292f0
TR-92: set country on config
apetrovici Apr 7, 2021
359a8fc
TR-92: fix 3DS block on submit
apetrovici Apr 7, 2021
8e7e55e
TR-92: bug fix for add payment method
apetrovici Apr 7, 2021
617832b
TR-92: update readme
apetrovici Apr 8, 2021
977ad13
TR-92: update readme
apetrovici Apr 8, 2021
b97ec1c
TR-92: no valdation for order pay
apetrovici Apr 8, 2021
628ffd6
TR-92: Error: Your plugin and author URIs are the same
apetrovici Apr 8, 2021
dd37ec1
TR-92: bug fix uncaught exception
apetrovici Apr 8, 2021
c7bf126
TR-92: bug fix
apetrovici Apr 8, 2021
f393717
TR-92: remove 3DS check for add payment method
apetrovici Apr 8, 2021
9d8030f
TR-92: bug fix remove notices from previous calls
apetrovici Apr 8, 2021
dd6951d
TR-92: add WP review feedback
apetrovici Apr 9, 2021
c8e076e
TR-92: include js scripts correctly
apetrovici Apr 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/frontend/css/globalpayments-secure-payment-fields.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.globalpayments iframe {
min-height: 3.6rem;
}

div[id^="GlobalPayments-overlay-"] {
z-index: 1001 !important;
}
1,862 changes: 1,862 additions & 0 deletions assets/frontend/js/globalpayments-3ds.js

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions assets/frontend/js/globalpayments-3ds.min.js

Large diffs are not rendered by default.

230 changes: 225 additions & 5 deletions assets/frontend/js/globalpayments-secure-payment-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
$,
wc_checkout_params,
GlobalPayments,
globalpayments_secure_payment_fields_params
GlobalPayments3DS,
globalpayments_secure_payment_fields_params,
globalpayments_secure_payment_threedsecure_params
) {
/**
* Frontend code for Global Payments in WooCommerce
*
* @param {object} options
*/
function GlobalPaymentsWooCommerce(options) {
function GlobalPaymentsWooCommerce( options, threeDSecureOptions ) {

/**
* Card form instance
Expand All @@ -26,18 +28,37 @@
* @type {string}
*/
this.id = options.id;

/**
* Payment field options
*
* @type {object}
*/
this.fieldOptions = options.field_options;

/**
* Payment gateway options
*
* @type {object}
*/
this.gatewayOptions = options.gateway_options;

/**
* 3DS endpoints
*/
this.threedsecure = threeDSecureOptions.threedsecure;

/**
* Order info
*/
this.order = threeDSecureOptions.order;

/**
*
* @type {null}
*/
this.tokenResponse = null;

this.attachEventHandlers();
};

Expand All @@ -64,12 +85,18 @@
// Order Pay + Add payment method
if ( $( document.body ).hasClass( 'woocommerce-order-pay' ) || $( 'form#add_payment_method' ).length > 0 ) {
$( document ).ready( this.renderPaymentFields.bind( this ) );
if ( 'globalpayments_gpapi' === this.id) {
$( document ).ready( this.threeDSSecure.bind( this ) );
}
return;
}

// Checkout
if ( wc_checkout_params.is_checkout ) {
$( document.body ).on( 'updated_checkout', this.renderPaymentFields.bind( this ) );
if ( 'globalpayments_gpapi' === this.id) {
$( document.body ).on( 'updated_checkout', this.threeDSSecure.bind( this ) );
}
return;
}
},
Expand Down Expand Up @@ -198,7 +225,7 @@
return;
}

console.log(response);
this.tokenResponse = JSON.stringify(response);

var that = this;

Expand Down Expand Up @@ -232,6 +259,165 @@
});
},

/**
* Validate mandatory checkout fields
*
* @returns {boolean}
*/
validateFields: function() {
if ( ! $( '#billing_first_name' ).val()
|| ! $( '#billing_last_name' ).val()
|| ! $( '#billing_address_1' ).val()
|| ! $( '#billing_city' ).val()
|| ! $( '#billing_postcode' ).val()
|| ! $( '#billing_phone' ).val()
|| ! $( '#billing_email' ).val() ) {
this.showPaymentError( 'Please fill in the required fields.' );
return false;
}

if ( ! this.isValidZipCode( $( '#billing_postcode' ).val() ) ) {
this.showPaymentError( 'Billing ZIP is not a valid postcode / ZIP. ' );
return false;
}

return true;
},

/**
* Validate zipcode
*
* @param {String} zipcode
* @return {Boolean}
*/
isValidZipCode: function ( zipcode ) {
let pattern = /^[a-zA-Z0-9-\s]{1,16}$/;

return pattern.test(zipcode);
},

/**
* 3DS Process
*/
threeDSSecure: function () {
const {
checkVersion,
initiateAuthentication,
ChallengeWindowSize,
} = GlobalPayments.ThreeDSecure;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use const/let, async/await, or arrow functions due to older browser incompatibilities (e.g. IE 11).


const checkVersionButton = $( this.getPlaceOrderButtonSelector() );
if ( ! checkVersionButton ) {
console.error( 'Warning! Place Order button cannot be loaded' );
return;
}

// handle 3DS 2.0 workflow
const start3DS = async (e) => {
e.preventDefault();

if ( wc_checkout_params.is_checkout && ! this.validateFields() ) {
return;
}

try {
versionCheckData = await checkVersion(this.threedsecure.checkEnrollmentUrl, {
tokenResponse: this.tokenResponse,
wcTokenId: $( 'input[name="wc-' + this.id + '-payment-token"]:checked', this.getForm() ).val(),
amount: this.order.amount,
currency: this.order.currency,
challengeWindow: {
windowSize: ChallengeWindowSize.Windowed500x600,
displayMode: 'lightbox',
hide: false,
},
});

// Card holder not enrolled in 3D Secure, continue the WooCommerce flow.
if (versionCheckData.enrolled === "NOT_ENROLLED") {
$( this.getForm() ).submit();
return;
}

//Something went wrong with CheckEnrolment request on server side
if (versionCheckData.error) {
this.showPaymentError( versionCheckData.message );
return;
}
} catch ( e ) {
console.error( e.reasons );
this.showPaymentError( e.reasons[0].message );
return;
}

if ( "ONE" === versionCheckData.version ) {
this.createInputElement( 'serverTransId', versionCheckData.serverTransactionId );
this.createInputElement( 'PaRes', versionCheckData.challenge.response.data.PaRes );
$( this.getForm() ).submit();
return;
}

try {
authenticationData = await initiateAuthentication(this.threedsecure.initiateAuthenticationUrl, {
tokenResponse: this.tokenResponse,
wcTokenId: $( 'input[name="wc-' + this.id + '-payment-token"]:checked', this.getForm() ).val(),
versionCheckData: versionCheckData,
challengeWindow: {
windowSize: ChallengeWindowSize.Windowed500x600,
displayMode: 'lightbox',
},
order: this.order,
});

switch (authenticationData.result) {
case "SUCCESS_AUTHENTICATED":
case "AUTHENTICATION_SUCCESSFUL":
// frictionless authentication success
this.createInputElement( 'serverTransId', authenticationData.serverTransactionId );
$( this.getForm() ).submit();
return;
case "CHALLENGE_REQUIRED":
// challenge authentication success
if (authenticationData.challenge.response.data.transStatus == "Y") {
this.createInputElement( 'serverTransId', versionCheckData.serverTransactionId);
$( this.getForm() ).submit();
return;
}
// challenge authentication failure
this.showPaymentError('3DS Authentication failed. Please try again!');
return;
case "NOT_AUTHENTICATED":
case "FAILED":
default:
this.showPaymentError('3DS Authentication failed. Please try again!');
return;
}
} catch (e) {
console.error( e );
this.showPaymentError( e.reasons );
return;
}

return false;
};

checkVersionButton.on('click', start3DS );
},

createInputElement: function ( name, value ) {
var inputElement = (document.getElementById( this.id + '-' + name ));

if ( ! inputElement) {
inputElement = document.createElement( 'input' );
inputElement.id = this.id + '-' + name;
inputElement.name = this.id + '[' + name + ']';
inputElement.type = 'hidden';
this.getForm().appendChild( inputElement );
}

inputElement.value = value;
},

/**
* Places/submits the order to WooCommerce
*
Expand Down Expand Up @@ -307,6 +493,28 @@
$( '.' + this.id + '.' + fieldType + ' .validation-error' ).show();
},

/**
* Shows payment error and scrolls to it
*
* @param {string} message Error message
*
* @returns
*/
showPaymentError: function ( message ) {
var $form = $( this.getForm() );

this.unblockOnError();

// Remove notices from all sources
$( '.woocommerce-error, .woocommerce-message' ).remove();
apetrovici marked this conversation as resolved.
Show resolved Hide resolved

$form.prepend( '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-updateOrderReview woocommerce-error">' + message + '</div>' );
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any exposed WooCommerce JS methods for displaying error messages so we don't have to keep this in sync with WC?


$( 'html, body' ).animate( {
scrollTop: ( $form.offset().top - 100 )
}, 1000 );
},

/**
* Handles errors from the payment field iframes
*
Expand Down Expand Up @@ -613,7 +821,7 @@
}
};

new GlobalPaymentsWooCommerce( globalpayments_secure_payment_fields_params );
new GlobalPaymentsWooCommerce( globalpayments_secure_payment_fields_params, globalpayments_secure_payment_threedsecure_params );
}(
/**
* Global `jQuery` reference
Expand All @@ -633,10 +841,22 @@
* @type {any}
*/
(window).GlobalPayments,
/**
* Global `GlobalPayments` reference
*
* @type {any}
*/
(window).GlobalPayments.ThreeDSecure,
/**
* Global `globalpayments_secure_payment_fields_params` reference
*
* @type {any}
*/
(window).globalpayments_secure_payment_fields_params
(window).globalpayments_secure_payment_fields_params,
/**
* Global `globalpayments_secure_payment_threedsecure_params` reference
*
* @type {any}
*/
(window).globalpayments_secure_payment_threedsecure_params || {}
));
Loading