From f12daec1a1dba46ec4e26ce7c313bc132f9537f8 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Fri, 27 Apr 2018 14:09:10 +0200 Subject: [PATCH 01/18] [FIX] web: don't change page before saving When we edit a list view and change page before the change has been savec, the saving and page changing will be done concurrently thus possibly causing an error if the page is changed before the saved is finished: the save will try to modify the page that is no more displayed. In this change, the list view editable wait for the saving to be finished before reloading its content. note: for 9.0 up to saas-15 opw-1839149 closes #24471 --- addons/web/static/src/js/views/list_view.js | 10 ++++++++-- addons/web/static/src/js/views/list_view_editable.js | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js index 98462e68493..f742c9fb435 100644 --- a/addons/web/static/src/js/views/list_view.js +++ b/addons/web/static/src/js/views/list_view.js @@ -352,7 +352,7 @@ var ListView = View.extend( /** @lends instance.web.ListView# */ { } else if (self.page > max_page_index) { self.page = 0; } - self.reload_content(); + self.reload_content_when_ready(); }).find('.oe_list_pager_state') .click(function (e) { e.stopPropagation(); @@ -370,7 +370,7 @@ var ListView = View.extend( /** @lends instance.web.ListView# */ { var val = parseInt($select.val(), 10); self._limit = (isNaN(val) ? null : val); self.page = 0; - self.reload_content(); + self.reload_content_when_ready(); }).blur(function() { $(this).trigger('change'); }) @@ -542,6 +542,12 @@ var ListView = View.extend( /** @lends instance.web.ListView# */ { }); return reloaded.promise(); }), + /** + * Proxy allowing override when reload_content can't be called directly + */ + reload_content_when_ready: function() { + return this.reload_content.apply(this, arguments); + }, reload: function () { return this.reload_content(); }, diff --git a/addons/web/static/src/js/views/list_view_editable.js b/addons/web/static/src/js/views/list_view_editable.js index b522e1e37a0..d7f15bd89f2 100644 --- a/addons/web/static/src/js/views/list_view_editable.js +++ b/addons/web/static/src/js/views/list_view_editable.js @@ -401,6 +401,17 @@ ListView.include(/** @lends instance.web.ListView# */{ }); return cells; }, + /** + * Prevent reloading content while an ongoing save + */ + reload_content_when_ready: function() { + var self = this; + var self_super = this._super; + var original_arguments = arguments; + return this.saving_mutex.exec(function() { + return self_super.apply(self, original_arguments); + }); + }, /** * If currently editing a row, resizes all registered form fields based * on the corresponding row cell From 7353405aa4fc88ede6b85bbb46fe0308b17c1052 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Wed, 2 May 2018 17:14:50 +0200 Subject: [PATCH 02/18] [FIX] stock: Scheduled date purchase order wrong When running the scheduler for a reordering rule, the delivery lead time of the seller was not taken into account. opw:1837550 --- addons/stock/models/stock_warehouse.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py index d81efe07404..36a6e696cc6 100644 --- a/addons/stock/models/stock_warehouse.py +++ b/addons/stock/models/stock_warehouse.py @@ -845,7 +845,8 @@ class Orderpoint(models.Model): days = self.lead_days or 0.0 if self.lead_type == 'supplier': # These days will be substracted when creating the PO - days += self.product_id._select_seller().delay or 0.0 + qty = self.env.context.get('product_qty', 0.0) + days += self.product_id._select_seller(quantity=qty).delay or 0.0 date_planned = start_date + relativedelta.relativedelta(days=days) return date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT) @@ -853,7 +854,7 @@ class Orderpoint(models.Model): def _prepare_procurement_values(self, product_qty, date=False, group=False): return { 'name': self.name, - 'date_planned': date or self._get_date_planned(datetime.today()), + 'date_planned': date or self.with_context(product_qty=product_qty)._get_date_planned(datetime.today()), 'product_id': self.product_id.id, 'product_qty': product_qty, 'company_id': self.company_id.id, From 8e73023f689d76dc6d545e617ab1c7ce18334068 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 3 May 2018 12:15:40 +0200 Subject: [PATCH 03/18] [FIX] account: do not block reconciliation on different partners This constraint was added during the Great Accounting Reform of v9, in an attempt to help users avoid reconciliation mistakes. It turns out that such mistakes are difficult to make in normal situations, since the system only offers matching entries to reconcile, so the constraint is largely redundant. On the other hand, it does block legit cases of reconciliation, such as those where a large number of lines with different partners are reconciled together. This often happens when reversing a Journal Entry that encompasses multiple customers, such as a POS closing entry, or a manual entry. To make the system more flexible, let's consider that when a manual reconciliation breaks the "single partner" rule explicitly, it's for a good reason, so we should allow it. OPW: 1840437 --- addons/account/models/account_move.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index b2daa735434..f8b46f43dc0 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1015,8 +1015,6 @@ class AccountMoveLine(models.Model): raise UserError(_('Entries are not of the same account!')) if not (all_accounts[0].reconcile or all_accounts[0].internal_type == 'liquidity'): raise UserError(_('The account %s (%s) is not marked as reconciliable !') % (all_accounts[0].name, all_accounts[0].code)) - if len(partners) > 1: - raise UserError(_('The partner has to be the same on all lines for receivable and payable accounts!')) #reconcile everything that can be remaining_moves = self.auto_reconcile_lines() From 78ce64a6a79a41e673196939f2bb60a44db27f55 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 3 May 2018 10:49:23 +0200 Subject: [PATCH 04/18] [FIX] account: do not block reconciliation on different partners This constraint was added during the Great Accounting Reform of v9, in an attempt to help users avoid reconciliation mistakes. It turns out that such mistakes are difficult to make in normal situations, since the system only offers matching entries to reconcile, so the constraint is largely redundant. On the other hand, it does block legit cases of reconciliation, such as those where a large number of lines with different partners are reconciled together. This often happens when reversing a Journal Entry that encompasses multiple customers, such as a POS closing entry, or a manual entry. To make the system more flexible, let's consider that when a manual reconciliation breaks the "single partner" rule explicitly, it's for a good reason, so we should allow it. OPW: 1840437 Backport of 8e73023f689d76dc6d545e617ab1c7ce18334068 --- addons/account/models/account_move.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 1c0bec65626..c8931900ac9 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -905,8 +905,6 @@ class AccountMoveLine(models.Model): raise UserError(_('Entries are not of the same account!')) if not all_accounts[0].reconcile: raise UserError(_('The account %s (%s) is not marked as reconciliable !') % (all_accounts[0].name, all_accounts[0].code)) - if len(partners) > 1: - raise UserError(_('The partner has to be the same on all lines for receivable and payable accounts!')) #reconcile everything that can be remaining_moves = self.auto_reconcile_lines() From f49a6b6ebe64688a53b224c10216790812c864e9 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Thu, 3 May 2018 09:58:38 +0200 Subject: [PATCH 05/18] [FIX] website_slides: avoid double slash in slide url --- addons/website_slides/models/slides.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/website_slides/models/slides.py b/addons/website_slides/models/slides.py index 15abfedded9..61fb0aa9816 100644 --- a/addons/website_slides/models/slides.py +++ b/addons/website_slides/models/slides.py @@ -351,6 +351,8 @@ class Slide(models.Model): def _get_embed_code(self): base_url = request and request.httprequest.url_root or self.env['ir.config_parameter'].sudo().get_param('web.base.url') + if base_url[-1] == '/': + base_url = base_url[:-1] for record in self: if record.datas and (not record.document_id or record.slide_type in ['document', 'presentation']): slide_url = base_url + url_for('/slides/embed/%s?page=1' % record.id) From cce6030c0da77a5739af01d57cd53822fc3ab394 Mon Sep 17 00:00:00 2001 From: Simon Lejeune Date: Wed, 2 May 2018 20:36:22 +0200 Subject: [PATCH 06/18] [FIX] stock: symmetric reserve and unreserve When an internal locations has its `scrapped` field set to True, reserving will increment the quant's `reserved_quantity` while unreserving will bypass the reservation mechanism (as in a supplier location). This leads to a desynchronisation between the partially_available/available move lines and the quant's `reserved_quantity`, leading later on to "cannot unreserve more than available" errors. To prevent this kind of issues, there's a `should_bypass_reservation` method set on the location that we *should* use everywhere, it was implemented by [0]. Sadly, this line was not adapted since its implementaton in [1]. Co-authored by len-odoo opw 1837900 [0] e1cea2640fc064a56b0dba4f79e6b8a91a48b4fc [1] 0469d2e7126c46e019ed5f4233ef7b20d3499a0e --- addons/stock/models/stock_move.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 3abf0979c0a..358f3ab9d2f 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -895,7 +895,7 @@ class StockMove(models.Model): assigned_moves = self.env['stock.move'] partially_available_moves = self.env['stock.move'] for move in self.filtered(lambda m: m.state in ['confirmed', 'waiting', 'partially_available']): - if move.location_id.usage in ('supplier', 'inventory', 'production', 'customer')\ + if move.location_id.should_bypass_reservation()\ or move.product_id.type == 'consu': # create the move line(s) but do not impact quants if move.product_id.tracking == 'serial' and (move.picking_type_id.use_create_lots or move.picking_type_id.use_existing_lots): From 8b7fb9a764143946c21548fb4475156238294e0f Mon Sep 17 00:00:00 2001 From: Akash Bhavsar Date: Thu, 3 May 2018 23:16:56 +1000 Subject: [PATCH 07/18] [FIX] mail: Do not close chat widnow if ESCAPE key is pressed on document viewer and keep focus on chat window input when document viewer is closed (#22741) If document viewer is opened from chat window and when document viewer is opened then focus remains on it's modal, pressing escape should set focus back to chat window's input element, if file selecor dialog is opened and if user press ESCAPE on file selector dialog to cancel file selector dialog then it should not close chat window instead it should set focus on chat window input and on second ESCAPE key chat window should be closed also increase z-index of document viewer dialog so image remain on top of cht window OPW: 1777937 --- addons/mail/static/src/js/chat_window.js | 6 +- addons/mail/static/src/js/composer.js | 6 ++ addons/mail/static/src/js/document_viewer.js | 16 ++++ addons/mail/static/src/js/thread.js | 1 + addons/mail/static/src/less/composer.less | 1 + addons/mail/static/src/xml/thread.xml | 2 +- addons/mail/static/tests/chat_window_test.js | 78 ++++++++++++++++++++ 7 files changed, 108 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/js/chat_window.js b/addons/mail/static/src/js/chat_window.js index 0c3a2270045..3553f8f01ab 100644 --- a/addons/mail/static/src/js/chat_window.js +++ b/addons/mail/static/src/js/chat_window.js @@ -16,7 +16,8 @@ var HEIGHT_FOLDED = '34px'; return Widget.extend({ template: "mail.ChatWindow", custom_events: { - escape_pressed: '_onEscapePressed' + escape_pressed: '_onEscapePressed', + document_viewer_closed: '_onDocumentViewerClose', }, events: { 'click .o_chat_composer': '_onComposerClick', @@ -180,6 +181,9 @@ return Widget.extend({ } this.focus_input(); }, + _onDocumentViewerClose: function (ev) { + this.focus_input(); + }, /** * @private */ diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js index e342074c5bd..6a83c39d900 100644 --- a/addons/mail/static/src/js/composer.js +++ b/addons/mail/static/src/js/composer.js @@ -514,6 +514,9 @@ var BasicComposer = Widget.extend(chat_mixin, { on_click_add_attachment: function () { this.$('input.o_input_file').click(); this.$input.focus(); + // set ignoreEscape to avoid escape_pressed event when file selector dialog is opened + // when user press escape to cancel file selector dialog then escape_pressed event should not be trigerred + this.ignoreEscape = true; }, setState: function (state) { @@ -565,6 +568,8 @@ var BasicComposer = Widget.extend(chat_mixin, { if (this.mention_manager.is_open()) { event.stopPropagation(); this.mention_manager.reset_suggestions(); + } else if (this.ignoreEscape) { + this.ignoreEscape = false; } else { this.trigger_up("escape_pressed"); } @@ -789,6 +794,7 @@ var BasicComposer = Widget.extend(chat_mixin, { * @param {MouseEvent} event */ _onAttachmentView: function (event) { + event.stopPropagation(); var activeAttachmentID = $(event.currentTarget).data('id'); var attachments = this.get('attachment_ids'); if (activeAttachmentID) { diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js index 0aac950cf5b..d7c43b2d4f6 100644 --- a/addons/mail/static/src/js/document_viewer.js +++ b/addons/mail/static/src/js/document_viewer.js @@ -25,6 +25,7 @@ var DocumentViewer = Widget.extend({ 'DOMMouseScroll .o_viewer_content': '_onScroll', // Firefox 'mousewheel .o_viewer_content': '_onScroll', // Chrome, Safari, IE 'keydown': '_onKeydown', + 'keyup': '_onKeyUp', 'mousedown .o_viewer_img': '_onStartDrag', 'mousemove .o_viewer_content': '_onDrag', 'mouseup .o_viewer_content': '_onEndDrag' @@ -152,6 +153,7 @@ var DocumentViewer = Widget.extend({ _onClose: function (e) { e.preventDefault(); this.$el.modal('hide'); + this.trigger_up('document_viewer_closed'); }, /** * When popup close complete destroyed modal even DOM footprint too @@ -232,6 +234,20 @@ var DocumentViewer = Widget.extend({ break; } }, + /** + * Close popup on ESCAPE keyup + * + * @private + * @param {KeyEvent} e + */ + _onKeyUp: function (e) { + switch (e.which) { + case $.ui.keyCode.ESCAPE: + e.preventDefault(); + this._onClose(e); + break; + } + }, /** * @private * @param {MouseEvent} e diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index fcb1dda324f..eb060a06733 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -328,6 +328,7 @@ var Thread = Widget.extend({ * @param {MouseEvent} event */ _onAttachmentView: function (event) { + event.stopPropagation(); var activeAttachmentID = $(event.currentTarget).data('id'); if (activeAttachmentID) { var attachmentViewer = new DocumentViewer(this, this.attachments, activeAttachmentID); diff --git a/addons/mail/static/src/less/composer.less b/addons/mail/static/src/less/composer.less index 71af37fc054..9213fb6c416 100644 --- a/addons/mail/static/src/less/composer.less +++ b/addons/mail/static/src/less/composer.less @@ -339,6 +339,7 @@ } .o_modal_fullscreen { + z-index: @o-chat-window-zindex + 1; // To overlap chat window .o_viewer_content { width: 100%; height: 100%; diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml index 9a707693ce0..180eac17b48 100644 --- a/addons/mail/static/src/xml/thread.xml +++ b/addons/mail/static/src/xml/thread.xml @@ -76,7 +76,7 @@ -