diff --git a/addons/sale/views/sale_portal_templates.xml b/addons/sale/views/sale_portal_templates.xml
index c8bbb314ebc..90e9d03ce4b 100644
--- a/addons/sale/views/sale_portal_templates.xml
+++ b/addons/sale/views/sale_portal_templates.xml
@@ -310,7 +310,7 @@
-
+
@@ -428,7 +428,7 @@
-
+
| Products |
@@ -519,48 +519,7 @@
-
-
-
- | Subtotal |
-
-
- |
-
-
-
-
- |
-
- on
- |
-
-
- |
-
-
-
-
- |
-
-
- |
-
-
-
-
- | Total |
-
-
- |
-
-
+
diff --git a/addons/sale_management/controllers/portal.py b/addons/sale_management/controllers/portal.py
index eb4e945b8d3..a2690237709 100644
--- a/addons/sale_management/controllers/portal.py
+++ b/addons/sale_management/controllers/portal.py
@@ -12,12 +12,27 @@ from odoo.addons.sale.controllers.portal import CustomerPortal
class CustomerPortal(CustomerPortal):
- @http.route(['/my/orders//update_line'], type='json', auth="public", website=True)
- def update(self, line_id, remove=False, unlink=False, order_id=None, access_token=None, **post):
- values = self.update_line_dict(line_id, remove, unlink, order_id, access_token, **post)
- if values:
- return [values['order_line_product_uom_qty'], values['order_amount_total']]
- return values
+ def _get_portal_order_details(self, order_sudo, order_line=False):
+ currency = order_sudo.currency_id
+ format_price = partial(formatLang, request.env, digits=currency.decimal_places)
+ results = {
+ 'order_amount_total': format_price(order_sudo.amount_total),
+ 'order_amount_untaxed': format_price(order_sudo.amount_untaxed),
+ 'order_amount_tax': format_price(order_sudo.amount_tax),
+ 'order_amount_undiscounted': format_price(order_sudo.amount_undiscounted),
+ }
+ if order_line:
+ results.update({
+ 'order_line_product_uom_qty': str(order_line.product_uom_qty),
+ 'order_line_price_total': format_price(order_line.price_total),
+ 'order_line_price_subtotal': format_price(order_line.price_subtotal)
+ })
+ try:
+ results['order_totals_table'] = request.env['ir.ui.view'].render_template('sale.sale_order_portal_content_totals_table', {'sale_order': order_sudo})
+ except ValueError:
+ pass
+
+ return results
@http.route(['/my/orders//update_line_dict'], type='json', auth="public", website=True)
def update_line_dict(self, line_id, remove=False, unlink=False, order_id=None, access_token=None, input_quantity=False, **kwargs):
@@ -31,9 +46,6 @@ class CustomerPortal(CustomerPortal):
order_line = request.env['sale.order.line'].sudo().browse(int(line_id))
if order_line.order_id != order_sudo:
return False
- if unlink:
- order_line.unlink()
- return False # return False to reload the page, the line must move back to options and the JS doesn't handle it
if input_quantity is not False:
quantity = input_quantity
@@ -41,29 +53,24 @@ class CustomerPortal(CustomerPortal):
number = -1 if remove else 1
quantity = order_line.product_uom_qty + number
- if quantity < 0:
- quantity = 0.0
- order_line.write({'product_uom_qty': quantity})
- currency = order_sudo.currency_id
- format_price = partial(formatLang, request.env, digits=currency.decimal_places)
+ if unlink or quantity <= 0:
+ order_line.unlink()
+ results = self._get_portal_order_details(order_sudo)
+ results.update({
+ 'unlink': True,
+ 'sale_template': request.env['ir.ui.view'].render_template('sale.sale_order_portal_content', {
+ 'sale_order': order_sudo,
+ 'report_type': "html"
+ }),
+ })
+ return results
- results = {
- 'order_line_product_uom_qty': str(quantity),
- 'order_line_price_total': format_price(order_line.price_total),
- 'order_line_price_subtotal': format_price(order_line.price_subtotal),
- 'order_amount_total': format_price(order_sudo.amount_total),
- 'order_amount_untaxed': format_price(order_sudo.amount_untaxed),
- 'order_amount_tax': format_price(order_sudo.amount_tax),
- 'order_amount_undiscounted': format_price(order_sudo.amount_undiscounted),
- }
- try:
- results['order_totals_table'] = request.env['ir.ui.view'].render_template('sale.sale_order_portal_content_totals_table', {'sale_order': order_sudo})
- except ValueError:
- pass
+ order_line.write({'product_uom_qty': quantity})
+ results = self._get_portal_order_details(order_sudo, order_line)
return results
- @http.route(["/my/orders//add_option/"], type='http', auth="public", website=True)
+ @http.route(["/my/orders//add_option/"], type='json', auth="public", website=True)
def add(self, order_id, option_id, access_token=None, **post):
try:
order_sudo = self._document_check_access('sale.order', order_id, access_token=access_token)
@@ -76,5 +83,9 @@ class CustomerPortal(CustomerPortal):
return request.redirect(order_sudo.get_portal_url())
option_sudo.add_option_to_order()
-
- return request.redirect(option_sudo.order_id.get_portal_url(anchor='details'))
+ results = self._get_portal_order_details(order_sudo)
+ results['sale_template'] = request.env['ir.ui.view'].render_template("sale.sale_order_portal_content", {
+ 'sale_order': option_sudo.order_id,
+ 'report_type': "html"
+ })
+ return results
diff --git a/addons/sale_management/static/src/js/sale_management.js b/addons/sale_management/static/src/js/sale_management.js
index 7092ac06355..eaa126ccabf 100644
--- a/addons/sale_management/static/src/js/sale_management.js
+++ b/addons/sale_management/static/src/js/sale_management.js
@@ -4,56 +4,88 @@ odoo.define('sale_management.sale_management', function (require) {
var publicWidget = require('web.public.widget');
publicWidget.registry.SaleUpdateLineButton = publicWidget.Widget.extend({
- selector: '.o_portal_sale_sidebar a.js_update_line_json',
+ selector: '.o_portal_sale_sidebar',
events: {
- 'click': '_onClick',
+ 'click a.js_update_line_json': '_onClick',
+ 'click a.js_add_optional_products': '_onClickOptionalProduct',
+ 'change .js_quantity': '_onChangeQuantity'
},
/**
* @override
*/
- start: function () {
- var self = this;
- return this._super.apply(this, arguments).then(function () {
- self.elems = self._getUpdatableElements();
- self.elems.$lineQuantity.change(function (ev) {
- var quantity = parseInt(this.value);
- self._onChangeQuantity(quantity);
- });
- });
- },
+ async start() {
+ await this._super(...arguments);
+ this.orderDetail = this.$el.find('table#sales_order_table').data();
+ this.elems = this._getUpdatableElements();
+ },
/**
* Process the change in line quantity
*
* @private
- * @param {Int} quantity, the new quantity of the line
- * If not present it will increment/decrement the existing quantity
+ * @param {Event} ev
*/
- _onChangeQuantity: function (quantity) {
- var href = this.$el.attr("href");
- var orderID = href.match(/my\/orders\/([0-9]+)/);
- var lineID = href.match(/update_line\/([0-9]+)/);
- var params = {
- 'line_id': parseInt(lineID[1]),
- 'remove': this.$el.is('[href*="remove"]'),
- 'unlink': this.$el.is('[href*="unlink"]'),
- 'input_quantity': quantity >= 0 ? quantity : false,
- };
- var token = href.match(/token=([\w\d-]*)/)[1];
- if (token) {
- params['access_token'] = token;
- }
+ _onChangeQuantity(ev) {
+ ev.preventDefault();
+ let self = this,
+ $target = $(ev.currentTarget),
+ quantity = parseInt($target.val());
- orderID = parseInt(orderID[1]);
- this._callUpdateLineRoute(orderID, params).then(this._updateOrderValues.bind(this));
+ this._callUpdateLineRoute(self.orderDetail.orderId, {
+ 'line_id': $target.data('lineId'),
+ 'input_quantity': quantity >= 0 ? quantity : false,
+ 'access_token': self.orderDetail.token
+ }).then((data) => {
+ self._updateOrderLineValues($target.closest('tr'), data);
+ self._updateOrderValues(data);
+ });
},
/**
* Reacts to the click on the -/+ buttons
*
* @param {Event} ev
*/
- _onClick: function (ev) {
+ _onClick(ev) {
ev.preventDefault();
- return this._onChangeQuantity();
+ let self = this,
+ $target = $(ev.currentTarget);
+ this._callUpdateLineRoute(self.orderDetail.orderId, {
+ 'line_id': $target.data('lineId'),
+ 'remove': $target.data('remove'),
+ 'unlink': $target.data('unlink'),
+ 'access_token': self.orderDetail.token
+ }).then((data) => {
+ var $saleTemplate = $(data['sale_template']);
+ if ($saleTemplate.length && data['unlink']) {
+ self.$('#portal_sale_content').html($saleTemplate);
+ self.elems = self._getUpdatableElements();
+ }
+ self._updateOrderLineValues($target.closest('tr'), data);
+ self._updateOrderValues(data);
+ });
+ },
+ /**
+ * trigger when optional product added to order from portal.
+ *
+ * @private
+ * @param {Event} ev
+ */
+ _onClickOptionalProduct(ev) {
+ ev.preventDefault();
+ let self = this,
+ $target = $(ev.currentTarget);
+ // to avoid double click on link with href.
+ $target.css('pointer-events', 'none');
+
+ this._rpc({
+ route: "/my/orders/" + self.orderDetail.orderId + "/add_option/" + $target.data('optionId'),
+ params: {access_token: self.orderDetail.token}
+ }).then((data) => {
+ if (data) {
+ self.$('#portal_sale_content').html($(data['sale_template']));
+ self.elems = self._getUpdatableElements();
+ self._updateOrderValues(data);
+ }
+ });
},
/**
* Calls the route to get updated values of the line and order
@@ -64,43 +96,48 @@ publicWidget.registry.SaleUpdateLineButton = publicWidget.Widget.extend({
* @param {Object} params
* @return {Deferred}
*/
- _callUpdateLineRoute: function (order_id, params) {
- var url = "/my/orders/" + order_id + "/update_line_dict";
+ _callUpdateLineRoute(order_id, params) {
return this._rpc({
- route: url,
+ route: "/my/orders/" + order_id + "/update_line_dict",
params: params,
});
},
+ /**
+ * Processes data from the server to update the orderline UI
+ *
+ * @private
+ * @param {Element} $orderLine: orderline element to update
+ * @param {Object} data: contains order and line updated values
+ */
+ _updateOrderLineValues($orderLine, data) {
+ let linePriceTotal = data.order_line_price_total,
+ linePriceSubTotal = data.order_line_price_subtotal,
+ $linePriceTotal = $orderLine.find('.oe_order_line_price_total .oe_currency_value'),
+ $linePriceSubTotal = $orderLine.find('.oe_order_line_price_subtotal .oe_currency_value');
+
+ if (!$linePriceTotal.length && !$linePriceSubTotal.length) {
+ $linePriceTotal = $linePriceSubTotal = $orderLine.find('.oe_currency_value').last();
+ }
+
+ $orderLine.find('.js_quantity').val(data.order_line_product_uom_qty);
+ if ($linePriceTotal.length && linePriceTotal !== undefined) {
+ $linePriceTotal.text(linePriceTotal);
+ }
+ if ($linePriceSubTotal.length && linePriceSubTotal !== undefined) {
+ $linePriceSubTotal.text(linePriceSubTotal);
+ }
+ },
/**
* Processes data from the server to update the UI
*
* @private
* @param {Object} data: contains order and line updated values
*/
- _updateOrderValues: function (data) {
- if (!data) {
- window.location.reload();
- }
-
- var orderAmountTotal = data.order_amount_total;
- var orderAmountUntaxed = data.order_amount_untaxed;
- var orderAmountTax = data.order_amount_tax;
- var orderAmountUndiscounted = data.order_amount_undiscounted;
- var orderTotalsTable = $(data.order_totals_table);
-
- var lineProductUomQty = data.order_line_product_uom_qty;
- var linePriceTotal = data.order_line_price_total;
- var linePriceSubTotal = data.order_line_price_subtotal;
-
- this.elems.$lineQuantity.val(lineProductUomQty);
-
- if (this.elems.$linePriceTotal.length && linePriceTotal !== undefined) {
- this.elems.$linePriceTotal.text(linePriceTotal);
- }
- if (this.elems.$linePriceSubTotal.length && linePriceSubTotal !== undefined) {
- this.elems.$linePriceSubTotal.text(linePriceSubTotal);
- }
-
+ _updateOrderValues(data) {
+ let orderAmountTotal = data.order_amount_total,
+ orderAmountUntaxed = data.order_amount_untaxed,
+ orderAmountUndiscounted = data.order_amount_undiscounted,
+ $orderTotalsTable = $(data.order_totals_table);
if (orderAmountUntaxed !== undefined) {
this.elems.$orderAmountUntaxed.text(orderAmountUntaxed);
}
@@ -112,8 +149,8 @@ publicWidget.registry.SaleUpdateLineButton = publicWidget.Widget.extend({
if (orderAmountUndiscounted !== undefined) {
this.elems.$orderAmountUndiscounted.text(orderAmountUndiscounted);
}
- if (orderTotalsTable) {
- this.elems.$orderTotalsTable.find('table').replaceWith(orderTotalsTable);
+ if ($orderTotalsTable.length) {
+ this.elems.$orderTotalsTable.find('table').replaceWith($orderTotalsTable);
}
},
/**
@@ -124,18 +161,10 @@ publicWidget.registry.SaleUpdateLineButton = publicWidget.Widget.extend({
* @private
* @return {Object}: Jquery elements to update
*/
- _getUpdatableElements: function () {
- var $parentTr = this.$el.parents('tr:first');
- var $linePriceTotal = $parentTr.find('.oe_order_line_price_total .oe_currency_value');
- var $linePriceSubTotal = $parentTr.find('.oe_order_line_price_subtotal .oe_currency_value');
-
- if (!$linePriceTotal.length && !$linePriceSubTotal.length) {
- $linePriceTotal = $linePriceSubTotal = $parentTr.find('.oe_currency_value').last();
- }
-
- var $orderAmountUntaxed = $('[data-id="total_untaxed"]').find('span, b');
- var $orderAmountTotal = $('[data-id="total_amount"]').find('span, b');
- var $orderAmountUndiscounted = $('[data-id="amount_undiscounted"]').find('span, b');
+ _getUpdatableElements() {
+ let $orderAmountUntaxed = $('[data-id="total_untaxed"]').find('span, b'),
+ $orderAmountTotal = $('[data-id="total_amount"]').find('span, b'),
+ $orderAmountUndiscounted = $('[data-id="amount_undiscounted"]').find('span, b');
if (!$orderAmountUntaxed.length) {
$orderAmountUntaxed = $orderAmountTotal.eq(1);
@@ -143,9 +172,6 @@ publicWidget.registry.SaleUpdateLineButton = publicWidget.Widget.extend({
}
return {
- $lineQuantity: this.$el.closest('.input-group').find('.js_quantity'),
- $linePriceSubTotal: $linePriceSubTotal,
- $linePriceTotal: $linePriceTotal,
$orderAmountUntaxed: $orderAmountUntaxed,
$orderAmountTotal: $orderAmountTotal,
$orderTotalsTable: $('#total'),
diff --git a/addons/sale_management/views/sale_portal_templates.xml b/addons/sale_management/views/sale_portal_templates.xml
index 1f7fbcccf71..d248f2d2c2d 100644
--- a/addons/sale_management/views/sale_portal_templates.xml
+++ b/addons/sale_management/views/sale_portal_templates.xml
@@ -21,7 +21,7 @@
-
+
|
@@ -65,8 +65,8 @@
-
-
+
+
|
@@ -83,16 +83,16 @@
-
+