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 @@ - +
@@ -519,48 +519,7 @@
- -
Products
- - - - - - - - - - - - - - - - - - - - -
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 @@ - +