diff --git a/addons/account_payment/static/src/js/payment_form.js b/addons/account_payment/static/src/js/payment_form.js
index c15fffb386d..58f808a4976 100644
--- a/addons/account_payment/static/src/js/payment_form.js
+++ b/addons/account_payment/static/src/js/payment_form.js
@@ -1,33 +1,33 @@
/** @odoo-module **/
- import checkoutForm from "@payment/js/checkout_form";
- import manageForm from "@payment/js/manage_form";
+import checkoutForm from '@payment/js/checkout_form';
+import manageForm from '@payment/js/manage_form';
- const PaymentMixin = {
+const PaymentMixin = {
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- /**
- * Add `invoice_id` to the transaction route params if it is provided.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} code - The provider code of the selected payment option.
- * @param {number} paymentOptionId - The id of the selected payment option.
- * @param {string} flow - The online payment flow of the selected payment option.
- * @return {object} The extended transaction route params.
- */
- _prepareTransactionRouteParams: function (code, paymentOptionId, flow) {
- const transactionRouteParams = this._super(...arguments);
- return {
- ...transactionRouteParams,
- 'invoice_id': this.txContext.invoiceId ? parseInt(this.txContext.invoiceId) : null,
- };
- },
+ /**
+ * Add `invoice_id` to the transaction route params if it is provided.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} code - The provider code of the selected payment option.
+ * @param {number} paymentOptionId - The id of the selected payment option.
+ * @param {string} flow - The online payment flow of the selected payment option.
+ * @return {object} The extended transaction route params.
+ */
+ _prepareTransactionRouteParams: function (code, paymentOptionId, flow) {
+ const transactionRouteParams = this._super(...arguments);
+ return {
+ ...transactionRouteParams,
+ 'invoice_id': this.txContext.invoiceId ? parseInt(this.txContext.invoiceId) : null,
+ };
+ },
- };
+};
- checkoutForm.include(PaymentMixin);
- manageForm.include(PaymentMixin);
+checkoutForm.include(PaymentMixin);
+manageForm.include(PaymentMixin);
diff --git a/addons/payment/static/src/js/checkout_form.js b/addons/payment/static/src/js/checkout_form.js
index a1e89c1e2ae..32302fbc754 100644
--- a/addons/payment/static/src/js/checkout_form.js
+++ b/addons/payment/static/src/js/checkout_form.js
@@ -1,98 +1,98 @@
/** @odoo-module **/
- import publicWidget from "@web/legacy/js/public/public_widget";
+import publicWidget from '@web/legacy/js/public/public_widget';
+import paymentFormMixin from '@payment/js/payment_form_mixin';
+import { debounce } from '@web/core/utils/timing';
- import paymentFormMixin from "@payment/js/payment_form_mixin";
- import { debounce } from "@web/core/utils/timing";
+publicWidget.registry.PaymentCheckoutForm = publicWidget.Widget.extend(paymentFormMixin, {
+ selector: 'form[name="o_payment_checkout"]',
+ events: Object.assign({}, publicWidget.Widget.prototype.events, {
+ 'click div[name="o_payment_option_card"]': '_onClickPaymentOption',
+ 'click a[name="o_payment_icon_more"]': '_onClickMorePaymentIcons',
+ 'click a[name="o_payment_icon_less"]': '_onClickLessPaymentIcons',
+ 'click button[name="o_payment_submit_button"]': '_onClickPay',
+ 'submit': '_onSubmit',
+ }),
- publicWidget.registry.PaymentCheckoutForm = publicWidget.Widget.extend(paymentFormMixin, {
- selector: 'form[name="o_payment_checkout"]',
- events: Object.assign({}, publicWidget.Widget.prototype.events, {
- 'click div[name="o_payment_option_card"]': '_onClickPaymentOption',
- 'click a[name="o_payment_icon_more"]': '_onClickMorePaymentIcons',
- 'click a[name="o_payment_icon_less"]': '_onClickLessPaymentIcons',
- 'click button[name="o_payment_submit_button"]': '_onClickPay',
- 'submit': '_onSubmit',
- }),
+ /**
+ * @constructor
+ */
+ init: function () {
+ this.formType = 'checkout';
+ const preventDoubleClick = handlerMethod => {
+ return debounce(handlerMethod, 500, true);
+ };
+ this._super(...arguments);
+ // Prevent double-clicks and browser glitches on all inputs
+ this._onClickLessPaymentIcons = preventDoubleClick(this._onClickLessPaymentIcons);
+ this._onClickMorePaymentIcons = preventDoubleClick(this._onClickMorePaymentIcons);
+ this._onClickPay = preventDoubleClick(this._onClickPay);
+ this._onClickPaymentOption = preventDoubleClick(this._onClickPaymentOption);
+ this._onSubmit = preventDoubleClick(this._onSubmit);
+ },
- /**
- * @constructor
- */
- init: function () {
- this.formType = 'checkout';
- const preventDoubleClick = handlerMethod => {
- return debounce(handlerMethod, 500, true);
- };
- this._super(...arguments);
- // Prevent double-clicks and browser glitches on all inputs
- this._onClickLessPaymentIcons = preventDoubleClick(this._onClickLessPaymentIcons);
- this._onClickMorePaymentIcons = preventDoubleClick(this._onClickMorePaymentIcons);
- this._onClickPay = preventDoubleClick(this._onClickPay);
- this._onClickPaymentOption = preventDoubleClick(this._onClickPaymentOption);
- this._onSubmit = preventDoubleClick(this._onSubmit);
- },
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
+ /**
+ * Handle a direct payment, a payment with redirection, or a payment by token.
+ *
+ * Called when clicking on the 'Pay' button or when submitting the form.
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onClickPay: async function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
- /**
- * Handle a direct payment, a payment with redirection, or a payment by token.
- *
- * Called when clicking on the 'Pay' button or when submitting the form.
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onClickPay: async function (ev) {
- ev.stopPropagation();
- ev.preventDefault();
+ // Check that the user has selected a payment option
+ const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
+ if (!this._ensureRadioIsChecked($checkedRadios)) {
+ return;
+ }
+ const checkedRadio = $checkedRadios[0];
- // Check that the user has selected a payment option
- const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
- if (!this._ensureRadioIsChecked($checkedRadios)) {
- return;
- }
- const checkedRadio = $checkedRadios[0];
+ // Extract contextual values from the radio button
+ const provider = this._getProviderFromRadio(checkedRadio);
+ const paymentOptionId = this._getPaymentOptionIdFromRadio(checkedRadio);
+ const flow = this._getPaymentFlowFromRadio(checkedRadio);
- // Extract contextual values from the radio button
- const provider = this._getProviderFromRadio(checkedRadio);
- const paymentOptionId = this._getPaymentOptionIdFromRadio(checkedRadio);
- const flow = this._getPaymentFlowFromRadio(checkedRadio);
+ // Update the tx context with the value of the "Save my payment details" checkbox
+ if (flow !== 'token') {
+ const $inlineForm = this._getInlineFormFromRadio(checkedRadio);
+ const $tokenizeCheckbox = $inlineForm.find('input[name="o_payment_save_as_token"]');
+ this.txContext.tokenizationRequested = $tokenizeCheckbox.length === 1
+ && $tokenizeCheckbox[0].checked;
+ } else {
+ this.txContext.tokenizationRequested = false;
+ }
- // Update the tx context with the value of the "Save my payment details" checkbox
- if (flow !== 'token') {
- const $inlineForm = this._getInlineFormFromRadio(checkedRadio);
- const $tokenizeCheckbox = $inlineForm.find('input[name="o_payment_save_as_token"]');
- this.txContext.tokenizationRequested = $tokenizeCheckbox.length === 1
- && $tokenizeCheckbox[0].checked;
- } else {
- this.txContext.tokenizationRequested = false;
- }
+ // Make the payment
+ this._hideError(); // Don't keep the error displayed if the user is going through 3DS2
+ this._disableButton(true); // Disable until it is needed again
+ this.call('ui', 'block');
+ this._processPayment(provider, paymentOptionId, flow);
+ },
- // Make the payment
- this._hideError(); // Don't keep the error displayed if the user is going through 3DS2
- this._disableButton(true); // Disable until it is needed again
- this.call("ui", "block");
- this._processPayment(provider, paymentOptionId, flow);
- },
+ /**
+ * Delegate the handling of the payment request to `_onClickPay`.
+ *
+ * Called when submitting the form (e.g. through the Return key).
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onSubmit: function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
- /**
- * Delegate the handling of the payment request to `_onClickPay`.
- *
- * Called when submitting the form (e.g. through the Return key).
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onSubmit: function (ev) {
- ev.stopPropagation();
- ev.preventDefault();
+ this._onClickPay(ev);
+ },
- this._onClickPay(ev);
- },
+});
- });
- export default publicWidget.registry.PaymentCheckoutForm;
+export default publicWidget.registry.PaymentCheckoutForm;
diff --git a/addons/payment/static/src/js/express_checkout_form.js b/addons/payment/static/src/js/express_checkout_form.js
index 028364f94da..7d4e86b03ac 100644
--- a/addons/payment/static/src/js/express_checkout_form.js
+++ b/addons/payment/static/src/js/express_checkout_form.js
@@ -1,6 +1,6 @@
/** @odoo-module */
-import core from "@web/legacy/js/services/core";
+import core from '@web/legacy/js/services/core';
import publicWidget from '@web/legacy/js/public/public_widget';
publicWidget.registry.PaymentExpressCheckoutForm = publicWidget.Widget.extend({
diff --git a/addons/payment/static/src/js/manage_form.js b/addons/payment/static/src/js/manage_form.js
index f3182348cd1..ace737e3a38 100644
--- a/addons/payment/static/src/js/manage_form.js
+++ b/addons/payment/static/src/js/manage_form.js
@@ -1,224 +1,223 @@
/** @odoo-module **/
- import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
- import { renderToMarkup } from "@web/core/utils/render";
- import { _t } from "@web/core/l10n/translation";
- import publicWidget from "@web/legacy/js/public/public_widget";
+import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
+import { renderToMarkup } from "@web/core/utils/render";
+import { _t } from '@web/core/l10n/translation';
+import publicWidget from '@web/legacy/js/public/public_widget';
- import paymentFormMixin from "@payment/js/payment_form_mixin";
-import { debounce } from "@web/core/utils/timing";
+import paymentFormMixin from '@payment/js/payment_form_mixin';
+import { debounce } from '@web/core/utils/timing';
- publicWidget.registry.PaymentManageForm = publicWidget.Widget.extend(paymentFormMixin, {
- selector: 'form[name="o_payment_manage"]',
- events: Object.assign({}, publicWidget.Widget.prototype.events, {
- 'click div[name="o_payment_option_card"]': '_onClickPaymentOption',
- 'click a[name="o_payment_icon_more"]': '_onClickMorePaymentIcons',
- 'click a[name="o_payment_icon_less"]': '_onClickLessPaymentIcons',
- 'click button[name="o_payment_submit_button"]': '_onClickSaveToken',
- 'click button[name="o_payment_delete_token"]': '_onClickDeleteToken',
- 'submit': '_onSubmit',
- }),
+publicWidget.registry.PaymentManageForm = publicWidget.Widget.extend(paymentFormMixin, {
+ selector: 'form[name="o_payment_manage"]',
+ events: Object.assign({}, publicWidget.Widget.prototype.events, {
+ 'click div[name="o_payment_option_card"]': '_onClickPaymentOption',
+ 'click a[name="o_payment_icon_more"]': '_onClickMorePaymentIcons',
+ 'click a[name="o_payment_icon_less"]': '_onClickLessPaymentIcons',
+ 'click button[name="o_payment_submit_button"]': '_onClickSaveToken',
+ 'click button[name="o_payment_delete_token"]': '_onClickDeleteToken',
+ 'submit': '_onSubmit',
+ }),
- /**
- * @constructor
- */
- init: function () {
- this.formType = 'manage';
- const preventDoubleClick = handlerMethod => {
- return debounce(handlerMethod, 500, true);
- };
- this._super(...arguments);
- // Prevent double-clicks and browser glitches on all inputs
- this._onClickDeleteToken = preventDoubleClick(this._onClickDeleteToken);
- this._onClickLessPaymentIcons = preventDoubleClick(this._onClickLessPaymentIcons);
- this._onClickMorePaymentIcons = preventDoubleClick(this._onClickMorePaymentIcons);
- this._onClickPaymentOption = preventDoubleClick(this._onClickPaymentOption);
- this._onClickSaveToken = preventDoubleClick(this._onClickSaveToken);
- this._onSubmit = preventDoubleClick(this._onSubmit);
- },
+ /**
+ * @constructor
+ */
+ init: function () {
+ this.formType = 'manage';
+ const preventDoubleClick = handlerMethod => {
+ return debounce(handlerMethod, 500, true);
+ };
+ this._super(...arguments);
+ // Prevent double-clicks and browser glitches on all inputs
+ this._onClickDeleteToken = preventDoubleClick(this._onClickDeleteToken);
+ this._onClickLessPaymentIcons = preventDoubleClick(this._onClickLessPaymentIcons);
+ this._onClickMorePaymentIcons = preventDoubleClick(this._onClickMorePaymentIcons);
+ this._onClickPaymentOption = preventDoubleClick(this._onClickPaymentOption);
+ this._onClickSaveToken = preventDoubleClick(this._onClickSaveToken);
+ this._onSubmit = preventDoubleClick(this._onSubmit);
+ },
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- /**
- * Assign the token to a record.
- *
- * @private
- * @param {number} tokenId - The id of the token to assign
- * @return {undefined}
- */
- _assignToken: function (tokenId) {
- // Call the assign route to assign the token to a record
+ /**
+ * Assign the token to a record.
+ *
+ * @private
+ * @param {number} tokenId - The id of the token to assign
+ * @return {undefined}
+ */
+ _assignToken: function (tokenId) {
+ // Call the assign route to assign the token to a record
+ this._rpc({
+ route: this.txContext['assignTokenRoute'],
+ params: {
+ 'access_token': this.txContext.accessToken,
+ 'token_id': tokenId,
+ }
+ }).then(() => {
+ window.location = this.txContext['landingRoute'];
+ }).guardedCatch(error => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to save your payment method."),
+ error.message.data.message,
+ );
+ });
+ },
+
+ /**
+ * Build and open the confirmation dialog based on the linked records' information.
+ *
+ * @private
+ * @param {Array} linkedRecordsInfo - The list of information about linked records.
+ * @param confirmCallback - The callback method called when the user clicks on the confirmation
+ * button.
+ * @return {void}
+ */
+ _openConfirmationDialog: function (linkedRecordsInfo, confirmCallback) {
+ const body = renderToMarkup('payment.ManageFormConfirmationDialog', { linkedRecordsInfo });
+ this.call('dialog', 'add', ConfirmationDialog, {
+ title: _t("Warning!"),
+ body,
+ confirmLabel: _t("Confirm Deletion"),
+ confirm: confirmCallback,
+ cancel: () => {},
+ });
+ },
+
+ /**
+ * Search for documents linked to the token and ask the user for confirmation.
+ *
+ * If any such document is found, a confirmation dialog is shown.
+ *
+ * @private
+ * @param {number} tokenId - The id of the token to delete
+ * @return {undefined}
+ */
+ _deleteToken: function (tokenId) {
+ const execute = () => {
this._rpc({
- route: this.txContext.assignTokenRoute,
+ route: '/payment/archive_token',
params: {
- 'access_token': this.txContext.accessToken,
'token_id': tokenId,
- }
+ },
}).then(() => {
- window.location = this.txContext.landingRoute;
+ const $tokenCard = this.$(
+ `input[name="o_payment_radio"][data-payment-option-id="${tokenId}"]` +
+ `[data-payment-option-type="token"]`
+ ).closest('div[name="o_payment_option_card"]');
+ $tokenCard.siblings(`#o_payment_token_inline_manage_form_${tokenId}`).remove();
+ $tokenCard.remove();
+ this._disableButton(false);
}).guardedCatch(error => {
error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("We are not able to save your payment method."),
- error.message.data.message
- );
- });
- },
-
- /**
- * Build and open the confirmation dialog based on the linked records' information.
- *
- * @private
- * @param {Array} linkedRecordsInfo - The list of information about linked records.
- * @param confirmCallback - The callback method called when the user clicks on the
- * confirmation button.
- */
- _openConfirmationDialog: function (linkedRecordsInfo, confirmCallback) {
- const body = renderToMarkup(
- "payment.ManageFormConfirmationDialog",
- { linkedRecordsInfo }
- );
- this.call("dialog", "add", ConfirmationDialog, {
- title: _t("Warning!"),
- body,
- confirmLabel: _t("Confirm Deletion"),
- confirm: confirmCallback,
- cancel: () => {},
- });
- },
-
- /**
- * Search for documents linked to the token and ask the user for confirmation.
- *
- * If any such document is found, a confirmation dialog is shown.
- *
- * @private
- * @param {number} tokenId - The id of the token to delete
- * @return {undefined}
- */
- _deleteToken: function (tokenId) {
- const execute = () => {
- this._rpc({
- route: '/payment/archive_token',
- params: {
- 'token_id': tokenId,
- },
- }).then(() => {
- const $tokenCard = this.$(
- `input[name="o_payment_radio"][data-payment-option-id="${tokenId}"]` +
- `[data-payment-option-type="token"]`
- ).closest('div[name="o_payment_option_card"]');
- $tokenCard.siblings(`#o_payment_token_inline_manage_form_${tokenId}`).remove();
- $tokenCard.remove();
- this._disableButton(false);
- }).guardedCatch(error => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("We are not able to delete your payment method."),
- error.message.data.message
- );
- });
- };
-
- // Fetch documents linked to the token
- this._rpc({
- model: 'payment.token',
- method: 'get_linked_records_info',
- args: [tokenId],
- }).then(linkedRecordsInfo => {
- this._openConfirmationDialog(linkedRecordsInfo, execute);
- }).guardedCatch(error => {
this._displayError(
_t("Server Error"),
_t("We are not able to delete your payment method."),
- error.message.data.message
+ error.message.data.message,
);
});
- },
+ };
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
+ // Fetch documents linked to the token
+ this._rpc({
+ model: 'payment.token',
+ method: 'get_linked_records_info',
+ args: [tokenId],
+ }).then(linkedRecordsInfo => {
+ this._openConfirmationDialog(linkedRecordsInfo, execute);
+ }).guardedCatch(error => {
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to delete your payment method."),
+ error.message.data.message,
+ );
+ });
+ },
- /**
- * Find the radio button linked to the click 'Delete' button and trigger the token deletion.
- *
- * Let `_onClickPaymentOption` select the radio button and display the inline form.
- *
- * Called when clicking on the 'Delete' button of a token.
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onClickDeleteToken: function (ev) {
- ev.preventDefault();
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
- // Extract contextual values from the delete button
- const linkedRadio = $(ev.currentTarget).siblings().find('input[name="o_payment_radio"]')[0];
- const tokenId = this._getPaymentOptionIdFromRadio(linkedRadio);
+ /**
+ * Find the radio button linked to the click 'Delete' button and trigger the token deletion.
+ *
+ * Let `_onClickPaymentOption` select the radio button and display the inline form.
+ *
+ * Called when clicking on the 'Delete' button of a token.
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onClickDeleteToken: function (ev) {
+ ev.preventDefault();
- // Delete the token
- this._deleteToken(tokenId);
- },
+ // Extract contextual values from the delete button
+ const linkedRadio = $(ev.currentTarget).siblings().find('input[name="o_payment_radio"]')[0];
+ const tokenId = this._getPaymentOptionIdFromRadio(linkedRadio);
- /**
- * Handle the creation of a new token or the assignation of a token to a record.
- *
- * Called when clicking on the 'Save Payment Method' button of when submitting the form.
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onClickSaveToken: async function (ev) {
- ev.stopPropagation();
- ev.preventDefault();
+ // Delete the token
+ this._deleteToken(tokenId);
+ },
- // Check that the user has selected a payment option
- const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
- if (!this._ensureRadioIsChecked($checkedRadios)) {
- return;
- }
- const checkedRadio = $checkedRadios[0];
+ /**
+ * Handle the creation of a new token or the assignation of a token to a record.
+ *
+ * Called when clicking on the 'Save Payment Method' button of when submitting the form.
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onClickSaveToken: async function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
- // Extract contextual values from the radio button
- const provider = this._getProviderFromRadio(checkedRadio);
- const paymentOptionId = this._getPaymentOptionIdFromRadio(checkedRadio);
- const flow = this._getPaymentFlowFromRadio(checkedRadio);
+ // Check that the user has selected a payment option
+ const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
+ if (!this._ensureRadioIsChecked($checkedRadios)) {
+ return;
+ }
+ const checkedRadio = $checkedRadios[0];
- // Save the payment method
- this._hideError(); // Don't keep the error displayed if the user is going through 3DS2
- this._disableButton(true); // Disable until it is needed again
- this.call("ui", "block");
- if (flow !== 'token') { // Creation of a new token
- this.txContext.tokenizationRequested = true;
- this.txContext.isValidation = true;
- this._processPayment(provider, paymentOptionId, flow);
- } else if (this.txContext.allowTokenSelection) { // Assignation of a token to a record
- this._assignToken(paymentOptionId);
- }
- },
+ // Extract contextual values from the radio button
+ const provider = this._getProviderFromRadio(checkedRadio);
+ const paymentOptionId = this._getPaymentOptionIdFromRadio(checkedRadio);
+ const flow = this._getPaymentFlowFromRadio(checkedRadio);
- /**
- * Delegate the handling of the token to `_onClickSaveToken`.
- *
- * Called when submitting the form (e.g. through the Return key).
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onSubmit: function (ev) {
- ev.stopPropagation();
- ev.preventDefault();
+ // Save the payment method
+ this._hideError(); // Don't keep the error displayed if the user is going through 3DS2
+ this._disableButton(true); // Disable until it is needed again
+ this.call('ui', 'block');
+ if (flow !== 'token') { // Creation of a new token
+ this.txContext.tokenizationRequested = true;
+ this.txContext.isValidation = true;
+ this._processPayment(provider, paymentOptionId, flow);
+ } else if (this.txContext['allowTokenSelection']) { // Assignation of a token to a record
+ this._assignToken(paymentOptionId);
+ }
+ },
- this._onClickSaveToken(ev);
- },
+ /**
+ * Delegate the handling of the token to `_onClickSaveToken`.
+ *
+ * Called when submitting the form (e.g. through the Return key).
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onSubmit: function (ev) {
+ ev.stopPropagation();
+ ev.preventDefault();
- });
- export default publicWidget.registry.PaymentManageForm;
+ this._onClickSaveToken(ev);
+ },
+
+});
+
+export default publicWidget.registry.PaymentManageForm;
diff --git a/addons/payment/static/src/js/payment_form_mixin.js b/addons/payment/static/src/js/payment_form_mixin.js
index 1a9fd2b4180..a58a50f26c7 100644
--- a/addons/payment/static/src/js/payment_form_mixin.js
+++ b/addons/payment/static/src/js/payment_form_mixin.js
@@ -1,62 +1,63 @@
/** @odoo-module **/
- import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
- import { escape } from "@web/core/utils/strings";
- import core from "@web/legacy/js/services/core";
- import { _t } from "@web/core/l10n/translation";
+
+import { ConfirmationDialog } from '@web/core/confirmation_dialog/confirmation_dialog';
+import { escape } from '@web/core/utils/strings';
+import core from '@web/legacy/js/services/core';
+import { _t } from '@web/core/l10n/translation';
export default {
- /**
- * @override
- */
- start: async function () {
- this.txContext = {}; // Synchronously initialize txContext before any await.
- Object.assign(this.txContext, this.$el.data());
- await this._super(...arguments);
- window.addEventListener('pageshow', function (event) {
- if (event.persisted) {
- window.location.reload();
- }
- });
- this.$('[data-bs-toggle="tooltip"]').tooltip();
- const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
- if ($checkedRadios.length === 1) {
- const checkedRadio = $checkedRadios[0];
- this._displayInlineForm(checkedRadio);
- this._enableButton();
- } else {
- this._setPaymentFlow(); // Initialize the payment flow to let providers overwrite it
+ /**
+ * @override
+ */
+ start: async function () {
+ this.txContext = {}; // Synchronously initialize txContext before any await.
+ Object.assign(this.txContext, this.$el.data());
+ await this._super(...arguments);
+ window.addEventListener('pageshow', function (event) {
+ if (event.persisted) {
+ window.location.reload();
}
- // When a module wants to activate the button,
- // it must test its conditions and then call this bus.
- core.bus.on('enableButton', this, this._enableButton);
- },
+ });
+ this.$('[data-bs-toggle="tooltip"]').tooltip();
+ const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
+ if ($checkedRadios.length === 1) {
+ const checkedRadio = $checkedRadios[0];
+ this._displayInlineForm(checkedRadio);
+ this._enableButton();
+ } else {
+ this._setPaymentFlow(); // Initialize the payment flow to let providers overwrite it
+ }
+ // When a module wants to activate the button,
+ // it must test its conditions and then call this bus.
+ core.bus.on('enableButton', this, this._enableButton);
+ },
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- /**
- * Disable the submit button.
- *
- * The icons are updated to either show that an action is processing or that the button is
- * not ready, depending on the value of `showLoadingAnimation`.
- *
- * @private
- * @param {boolean} showLoadingAnimation - Whether a spinning loader should be shown
- * @return {undefined}
- */
- _disableButton(showLoadingAnimation = true) {
- const $submitButton = $('button[name="o_payment_submit_button"]');
- const iconClass = $submitButton.data('icon-class');
- $submitButton.attr('disabled', true);
- if (showLoadingAnimation) {
- $submitButton.find('i').removeClass(iconClass);
- $submitButton.prepend(
- ' '
- );
- }
- },
+ /**
+ * Disable the submit button.
+ *
+ * The icons are updated to either show that an action is processing or that the button is
+ * not ready, depending on the value of `showLoadingAnimation`.
+ *
+ * @private
+ * @param {boolean} showLoadingAnimation - Whether a spinning loader should be shown
+ * @return {undefined}
+ */
+ _disableButton(showLoadingAnimation = true) {
+ const $submitButton = $('button[name="o_payment_submit_button"]');
+ const iconClass = $submitButton.data('icon-class');
+ $submitButton.attr('disabled', true);
+ if (showLoadingAnimation) {
+ $submitButton.find('i').removeClass(iconClass);
+ $submitButton.prepend(
+ ' '
+ );
+ }
+ },
/**
* Display an error in the payment form.
@@ -69,485 +70,486 @@
* @param {string} title - The title of the error
* @param {string} description - The description of the error
* @param {string} error - The raw error message
+ * @return {void}
*/
_displayError: function (title, description = '', error = '') {
const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
if ($checkedRadios.length !== 1) { // Cannot find selected payment option, show dialog
- this.call("dialog", "add", ConfirmationDialog, {
+ this.call('dialog', 'add', ConfirmationDialog, {
title: _t("Error: %s", title),
- body: description || '',
+ body: description || "",
});
} else { // Show error in inline form
this._hideError(); // Remove any previous error
- // Build the html for the error
- let errorHtml = `
- ${escape(title)}`;
- if (description !== '') {
- errorHtml += `${escape(description)}`;
- }
- if (error !== '') {
- errorHtml += `${escape(error)}`;
- }
- errorHtml += '
';
-
- // Append error to inline form and center the page on the error
- const checkedRadio = $checkedRadios[0];
- const $inlineForm = this._getInlineFormFromRadio(checkedRadio);
- $inlineForm.removeClass('d-none'); // Show the inline form even if it was empty
- $inlineForm.append(errorHtml).find('div[name="o_payment_error"]')[0]
- .scrollIntoView({behavior: 'smooth', block: 'center'});
+ // Build the html for the error
+ let errorHtml = `
+ ${escape(title)}`;
+ if (description !== '') {
+ errorHtml += `${escape(description)}`;
}
- this._enableButton(); // Enable button back after it was disabled before processing
- this.call("ui", "unblock"); // The page is blocked at this point, unblock it
- },
-
- /**
- * Display the inline form of the selected payment option and hide others.
- *
- * @private
- * @param {HTMLInputElement} radio - The radio button linked to the payment option
- * @return {undefined}
- */
- _displayInlineForm: function (radio) {
- this._hideInlineForms(); // Collapse previously opened inline forms
- this._hideError(); // The error is only relevant until it is hidden with its inline form
- this._setPaymentFlow(); // Reset the payment flow to let providers overwrite it
-
- // Extract contextual values from the radio button
- const provider = this._getProviderFromRadio(radio);
- const paymentOptionId = this._getPaymentOptionIdFromRadio(radio);
- const flow = this._getPaymentFlowFromRadio(radio);
-
- // Prepare the inline form of the selected payment option and display it if not empty
- this._prepareInlineForm(provider, paymentOptionId, flow);
- const $inlineForm = this._getInlineFormFromRadio(radio);
- if ($inlineForm.children().length > 0) {
- $inlineForm.removeClass('d-none');
+ if (error !== '') {
+ errorHtml += `${escape(error)}`;
}
- },
+ errorHtml += '
';
- /**
- * Check if the submit button can be enabled and do it if so.
- *
- * The icons are updated to show that the button is ready.
- *
- * @private
- * @return {boolean} Whether the button was enabled.
- */
- _enableButton: function () {
- if (this._isButtonReady()) {
- const $submitButton = this.$('button[name="o_payment_submit_button"]');
- const iconClass = $submitButton.data('icon-class');
- $submitButton.attr('disabled', false);
- $submitButton.find('i').addClass(iconClass);
- $submitButton.find('span.o_loader').remove();
- return true;
- }
- return false;
- },
+ // Append error to inline form and center the page on the error
+ const checkedRadio = $checkedRadios[0];
+ const $inlineForm = this._getInlineFormFromRadio(checkedRadio);
+ $inlineForm.removeClass('d-none'); // Show the inline form even if it was empty
+ $inlineForm.append(errorHtml).find('div[name="o_payment_error"]')[0]
+ .scrollIntoView({behavior: 'smooth', block: 'center'});
+ }
+ this._enableButton(); // Enable button back after it was disabled before processing
+ this.call('ui', 'unblock'); // The page is blocked at this point, unblock it
+ },
- /**
- * Verify that exactly one radio button is checked and display an error otherwise.
- *
- * @private
- * @param {jQuery} $checkedRadios - The currently check radio buttons
- *
- * @return {boolean} Whether exactly one radio button among the provided radios is checked
- */
- _ensureRadioIsChecked: function ($checkedRadios) {
- if ($checkedRadios.length === 0) {
- this._displayError(
- _t("No payment option selected"),
- _t("Please select a payment option.")
- );
- return false;
- } else if ($checkedRadios.length > 1) {
- this._displayError(
- _t("Multiple payment options selected"),
- _t("Please select only one payment option.")
- );
- return false;
- }
+ /**
+ * Display the inline form of the selected payment option and hide others.
+ *
+ * @private
+ * @param {HTMLInputElement} radio - The radio button linked to the payment option
+ * @return {undefined}
+ */
+ _displayInlineForm: function (radio) {
+ this._hideInlineForms(); // Collapse previously opened inline forms
+ this._hideError(); // The error is only relevant until it is hidden with its inline form
+ this._setPaymentFlow(); // Reset the payment flow to let providers overwrite it
+
+ // Extract contextual values from the radio button
+ const provider = this._getProviderFromRadio(radio);
+ const paymentOptionId = this._getPaymentOptionIdFromRadio(radio);
+ const flow = this._getPaymentFlowFromRadio(radio);
+
+ // Prepare the inline form of the selected payment option and display it if not empty
+ this._prepareInlineForm(provider, paymentOptionId, flow);
+ const $inlineForm = this._getInlineFormFromRadio(radio);
+ if ($inlineForm.children().length > 0) {
+ $inlineForm.removeClass('d-none');
+ }
+ },
+
+ /**
+ * Check if the submit button can be enabled and do it if so.
+ *
+ * The icons are updated to show that the button is ready.
+ *
+ * @private
+ * @return {boolean} Whether the button was enabled.
+ */
+ _enableButton: function () {
+ if (this._isButtonReady()) {
+ const $submitButton = this.$('button[name="o_payment_submit_button"]');
+ const iconClass = $submitButton.data('icon-class');
+ $submitButton.attr('disabled', false);
+ $submitButton.find('i').addClass(iconClass);
+ $submitButton.find('span.o_loader').remove();
return true;
- },
+ }
+ return false;
+ },
- /**
- * Find and return the inline form of the selected payment option.
- *
- * @private
- * @param {HTMLInputElement} radio - The radio button linked to the payment option.
- * @return {jQuery} The inline form of the selected payment option.
- */
- _getInlineFormFromRadio: function (radio) {
- const paymentOptionId = this._getPaymentOptionIdFromRadio(radio);
- const paymentOptionType = $(radio).data('payment-option-type');
- const $inlineForm = this.$(
- `#o_payment_${paymentOptionType}_inline_${this.formType}_form_${paymentOptionId}`
+ /**
+ * Verify that exactly one radio button is checked and display an error otherwise.
+ *
+ * @private
+ * @param {jQuery} $checkedRadios - The currently check radio buttons
+ *
+ * @return {boolean} Whether exactly one radio button among the provided radios is checked
+ */
+ _ensureRadioIsChecked: function ($checkedRadios) {
+ if ($checkedRadios.length === 0) {
+ this._displayError(
+ _t("No payment option selected"),
+ _t("Please select a payment option.")
);
- return $inlineForm;
- },
-
- /**
- * Determine and return the online payment flow of the selected payment option.
- *
- * As some providers implement both the direct payment and the payment with redirection, the
- * flow cannot be inferred from the radio button only. The radio button only indicates
- * whether the payment option is a token. If not, the transaction context is looked up to
- * determine whether the flow is 'direct' or 'redirect'.
- *
- * @private
- * @param {HTMLInputElement} radio - The radio button linked to the payment option
- * @return {string} The flow of the selected payment option. redirect, direct or token.
- */
- _getPaymentFlowFromRadio: function (radio) {
- if (
- $(radio).data('payment-option-type') === 'token'
- || this.txContext.flow === 'token'
- ) {
- return 'token';
- } else if (this.txContext.flow === 'redirect') {
- return 'redirect';
- } else {
- return 'direct';
- }
- },
-
- /**
- * Determine and return the id of the selected payment option.
- *
- * @private
- * @param {HTMLInputElement} radio - The radio button linked to the payment option
- * @return {number} The provider id or the token id or of the payment option linked to the
- * radio button.
- */
- _getPaymentOptionIdFromRadio(radio) {
- return $(radio).data('payment-option-id');
- },
-
- /**
- * Determine and return the provider of the selected payment option.
- *
- * @private
- * @param {HTMLInputElement} radio - The radio button linked to the payment option
- * @return {number} The provider of the payment option linked to the radio button.
- */
- _getProviderFromRadio(radio) {
- return $(radio).data('provider');
- },
-
- /**
- * Remove the error in the inline form of the current widget.
- *
- * @private
- * @return {jQuery} The removed error
- */
- _hideError() {
- return this.$('div[name="o_payment_error"]').remove();
- },
-
- /**
- * Collapse all inline forms of the current widget.
- *
- * @private
- * @return {undefined}.
- */
- _hideInlineForms() {
- return this.$('[name="o_payment_inline_form"]').addClass('d-none');
- },
-
- /**
- * Hide the "Save my payment details" label and checkbox, and the submit button.
- *
- * The inputs should typically be hidden when the customer has to perform additional actions
- * in the inline form. All inputs are automatically shown again when the customer clicks on
- * another inline form.
- *
- * @private
- * @return {undefined}
- */
- _hideInputs: function () {
- const $submitButton = this.$('button[name="o_payment_submit_button"]');
- const $tokenizeCheckboxes = this.$('input[name="o_payment_save_as_token"]');
- $submitButton.addClass('d-none');
- $tokenizeCheckboxes.closest('label').addClass('d-none');
- },
-
- /**
- * Verify that the submit button is ready to be enabled.
- *
- * For a module to support a custom behavior for the submit button, it must override this
- * method and only return true if the result of this method is true and if nothing prevents
- * enabling the submit button for that custom behavior.
- *
- * @private
- *
- * @return {boolean} Whether the submit button can be enabled
- */
- _isButtonReady: function () {
- const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
- if ($checkedRadios.length === 1) {
- const checkedRadio = $checkedRadios[0];
- const flow = this._getPaymentFlowFromRadio(checkedRadio);
- return flow !== 'token' || this.txContext.allowTokenSelection;
- } else {
- return false;
- }
- },
-
- /**
- * Prepare the params to send to the transaction route.
- *
- * For a provider to overwrite generic params or to add provider-specific ones, it must
- * override this method and return the extended transaction route params.
- *
- * @private
- * @param {string} code - The code of the selected payment option provider
- * @param {number} paymentOptionId - The id of the selected payment option
- * @param {string} flow - The online payment flow of the selected payment option
- * @return {object} The transaction route params
- */
- _prepareTransactionRouteParams: function (code, paymentOptionId, flow) {
- return {
- 'payment_option_id': paymentOptionId,
- 'reference_prefix': this.txContext.referencePrefix !== undefined
- ? this.txContext.referencePrefix.toString() : null,
- 'amount': this.txContext.amount !== undefined
- ? parseFloat(this.txContext.amount) : null,
- 'currency_id': this.txContext.currencyId
- ? parseInt(this.txContext.currencyId) : null,
- 'partner_id': parseInt(this.txContext.partnerId),
- 'flow': flow,
- 'tokenization_requested': this.txContext.tokenizationRequested,
- 'landing_route': this.txContext.landingRoute,
- 'is_validation': this.txContext.isValidation,
- 'access_token': this.txContext.accessToken
- ? this.txContext.accessToken : undefined,
- 'csrf_token': odoo.csrf_token,
- };
- },
-
- /**
- * Prepare the provider-specific inline form of the selected payment option.
- *
- * For a provider to manage an inline form, it must override this method. When the override
- * is called, it must lookup the parameters to decide whether it is necessary to prepare its
- * inline form. Otherwise, the call must be sent back to the parent method.
- *
- * @private
- * @param {string} code - The code of the selected payment option's provider
- * @param {number} paymentOptionId - The id of the selected payment option
- * @param {string} flow - The online payment flow of the selected payment option
- * @return {Promise}
- */
- _prepareInlineForm(code, paymentOptionId, flow) {
- return Promise.resolve();
- },
-
- /**
- * Process the payment.
- *
- * For a provider to do pre-processing work on the transaction processing flow, or to
- * define its entire own flow that requires re-scheduling the RPC to the transaction route,
- * it must override this method.
- * If only post-processing work is needed, an override of `_processRedirectPayment`,
- * `_processDirectPayment` or `_processTokenPayment` might be more appropriate.
- *
- * @private
- * @param {string} code - The code of the payment option's provider
- * @param {number} paymentOptionId - The id of the payment option handling the transaction
- * @param {string} flow - The online payment flow of the transaction
- * @return {Promise}
- */
- _processPayment: function (code, paymentOptionId, flow) {
- // Call the transaction route to create a tx and retrieve the processing values
- return this._rpc({
- route: this.txContext.transactionRoute,
- params: this._prepareTransactionRouteParams(code, paymentOptionId, flow),
- }).then(processingValues => {
- if (flow === 'redirect') {
- return this._processRedirectPayment(
- code, paymentOptionId, processingValues
- );
- } else if (flow === 'direct') {
- return this._processDirectPayment(code, paymentOptionId, processingValues);
- } else if (flow === 'token') {
- return this._processTokenPayment(code, paymentOptionId, processingValues);
- }
- }).guardedCatch(error => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("We are not able to process your payment."),
- error.message.data.message
- );
- });
- },
-
- /**
- * Execute the provider-specific implementation of the direct payment flow.
- *
- * For a provider to redefine the processing of the direct payment flow, it must override
- * this method.
- *
- * @private
- * @param {string} code - The code of the provider
- * @param {number} providerId - The id of the provider handling the transaction
- * @param {object} processingValues - The processing values of the transaction
- * @return {Promise}
- */
- _processDirectPayment(code, providerId, processingValues) {
- return Promise.resolve();
- },
-
- /**
- * Redirect the customer by submitting the redirect form included in the processing values.
- *
- * For a provider to redefine the processing of the payment with redirection flow, it must
- * override this method.
- *
- * @private
- * @param {string} code - The code of the provider
- * @param {number} providerId - The id of the provider handling the transaction
- * @param {object} processingValues - The processing values of the transaction
- * @return {undefined}
- */
- _processRedirectPayment(code, providerId, processingValues) {
- // Append the redirect form to the body
- const $redirectForm = $(processingValues.redirect_form_html).attr(
- 'id', 'o_payment_redirect_form'
+ return false;
+ } else if ($checkedRadios.length > 1) {
+ this._displayError(
+ _t("Multiple payment options selected"),
+ _t("Please select only one payment option.")
);
- // Ensures external redirections when in an iframe.
- $redirectForm[0].setAttribute('target', '_top');
- $(document.getElementsByTagName('body')[0]).append($redirectForm);
+ return false;
+ }
+ return true;
+ },
- // Submit the form
- $redirectForm.submit();
- },
+ /**
+ * Find and return the inline form of the selected payment option.
+ *
+ * @private
+ * @param {HTMLInputElement} radio - The radio button linked to the payment option.
+ * @return {jQuery} The inline form of the selected payment option.
+ */
+ _getInlineFormFromRadio(radio) {
+ const paymentOptionId = this._getPaymentOptionIdFromRadio(radio);
+ const paymentOptionType = $(radio).data('payment-option-type');
+ const $inlineForm = this.$(
+ `#o_payment_${paymentOptionType}_inline_${this.formType}_form_${paymentOptionId}`
+ );
+ return $inlineForm;
+ },
- /**
- * Redirect the customer to the status route.
- *
- * For a provider to redefine the processing of the payment by token flow, it must override
- * this method.
- *
- * @private
- * @param {string} provider_code - The code of the token's provider
- * @param {number} tokenId - The id of the token handling the transaction
- * @param {object} processingValues - The processing values of the transaction
- * @return {undefined}
- */
- _processTokenPayment(provider_code, tokenId, processingValues) {
- // The flow is already completed as payments by tokens are immediately processed
- window.location = '/payment/status';
- },
+ /**
+ * Determine and return the online payment flow of the selected payment option.
+ *
+ * As some providers implement both the direct payment and the payment with redirection, the
+ * flow cannot be inferred from the radio button only. The radio button only indicates
+ * whether the payment option is a token. If not, the transaction context is looked up to
+ * determine whether the flow is 'direct' or 'redirect'.
+ *
+ * @private
+ * @param {HTMLInputElement} radio - The radio button linked to the payment option
+ * @return {string} The flow of the selected payment option. redirect, direct or token.
+ */
+ _getPaymentFlowFromRadio: function (radio) {
+ if (
+ $(radio).data('payment-option-type') === 'token'
+ || this.txContext.flow === 'token'
+ ) {
+ return 'token';
+ } else if (this.txContext.flow === 'redirect') {
+ return 'redirect';
+ } else {
+ return 'direct';
+ }
+ },
- /**
- * Set the online payment flow for the selected payment option.
- *
- * For a provider to manage direct payments, it must call this method from within its
- * override of `_prepareInlineForm` to declare its payment flow for the selected payment
- * option.
- *
- * @private
- * @param {string} flow - The flow for the selected payment option. Either 'redirect',
- * 'direct' or 'token'
- * @return {undefined}
- */
- _setPaymentFlow: function (flow = 'redirect') {
- if (flow !== 'redirect' && flow !== 'direct' && flow !== 'token') {
- console.warn(
- `payment_form_mixin: method '_setPaymentFlow' was called with invalid flow:
- ${flow}. Falling back to 'redirect'.`
+ /**
+ * Determine and return the id of the selected payment option.
+ *
+ * @private
+ * @param {HTMLInputElement} radio - The radio button linked to the payment option
+ * @return {number} The provider id or the token id or of the payment option linked to the
+ * radio button.
+ */
+ _getPaymentOptionIdFromRadio(radio) {
+ return $(radio).data('payment-option-id');
+ },
+
+ /**
+ * Determine and return the provider of the selected payment option.
+ *
+ * @private
+ * @param {HTMLInputElement} radio - The radio button linked to the payment option
+ * @return {number} The provider of the payment option linked to the radio button.
+ */
+ _getProviderFromRadio(radio) {
+ return $(radio).data('provider');
+ },
+
+ /**
+ * Remove the error in the inline form of the current widget.
+ *
+ * @private
+ * @return {jQuery} The removed error
+ */
+ _hideError() {
+ return this.$('div[name="o_payment_error"]').remove();
+ },
+
+ /**
+ * Collapse all inline forms of the current widget.
+ *
+ * @private
+ * @return {undefined}.
+ */
+ _hideInlineForms() {
+ return this.$('[name="o_payment_inline_form"]').addClass('d-none');
+ },
+
+ /**
+ * Hide the "Save my payment details" label and checkbox, and the submit button.
+ *
+ * The inputs should typically be hidden when the customer has to perform additional actions
+ * in the inline form. All inputs are automatically shown again when the customer clicks on
+ * another inline form.
+ *
+ * @private
+ * @return {undefined}
+ */
+ _hideInputs: function () {
+ const $submitButton = this.$('button[name="o_payment_submit_button"]');
+ const $tokenizeCheckboxes = this.$('input[name="o_payment_save_as_token"]');
+ $submitButton.addClass('d-none');
+ $tokenizeCheckboxes.closest('label').addClass('d-none');
+ },
+
+ /**
+ * Verify that the submit button is ready to be enabled.
+ *
+ * For a module to support a custom behavior for the submit button, it must override this
+ * method and only return true if the result of this method is true and if nothing prevents
+ * enabling the submit button for that custom behavior.
+ *
+ * @private
+ *
+ * @return {boolean} Whether the submit button can be enabled
+ */
+ _isButtonReady: function () {
+ const $checkedRadios = this.$('input[name="o_payment_radio"]:checked');
+ if ($checkedRadios.length === 1) {
+ const checkedRadio = $checkedRadios[0];
+ const flow = this._getPaymentFlowFromRadio(checkedRadio);
+ return flow !== 'token' || this.txContext['allowTokenSelection'];
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Prepare the params to send to the transaction route.
+ *
+ * For a provider to overwrite generic params or to add provider-specific ones, it must
+ * override this method and return the extended transaction route params.
+ *
+ * @private
+ * @param {string} code - The code of the selected payment option provider
+ * @param {number} paymentOptionId - The id of the selected payment option
+ * @param {string} flow - The online payment flow of the selected payment option
+ * @return {object} The transaction route params
+ */
+ _prepareTransactionRouteParams: function (code, paymentOptionId, flow) {
+ return {
+ 'payment_option_id': paymentOptionId,
+ 'reference_prefix': this.txContext['referencePrefix'] !== undefined
+ ? this.txContext['referencePrefix'].toString() : null,
+ 'amount': this.txContext.amount !== undefined
+ ? parseFloat(this.txContext.amount) : null,
+ 'currency_id': this.txContext.currencyId
+ ? parseInt(this.txContext.currencyId) : null,
+ 'partner_id': parseInt(this.txContext.partnerId),
+ 'flow': flow,
+ 'tokenization_requested': this.txContext.tokenizationRequested,
+ 'landing_route': this.txContext['landingRoute'],
+ 'is_validation': this.txContext.isValidation,
+ 'access_token': this.txContext.accessToken
+ ? this.txContext.accessToken : undefined,
+ 'csrf_token': odoo.csrf_token,
+ };
+ },
+
+ /**
+ * Prepare the provider-specific inline form of the selected payment option.
+ *
+ * For a provider to manage an inline form, it must override this method. When the override
+ * is called, it must lookup the parameters to decide whether it is necessary to prepare its
+ * inline form. Otherwise, the call must be sent back to the parent method.
+ *
+ * @private
+ * @param {string} code - The code of the selected payment option's provider
+ * @param {number} paymentOptionId - The id of the selected payment option
+ * @param {string} flow - The online payment flow of the selected payment option
+ * @return {Promise}
+ */
+ _prepareInlineForm(code, paymentOptionId, flow) {
+ return Promise.resolve();
+ },
+
+ /**
+ * Process the payment.
+ *
+ * For a provider to do pre-processing work on the transaction processing flow, or to
+ * define its entire own flow that requires re-scheduling the RPC to the transaction route,
+ * it must override this method.
+ * If only post-processing work is needed, an override of `_processRedirectPayment`,
+ * `_processDirectPayment` or `_processTokenPayment` might be more appropriate.
+ *
+ * @private
+ * @param {string} code - The code of the payment option's provider
+ * @param {number} paymentOptionId - The id of the payment option handling the transaction
+ * @param {string} flow - The online payment flow of the transaction
+ * @return {Promise}
+ */
+ _processPayment: function (code, paymentOptionId, flow) {
+ // Call the transaction route to create a tx and retrieve the processing values
+ return this._rpc({
+ route: this.txContext['transactionRoute'],
+ params: this._prepareTransactionRouteParams(code, paymentOptionId, flow),
+ }).then(processingValues => {
+ if (flow === 'redirect') {
+ return this._processRedirectPayment(
+ code, paymentOptionId, processingValues
);
- this.txContext.flow = 'redirect';
- } else {
- this.txContext.flow = flow;
+ } else if (flow === 'direct') {
+ return this._processDirectPayment(code, paymentOptionId, processingValues);
+ } else if (flow === 'token') {
+ return this._processTokenPayment(code, paymentOptionId, processingValues);
}
- },
+ }).guardedCatch(error => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to process your payment."),
+ error.message.data.message,
+ );
+ });
+ },
- /**
- * Show the "Save my payment details" label and checkbox, and the submit button.
- *
- * @private
- * @return {undefined}.
- */
- _showInputs: function () {
- const $submitButton = this.$('button[name="o_payment_submit_button"]');
- const $tokenizeCheckboxes = this.$('input[name="o_payment_save_as_token"]');
- $submitButton.removeClass('d-none');
- $tokenizeCheckboxes.closest('label').removeClass('d-none');
- },
+ /**
+ * Execute the provider-specific implementation of the direct payment flow.
+ *
+ * For a provider to redefine the processing of the direct payment flow, it must override
+ * this method.
+ *
+ * @private
+ * @param {string} code - The code of the provider
+ * @param {number} providerId - The id of the provider handling the transaction
+ * @param {object} processingValues - The processing values of the transaction
+ * @return {Promise}
+ */
+ _processDirectPayment(code, providerId, processingValues) {
+ return Promise.resolve();
+ },
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
+ /**
+ * Redirect the customer by submitting the redirect form included in the processing values.
+ *
+ * For a provider to redefine the processing of the payment with redirection flow, it must
+ * override this method.
+ *
+ * @private
+ * @param {string} code - The code of the provider
+ * @param {number} providerId - The id of the provider handling the transaction
+ * @param {object} processingValues - The processing values of the transaction
+ * @return {undefined}
+ */
+ _processRedirectPayment(code, providerId, processingValues) {
+ // Append the redirect form to the body
+ const $redirectForm = $(processingValues['redirect_form_html']).attr(
+ 'id', 'o_payment_redirect_form'
+ );
+ // Ensures external redirections when in an iframe.
+ $redirectForm[0].setAttribute('target', '_top');
+ $(document.getElementsByTagName('body')[0]).append($redirectForm);
- /**
- * Hide all extra payment method icons of the provider linked to the clicked button.
- *
- * Called when clicking on the "show less" button.
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onClickLessPaymentIcons(ev) {
- ev.preventDefault();
- ev.stopPropagation();
- // Hide the extra payment icons, and the "show less" button
- const $itemList = $(ev.currentTarget).parents('ul');
- const maxIconNumber = $itemList.data('max-icons-displayed');
- $itemList.children('li').slice(maxIconNumber).addClass('d-none');
- // Show the "show more" button
- $itemList.find('a[name="o_payment_icon_more"]').parents('li').removeClass('d-none');
- },
+ // Submit the form
+ $redirectForm.submit();
+ },
- /**
- * Display all the payment methods icons of the provider linked to the clicked button.
- *
- * Called when clicking on the "show more" button.
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onClickMorePaymentIcons(ev) {
- ev.preventDefault();
- ev.stopPropagation();
- // Display all the payment methods icons, and the "show less" button
- $(ev.currentTarget).parents('ul').children('li').removeClass('d-none');
- // Hide the "show more" button
- $(ev.currentTarget).parents('li').addClass('d-none');
- },
+ /**
+ * Redirect the customer to the status route.
+ *
+ * For a provider to redefine the processing of the payment by token flow, it must override
+ * this method.
+ *
+ * @private
+ * @param {string} provider_code - The code of the token's provider
+ * @param {number} tokenId - The id of the token handling the transaction
+ * @param {object} processingValues - The processing values of the transaction
+ * @return {undefined}
+ */
+ _processTokenPayment(provider_code, tokenId, processingValues) {
+ // The flow is already completed as payments by tokens are immediately processed
+ window.location = '/payment/status';
+ },
- /**
- * Mark the clicked card radio button as checked and open the inline form, if any.
- *
- * Called when clicking on the card of a payment option.
- *
- * @private
- * @param {Event} ev
- * @return {undefined}
- */
- _onClickPaymentOption: function (ev) {
- // Uncheck all radio buttons
- this.$('input[name="o_payment_radio"]').prop('checked', false);
- // Check radio button linked to selected payment option
- const checkedRadio = $(ev.currentTarget).find('input[name="o_payment_radio"]')[0];
- $(checkedRadio).prop('checked', true);
+ /**
+ * Set the online payment flow for the selected payment option.
+ *
+ * For a provider to manage direct payments, it must call this method from within its
+ * override of `_prepareInlineForm` to declare its payment flow for the selected payment
+ * option.
+ *
+ * @private
+ * @param {string} flow - The flow for the selected payment option. Either 'redirect',
+ * 'direct' or 'token'
+ * @return {undefined}
+ */
+ _setPaymentFlow: function (flow = 'redirect') {
+ if (flow !== 'redirect' && flow !== 'direct' && flow !== 'token') {
+ console.warn(
+ `payment_form_mixin: method '_setPaymentFlow' was called with invalid flow:
+ ${flow}. Falling back to 'redirect'.`
+ );
+ this.txContext.flow = 'redirect';
+ } else {
+ this.txContext.flow = flow;
+ }
+ },
- // Show the inputs in case they had been hidden
- this._showInputs();
+ /**
+ * Show the "Save my payment details" label and checkbox, and the submit button.
+ *
+ * @private
+ * @return {undefined}.
+ */
+ _showInputs: function () {
+ const $submitButton = this.$('button[name="o_payment_submit_button"]');
+ const $tokenizeCheckboxes = this.$('input[name="o_payment_save_as_token"]');
+ $submitButton.removeClass('d-none');
+ $tokenizeCheckboxes.closest('label').removeClass('d-none');
+ },
- // Disable the submit button while building the content
- this._disableButton(false);
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
- // Unfold and prepare the inline form of selected payment option
- this._displayInlineForm(checkedRadio);
+ /**
+ * Hide all extra payment method icons of the provider linked to the clicked button.
+ *
+ * Called when clicking on the "show less" button.
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onClickLessPaymentIcons(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ // Hide the extra payment icons, and the "show less" button
+ const $itemList = $(ev.currentTarget).parents('ul');
+ const maxIconNumber = $itemList.data('max-icons-displayed');
+ $itemList.children('li').slice(maxIconNumber).addClass('d-none');
+ // Show the "show more" button
+ $itemList.find('a[name="o_payment_icon_more"]').parents('li').removeClass('d-none');
+ },
- // Re-enable the submit button
- this._enableButton();
- },
+ /**
+ * Display all the payment methods icons of the provider linked to the clicked button.
+ *
+ * Called when clicking on the "show more" button.
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onClickMorePaymentIcons(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ // Display all the payment methods icons, and the "show less" button
+ $(ev.currentTarget).parents('ul').children('li').removeClass('d-none');
+ // Hide the "show more" button
+ $(ev.currentTarget).parents('li').addClass('d-none');
+ },
- };
+ /**
+ * Mark the clicked card radio button as checked and open the inline form, if any.
+ *
+ * Called when clicking on the card of a payment option.
+ *
+ * @private
+ * @param {Event} ev
+ * @return {undefined}
+ */
+ _onClickPaymentOption: function (ev) {
+ // Uncheck all radio buttons
+ this.$('input[name="o_payment_radio"]').prop('checked', false);
+ // Check radio button linked to selected payment option
+ const checkedRadio = $(ev.currentTarget).find('input[name="o_payment_radio"]')[0];
+ $(checkedRadio).prop('checked', true);
+
+ // Show the inputs in case they had been hidden
+ this._showInputs();
+
+ // Disable the submit button while building the content
+ this._disableButton(false);
+
+ // Unfold and prepare the inline form of selected payment option
+ this._displayInlineForm(checkedRadio);
+
+ // Re-enable the submit button
+ this._enableButton();
+ },
+
+};
diff --git a/addons/payment/static/src/js/post_processing.js b/addons/payment/static/src/js/post_processing.js
index c32908ac287..4254701cad1 100644
--- a/addons/payment/static/src/js/post_processing.js
+++ b/addons/payment/static/src/js/post_processing.js
@@ -1,9 +1,9 @@
/** @odoo-module **/
-import publicWidget from "@web/legacy/js/public/public_widget";
-import { renderToElement } from "@web/core/utils/render";
-import { markup } from "@odoo/owl";
-import { _t } from "@web/core/l10n/translation";
+ import publicWidget from '@web/legacy/js/public/public_widget';
+ import { renderToElement } from '@web/core/utils/render';
+ import { markup } from "@odoo/owl";
+ import { _t } from '@web/core/l10n/translation';
publicWidget.registry.PaymentPostProcessing = publicWidget.Widget.extend({
selector: 'div[name="o_payment_status"]',
diff --git a/addons/payment_adyen/static/src/js/payment_form.js b/addons/payment_adyen/static/src/js/payment_form.js
index 9bae59f8f69..4a4160fc993 100644
--- a/addons/payment_adyen/static/src/js/payment_form.js
+++ b/addons/payment_adyen/static/src/js/payment_form.js
@@ -1,219 +1,218 @@
/** @odoo-module **/
/* global AdyenCheckout */
- import { _t } from "@web/core/l10n/translation";
- import checkoutForm from "@payment/js/checkout_form";
- import manageForm from "@payment/js/manage_form";
+import { _t } from '@web/core/l10n/translation';
+import checkoutForm from '@payment/js/checkout_form';
+import manageForm from '@payment/js/manage_form';
- const adyenMixin = {
+const adyenMixin = {
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- /**
- * Handle the additional details event of the Adyen drop-in.
- *
- * @private
- * @param {object} state - The state of the drop-in
- * @param {object} dropin - The drop-in
- * @return {Promise}
- */
- _dropinOnAdditionalDetails: function (state, dropin) {
+ /**
+ * Handle the additional details event of the Adyen drop-in.
+ *
+ * @private
+ * @param {object} state - The state of the drop-in
+ * @param {object} dropin - The drop-in
+ * @return {Promise}
+ */
+ _dropinOnAdditionalDetails: function (state, dropin) {
+ return this._rpc({
+ route: '/payment/adyen/payment_details',
+ params: {
+ 'provider_id': dropin.providerId,
+ 'reference': this.adyenDropin.reference,
+ 'payment_details': state.data,
+ },
+ }).then(paymentDetails => {
+ if (paymentDetails.action) { // Additional action required from the shopper
+ dropin.handleAction(paymentDetails.action);
+ } else { // The payment reached a final state, redirect to the status page
+ window.location = '/payment/status';
+ }
+ }).guardedCatch((error) => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to process your payment."),
+ error.message.data.message,
+ );
+ });
+ },
+
+ /**
+ * Handle the error event of the Adyen drop-in.
+ *
+ * @private
+ * @param {object} error - The error in the drop-in
+ * @return {undefined}
+ */
+ _dropinOnError: function (error) {
+ if (!this.$('div[name="o_payment_error"]')) { // Don't replace a specific server error.
+ this._displayError(
+ _t("Incorrect Payment Details"),
+ _t("Please verify your payment details."),
+ );
+ } else {
+ this._enableButton();
+ this.call('ui', 'unblock');
+ }
+ },
+
+ /**
+ * Handle the submit event of the Adyen drop-in and initiate the payment.
+ *
+ * @private
+ * @param {object} state - The state of the drop-in
+ * @param {object} dropin - The drop-in
+ * @return {Promise}
+ */
+ _dropinOnSubmit: function (state, dropin) {
+ // Create the transaction and retrieve the processing values
+ return this._rpc({
+ route: this.txContext.transactionRoute,
+ params: this._prepareTransactionRouteParams('adyen', dropin.providerId, 'direct'),
+ }).then(processingValues => {
+ this.adyenDropin.reference = processingValues.reference; // Store final reference
+ // Initiate the payment
return this._rpc({
- route: '/payment/adyen/payment_details',
+ route: '/payment/adyen/payments',
params: {
'provider_id': dropin.providerId,
- 'reference': this.adyenDropin.reference,
- 'payment_details': state.data,
+ 'reference': processingValues.reference,
+ 'converted_amount': processingValues.converted_amount,
+ 'currency_id': processingValues.currency_id,
+ 'partner_id': processingValues.partner_id,
+ 'payment_method': state.data.paymentMethod,
+ 'access_token': processingValues.access_token,
+ 'browser_info': state.data.browserInfo,
},
- }).then(paymentDetails => {
- if (paymentDetails.action) { // Additional action required from the shopper
- dropin.handleAction(paymentDetails.action);
- } else { // The payment reached a final state, redirect to the status page
- window.location = '/payment/status';
- }
- }).guardedCatch((error) => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("We are not able to process your payment."),
- error.message.data.message
- );
});
- },
-
- /**
- * Handle the error event of the Adyen drop-in.
- *
- * @private
- * @param {object} error - The error in the drop-in
- * @return {undefined}
- */
- _dropinOnError: function (error) {
- if (!this.$('div[name="o_payment_error"]')) { // Don't replace a specific server error.
- this._displayError(
- _t("Incorrect Payment Details"),
- _t("Please verify your payment details.")
- );
+ }).then(paymentResponse => {
+ if (paymentResponse.action) { // Additional action required from the shopper
+ this._hideInputs(); // Only the inputs of the inline form should be used
+ this.call('ui', 'unblock'); // The page is blocked at this point, unblock it
+ dropin.handleAction(paymentResponse.action);
+ } else { // The payment reached a final state, redirect to the status page
+ window.location = '/payment/status';
}
- else {
- this._enableButton();
- this.call("ui", "unblock");
- }
- },
+ }).guardedCatch((error) => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to process your payment."),
+ error.message.data.message,
+ );
+ });
+ },
- /**
- * Handle the submit event of the Adyen drop-in and initiate the payment.
- *
- * @private
- * @param {object} state - The state of the drop-in
- * @param {object} dropin - The drop-in
- * @return {Promise}
- */
- _dropinOnSubmit: function (state, dropin) {
- // Create the transaction and retrieve the processing values
+ /**
+ * Prepare the inline form of Adyen for direct payment.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} code - The code of the selected payment option's provider
+ * @param {number} paymentOptionId - The id of the selected payment option
+ * @param {string} flow - The online payment flow of the selected payment option
+ * @return {Promise}
+ */
+ _prepareInlineForm: function (code, paymentOptionId, flow) {
+ if (code !== 'adyen') {
+ return this._super(...arguments);
+ }
+
+ // Check if instantiation of the drop-in is needed
+ if (flow === 'token') {
+ return Promise.resolve(); // No drop-in for tokens
+ } else if (this.adyenDropin && this.adyenDropin.providerId === paymentOptionId) {
+ this._setPaymentFlow('direct'); // Overwrite the flow even if no re-instantiation
+ return Promise.resolve(); // Don't re-instantiate if already done for this provider
+ }
+
+ // Overwrite the flow of the select payment option
+ this._setPaymentFlow('direct');
+
+ // Get public information on the provider (state, client_key)
+ return this._rpc({
+ route: '/payment/adyen/provider_info',
+ params: {
+ 'provider_id': paymentOptionId,
+ },
+ }).then(providerInfo => {
+ // Get the available payment methods
return this._rpc({
- route: this.txContext.transactionRoute,
- params: this._prepareTransactionRouteParams('adyen', dropin.providerId, 'direct'),
- }).then(processingValues => {
- this.adyenDropin.reference = processingValues.reference; // Store final reference
- // Initiate the payment
- return this._rpc({
- route: '/payment/adyen/payments',
- params: {
- 'provider_id': dropin.providerId,
- 'reference': processingValues.reference,
- 'converted_amount': processingValues.converted_amount,
- 'currency_id': processingValues.currency_id,
- 'partner_id': processingValues.partner_id,
- 'payment_method': state.data.paymentMethod,
- 'access_token': processingValues.access_token,
- 'browser_info': state.data.browserInfo,
- },
- });
- }).then(paymentResponse => {
- if (paymentResponse.action) { // Additional action required from the shopper
- this._hideInputs(); // Only the inputs of the inline form should be used
- this.call("ui", "unblock"); // The page is blocked at this point, unblock it
- dropin.handleAction(paymentResponse.action);
- } else { // The payment reached a final state, redirect to the status page
- window.location = '/payment/status';
- }
- }).guardedCatch((error) => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("We are not able to process your payment."),
- error.message.data.message
- );
- });
- },
-
- /**
- * Prepare the inline form of Adyen for direct payment.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} code - The code of the selected payment option's provider
- * @param {number} paymentOptionId - The id of the selected payment option
- * @param {string} flow - The online payment flow of the selected payment option
- * @return {Promise}
- */
- _prepareInlineForm: function (code, paymentOptionId, flow) {
- if (code !== 'adyen') {
- return this._super(...arguments);
- }
-
- // Check if instantiation of the drop-in is needed
- if (flow === 'token') {
- return Promise.resolve(); // No drop-in for tokens
- } else if (this.adyenDropin && this.adyenDropin.providerId === paymentOptionId) {
- this._setPaymentFlow('direct'); // Overwrite the flow even if no re-instantiation
- return Promise.resolve(); // Don't re-instantiate if already done for this provider
- }
-
- // Overwrite the flow of the select payment option
- this._setPaymentFlow('direct');
-
- // Get public information on the provider (state, client_key)
- return this._rpc({
- route: '/payment/adyen/provider_info',
+ route: '/payment/adyen/payment_methods',
params: {
'provider_id': paymentOptionId,
+ 'partner_id': parseInt(this.txContext.partnerId),
+ 'amount': this.txContext.amount
+ ? parseFloat(this.txContext.amount)
+ : undefined,
+ 'currency_id': this.txContext.currencyId
+ ? parseInt(this.txContext.currencyId)
+ : undefined,
},
- }).then(providerInfo => {
- // Get the available payment methods
- return this._rpc({
- route: '/payment/adyen/payment_methods',
- params: {
- 'provider_id': paymentOptionId,
- 'partner_id': parseInt(this.txContext.partnerId),
- 'amount': this.txContext.amount
- ? parseFloat(this.txContext.amount)
- : undefined,
- 'currency_id': this.txContext.currencyId
- ? parseInt(this.txContext.currencyId)
- : undefined,
+ }).then(paymentMethodsResult => {
+ // Instantiate the drop-in
+ const configuration = {
+ paymentMethodsResponse: paymentMethodsResult,
+ clientKey: providerInfo.client_key,
+ locale: (this._getContext().lang || 'en-US').replace('_', '-'),
+ environment: providerInfo.state === 'enabled' ? 'live' : 'test',
+ onAdditionalDetails: this._dropinOnAdditionalDetails.bind(this),
+ onError: this._dropinOnError.bind(this),
+ onSubmit: this._dropinOnSubmit.bind(this),
+ };
+ const checkout = new AdyenCheckout(configuration);
+ this.adyenDropin = checkout.create(
+ 'dropin', {
+ openFirstPaymentMethod: true,
+ openFirstStoredPaymentMethod: false,
+ showStoredPaymentMethods: false,
+ showPaymentMethods: true,
+ showPayButton: false,
+ setStatusAutomatically: true,
},
- }).then(paymentMethodsResult => {
- // Instantiate the drop-in
- const configuration = {
- paymentMethodsResponse: paymentMethodsResult,
- clientKey: providerInfo.client_key,
- locale: (this._getContext().lang || 'en-US').replace('_', '-'),
- environment: providerInfo.state === 'enabled' ? 'live' : 'test',
- onAdditionalDetails: this._dropinOnAdditionalDetails.bind(this),
- onError: this._dropinOnError.bind(this),
- onSubmit: this._dropinOnSubmit.bind(this),
- };
- const checkout = new AdyenCheckout(configuration);
- this.adyenDropin = checkout.create(
- 'dropin', {
- openFirstPaymentMethod: true,
- openFirstStoredPaymentMethod: false,
- showStoredPaymentMethods: false,
- showPaymentMethods: true,
- showPayButton: false,
- setStatusAutomatically: true,
- },
- ).mount(`#o_adyen_${this.formType}_dropin_container_${paymentOptionId}`);
- this.adyenDropin.providerId = paymentOptionId;
- });
- }).guardedCatch((error) => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("An error occurred when displayed this payment form."),
- error.message.data.message
- );
+ ).mount(`#o_adyen_${this.formType}_dropin_container_${paymentOptionId}`);
+ this.adyenDropin.providerId = paymentOptionId;
});
- },
+ }).guardedCatch((error) => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("An error occurred when displayed this payment form."),
+ error.message.data.message,
+ );
+ });
+ },
- /**
- * Trigger the payment processing by submitting the drop-in.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} provider - The provider of the payment option's provider
- * @param {number} paymentOptionId - The id of the payment option handling the transaction
- * @param {string} flow - The online payment flow of the transaction
- * @return {Promise}
- */
- async _processPayment(provider, paymentOptionId, flow) {
- if (provider !== 'adyen' || flow === 'token') {
- return this._super(...arguments); // Tokens are handled by the generic flow
- }
- if (this.adyenDropin === undefined) { // The drop-in has not been properly instantiated
- this._displayError(
- _t("Server Error"), _t("We are not able to process your payment.")
- );
- } else {
- return await this.adyenDropin.submit();
- }
- },
+ /**
+ * Trigger the payment processing by submitting the drop-in.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} provider - The provider of the payment option's provider
+ * @param {number} paymentOptionId - The id of the payment option handling the transaction
+ * @param {string} flow - The online payment flow of the transaction
+ * @return {Promise}
+ */
+ async _processPayment(provider, paymentOptionId, flow) {
+ if (provider !== 'adyen' || flow === 'token') {
+ return this._super(...arguments); // Tokens are handled by the generic flow
+ }
+ if (this.adyenDropin === undefined) { // The drop-in has not been properly instantiated
+ this._displayError(
+ _t("Server Error"), _t("We are not able to process your payment.")
+ );
+ } else {
+ return await this.adyenDropin.submit();
+ }
+ },
- };
+};
- checkoutForm.include(adyenMixin);
- manageForm.include(adyenMixin);
+checkoutForm.include(adyenMixin);
+manageForm.include(adyenMixin);
diff --git a/addons/payment_authorize/static/src/js/payment_form.js b/addons/payment_authorize/static/src/js/payment_form.js
index e0dcacbf092..d36f53a442b 100644
--- a/addons/payment_authorize/static/src/js/payment_form.js
+++ b/addons/payment_authorize/static/src/js/payment_form.js
@@ -1,209 +1,209 @@
/** @odoo-module **/
/* global Accept */
- import { _t } from "@web/core/l10n/translation";
- import { loadJS } from "@web/core/assets";
+import { _t } from '@web/core/l10n/translation';
+import { loadJS } from '@web/core/assets';
- import checkoutForm from "@payment/js/checkout_form";
- import manageForm from "@payment/js/manage_form";
+import checkoutForm from '@payment/js/checkout_form';
+import manageForm from '@payment/js/manage_form';
- const authorizeMixin = {
+const authorizeMixin = {
- /**
- * Return all relevant inline form inputs based on the payment method type of the provider.
- *
- * @private
- * @param {number} providerId - The id of the selected provider
- * @return {Object} - An object mapping the name of inline form inputs to their DOM element
- */
- _getInlineFormInputs: function (providerId) {
- if (this.authorizeInfo.payment_method_type === "credit_card") {
- return {
- card: this.el.querySelector(`#o_authorize_card_${providerId}`),
- month: this.el.querySelector(`#o_authorize_month_${providerId}`),
- year: this.el.querySelector(`#o_authorize_year_${providerId}`),
- code: this.el.querySelector(`#o_authorize_code_${providerId}`),
- };
- } else {
- return {
- accountName: this.el.querySelector(`#o_authorize_account_name_${providerId}`),
- accountNumber: this.el.querySelector(
- `#o_authorize_account_number_${providerId}`
- ),
- abaNumber: this.el.querySelector(`#o_authorize_aba_number_${providerId}`),
- accountType: this.el.querySelector(`#o_authorize_account_type_${providerId}`),
- };
- }
- },
-
- /**
- * Return the credit card or bank data to pass to the Accept.dispatch request.
- *
- * @private
- * @param {number} providerId - The id of the selected provider
- * @return {Object} - Data to pass to the Accept.dispatch request
- */
- _getPaymentDetails: function (providerId) {
- const inputs = this._getInlineFormInputs(providerId);
- if (this.authorizeInfo.payment_method_type === 'credit_card') {
- return {
- cardData: {
- cardNumber: inputs.card.value.replace(/ /g, ''), // Remove all spaces
- month: inputs.month.value,
- year: inputs.year.value,
- cardCode: inputs.code.value,
- },
- };
- } else {
- return {
- bankData: {
- nameOnAccount: inputs.accountName.value.substring(0, 22), // Max allowed by acceptjs
- accountNumber: inputs.accountNumber.value,
- routingNumber: inputs.abaNumber.value,
- accountType: inputs.accountType.value,
- },
- };
- }
- },
-
- /**
- * Prepare the inline form of Authorize.Net for direct payment.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} provider - The provider of the selected payment option's provider
- * @param {number} paymentOptionId - The id of the selected payment option
- * @param {string} flow - The online payment flow of the selected payment option
- * @return {Promise}
- */
- _prepareInlineForm: function (code, paymentOptionId, flow) {
- if (code !== 'authorize') {
- return this._super(...arguments);
- }
-
- if (flow === 'token') {
- return Promise.resolve(); // Don't show the form for tokens
- }
-
- this._setPaymentFlow('direct');
-
- let acceptJSUrl = 'https://js.authorize.net/v1/Accept.js';
- return this._rpc({
- route: '/payment/authorize/get_provider_info',
- params: {
- 'provider_id': paymentOptionId,
- },
- }).then(providerInfo => {
- if (providerInfo.state !== 'enabled') {
- acceptJSUrl = 'https://jstest.authorize.net/v1/Accept.js';
- }
- this.authorizeInfo = providerInfo;
- }).then(() => {
- loadJS(acceptJSUrl);
- }).guardedCatch((error) => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("An error occurred when displayed this payment form."),
- error.message.data.message
- );
- });
- },
-
- /**
- * Dispatch the secure data to Authorize.Net.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} code - The code of the payment option's provider
- * @param {number} paymentOptionId - The id of the payment option handling the transaction
- * @param {string} flow - The online payment flow of the transaction
- * @return {Promise}
- */
- _processPayment: function (code, paymentOptionId, flow) {
- if (code !== 'authorize' || flow === 'token') {
- return this._super(...arguments); // Tokens are handled by the generic flow
- }
-
- if (!this._validateFormInputs(paymentOptionId)) {
- this._enableButton(); // The submit button is disabled at this point, enable it
- this.call("ui", "unblock"); // The page is blocked at this point, unblock it
- return Promise.resolve();
- }
-
- // Build the authentication and card data objects to be dispatched to Authorized.Net
- const secureData = {
- authData: {
- apiLoginID: this.authorizeInfo.login_id,
- clientKey: this.authorizeInfo.client_key,
- },
- ...this._getPaymentDetails(paymentOptionId),
+ /**
+ * Return all relevant inline form inputs based on the payment method type of the provider.
+ *
+ * @private
+ * @param {number} providerId - The id of the selected provider
+ * @return {Object} - An object mapping the name of inline form inputs to their DOM element
+ */
+ _getInlineFormInputs: function (providerId) {
+ if (this.authorizeInfo['payment_method_type'] === 'credit_card') {
+ return {
+ card: this.el.querySelector(`#o_authorize_card_${providerId}`),
+ month: this.el.querySelector(`#o_authorize_month_${providerId}`),
+ year: this.el.querySelector(`#o_authorize_year_${providerId}`),
+ code: this.el.querySelector(`#o_authorize_code_${providerId}`),
};
+ } else {
+ return {
+ accountName: this.el.querySelector(`#o_authorize_account_name_${providerId}`),
+ accountNumber: this.el.querySelector(
+ `#o_authorize_account_number_${providerId}`
+ ),
+ abaNumber: this.el.querySelector(`#o_authorize_aba_number_${providerId}`),
+ accountType: this.el.querySelector(`#o_authorize_account_type_${providerId}`),
+ };
+ }
+ },
- // Dispatch secure data to Authorize.Net to get a payment nonce in return
- return Accept.dispatchData(
- secureData, response => this._responseHandler(paymentOptionId, response)
- );
- },
+ /**
+ * Return the credit card or bank data to pass to the Accept.dispatch request.
+ *
+ * @private
+ * @param {number} providerId - The id of the selected provider
+ * @return {Object} - Data to pass to the Accept.dispatch request
+ */
+ _getPaymentDetails: function (providerId) {
+ const inputs = this._getInlineFormInputs(providerId);
+ if (this.authorizeInfo['payment_method_type'] === 'credit_card') {
+ return {
+ cardData: {
+ cardNumber: inputs.card.value.replace(/ /g, ''), // Remove all spaces
+ month: inputs.month.value,
+ year: inputs.year.value,
+ cardCode: inputs.code.value,
+ },
+ };
+ } else {
+ return {
+ bankData: {
+ nameOnAccount: inputs.accountName.value.substring(0, 22), // Max allowed by acceptjs
+ accountNumber: inputs.accountNumber.value,
+ routingNumber: inputs.abaNumber.value,
+ accountType: inputs.accountType.value,
+ },
+ };
+ }
+ },
- /**
- * Handle the response from Authorize.Net and initiate the payment.
- *
- * @private
- * @param {number} providerId - The id of the selected provider
- * @param {object} response - The payment nonce returned by Authorized.Net
- * @return {Promise}
- */
- _responseHandler: function (providerId, response) {
- if (response.messages.resultCode === 'Error') {
- let error = "";
- response.messages.message.forEach(msg => error += `${msg.code}: ${msg.text}\n`);
- this._displayError(
- _t("Server Error"),
- _t("We are not able to process your payment."),
- error
- );
- return Promise.resolve();
+ /**
+ * Prepare the inline form of Authorize.Net for direct payment.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} provider - The provider of the selected payment option's provider
+ * @param {number} paymentOptionId - The id of the selected payment option
+ * @param {string} flow - The online payment flow of the selected payment option
+ * @return {Promise}
+ */
+ _prepareInlineForm: function (code, paymentOptionId, flow) {
+ if (code !== 'authorize') {
+ return this._super(...arguments);
+ }
+
+ if (flow === 'token') {
+ return Promise.resolve(); // Don't show the form for tokens
+ }
+
+ this._setPaymentFlow('direct');
+
+ let acceptJSUrl = 'https://js.authorize.net/v1/Accept.js';
+ return this._rpc({
+ route: '/payment/authorize/get_provider_info',
+ params: {
+ 'provider_id': paymentOptionId,
+ },
+ }).then(providerInfo => {
+ if (providerInfo.state !== 'enabled') {
+ acceptJSUrl = 'https://jstest.authorize.net/v1/Accept.js';
}
+ this.authorizeInfo = providerInfo;
+ }).then(() => {
+ loadJS(acceptJSUrl);
+ }).guardedCatch((error) => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("An error occurred when displayed this payment form."),
+ error.message.data.message,
+ );
+ });
+ },
- // Create the transaction and retrieve the processing values
+ /**
+ * Dispatch the secure data to Authorize.Net.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} code - The code of the payment option's provider
+ * @param {number} paymentOptionId - The id of the payment option handling the transaction
+ * @param {string} flow - The online payment flow of the transaction
+ * @return {Promise}
+ */
+ _processPayment: function (code, paymentOptionId, flow) {
+ if (code !== 'authorize' || flow === 'token') {
+ return this._super(...arguments); // Tokens are handled by the generic flow
+ }
+
+ if (!this._validateFormInputs(paymentOptionId)) {
+ this._enableButton(); // The submit button is disabled at this point, enable it
+ this.call('ui', 'unblock'); // The page is blocked at this point, unblock it
+ return Promise.resolve();
+ }
+
+ // Build the authentication and card data objects to be dispatched to Authorized.Net
+ const secureData = {
+ authData: {
+ apiLoginID: this.authorizeInfo.login_id,
+ clientKey: this.authorizeInfo.client_key,
+ },
+ ...this._getPaymentDetails(paymentOptionId),
+ };
+
+ // Dispatch secure data to Authorize.Net to get a payment nonce in return
+ return Accept.dispatchData(
+ secureData, response => this._responseHandler(paymentOptionId, response)
+ );
+ },
+
+ /**
+ * Handle the response from Authorize.Net and initiate the payment.
+ *
+ * @private
+ * @param {number} providerId - The id of the selected provider
+ * @param {object} response - The payment nonce returned by Authorized.Net
+ * @return {Promise}
+ */
+ _responseHandler: function (providerId, response) {
+ if (response.messages.resultCode === 'Error') {
+ let error = '';
+ response.messages.message.forEach(msg => error += `${msg.code}: ${msg.text}\n`);
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to process your payment."),
+ error
+ );
+ return Promise.resolve();
+ }
+
+ // Create the transaction and retrieve the processing values
+ return this._rpc({
+ route: this.txContext.transactionRoute,
+ params: this._prepareTransactionRouteParams('authorize', providerId, 'direct'),
+ }).then(processingValues => {
+ // Initiate the payment
return this._rpc({
- route: this.txContext.transactionRoute,
- params: this._prepareTransactionRouteParams('authorize', providerId, 'direct'),
- }).then(processingValues => {
- // Initiate the payment
- return this._rpc({
- route: '/payment/authorize/payment',
- params: {
- 'reference': processingValues.reference,
- 'partner_id': processingValues.partner_id,
- 'opaque_data': response.opaqueData,
- 'access_token': processingValues.access_token,
- }
- }).then(() => window.location = '/payment/status');
- }).guardedCatch((error) => {
- error.event.preventDefault();
- this._displayError(
- _t("Server Error"),
- _t("We are not able to process your payment."),
- error.message.data.message
- );
- });
- },
+ route: '/payment/authorize/payment',
+ params: {
+ 'reference': processingValues.reference,
+ 'partner_id': processingValues.partner_id,
+ 'opaque_data': response.opaqueData,
+ 'access_token': processingValues.access_token,
+ }
+ }).then(() => window.location = '/payment/status');
+ }).guardedCatch((error) => {
+ error.event.preventDefault();
+ this._displayError(
+ _t("Server Error"),
+ _t("We are not able to process your payment."),
+ error.message.data.message,
+ );
+ });
+ },
- /**
- * Checks that all payment inputs adhere to the DOM validation constraints.
- *
- * @private
- * @param {number} providerId - The id of the selected provider
- * @return {boolean} - Whether all elements pass the validation constraints
- */
- _validateFormInputs: function (providerId) {
- const inputs = Object.values(this._getInlineFormInputs(providerId));
- return inputs.every(element => element.reportValidity());
- },
+ /**
+ * Checks that all payment inputs adhere to the DOM validation constraints.
+ *
+ * @private
+ * @param {number} providerId - The id of the selected provider
+ * @return {boolean} - Whether all elements pass the validation constraints
+ */
+ _validateFormInputs: function (providerId) {
+ const inputs = Object.values(this._getInlineFormInputs(providerId));
+ return inputs.every(element => element.reportValidity());
+ },
- };
+};
- checkoutForm.include(authorizeMixin);
- manageForm.include(authorizeMixin);
+checkoutForm.include(authorizeMixin);
+manageForm.include(authorizeMixin);
diff --git a/addons/payment_custom/static/src/js/post_processing.js b/addons/payment_custom/static/src/js/post_processing.js
index 5f3f33af107..586736aca44 100644
--- a/addons/payment_custom/static/src/js/post_processing.js
+++ b/addons/payment_custom/static/src/js/post_processing.js
@@ -1,6 +1,6 @@
/** @odoo-module **/
-import paymentPostProcessing from "@payment/js/post_processing";
+import paymentPostProcessing from '@payment/js/post_processing';
paymentPostProcessing.include({
/**
diff --git a/addons/payment_demo/static/src/js/payment_form.js b/addons/payment_demo/static/src/js/payment_form.js
index 843c406f6cd..e0d15b5a160 100644
--- a/addons/payment_demo/static/src/js/payment_form.js
+++ b/addons/payment_demo/static/src/js/payment_form.js
@@ -1,62 +1,64 @@
/** @odoo-module **/
- import checkoutForm from "@payment/js/checkout_form";
- import manageForm from "@payment/js/manage_form";
+import checkoutForm from '@payment/js/checkout_form';
+import manageForm from '@payment/js/manage_form';
- const paymentDemoMixin = {
+const paymentDemoMixin = {
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- /**
- * Simulate a feedback from a payment provider and redirect the customer to the status page.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} code - The code of the provider
- * @param {number} providerId - The id of the provider handling the transaction
- * @param {object} processingValues - The processing values of the transaction
- * @return {Promise}
- */
- _processDirectPayment: function (code, providerId, processingValues) {
- if (code !== 'demo') {
- return this._super(...arguments);
- }
+ /**
+ * Simulate a feedback from a payment provider and redirect the customer to the status page.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} code - The code of the provider
+ * @param {number} providerId - The id of the provider handling the transaction
+ * @param {object} processingValues - The processing values of the transaction
+ * @return {Promise}
+ */
+ _processDirectPayment: function (code, providerId, processingValues) {
+ if (code !== 'demo') {
+ return this._super(...arguments);
+ }
- const customerInput = document.getElementById('customer_input').value;
- const simulatedPaymentState = document.getElementById('simulated_payment_state').value;
- return this._rpc({
- route: '/payment/demo/simulate_payment',
- params: {
- 'reference': processingValues.reference,
- 'payment_details': customerInput,
- 'simulated_state': simulatedPaymentState,
- },
- }).then(() => {
- window.location = '/payment/status';
- });
- },
+ const customerInput = document.getElementById('customer_input').value;
+ const simulatedPaymentState = document.getElementById('simulated_payment_state').value;
+ return this._rpc({
+ route: '/payment/demo/simulate_payment',
+ params: {
+ 'reference': processingValues.reference,
+ 'payment_details': customerInput,
+ 'simulated_state': simulatedPaymentState,
+ },
+ }).then(() => {
+ window.location = '/payment/status';
+ });
+ },
- /**
- * Prepare the inline form of Demo for direct payment.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} code - The code of the selected payment option's provider
- * @param {integer} paymentOptionId - The id of the selected payment option
- * @param {string} flow - The online payment flow of the selected payment option
- * @return {Promise}
- */
- _prepareInlineForm: function (code, paymentOptionId, flow) {
- if (code !== 'demo') {
- return this._super(...arguments);
- } else if (flow === 'token') {
- return Promise.resolve();
- }
- this._setPaymentFlow('direct');
- return Promise.resolve()
- },
- };
- checkoutForm.include(paymentDemoMixin);
- manageForm.include(paymentDemoMixin);
+ /**
+ * Prepare the inline form of Demo for direct payment.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} code - The code of the selected payment option's provider
+ * @param {integer} paymentOptionId - The id of the selected payment option
+ * @param {string} flow - The online payment flow of the selected payment option
+ * @return {Promise}
+ */
+ _prepareInlineForm: function (code, paymentOptionId, flow) {
+ if (code !== 'demo') {
+ return this._super(...arguments);
+ } else if (flow === 'token') {
+ return Promise.resolve();
+ }
+ this._setPaymentFlow('direct');
+ return Promise.resolve();
+ },
+
+};
+
+checkoutForm.include(paymentDemoMixin);
+manageForm.include(paymentDemoMixin);
diff --git a/addons/payment_stripe/static/src/js/checkout_form.js b/addons/payment_stripe/static/src/js/checkout_form.js
index a4cc951c892..3e6389939d2 100644
--- a/addons/payment_stripe/static/src/js/checkout_form.js
+++ b/addons/payment_stripe/static/src/js/checkout_form.js
@@ -1,6 +1,6 @@
/** @odoo-module */
-import checkoutForm from "@payment/js/checkout_form";
+import checkoutForm from '@payment/js/checkout_form';
import stripeMixin from '@payment_stripe/js/stripe_mixin';
checkoutForm.include(stripeMixin);
diff --git a/addons/payment_stripe/static/src/js/express_checkout_form.js b/addons/payment_stripe/static/src/js/express_checkout_form.js
index 96a4bbeff35..1282ebf95d0 100644
--- a/addons/payment_stripe/static/src/js/express_checkout_form.js
+++ b/addons/payment_stripe/static/src/js/express_checkout_form.js
@@ -1,7 +1,7 @@
/** @odoo-module **/
/* global Stripe */
-import { _t } from "@web/core/l10n/translation";
+import { _t } from '@web/core/l10n/translation';
import { paymentExpressCheckoutForm } from '@payment/js/express_checkout_form';
import { StripeOptions } from '@payment_stripe/js/stripe_options';
@@ -175,7 +175,7 @@ paymentExpressCheckoutForm.include({
shippingOptions: availableCarriers.map(carrier => ({
id: String(carrier.id),
label: carrier.name,
- detail: carrier.description ? carrier.description:"",
+ detail: carrier.description ? carrier.description:'',
amount: carrier.minorAmount,
})),
...this._getOrderDetails(availableCarriers[0].minorAmount),
diff --git a/addons/payment_stripe/static/src/js/manage_form.js b/addons/payment_stripe/static/src/js/manage_form.js
index e6b24045271..62164dc58c1 100644
--- a/addons/payment_stripe/static/src/js/manage_form.js
+++ b/addons/payment_stripe/static/src/js/manage_form.js
@@ -1,6 +1,6 @@
/** @odoo-module */
-import manageForm from "@payment/js/manage_form";
+import manageForm from '@payment/js/manage_form';
import stripeMixin from '@payment_stripe/js/stripe_mixin';
manageForm.include(stripeMixin);
diff --git a/addons/payment_stripe/static/src/js/stripe_mixin.js b/addons/payment_stripe/static/src/js/stripe_mixin.js
index 404dabe7e12..7f0133df6bb 100644
--- a/addons/payment_stripe/static/src/js/stripe_mixin.js
+++ b/addons/payment_stripe/static/src/js/stripe_mixin.js
@@ -1,7 +1,7 @@
/** @odoo-module */
/* global Stripe */
-import { _t } from "@web/core/l10n/translation";
+import { _t } from '@web/core/l10n/translation';
import { StripeOptions } from '@payment_stripe/js/stripe_options';
export default {
@@ -63,7 +63,7 @@ export default {
const tokenizationCheckbox = document.getElementById(
`o_payment_provider_inline_${this.formType}_form_${paymentOptionId}`
- ).querySelector("input[name='o_payment_save_as_token']");
+ ).querySelector('input[name="o_payment_save_as_token"]');
if (this.formType === 'checkout' && tokenizationCheckbox) {
// Disable the tokenization checkbox for non-compatible payment methods.
paymentElement.addEventListener('change', ev => {
diff --git a/addons/sale/static/src/js/payment_form.js b/addons/sale/static/src/js/payment_form.js
index a577cee0279..39720d56d23 100644
--- a/addons/sale/static/src/js/payment_form.js
+++ b/addons/sale/static/src/js/payment_form.js
@@ -1,34 +1,34 @@
/** @odoo-module **/
- import checkoutForm from "@payment/js/checkout_form";
- import manageForm from "@payment/js/manage_form";
+import checkoutForm from '@payment/js/checkout_form';
+import manageForm from '@payment/js/manage_form';
- const salePaymentMixin = {
+const salePaymentMixin = {
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
- /**
- * Add `sale_order_id` to the transaction route params if it is provided.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @param {string} code - The code of the selected payment option's provider
- * @param {number} paymentOptionId - The id of the selected payment option
- * @param {string} flow - The online payment flow of the selected payment option
- * @return {object} The extended transaction route params
- */
- _prepareTransactionRouteParams: function (code, paymentOptionId, flow) {
- const transactionRouteParams = this._super(...arguments);
- return {
- ...transactionRouteParams,
- 'sale_order_id': this.txContext.saleOrderId
- ? parseInt(this.txContext.saleOrderId) : undefined,
- };
- },
+ /**
+ * Add `sale_order_id` to the transaction route params if it is provided.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @param {string} code - The code of the selected payment option's provider
+ * @param {number} paymentOptionId - The id of the selected payment option
+ * @param {string} flow - The online payment flow of the selected payment option
+ * @return {object} The extended transaction route params
+ */
+ _prepareTransactionRouteParams: function (code, paymentOptionId, flow) {
+ const transactionRouteParams = this._super(...arguments);
+ return {
+ ...transactionRouteParams,
+ 'sale_order_id': this.txContext.saleOrderId
+ ? parseInt(this.txContext.saleOrderId) : undefined,
+ };
+ },
- };
+};
- checkoutForm.include(salePaymentMixin);
- manageForm.include(salePaymentMixin);
+checkoutForm.include(salePaymentMixin);
+manageForm.include(salePaymentMixin);
diff --git a/addons/website_payment/static/src/js/website_payment_form.js b/addons/website_payment/static/src/js/website_payment_form.js
index e6df049d076..1ec0f3078ef 100644
--- a/addons/website_payment/static/src/js/website_payment_form.js
+++ b/addons/website_payment/static/src/js/website_payment_form.js
@@ -1,6 +1,6 @@
/** @odoo-module **/
-import core from "@web/legacy/js/services/core";
+import core, from '@web/legacy/js/services/core';
import checkoutForm from '@payment/js/checkout_form';
import { _t } from "@web/core/l10n/translation";
@@ -61,6 +61,7 @@ checkoutForm.include({
}
return this._super(...arguments);
},
+
/**
* Add params used by the donation snippet to the transaction route params.
*
diff --git a/addons/website_sale/static/src/js/website_sale_payment.js b/addons/website_sale/static/src/js/website_sale_payment.js
index ce3eb04186c..b03869a5bee 100644
--- a/addons/website_sale/static/src/js/website_sale_payment.js
+++ b/addons/website_sale/static/src/js/website_sale_payment.js
@@ -1,17 +1,97 @@
/** @odoo-module **/
- import { debounce } from "@web/core/utils/timing";
-import checkoutForm from "@payment/js/checkout_form";
- import publicWidget from "@web/legacy/js/public/public_widget";
+import { debounce } from '@web/core/utils/timing';
+import checkoutForm from '@payment/js/checkout_form';
+import publicWidget from '@web/legacy/js/public/public_widget';
- const websiteSalePaymentMixin = {
+const websiteSalePaymentMixin = {
- /**
- * @override
- */
- init: function () {
- this._onClickTCCheckbox = debounce(this._onClickTCCheckbox, 100, true);
- this._super(...arguments);
+ /**
+ * @override
+ */
+ init: function () {
+ this._onClickTCCheckbox = debounce(this._onClickTCCheckbox, 100, true);
+ this._super(...arguments);
+ },
+
+ /**
+ * @override
+ */
+ start: function () {
+ this.$checkbox = this.$('#checkbox_tc');
+ this.$submitButton = this.$('button[name="o_payment_submit_button"]');
+ this._adaptConfirmButton();
+ return this._super(...arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Update the data on the submit button with the status of the Terms and Conditions input.
+ *
+ * @private
+ * @return {undefined}
+ */
+ _adaptConfirmButton: function () {
+ if (this.$checkbox.length > 0) {
+ const disabledReasons = this.$submitButton.data('disabled_reasons') || {};
+ disabledReasons.tc = !this.$checkbox.prop('checked');
+ this.$submitButton.data('disabled_reasons', disabledReasons);
+ }
+ },
+
+};
+
+checkoutForm.include(Object.assign({}, websiteSalePaymentMixin, {
+ events: Object.assign({}, checkoutForm.prototype.events, {
+ 'change #checkbox_tc': '_onClickTCCheckbox',
+ }),
+
+ //----------------------------------------------------------------------
+ // Private
+ //----------------------------------------------------------------------
+
+ /**
+ * Verify that the Terms and Condition checkbox is checked.
+ *
+ * @override method from @payment/js/payment_form_mixin
+ * @private
+ * @return {boolean} Whether the submit button can be enabled
+ */
+ _isButtonReady: function () {
+ const disabledReasonFound = Object.values(
+ this.$submitButton.data('disabled_reasons') || {}
+ ).includes(true);
+ return !disabledReasonFound && this._super();
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Enable the submit button if it all conditions are met.
+ *
+ * @private
+ * @return {undefined}
+ */
+ _onClickTCCheckbox: function () {
+ this._adaptConfirmButton();
+
+ if (!this._enableButton()) {
+ this._disableButton(false);
+ }
+ },
+
+}));
+
+publicWidget.registry.WebsiteSalePayment = publicWidget.Widget.extend(
+ Object.assign({}, websiteSalePaymentMixin, {
+ selector: 'div[name="o_website_sale_free_cart"]',
+ events: {
+ 'change #checkbox_tc': '_onClickTCCheckbox',
},
/**
@@ -20,53 +100,10 @@ import checkoutForm from "@payment/js/checkout_form";
start: function () {
this.$checkbox = this.$('#checkbox_tc');
this.$submitButton = this.$('button[name="o_payment_submit_button"]');
- this._adaptConfirmButton();
+ this._onClickTCCheckbox();
return this._super(...arguments);
},
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * Update the data on the submit button with the status of the Terms and Conditions input.
- *
- * @private
- * @return {undefined}
- */
- _adaptConfirmButton: function () {
- if (this.$checkbox.length > 0) {
- const disabledReasons = this.$submitButton.data('disabled_reasons') || {};
- disabledReasons.tc = !this.$checkbox.prop('checked');
- this.$submitButton.data('disabled_reasons', disabledReasons);
- }
- },
-
- };
-
- checkoutForm.include(Object.assign({}, websiteSalePaymentMixin, {
- events: Object.assign({}, checkoutForm.prototype.events, {
- 'change #checkbox_tc': '_onClickTCCheckbox',
- }),
-
- //----------------------------------------------------------------------
- // Private
- //----------------------------------------------------------------------
-
- /**
- * Verify that the Terms and Condition checkbox is checked.
- *
- * @override method from @payment/js/payment_form_mixin
- * @private
- * @return {boolean} Whether the submit button can be enabled
- */
- _isButtonReady: function () {
- const disabledReasonFound = Object.values(
- this.$submitButton.data("disabled_reasons") || {}
- ).includes(true);
- return !disabledReasonFound && this._super();
- },
-
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
@@ -79,46 +116,9 @@ import checkoutForm from "@payment/js/checkout_form";
*/
_onClickTCCheckbox: function () {
this._adaptConfirmButton();
-
- if (!this._enableButton()) {
- this._disableButton(false);
- }
+ const disabledReasonFound = Object.values(
+ this.$submitButton.data('disabled_reasons') || {}
+ ).includes(true);
+ this.$submitButton.prop('disabled', disabledReasonFound);
},
-
}));
-
- publicWidget.registry.WebsiteSalePayment = publicWidget.Widget.extend(
- Object.assign({}, websiteSalePaymentMixin, {
- selector: 'div[name="o_website_sale_free_cart"]',
- events: {
- 'change #checkbox_tc': '_onClickTCCheckbox',
- },
-
- /**
- * @override
- */
- start: function () {
- this.$checkbox = this.$('#checkbox_tc');
- this.$submitButton = this.$('button[name="o_payment_submit_button"]');
- this._onClickTCCheckbox();
- return this._super(...arguments);
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Enable the submit button if it all conditions are met.
- *
- * @private
- * @return {undefined}
- */
- _onClickTCCheckbox: function () {
- this._adaptConfirmButton();
- const disabledReasonFound = Object.values(
- this.$submitButton.data("disabled_reasons") || {}
- ).includes(true);
- this.$submitButton.prop('disabled', disabledReasonFound);
- },
- }));