summaryrefslogtreecommitdiff
path: root/addons/payment_stripe/static/src/js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/payment_stripe/static/src/js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/payment_stripe/static/src/js')
-rw-r--r--addons/payment_stripe/static/src/js/payment_form.js212
-rw-r--r--addons/payment_stripe/static/src/js/payment_processing.js48
-rw-r--r--addons/payment_stripe/static/src/js/stripe.js81
3 files changed, 341 insertions, 0 deletions
diff --git a/addons/payment_stripe/static/src/js/payment_form.js b/addons/payment_stripe/static/src/js/payment_form.js
new file mode 100644
index 00000000..4a11e289
--- /dev/null
+++ b/addons/payment_stripe/static/src/js/payment_form.js
@@ -0,0 +1,212 @@
+odoo.define('payment_stripe.payment_form', function (require) {
+"use strict";
+
+var ajax = require('web.ajax');
+var core = require('web.core');
+var Dialog = require('web.Dialog');
+var PaymentForm = require('payment.payment_form');
+
+var qweb = core.qweb;
+var _t = core._t;
+
+ajax.loadXML('/payment_stripe/static/src/xml/stripe_templates.xml', qweb);
+
+PaymentForm.include({
+
+ willStart: function () {
+ return this._super.apply(this, arguments).then(function () {
+ return ajax.loadJS("https://js.stripe.com/v3/");
+ })
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * called to create payment method object for credit card/debit card.
+ *
+ * @private
+ * @param {Object} stripe
+ * @param {Object} formData
+ * @param {Object} card
+ * @param {Boolean} addPmEvent
+ * @returns {Promise}
+ */
+ _createPaymentMethod: function (stripe, formData, card, addPmEvent) {
+ if (addPmEvent) {
+ return this._rpc({
+ route: '/payment/stripe/s2s/create_setup_intent',
+ params: {'acquirer_id': formData.acquirer_id}
+ }).then(function(intent_secret) {
+ return stripe.handleCardSetup(intent_secret, card);
+ });
+ } else {
+ return stripe.createPaymentMethod({
+ type: 'card',
+ card: card,
+ });
+ }
+ },
+
+ /**
+ * called when clicking on pay now or add payment event to create token for credit card/debit card.
+ *
+ * @private
+ * @param {Event} ev
+ * @param {DOMElement} checkedRadio
+ * @param {Boolean} addPmEvent
+ */
+ _createStripeToken: function (ev, $checkedRadio, addPmEvent) {
+ var self = this;
+ if (ev.type === 'submit') {
+ var button = $(ev.target).find('*[type="submit"]')[0]
+ } else {
+ var button = ev.target;
+ }
+ this.disableButton(button);
+ var acquirerID = this.getAcquirerIdFromRadio($checkedRadio);
+ var acquirerForm = this.$('#o_payment_add_token_acq_' + acquirerID);
+ var inputsForm = $('input', acquirerForm);
+ if (this.options.partnerId === undefined) {
+ console.warn('payment_form: unset partner_id when adding new token; things could go wrong');
+ }
+
+ var formData = self.getFormData(inputsForm);
+ var stripe = this.stripe;
+ var card = this.stripe_card_element;
+ if (card._invalid) {
+ return;
+ }
+ this._createPaymentMethod(stripe, formData, card, addPmEvent).then(function(result) {
+ if (result.error) {
+ return Promise.reject({"message": {"data": { "arguments": [result.error.message]}}});
+ } else {
+ const paymentMethod = addPmEvent ? result.setupIntent.payment_method : result.paymentMethod.id;
+ _.extend(formData, {"payment_method": paymentMethod});
+ return self._rpc({
+ route: formData.data_set,
+ params: formData,
+ });
+ }
+ }).then(function(result) {
+ if (addPmEvent) {
+ if (formData.return_url) {
+ window.location = formData.return_url;
+ } else {
+ window.location.reload();
+ }
+ } else {
+ $checkedRadio.val(result.id);
+ self.el.submit();
+ }
+ }).guardedCatch(function (error) {
+ // We don't want to open the Error dialog since
+ // we already have a container displaying the error
+ if (error.event) {
+ error.event.preventDefault();
+ }
+ // if the rpc fails, pretty obvious
+ self.enableButton(button);
+ self.displayError(
+ _t('Unable to save card'),
+ _t("We are not able to add your payment method at the moment. ") +
+ self._parseError(error)
+ );
+ });
+ },
+ /**
+ * called when clicking a Stripe radio if configured for s2s flow; instanciates the card and bind it to the widget.
+ *
+ * @private
+ * @param {DOMElement} checkedRadio
+ */
+ _bindStripeCard: function ($checkedRadio) {
+ var acquirerID = this.getAcquirerIdFromRadio($checkedRadio);
+ var acquirerForm = this.$('#o_payment_add_token_acq_' + acquirerID);
+ var inputsForm = $('input', acquirerForm);
+ var formData = this.getFormData(inputsForm);
+ var stripe = Stripe(formData.stripe_publishable_key);
+ var element = stripe.elements();
+ var card = element.create('card', {hidePostalCode: true});
+ card.mount('#card-element');
+ card.on('ready', function(ev) {
+ card.focus();
+ });
+ card.addEventListener('change', function (event) {
+ var displayError = document.getElementById('card-errors');
+ displayError.textContent = '';
+ if (event.error) {
+ displayError.textContent = event.error.message;
+ }
+ });
+ this.stripe = stripe;
+ this.stripe_card_element = card;
+ },
+ /**
+ * destroys the card element and any stripe instance linked to the widget.
+ *
+ * @private
+ */
+ _unbindStripeCard: function () {
+ if (this.stripe_card_element) {
+ this.stripe_card_element.destroy();
+ }
+ this.stripe = undefined;
+ this.stripe_card_element = undefined;
+ },
+ /**
+ * @override
+ */
+ updateNewPaymentDisplayStatus: function () {
+ var $checkedRadio = this.$('input[type="radio"]:checked');
+
+ if ($checkedRadio.length !== 1) {
+ return;
+ }
+ var provider = $checkedRadio.data('provider')
+ if (provider === 'stripe') {
+ // always re-init stripe (in case of multiple acquirers for stripe, make sure the stripe instance is using the right key)
+ this._unbindStripeCard();
+ if (this.isNewPaymentRadio($checkedRadio)) {
+ this._bindStripeCard($checkedRadio);
+ }
+ }
+ return this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ payEvent: function (ev) {
+ ev.preventDefault();
+ var $checkedRadio = this.$('input[type="radio"]:checked');
+
+ // first we check that the user has selected a stripe as s2s payment method
+ if ($checkedRadio.length === 1 && this.isNewPaymentRadio($checkedRadio) && $checkedRadio.data('provider') === 'stripe') {
+ return this._createStripeToken(ev, $checkedRadio);
+ } else {
+ return this._super.apply(this, arguments);
+ }
+ },
+ /**
+ * @override
+ */
+ addPmEvent: function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ var $checkedRadio = this.$('input[type="radio"]:checked');
+
+ // first we check that the user has selected a stripe as add payment method
+ if ($checkedRadio.length === 1 && this.isNewPaymentRadio($checkedRadio) && $checkedRadio.data('provider') === 'stripe') {
+ return this._createStripeToken(ev, $checkedRadio, true);
+ } else {
+ return this._super.apply(this, arguments);
+ }
+ },
+});
+});
diff --git a/addons/payment_stripe/static/src/js/payment_processing.js b/addons/payment_stripe/static/src/js/payment_processing.js
new file mode 100644
index 00000000..f98cd05a
--- /dev/null
+++ b/addons/payment_stripe/static/src/js/payment_processing.js
@@ -0,0 +1,48 @@
+odoo.define('payment_stripe.processing', function (require) {
+'use strict';
+
+var ajax = require('web.ajax');
+var rpc = require('web.rpc')
+var publicWidget = require('web.public.widget');
+
+var PaymentProcessing = publicWidget.registry.PaymentProcessing;
+
+return PaymentProcessing.include({
+ init: function () {
+ this._super.apply(this, arguments);
+ this._authInProgress = false;
+ },
+ willStart: function () {
+ return this._super.apply(this, arguments).then(function () {
+ return ajax.loadJS("https://js.stripe.com/v3/");
+ })
+ },
+ _stripeAuthenticate: function (tx) {
+ var stripe = Stripe(tx.stripe_publishable_key);
+ return stripe.handleCardPayment(tx.stripe_payment_intent_secret)
+ .then(function(result) {
+ if (result.error) {
+ return Promise.reject({"message": {"data": { "message": result.error.message}}});
+ }
+ return rpc.query({
+ route: '/payment/stripe/s2s/process_payment_intent',
+ params: _.extend({}, result.paymentIntent, {reference: tx.reference}),
+ });
+ }).then(function() {
+ window.location = '/payment/process';
+ }).guardedCatch(function () {
+ this._authInProgress = false;
+ });
+ },
+ processPolledData: function(transactions) {
+ this._super.apply(this, arguments);
+ for (var itx=0; itx < transactions.length; itx++) {
+ var tx = transactions[itx];
+ if (tx.acquirer_provider === 'stripe' && tx.state === 'pending' && tx.stripe_payment_intent_secret && !this._authInProgress) {
+ this._authInProgress = true;
+ this._stripeAuthenticate(tx);
+ }
+ }
+ },
+});
+}); \ No newline at end of file
diff --git a/addons/payment_stripe/static/src/js/stripe.js b/addons/payment_stripe/static/src/js/stripe.js
new file mode 100644
index 00000000..4868c9db
--- /dev/null
+++ b/addons/payment_stripe/static/src/js/stripe.js
@@ -0,0 +1,81 @@
+odoo.define('payment_stripe.stripe', function (require) {
+"use strict";
+
+var ajax = require('web.ajax');
+var core = require('web.core');
+
+var qweb = core.qweb;
+var _t = core._t;
+
+ajax.loadXML('/payment_stripe/static/src/xml/stripe_templates.xml', qweb);
+
+if ($.blockUI) {
+ // our message needs to appear above the modal dialog
+ $.blockUI.defaults.baseZ = 2147483647; //same z-index as StripeCheckout
+ $.blockUI.defaults.css.border = '0';
+ $.blockUI.defaults.css["background-color"] = '';
+ $.blockUI.defaults.overlayCSS["opacity"] = '0.9';
+}
+
+require('web.dom_ready');
+if (!$('.o_payment_form').length) {
+ return Promise.reject("DOM doesn't contain '.o_payment_form'");
+}
+
+var observer = new MutationObserver(function (mutations, observer) {
+ for (var i = 0; i < mutations.length; ++i) {
+ for (var j = 0; j < mutations[i].addedNodes.length; ++j) {
+ if (mutations[i].addedNodes[j].tagName.toLowerCase() === "form" && mutations[i].addedNodes[j].getAttribute('provider') === 'stripe') {
+ _redirectToStripeCheckout($(mutations[i].addedNodes[j]));
+ }
+ }
+ }
+});
+
+function displayError(message) {
+ var wizard = $(qweb.render('stripe.error', {'msg': message || _t('Payment error')}));
+ wizard.appendTo($('body')).modal({'keyboard': true});
+ if ($.blockUI) {
+ $.unblockUI();
+ }
+ $("#o_payment_form_pay").removeAttr('disabled');
+}
+
+
+function _redirectToStripeCheckout(providerForm) {
+ // Open Checkout with further options
+ if ($.blockUI) {
+ var msg = _t("Just one more second, We are redirecting you to Stripe...");
+ $.blockUI({
+ 'message': '<h2 class="text-white"><img src="/web/static/src/img/spin.png" class="fa-pulse"/>' +
+ ' <br />' + msg +
+ '</h2>'
+ });
+ }
+
+ var paymentForm = $('.o_payment_form');
+ if (!paymentForm.find('i').length) {
+ paymentForm.append('<i class="fa fa-spinner fa-spin"/>');
+ paymentForm.attr('disabled', 'disabled');
+ }
+
+ var _getStripeInputValue = function (name) {
+ return providerForm.find('input[name="' + name + '"]').val();
+ };
+
+ var stripe = Stripe(_getStripeInputValue('stripe_key'));
+
+ stripe.redirectToCheckout({
+ sessionId: _getStripeInputValue('session_id')
+ }).then(function (result) {
+ if (result.error) {
+ displayError(result.error.message);
+ }
+ });
+}
+
+$.getScript("https://js.stripe.com/v3/", function (data, textStatus, jqxhr) {
+ observer.observe(document.body, {childList: true});
+ _redirectToStripeCheckout($('form[provider="stripe"]'));
+});
+});