diff --git a/addons/website_payment/__openerp__.py b/addons/website_payment/__openerp__.py index 9a4886c0d66..2a01d2f1aec 100644 --- a/addons/website_payment/__openerp__.py +++ b/addons/website_payment/__openerp__.py @@ -31,7 +31,7 @@ 'website', 'payment_acquirer', 'payment_acquirer_ogone', - 'payment_acquirer_paypal' + 'payment_acquirer_paypal', 'payment_acquirer_transfer', ], 'data': [ diff --git a/addons/website_payment/static/lib/jquery.payment/jquery.payment.js b/addons/website_payment/static/lib/jquery.payment/jquery.payment.js new file mode 100644 index 00000000000..c81c6e00d81 --- /dev/null +++ b/addons/website_payment/static/lib/jquery.payment/jquery.payment.js @@ -0,0 +1,497 @@ +// Generated by CoffeeScript 1.4.0 +(function() { + var $, cardFromNumber, cardFromType, cards, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardNumber, formatExpiry, formatForwardExpiry, formatForwardSlash, hasTextSelected, luhnCheck, reFormatCardNumber, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric, setCardType, + __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + _this = this; + + $ = jQuery; + + $.payment = {}; + + $.payment.fn = {}; + + $.fn.payment = function() { + var args, method; + method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + return $.payment.fn[method].apply(this, args); + }; + + defaultFormat = /(\d{1,4})/g; + + cards = [ + { + type: 'maestro', + pattern: /^(5018|5020|5038|6304|6759|676[1-3])/, + format: defaultFormat, + length: [12, 13, 14, 15, 16, 17, 18, 19], + cvcLength: [3], + luhn: true + }, { + type: 'dinersclub', + pattern: /^(36|38|30[0-5])/, + format: defaultFormat, + length: [14], + cvcLength: [3], + luhn: true + }, { + type: 'laser', + pattern: /^(6706|6771|6709)/, + format: defaultFormat, + length: [16, 17, 18, 19], + cvcLength: [3], + luhn: true + }, { + type: 'jcb', + pattern: /^35/, + format: defaultFormat, + length: [16], + cvcLength: [3], + luhn: true + }, { + type: 'unionpay', + pattern: /^62/, + format: defaultFormat, + length: [16, 17, 18, 19], + cvcLength: [3], + luhn: false + }, { + type: 'discover', + pattern: /^(6011|65|64[4-9]|622)/, + format: defaultFormat, + length: [16], + cvcLength: [3], + luhn: true + }, { + type: 'mastercard', + pattern: /^5[1-5]/, + format: defaultFormat, + length: [16], + cvcLength: [3], + luhn: true + }, { + type: 'amex', + pattern: /^3[47]/, + format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/, + length: [15], + cvcLength: [3, 4], + luhn: true + }, { + type: 'visa', + pattern: /^4/, + format: defaultFormat, + length: [13, 14, 15, 16], + cvcLength: [3], + luhn: true + } + ]; + + cardFromNumber = function(num) { + var card, _i, _len; + num = (num + '').replace(/\D/g, ''); + for (_i = 0, _len = cards.length; _i < _len; _i++) { + card = cards[_i]; + if (card.pattern.test(num)) { + return card; + } + } + }; + + cardFromType = function(type) { + var card, _i, _len; + for (_i = 0, _len = cards.length; _i < _len; _i++) { + card = cards[_i]; + if (card.type === type) { + return card; + } + } + }; + + luhnCheck = function(num) { + var digit, digits, odd, sum, _i, _len; + odd = true; + sum = 0; + digits = (num + '').split('').reverse(); + for (_i = 0, _len = digits.length; _i < _len; _i++) { + digit = digits[_i]; + digit = parseInt(digit, 10); + if ((odd = !odd)) { + digit *= 2; + } + if (digit > 9) { + digit -= 9; + } + sum += digit; + } + return sum % 10 === 0; + }; + + hasTextSelected = function($target) { + var _ref; + if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== $target.prop('selectionEnd')) { + return true; + } + if (typeof document !== "undefined" && document !== null ? (_ref = document.selection) != null ? typeof _ref.createRange === "function" ? _ref.createRange().text : void 0 : void 0 : void 0) { + return true; + } + return false; + }; + + reFormatCardNumber = function(e) { + var _this = this; + return setTimeout(function() { + var $target, value; + $target = $(e.currentTarget); + value = $target.val(); + value = $.payment.formatCardNumber(value); + return $target.val(value); + }); + }; + + formatCardNumber = function(e) { + var $target, card, digit, length, re, upperLength, value; + digit = String.fromCharCode(e.which); + if (!/^\d+$/.test(digit)) { + return; + } + $target = $(e.currentTarget); + value = $target.val(); + card = cardFromNumber(value + digit); + length = (value.replace(/\D/g, '') + digit).length; + upperLength = 16; + if (card) { + upperLength = card.length[card.length.length - 1]; + } + if (length >= upperLength) { + return; + } + if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { + return; + } + if (card && card.type === 'amex') { + re = /^(\d{4}|\d{4}\s\d{6})$/; + } else { + re = /(?:^|\s)(\d{4})$/; + } + if (re.test(value)) { + e.preventDefault(); + return $target.val(value + ' ' + digit); + } else if (re.test(value + digit)) { + e.preventDefault(); + return $target.val(value + digit + ' '); + } + }; + + formatBackCardNumber = function(e) { + var $target, value; + $target = $(e.currentTarget); + value = $target.val(); + if (e.meta) { + return; + } + if (e.which !== 8) { + return; + } + if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { + return; + } + if (/\d\s$/.test(value)) { + e.preventDefault(); + return $target.val(value.replace(/\d\s$/, '')); + } else if (/\s\d?$/.test(value)) { + e.preventDefault(); + return $target.val(value.replace(/\s\d?$/, '')); + } + }; + + formatExpiry = function(e) { + var $target, digit, val; + digit = String.fromCharCode(e.which); + if (!/^\d+$/.test(digit)) { + return; + } + $target = $(e.currentTarget); + val = $target.val() + digit; + if (/^\d$/.test(val) && (val !== '0' && val !== '1')) { + e.preventDefault(); + return $target.val("0" + val + " / "); + } else if (/^\d\d$/.test(val)) { + e.preventDefault(); + return $target.val("" + val + " / "); + } + }; + + formatForwardExpiry = function(e) { + var $target, digit, val; + digit = String.fromCharCode(e.which); + if (!/^\d+$/.test(digit)) { + return; + } + $target = $(e.currentTarget); + val = $target.val(); + if (/^\d\d$/.test(val)) { + return $target.val("" + val + " / "); + } + }; + + formatForwardSlash = function(e) { + var $target, slash, val; + slash = String.fromCharCode(e.which); + if (slash !== '/') { + return; + } + $target = $(e.currentTarget); + val = $target.val(); + if (/^\d$/.test(val) && val !== '0') { + return $target.val("0" + val + " / "); + } + }; + + formatBackExpiry = function(e) { + var $target, value; + if (e.meta) { + return; + } + $target = $(e.currentTarget); + value = $target.val(); + if (e.which !== 8) { + return; + } + if (($target.prop('selectionStart') != null) && $target.prop('selectionStart') !== value.length) { + return; + } + if (/\d(\s|\/)+$/.test(value)) { + e.preventDefault(); + return $target.val(value.replace(/\d(\s|\/)*$/, '')); + } else if (/\s\/\s?\d?$/.test(value)) { + e.preventDefault(); + return $target.val(value.replace(/\s\/\s?\d?$/, '')); + } + }; + + restrictNumeric = function(e) { + var input; + if (e.metaKey || e.ctrlKey) { + return true; + } + if (e.which === 32) { + return false; + } + if (e.which === 0) { + return true; + } + if (e.which < 33) { + return true; + } + input = String.fromCharCode(e.which); + return !!/[\d\s]/.test(input); + }; + + restrictCardNumber = function(e) { + var $target, card, digit, value; + $target = $(e.currentTarget); + digit = String.fromCharCode(e.which); + if (!/^\d+$/.test(digit)) { + return; + } + if (hasTextSelected($target)) { + return; + } + value = ($target.val() + digit).replace(/\D/g, ''); + card = cardFromNumber(value); + if (card) { + return value.length <= card.length[card.length.length - 1]; + } else { + return value.length <= 16; + } + }; + + restrictExpiry = function(e) { + var $target, digit, value; + $target = $(e.currentTarget); + digit = String.fromCharCode(e.which); + if (!/^\d+$/.test(digit)) { + return; + } + if (hasTextSelected($target)) { + return; + } + value = $target.val() + digit; + value = value.replace(/\D/g, ''); + if (value.length > 6) { + return false; + } + }; + + restrictCVC = function(e) { + var $target, digit, val; + $target = $(e.currentTarget); + digit = String.fromCharCode(e.which); + if (!/^\d+$/.test(digit)) { + return; + } + val = $target.val() + digit; + return val.length <= 4; + }; + + setCardType = function(e) { + var $target, allTypes, card, cardType, val; + $target = $(e.currentTarget); + val = $target.val(); + cardType = $.payment.cardType(val) || 'unknown'; + if (!$target.hasClass(cardType)) { + allTypes = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = cards.length; _i < _len; _i++) { + card = cards[_i]; + _results.push(card.type); + } + return _results; + })(); + $target.removeClass('unknown'); + $target.removeClass(allTypes.join(' ')); + $target.addClass(cardType); + $target.toggleClass('identified', cardType !== 'unknown'); + return $target.trigger('payment.cardType', cardType); + } + }; + + $.payment.fn.formatCardCVC = function() { + this.payment('restrictNumeric'); + this.on('keypress', restrictCVC); + return this; + }; + + $.payment.fn.formatCardExpiry = function() { + this.payment('restrictNumeric'); + this.on('keypress', restrictExpiry); + this.on('keypress', formatExpiry); + this.on('keypress', formatForwardSlash); + this.on('keypress', formatForwardExpiry); + this.on('keydown', formatBackExpiry); + return this; + }; + + $.payment.fn.formatCardNumber = function() { + this.payment('restrictNumeric'); + this.on('keypress', restrictCardNumber); + this.on('keypress', formatCardNumber); + this.on('keydown', formatBackCardNumber); + this.on('keyup', setCardType); + this.on('paste', reFormatCardNumber); + return this; + }; + + $.payment.fn.restrictNumeric = function() { + this.on('keypress', restrictNumeric); + return this; + }; + + $.payment.fn.cardExpiryVal = function() { + return $.payment.cardExpiryVal($(this).val()); + }; + + $.payment.cardExpiryVal = function(value) { + var month, prefix, year, _ref; + value = value.replace(/\s/g, ''); + _ref = value.split('/', 2), month = _ref[0], year = _ref[1]; + if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) { + prefix = (new Date).getFullYear(); + prefix = prefix.toString().slice(0, 2); + year = prefix + year; + } + month = parseInt(month, 10); + year = parseInt(year, 10); + return { + month: month, + year: year + }; + }; + + $.payment.validateCardNumber = function(num) { + var card, _ref; + num = (num + '').replace(/\s+|-/g, ''); + if (!/^\d+$/.test(num)) { + return false; + } + card = cardFromNumber(num); + if (!card) { + return false; + } + return (_ref = num.length, __indexOf.call(card.length, _ref) >= 0) && (card.luhn === false || luhnCheck(num)); + }; + + $.payment.validateCardExpiry = function(month, year) { + var currentTime, expiry, prefix, _ref; + if (typeof month === 'object' && 'month' in month) { + _ref = month, month = _ref.month, year = _ref.year; + } + if (!(month && year)) { + return false; + } + month = $.trim(month); + year = $.trim(year); + if (!/^\d+$/.test(month)) { + return false; + } + if (!/^\d+$/.test(year)) { + return false; + } + if (!(parseInt(month, 10) <= 12)) { + return false; + } + if (year.length === 2) { + prefix = (new Date).getFullYear(); + prefix = prefix.toString().slice(0, 2); + year = prefix + year; + } + expiry = new Date(year, month); + currentTime = new Date; + expiry.setMonth(expiry.getMonth() - 1); + expiry.setMonth(expiry.getMonth() + 1, 1); + return expiry > currentTime; + }; + + $.payment.validateCardCVC = function(cvc, type) { + var _ref, _ref1; + cvc = $.trim(cvc); + if (!/^\d+$/.test(cvc)) { + return false; + } + if (type) { + return _ref = cvc.length, __indexOf.call((_ref1 = cardFromType(type)) != null ? _ref1.cvcLength : void 0, _ref) >= 0; + } else { + return cvc.length >= 3 && cvc.length <= 4; + } + }; + + $.payment.cardType = function(num) { + var _ref; + if (!num) { + return null; + } + return ((_ref = cardFromNumber(num)) != null ? _ref.type : void 0) || null; + }; + + $.payment.formatCardNumber = function(num) { + var card, groups, upperLength, _ref; + card = cardFromNumber(num); + if (!card) { + return num; + } + upperLength = card.length[card.length.length - 1]; + num = num.replace(/\D/g, ''); + num = num.slice(0, +upperLength + 1 || 9e9); + if (card.format.global) { + return (_ref = num.match(card.format)) != null ? _ref.join(' ') : void 0; + } else { + groups = card.format.exec(num); + if (groups != null) { + groups.shift(); + } + return groups != null ? groups.join(' ') : void 0; + } + }; + +}).call(this); diff --git a/addons/website_payment/static/src/css/Makefile b/addons/website_payment/static/src/css/Makefile new file mode 100644 index 00000000000..7f7f16d3616 --- /dev/null +++ b/addons/website_payment/static/src/css/Makefile @@ -0,0 +1,2 @@ +sass: + sass --trace -t expanded website_payment.sass:website_payment.css diff --git a/addons/website_payment/static/src/css/website_payment.css b/addons/website_payment/static/src/css/website_payment.css new file mode 100644 index 00000000000..e61696fcd30 --- /dev/null +++ b/addons/website_payment/static/src/css/website_payment.css @@ -0,0 +1,24 @@ +@charset "UTF-8"; + +input#cc_number { + background-image: url('/website_payment/static/src/img/grey-dots.png'); + background-repeat: no-repeat; + background-position: 14px 14px; +} + +div.card_placeholder { + background-image: url('/website_payment/static/src/img/placeholder.png'); + background-repeat: no-repeat; + width: 32px; + height: 20px; +} + +/*div.visa { + background-image: url('/website_payment/static/src/img/placeholder.png'); + background-repeat: no-repeat; + background-position: 14px 14px; +}*/ + +input#cc_number:active, input#cc_number:focus { + background-image: none; +} diff --git a/addons/website_payment/static/src/css/website_payment.sass b/addons/website_payment/static/src/css/website_payment.sass new file mode 100644 index 00000000000..d467df2de47 --- /dev/null +++ b/addons/website_payment/static/src/css/website_payment.sass @@ -0,0 +1,29 @@ +@charset "utf-8" + +@import "compass/css3" + +.css_website_mail + .has-error + border-color: red + .css_nav_month + display: none + &:first-of-type + display: block + +.blog_content + a.oe_mail_expand:after + content: " →" + a.oe_mail_expand + font-weight: bold + +p.post-meta + position: relative + top: -5px + +.js_website_blog + div#right_column + section + +opacity(0.6) + section:hover + +opacity(1) + @include transition(all 0.2s ease-out) diff --git a/addons/website_payment/static/src/img/amex.png b/addons/website_payment/static/src/img/amex.png new file mode 100644 index 00000000000..7de472cdd9b Binary files /dev/null and b/addons/website_payment/static/src/img/amex.png differ diff --git a/addons/website_payment/static/src/img/diners.png b/addons/website_payment/static/src/img/diners.png new file mode 100644 index 00000000000..93b909d1b33 Binary files /dev/null and b/addons/website_payment/static/src/img/diners.png differ diff --git a/addons/website_payment/static/src/img/discover.png b/addons/website_payment/static/src/img/discover.png new file mode 100644 index 00000000000..692bd76d403 Binary files /dev/null and b/addons/website_payment/static/src/img/discover.png differ diff --git a/addons/website_payment/static/src/img/grey-dots.png b/addons/website_payment/static/src/img/grey-dots.png new file mode 100644 index 00000000000..bf5391ef906 Binary files /dev/null and b/addons/website_payment/static/src/img/grey-dots.png differ diff --git a/addons/website_payment/static/src/img/jcb.png b/addons/website_payment/static/src/img/jcb.png new file mode 100644 index 00000000000..4160175eb5f Binary files /dev/null and b/addons/website_payment/static/src/img/jcb.png differ diff --git a/addons/website_payment/static/src/img/mastercard.png b/addons/website_payment/static/src/img/mastercard.png new file mode 100644 index 00000000000..b51a920d156 Binary files /dev/null and b/addons/website_payment/static/src/img/mastercard.png differ diff --git a/addons/website_payment/static/src/img/placeholder.png b/addons/website_payment/static/src/img/placeholder.png new file mode 100644 index 00000000000..665f42efba8 Binary files /dev/null and b/addons/website_payment/static/src/img/placeholder.png differ diff --git a/addons/website_payment/static/src/img/visa.png b/addons/website_payment/static/src/img/visa.png new file mode 100644 index 00000000000..0358fbf00b6 Binary files /dev/null and b/addons/website_payment/static/src/img/visa.png differ diff --git a/addons/website_payment/static/src/js/payment_acquirer.js b/addons/website_payment/static/src/js/payment_acquirer.js new file mode 100644 index 00000000000..0b0a2369c4e --- /dev/null +++ b/addons/website_payment/static/src/js/payment_acquirer.js @@ -0,0 +1,12 @@ +$(document).ready(function () { + + $('input#cc_number').payment('formatCardNumber'); + $('input#cc_cvc').payment('formatCardCVC'); + $('input#cc_expiry_mm').payment('restrictNumeric'); + $('input#cc_expiry_yy').payment('restrictNumeric'); + + $('input#cc_number').on('focusout', function (e) { + var valid_value = $.payment.validateCardNumber(this.value); + console.log('check: ', valid_value); + }); +}); diff --git a/addons/website_payment/views/website_payment_templates.xml b/addons/website_payment/views/website_payment_templates.xml index 924be2ed848..3201283dd5e 100644 --- a/addons/website_payment/views/website_payment_templates.xml +++ b/addons/website_payment/views/website_payment_templates.xml @@ -1,32 +1,79 @@ - + Paypal (Test) /payment/paypal/test - 50 + 90 - - + Ogone (Test) /payment/ogone/test - 50 + 91 + + + + Transfer (Test) + /payment/transfer/test + + 92 - + - + + +