diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..018c0cbb6b1d62c3be1f7317fc9a67ae1dbc0193 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js @@ -0,0 +1,72 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'mageUtils', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator/credit-card-type' + ], + function (utils, luhn10, creditCardTypes) { + 'use strict'; + + function result(card, isPotentiallyValid, isValid) { + return { + card: card, + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function (value) { + var potentialTypes, + cardType, + valid, + i, + maxLength; + + if (utils.isEmpty(value)) { + return result(null, false, false); + } + + value = value.replace(/\-|\s/g, ''); + + if (!/^\d*$/.test(value)) { + return result(null, false, false); + } + + potentialTypes = creditCardTypes.getCardTypes(value); + + if (potentialTypes.length === 0) { + return result(null, false, false); + } else if (potentialTypes.length !== 1) { + return result(null, true, false); + } + + cardType = potentialTypes[0]; + + if (cardType.type === 'unionpay') { // UnionPay is not Luhn 10 compliant + valid = true; + } else { + valid = luhn10(value); + } + + for (i = 0; i < cardType.lengths.length; i++) { + if (cardType.lengths[i] === value.length) { + return result(cardType, valid, valid); + } + } + + maxLength = Math.max.apply(null, cardType.lengths); + + if (value.length < maxLength) { + return result(cardType, true, false); + } + + return result(cardType, false, false); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js new file mode 100644 index 0000000000000000000000000000000000000000..7ace4e1594b796425b4d2788aa94a0a7dafc1f3d --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js @@ -0,0 +1,130 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'jquery', + 'mageUtils' + ], + function ($, utils) { + 'use strict'; + var types = [ + { + niceType: 'Visa', + type: 'visa', + pattern: '^4\\d*$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CVV', + size: 3 + } + }, + { + niceType: 'MasterCard', + type: 'master-card', + pattern: '^5([1-5]\\d*)?$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CVC', + size: 3 + } + }, + { + niceType: 'American Express', + type: 'american-express', + pattern: '^3([47]\\d*)?$', + isAmex: true, + gaps: [4, 10], + lengths: [15], + code: { + name: 'CID', + size: 4 + } + }, + { + niceType: 'DinersClub', + type: 'diners-club', + pattern: '^3((0([0-5]\\d*)?)|[689]\\d*)?$', + gaps: [4, 10], + lengths: [14], + code: { + name: 'CVV', + size: 3 + } + }, + { + niceType: 'Discover', + type: 'discover', + pattern: '^6(0|01|011\\d*|5\\d*|4|4[4-9]\\d*)?$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CID', + size: 3 + } + }, + { + niceType: 'JCB', + type: 'jcb', + pattern: '^((2|21|213|2131\\d*)|(1|18|180|1800\\d*)|(3|35\\d*))$', + gaps: [4, 8, 12], + lengths: [16], + code: { + name: 'CVV', + size: 3 + } + }, + { + niceType: 'UnionPay', + type: 'unionpay', + pattern: '^6(2\\d*)?$', + gaps: [4, 8, 12], + lengths: [16, 17, 18, 19], + code: { + name: 'CVN', + size: 3 + } + }, + { + niceType: 'Maestro', + type: 'maestro', + pattern: '^((5((0|[6-9])\\d*)?)|(6|6[37]\\d*))$', + gaps: [4, 8, 12], + lengths: [12, 13, 14, 15, 16, 17, 18, 19], + code: { + name: 'CVC', + size: 3 + } + } + ]; + + return { + getCardTypes: function (cardNumber) { + var i, value, + result = []; + + if (utils.isEmpty(cardNumber)) { + return result; + } + + if (cardNumber === '') { + return $.extend(true, {}, types); + } + + for (i = 0; i < types.length; i++) { + value = types[i]; + + if (new RegExp(value.pattern).test(cardNumber)) { + result.push($.extend(true, {}, value)); + } + } + return result; + } + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..22d5f8acdd93a33419abdf644dbbf4b563c853aa --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js @@ -0,0 +1,19 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + return function(a,b,c,d,e) { + for(d = +a[b = a.length-1], e=0; b--;) { + c = +a[b]; + d += ++e % 2 ? 2 * c % 10 + (c > 4) : c; + } + return !(d%10) + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..812ee62b363aa58e857db7df4a6c8e23be8e6471 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js @@ -0,0 +1,39 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + + function result(isValid, isPotentiallyValid) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function(value, maxLength) { + var DEFAULT_LENGTH = 3; + maxLength = maxLength || DEFAULT_LENGTH; + + if (!/^\d*$/.test(value)) { + return result(false, false); + } + if (value.length === maxLength) { + return result(true, true); + } + if (value.length < maxLength) { + return result(false, true); + } + if (value.length > maxLength) { + return result(false, false); + } + + return result(true, true); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..1dda53d0721e1aa1b10dd022c2aa32c4e43553e8 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js @@ -0,0 +1,51 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [ + 'mageUtils', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/parse-date', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator' + ], + function(utils, parseDate, expirationMonth, expirationYear) { + 'use strict'; + + function result(isValid, isPotentiallyValid, month, year) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid, + month: month, + year: year + }; + } + + return function(value) { + var date, + monthValid, + yearValid; + + if (utils.isEmpty(value)) { + return result(false, false, null, null); + } + + value = value.replace(/^(\d\d) (\d\d(\d\d)?)$/, '$1/$2'); + date = parseDate(value); + monthValid = expirationMonth(date.month); + yearValid = expirationYear(date.year); + + if (monthValid.isValid && yearValid.isValid) { + return result(true, true, date.month, date.year); + } + + if (monthValid.isPotentiallyValid && yearValid.isPotentiallyValid) { + return result(false, true, null, null); + } + + return result(false, false, null, null); + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..d9f9729a7c6dd0d27e80af92f6864a4e29098a68 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js @@ -0,0 +1,41 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function () { + 'use strict'; + + function result(isValid, isPotentiallyValid) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function (value) { + var month, + monthValid; + + if ((value.replace(/\s/g, '') === '') || (value === '0')) { + return result(false, true); + } + + if (!/^\d*$/.test(value)) { + return result(false, false); + } + + if (isNaN(value)) { + return result(false, false); + } + + month = parseInt(value, 10); + monthValid = month > 0 && month < 13; + + return result(monthValid, monthValid); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js new file mode 100644 index 0000000000000000000000000000000000000000..5b0c1da544b57c717f5096c44a0a42702b2e4e68 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js @@ -0,0 +1,63 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + + function result(isValid, isPotentiallyValid) { + return { + isValid: isValid, + isPotentiallyValid: isPotentiallyValid + }; + } + + return function(value) { + var currentFirstTwo, + currentYear = new Date().getFullYear(), + firstTwo, + len = value.length, + twoDigitYear, + valid, + maxYear = 19; + + if (value.replace(/\s/g, '') === '') { + return result(false, true); + } + + if (!/^\d*$/.test(value)) { + return result(false, false); + } + + if (len < 2) { + return result(false, true); + } + + if (len === 3) { + // 20x === 20x + firstTwo = value.slice(0, 2); + currentFirstTwo = String(currentYear).slice(0, 2); + return result(false, firstTwo === currentFirstTwo); + } + + if (len > 4) { + return result(false, false); + } + + value = parseInt(value, 10); + twoDigitYear = Number(String(currentYear).substr(2, 2)); + + if (len === 2) { + valid = value >= twoDigitYear && value <= twoDigitYear + maxYear; + } else if (len === 4) { + valid = value >= currentYear && value <= currentYear + maxYear; + } + + return result(valid, valid); + }; + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js new file mode 100644 index 0000000000000000000000000000000000000000..56c281a516e7af401a013b292107ccb1211e8932 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js @@ -0,0 +1,32 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define( + [], + function() { + 'use strict'; + return function(value) { + var month, len; + + if (value.match('/')) { + value = value.split(/\s*\/\s*/g); + + return { + month: value[0], + year: value.slice(1).join() + }; + } + + len = value[0] === '0' || value.length > 5 || value.length === 4 || value.length === 3 ? 2 : 1; + month = value.substr(0, len); + + return { + month: month, + year: value.substr(month.length, 4) + }; + } + } +); diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js new file mode 100644 index 0000000000000000000000000000000000000000..dea84a03bdd04e7b5fed66678f704e553ad5a371 --- /dev/null +++ b/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js @@ -0,0 +1,61 @@ +/** + * Copyright © 2015 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +(function (factory) { + if (typeof define === 'function' && define.amd) { + define([ + 'jquery', + 'Magento_Payment/js/model/credit-card-validation/cvv-validator', + 'Magento_Payment/js/model/credit-card-validation/credit-card-number-validator', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator', + 'Magento_Payment/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator' + ], factory); + } else { + factory(jQuery); + } +}(function ($, cvvValidator, creditCardNumberValidator, expirationDateValidator, monthValidator) { + "use strict"; + + $.each({ + 'validate-card-number': [ + /** + * Validate credit card number based on mod 10 + * @param number - credit card number + * @return {boolean} + */ + function (number) { + return creditCardNumberValidator(number).isValid; + }, + 'Please enter a valid credit card number11.' + ], + 'validate-card-date': [ + /** + * Validate credit card number based on mod 10 + * @param date - month + * @return {boolean} + */ + function (date) { + return monthValidator(date).isValid; + }, + 'Incorrect credit card expiration date11.' + ], + 'validate-card-cvv': [ + /** + * Validate credit card number based on mod 10 + * @param cvv - month + * @return {boolean} + */ + function (cvv) { + return cvvValidator(cvv).isValid; + }, + 'Please enter a valid credit card verification number11.' + ] + + }, function (i, rule) { + rule.unshift(i); + $.validator.addMethod.apply($.validator, rule); + }); +})); \ No newline at end of file diff --git a/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html b/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html index dcd12d8931523a68ba8d82348a61d2748bb45c9d..52a675b890224981ef5ebd5eb4fa76f71ce6b5af 100644 --- a/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html +++ b/app/code/Magento/Payment/view/frontend/web/template/payment/cc-form.html @@ -36,7 +36,7 @@ </label> <div class="control"> <input type="text" name="payment[cc_number]" class="input-text" value="" - data-bind="attr: {id: getCode() + '_cc_number', title: $t('Credit Card Number'), 'data-container': getCode() + '-cc-number', 'data-validate': JSON.stringify({'required-number':true, 'validate-cc-number':'#' + getCode() + '_cc_type', 'validate-cc-type':'#' + getCode() + '_cc_type'})}, + data-bind="attr: {id: getCode() + '_cc_number', title: $t('Credit Card Number'), 'data-container': getCode() + '-cc-number', 'data-validate': JSON.stringify({'required-number':true, 'validate-card-number':'#' + getCode() + '_cc_type', 'validate-cc-type':'#' + getCode() + '_cc_type'})}, enable: isActive($parents), value: creditCardNumber"/> </div> @@ -51,7 +51,7 @@ <div class="control"> <select name="payment[cc_exp_month]" class="select select-month" - data-bind="attr: {id: getCode() + '_expiration', 'data-container': getCode() + '-cc-month', 'data-validate': JSON.stringify({required:true, 'validate-cc-exp':'#' + getCode() + '_expiration_yr'})}, + data-bind="attr: {id: getCode() + '_expiration', 'data-container': getCode() + '-cc-month', 'data-validate': JSON.stringify({required:true, 'validate-card-date':'#' + getCode() + '_expiration_yr'})}, enable: isActive($parents), options: getCcMonthsValues(), optionsValue: 'value', @@ -85,7 +85,7 @@ </label> <div class="control _with-tooltip"> <input type="text" class="input-text cvv" name="payment[cc_cid]" value="" - data-bind="attr: {id: getCode() + '_cc_cid', title: $t('Card Verification Number'), 'data-container': getCode() + '-cc-cvv', 'data-validate': JSON.stringify({'required-number':true, 'validate-cc-cvn':'#' + getCode() + '_cc_type'})}, + data-bind="attr: {id: getCode() + '_cc_cid', title: $t('Card Verification Number'), 'data-container': getCode() + '-cc-cvv', 'data-validate': JSON.stringify({'required-number':true, 'validate-card-cvv':'#' + getCode() + '_cc_type'})}, enable: isActive($parents), value: creditCardVerificationNumber"/> <div class="field-tooltip toggle"> diff --git a/app/code/Magento/Payment/view/frontend/web/transparent.js b/app/code/Magento/Payment/view/frontend/web/transparent.js index 7b2ba69366d0bedd69a931d32ce00ec667e57809..2060ca7c8ea5e5a344329c0e48ad935859f77f8a 100644 --- a/app/code/Magento/Payment/view/frontend/web/transparent.js +++ b/app/code/Magento/Payment/view/frontend/web/transparent.js @@ -6,9 +6,10 @@ define([ "jquery", "mage/template", - "jquery/ui" + "jquery/ui", + "Magento_Payment/js/model/credit-card-validation/validator" ], function($, mageTemplate){ - "use strict"; + 'use strict'; $.widget('mage.transparent', { options: {