From ce2fdc02abb909d984abf28a4fdb45c072655da8 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Mon, 30 Jul 2018 10:02:03 +0200 Subject: [PATCH 01/24] [FIX] im_livechat: bad rating=1 not 0 w/ 75d3121c In 75d3121c9 the bad rating was change from 0 to 1. This commit update the javascript feedback part so the behavior is the one expected. related to opw-1863312 closes #26043 --- addons/im_livechat/static/src/js/im_livechat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/im_livechat/static/src/js/im_livechat.js b/addons/im_livechat/static/src/js/im_livechat.js index 878f5e268b6..1cb57e11265 100644 --- a/addons/im_livechat/static/src/js/im_livechat.js +++ b/addons/im_livechat/static/src/js/im_livechat.js @@ -280,7 +280,7 @@ var Feedback = Widget.extend({ // only display textearea if bad smiley selected var close_chat = false; - if (this.rating === 0) { + if (this.rating === 1) { this.$('.o_livechat_rating_reason').show(); } else { this.$('.o_livechat_rating_reason').hide(); From 5dc180a3ea50083c88399a58ee07cd130fa8289d Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Mon, 30 Jul 2018 10:35:24 +0200 Subject: [PATCH 02/24] [FIX] im_livechat: double click on :) => 1 message Prevent sending multiple messages when multiple clicks on one feedback icon. opw-1863312 closes #26047 --- addons/im_livechat/static/src/js/im_livechat.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/im_livechat/static/src/js/im_livechat.js b/addons/im_livechat/static/src/js/im_livechat.js index 10cc5610214..e9cc424f2a2 100644 --- a/addons/im_livechat/static/src/js/im_livechat.js +++ b/addons/im_livechat/static/src/js/im_livechat.js @@ -3,6 +3,7 @@ odoo.define('im_livechat.im_livechat', function (require) { var local_storage = require('web.local_storage'); var bus = require('bus.bus').bus; +var concurrency = require('web.concurrency'); var config = require('web.config'); var core = require('web.core'); var session = require('web.session'); @@ -304,6 +305,7 @@ var Feedback = Widget.extend({ this.channel_uuid = channel_uuid; this.server_origin = session.origin; this.rating = undefined; + this.dp = new concurrency.DropPrevious(); }, on_click_smiley: function (ev) { @@ -339,7 +341,7 @@ var Feedback = Widget.extend({ rate: this.rating, reason : options.reason }; - return session.rpc('/im_livechat/feedback', args).then(function () { + this.dp.add(session.rpc('/im_livechat/feedback', args)).then(function () { if (options.close) { var content = _.str.sprintf(_t("Rating: :rating_%d"), self.rating); if (options.reason) { From 862c24557628a0ed9d80db20d6191454b6a55def Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Thu, 19 Jul 2018 09:55:59 +0200 Subject: [PATCH 03/24] [FIX] account: default_get aml compute balance Create an account.move, create a line, then add an item to start to add a second aml The current balance of the move is put in debit (or credit) to help automatically making the second line Save the move. Edit the move Delete a line Add a new line Before this commit, the balance was not correctly computed because the default_get did not compute the balance on deleted lines The move ended up with wrong unbalanced new lines After this commit, the balance is computed with deleted lines taken into account --- addons/account/models/account_move.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index be4be9d3918..879fa6cb6d4 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -475,8 +475,11 @@ class AccountMoveLine(models.Model): #compute the default credit/debit of the next line in case of a manual entry balance = 0 for line in self._context['line_ids']: - if line[2]: + if line[2]: # in case of command 0: add a record with values balance += line[2].get('debit', 0) - line[2].get('credit', 0) + elif line[0] == 2: # line has been deleted + line_obj = self.browse(line[1]) + balance -= line_obj.debit - line_obj.credit if balance < 0: rec.update({'debit': -balance}) if balance > 0: From ebca7c3d372d3eac25db1491e9f7d49f92802f09 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Fri, 20 Jul 2018 15:10:54 +0200 Subject: [PATCH 04/24] [FIX] account: reconciliation widget: remove prop to attain balance In manual reconciliation (but probably automatic too) Have 3 lines for one account 2 of them are balanced the third is of an amount X Add the three lines to the reconciliation A write-off proposal of -X should appear Now, remove the third line by clicking on it Click on Reconcile Before this commit, the values sent to the server were wrong, as the write-off was still included After this commit, we make sure we don't send lines that are not displayed --- .../js/reconciliation/reconciliation_model.js | 4 +- .../static/tests/reconciliation_tests.js | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index dc3451ee110..0f37d6fc3ef 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -646,7 +646,7 @@ var StatementModel = BasicModel.extend({ return !isNaN(prop.id) && prop.already_paid; }), 'id'), "new_aml_dicts": _.map(_.filter(props, function (prop) { - return isNaN(prop.id); + return isNaN(prop.id) && prop.display; }), self._formatToProcessReconciliation.bind(self, line)), }; @@ -1240,7 +1240,7 @@ var ManualModel = StatementModel.extend({ }); } else { var mv_line_ids = _.pluck(_.filter(props, function (prop) {return !isNaN(prop.id);}), 'id'); - var new_mv_line_dicts = _.map(_.filter(props, function (prop) {return isNaN(prop.id);}), self._formatToProcessReconciliation.bind(self, line)); + var new_mv_line_dicts = _.map(_.filter(props, function (prop) {return isNaN(prop.id) && prop.display;}), self._formatToProcessReconciliation.bind(self, line)); process_reconciliations.push({ id: null, type: null, diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index e5ae62811fe..111c5834b0a 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -1687,5 +1687,78 @@ QUnit.module('account', { clientAction.destroy(); }); + + QUnit.test('Manual Reconciliation: remove a prop to attain balance and reconcile', function (assert) { + assert.expect(5); + + // tweak the data to fit our needs + this.params.data_for_manual_reconciliation_widget['[283, null, "", 0, 6]'] = _.extend({}, this.params.data_for_manual_reconciliation_widget['[null,null]']); + this.params.data_for_manual_reconciliation_widget['[283, null, "", 0, 6]'].accounts[0].reconciliation_proposition = [ + {account_id: 283, account_type: "other", amount_currency_str: "", currency_id: false, date_maturity: "2017-03-18", date: "2017-02-16", + total_amount_str: "$ 500.00", partner_id: 8, account_name: "101000 Current Assets", name: "INV/2017/0987", partner_name: "Agrolait", + total_amount_currency_str: "", id: 999, credit: 0.0, journal_id: [1, "Customer Invoices"], amount_str: "$ 500.00", debit: 500.0, + account_code: "101000", ref: "", already_paid: false} + ]; + + var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); + testUtils.addMockEnvironment(clientAction, { + data: this.params.data, + mockRPC: function (route, args) { + if (args.method === 'process_reconciliations') { + assert.deepEqual(args.args, + [ + [{id: null, type: null, + mv_line_ids: [399, 402], + new_mv_line_dicts: []} + ] + ], "should call process_reconciliations without the new mv line dict"); + } + + return this._super(route, args); + }, + session: { + currencies: { + 3: { + digits: [69, 2], + position: "before", + symbol: "$" + } + } + }, + }); + + clientAction.appendTo($('#qunit-fixture')); + + // The first reconciliation "line" is where it happens + var widget = clientAction.widgets[0]; + + // Add first prop + widget.$('.match .cell_account_code:first').trigger('click'); + assert.notOk( widget.$('.cell_right .line_info_button').length, + "should not display the partial reconciliation alert"); + + // Add second prop + widget.$('.match .cell_account_code:first').trigger('click'); + + // Check that a create form is here + var writeOffCreate = widget.$('div.create'); + + assert.equal(writeOffCreate.length, 1, + 'A write-off creation should be present'); + + assert.equal(writeOffCreate.find('input[name=amount]').val(), 500, + 'The right amount should be proposed for the write-off'); + + // remove the first line, the other two will balance one another + widget.$('tr[data-line-id="999"] td:first').click() + + var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)'); + assert.equal($buttonReconcile.length, 1, + 'The reconcile button must be visible'); + + $buttonReconcile.click(); + + clientAction.destroy(); + }); }); }); From aa7bc410f01ffdbe2ff1d1dbb82f8daa194358e4 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Fri, 20 Jul 2018 15:46:16 +0200 Subject: [PATCH 05/24] [FIX] account: reconciliation widget: empty line should open write off In manual reconciliation, have an accound with no direct proposal. An empty line should be present Click on it Before this commit, there was a traceback After this commit, a write-off creation appears --- .../reconciliation/reconciliation_renderer.js | 7 ++-- .../static/tests/reconciliation_tests.js | 38 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js index 66c471dfbd3..33f969237d1 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js @@ -406,7 +406,8 @@ var LineRenderer = Widget.extend(FieldManagerMixin, { // mv_lines var $mv_lines = this.$('.match table tbody').empty(); - _.each(state.mv_lines.slice(0, state.limitMoveLines), function (line) { + var stateMvLines = state.mv_lines || []; + _.each(stateMvLines.slice(0, state.limitMoveLines), function (line) { var $line = $(qweb.render("reconciliation.line.mv_line", {'line': line, 'state': state})); if (!isNaN(line.id)) { $('') @@ -415,9 +416,9 @@ var LineRenderer = Widget.extend(FieldManagerMixin, { } $mv_lines.append($line); }); - this.$('.match .fa-chevron-right').toggleClass('disabled', state.mv_lines.length <= state.limitMoveLines); + this.$('.match .fa-chevron-right').toggleClass('disabled', stateMvLines.length <= state.limitMoveLines); this.$('.match .fa-chevron-left').toggleClass('disabled', !state.offset); - this.$('.match').css('max-height', !state.mv_lines.length && !state.filter.length ? '0px' : ''); + this.$('.match').css('max-height', !stateMvLines.length && !state.filter.length ? '0px' : ''); // balance this.$('.popover').remove(); diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index 111c5834b0a..513f642adfc 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -1760,5 +1760,43 @@ QUnit.module('account', { clientAction.destroy(); }); + + QUnit.test('Manual Reconciliation: No lines for account', function (assert) { + assert.expect(2); + + var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); + testUtils.addMockEnvironment(clientAction, { + data: this.params.data, + session: { + currencies: { + 3: { + digits: [69, 2], + position: "before", + symbol: "$" + } + } + }, + }); + + clientAction.appendTo($('#qunit-fixture')); + + // The second reconciliation "line" is where it happens + var widget = clientAction.widgets[1]; + + var emptyLine = widget.$('tr.mv_line'); + + assert.notOk('data-line-id' in emptyLine.getAttributes(), + 'Empty line should be empty'); + + emptyLine.find('td:first').click(); + + // Check that a create form is here + var writeOffCreate = widget.$('div.create .create_account_id'); + + assert.equal(writeOffCreate.length, 1, + 'A write-off creation should be present'); + + clientAction.destroy(); + }); }); }); From 93e71d181ef85bbb5d22091f20c64de42265c957 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Mon, 23 Jul 2018 16:44:52 +0200 Subject: [PATCH 06/24] [FIX] account: reconciliation widget: Don't loose pager on adding last line Have a statement line with multiple pages of propositions Go to the last page Add everything Before this commit, after clicking on the last item of the list, a write-off creation was displayed, without any means to come back to the other propositions After this commit, we display the page before --- .../js/reconciliation/reconciliation_model.js | 14 ++++++ .../static/tests/reconciliation_tests.js | 49 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index 0f37d6fc3ef..f76304e6908 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -128,6 +128,20 @@ var StatementModel = BasicModel.extend({ var line = this.getLine(handle); var prop = _.clone(_.find(line.mv_lines, {'id': mv_line_id})); this._addProposition(line, prop); + + // Check whether we have some propositions left + // If we don't, it means we are on an empty page + // so let's go back to the previous page + // Through the offset + var propLineIds = _.map(line.reconciliation_proposition, function(prop) { + return prop.id; + }); + var leftOversProps = _.filter(line.mv_lines, function(mv_line) { + return propLineIds.indexOf(mv_line.id) === -1; + }); + if (line.offset && !leftOversProps.length) { + line.offset -= line.limitMoveLines; + } return $.when(this._computeLine(line), this._performMoveLine(handle)); }, /** diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index 513f642adfc..43be1879195 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -1798,5 +1798,54 @@ QUnit.module('account', { clientAction.destroy(); }); + + QUnit.test('Automatic Reconciliation: Don\'t loose pager when adding last line of a page', function (assert) { + assert.expect(2); + + function standard_partner (list, partner_id) { + _.each(list, function (item) { + item.partner_id = partner_id; + }); + }; + + this.params.options.params.limitMoveLines = 1; + standard_partner(this.params.mv_lines['[5,"",0,6]'], 8); + + // Overlap of those requests is normal + // the pager is implemented as: + // if there is at least 1 more line than my limit, the pager is active + this.params.mv_lines['[5,"",0,2]'] = this.params.mv_lines['[5,"",0,6]'].slice(0,2); + this.params.mv_lines['[5,"",1,2]'] = this.params.mv_lines['[5,"",0,6]'].slice(1,2); + + var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); + testUtils.addMockEnvironment(clientAction, { + data: this.params.data, + session: { + currencies: { + 3: { + digits: [69, 2], + position: "before", + symbol: "$" + } + } + }, + }); + clientAction.appendTo($('#qunit-fixture')); + + var widget = clientAction.widgets[0]; + + var $nextPage = widget.$('.match .match_controls .fa-chevron-right:not(disabled)'); + assert.ok($nextPage.length, + 'We should have a next page'); + $nextPage.click(); + + // Add the second's page record + widget.$('.match tr[data-line-id=112] td:first').click(); + + assert.ok(widget.$('.match tr[data-line-id=109]').length, + 'the record of the first page must be proposed'); + + clientAction.destroy(); + }); }); }); From e11908d429435091828f224ee0751b90de8c99aa Mon Sep 17 00:00:00 2001 From: Romain Derie Date: Fri, 27 Jul 2018 14:33:38 +0200 Subject: [PATCH 07/24] [FIX] website_sale: _get_pl_partner_order With 60300fc, people can use promo code on website. But the condition leads to a side effect, if a partner has a pricelist set for him, he will never be able to see the dropdown list of pricelist since he will enter the else condition with show_visible set to true. Now, user is able to see selectable pricelists. opw-1869371 --- addons/website_sale/models/sale_order.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 1c757098a32..111f208f60b 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -239,8 +239,8 @@ class Website(models.Model): if not pricelists: # no pricelist for this country, or no GeoIP pricelists |= all_pl.filtered(lambda pl: not show_visible or pl.selectable or pl.id in (current_pl, order_pl)) - else: - pricelists |= all_pl.filtered(lambda pl: not show_visible and pl.sudo().code) + if not show_visible and not country_code: + pricelists |= all_pl.filtered(lambda pl: pl.sudo().code) # This method is cached, must not return records! See also #8795 return pricelists.ids From 47acea1523e1e27306d15cce21d8499825b3173a Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Mon, 30 Jul 2018 16:18:20 +0200 Subject: [PATCH 08/24] [FIX] website_sale_wishlist: Wrong displayed currency in the wishlist Steps to reproduce: 1. Activate multi-currency and associate a price list "Other list" with secondary currency as an alternative for "Public Price List". 2. Enable the price list to be selectable on the website. 3. Enable wishlist functionality on Website module 4. Navigate to website without logging in 5. Add a product to the wishlist (with the default price list) 6. Switch price lists. Bug: The wrong currency was displayed in the wishlist for the new price. PS: In function "compute_new_price", price_new = website_price opw:1867314 --- .../views/website_sale_wishlist_template.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml b/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml index 1d306318534..b2bca7fd93c 100644 --- a/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml +++ b/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml @@ -69,7 +69,7 @@
- + From bf332e2e08ebe8533c91f39aa5b24e9dc297af67 Mon Sep 17 00:00:00 2001 From: Can Tecim Date: Mon, 30 Jul 2018 18:09:33 +0300 Subject: [PATCH 09/24] [FIX] purchase: P3-style super call 3869cdf7d8202c8157c1134d74549b3096758253 merged a fix which used a P3-style super call, which is not compatible with Python 2. While 11.0 is not really exactly officially supported on Python 2, we originally decided not to break compatibility unless there were very good reasons to do so. --- addons/purchase/models/stock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/models/stock.py b/addons/purchase/models/stock.py index 8f6c1e58fcb..f312fa91c6d 100644 --- a/addons/purchase/models/stock.py +++ b/addons/purchase/models/stock.py @@ -190,6 +190,6 @@ class PushedFlow(models.Model): _inherit = "stock.location.path" def _prepare_move_copy_values(self, move_to_copy, new_date): - res = super()._prepare_move_copy_values(move_to_copy, new_date) + res = super(PushedFlow, self)._prepare_move_copy_values(move_to_copy, new_date) res['purchase_line_id'] = None return res From e1da65841a9999e67d5c50e116fb15123edfce56 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 31 Jul 2018 11:21:15 +0200 Subject: [PATCH 10/24] [FIX] stock: Display issue on product categ This text is not written at the right place and it's useless. So it's confusing for the users. opw:1870443 --- addons/stock/views/product_views.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/stock/views/product_views.xml b/addons/stock/views/product_views.xml index c03c4937edf..92def7b93a9 100644 --- a/addons/stock/views/product_views.xml +++ b/addons/stock/views/product_views.xml @@ -11,7 +11,6 @@
- The following routes will apply to the products in this category taking into account parent categories:
From 81a206fa38b95fe66b7a30f8399b72dbc9c01ba2 Mon Sep 17 00:00:00 2001 From: Olivier Colson Date: Tue, 31 Jul 2018 13:35:57 +0200 Subject: [PATCH 11/24] [IMP] account: bank journal open in regular journal form view: don't show 'partner_id' field in account creation popup, and fill it with company partner by default. --- addons/account/views/account_view.xml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 4cb793ab461..a98e08c2c19 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -338,7 +338,8 @@ - + + @@ -352,6 +353,18 @@ + + company.res.partner.bank.form + res.partner.bank + + primary + + + 1 + + + + account.bank.journal.tree account.journal @@ -1551,7 +1564,7 @@ - + From c75f4fbcd121bfb21ce6221b0d810cc55e814d9b Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Tue, 31 Jul 2018 11:51:37 +0200 Subject: [PATCH 12/24] [FIX] stock: Source and Destination on pickings Steps to reproduce the bug: - Go on a picking with an operation type of type "vendor" (e.g. a receipt) : the field source location appears while it should be the destination location. - Go on a picking with an operation type of type "customer " (e.g. a delivery) : the field destination location appears while it should be the source location. opw:1869145 --- addons/stock/views/stock_picking_views.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/stock/views/stock_picking_views.xml b/addons/stock/views/stock_picking_views.xml index 18f248f58d4..fc12abbdbad 100644 --- a/addons/stock/views/stock_picking_views.xml +++ b/addons/stock/views/stock_picking_views.xml @@ -242,8 +242,8 @@ - - + + From e57a1a8e6f6b79e3bb369d88eee295bb5a7788f3 Mon Sep 17 00:00:00 2001 From: len-odoo Date: Fri, 27 Jul 2018 15:38:23 +0200 Subject: [PATCH 13/24] [FIX] web: fix 'drag and drop' test function to work in both directions The 'drag and drop' function defined in test_utils should be aware of four different cases, moving up or down, above or below another row. We need an offset of one pixel for the function to work when moving down (this is a case of broken symmetry because of <=) Related to opw 1867049 regarding sequences of resequence moves. --- addons/web/static/tests/helpers/test_utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js index c2828802891..fc26aa80713 100644 --- a/addons/web/static/tests/helpers/test_utils.js +++ b/addons/web/static/tests/helpers/test_utils.js @@ -414,10 +414,11 @@ function dragAndDrop($el, $to, options) { var toOffset = $to.offset(); toOffset.top += $to.outerHeight()/2; toOffset.left += $to.outerWidth()/2; + var vertical_offset = (toOffset.top < elementCenter.top) ? -1 : 1; if (position === 'top') { - toOffset.top -= $to.outerHeight()/2; + toOffset.top -= $to.outerHeight()/2 + vertical_offset; } else if (position === 'bottom') { - toOffset.top += $to.outerHeight()/2; + toOffset.top += $to.outerHeight()/2 - vertical_offset; } else if (position === 'left') { toOffset.left -= $to.outerWidth()/2; } else if (position === 'right') { From 65ad60665e54a7e61d3d064df63457d0097587bd Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 31 Jul 2018 16:03:33 +0200 Subject: [PATCH 14/24] [FIX] base: fix users' groups assignation Avoid sharing of users'groups when writing on multiple users. When changing groups of multiple users, all implied groups were shared between written users. Oversight of new-api rewrite. Fixes #26036 --- odoo/addons/base/res/res_users.py | 2 +- odoo/addons/base/tests/__init__.py | 1 + odoo/addons/base/tests/test_non_regression.py | 26 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 odoo/addons/base/tests/test_non_regression.py diff --git a/odoo/addons/base/res/res_users.py b/odoo/addons/base/res/res_users.py index a78ecb9829c..74245dced0c 100644 --- a/odoo/addons/base/res/res_users.py +++ b/odoo/addons/base/res/res_users.py @@ -679,7 +679,7 @@ class UsersImplied(models.Model): for user in self.with_context({}): gs = set(concat(g.trans_implied_ids for g in user.groups_id)) vals = {'groups_id': [(4, g.id) for g in gs]} - super(UsersImplied, self).write(vals) + super(UsersImplied, user).write(vals) return res # diff --git a/odoo/addons/base/tests/__init__.py b/odoo/addons/base/tests/__init__.py index 06c06cbbc5d..e40c2d042c3 100644 --- a/odoo/addons/base/tests/__init__.py +++ b/odoo/addons/base/tests/__init__.py @@ -31,3 +31,4 @@ import test_view_validation import test_views import test_xmlrpc import test_res_partner_bank +import test_non_regression diff --git a/odoo/addons/base/tests/test_non_regression.py b/odoo/addons/base/tests/test_non_regression.py new file mode 100644 index 00000000000..1f75578079a --- /dev/null +++ b/odoo/addons/base/tests/test_non_regression.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +""" + Non-Regression Tests +""" + +from openerp.tests.common import TransactionCase + + +class TestNR(TransactionCase): + def test_issue26036(self): + U = self.env["res.users"] + G = self.env["res.groups"] + + group_A = G.create({"name": "A"}) + group_AA = G.create({"name": "AA", "implied_ids": [(6, 0, [group_A.id])]}) + group_B = G.create({"name": "B"}) + group_BB = G.create({"name": "BB", "implied_ids": [(6, 0, [group_B.id])]}) + group_C = G.create({"name": "C"}) + + user_a = U.create({"name": "a", "login": "a", "groups_id": [(6, 0, [group_AA.id])]}) + user_b = U.create({"name": "b", "login": "b", "groups_id": [(6, 0, [group_BB.id])]}) + + (user_a + user_b).write({"groups_id": [(4, group_C.id)]}) + + self.assertEqual(user_a.groups_id, (group_AA + group_A + group_C)) + self.assertEqual(user_b.groups_id, (group_BB + group_B + group_C)) From 11a0dd58a7c6f874388f06d2ece33cb1237f79d1 Mon Sep 17 00:00:00 2001 From: Olivier Colson Date: Tue, 31 Jul 2018 17:15:29 +0200 Subject: [PATCH 15/24] [FIX] account: set 'multi' field to False for payments generated when choosing to register payment for multiple invoices with distinct partners This field is used by the multiple payment wizard; the payments it generates are always individual and should never have multi=True. Before this commit, they did, because of the values given in context when calling the payment wizard. --- addons/account/models/account_payment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index e0b6864b0f7..50387ded587 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -197,6 +197,7 @@ class account_register_payments(models.TransientModel): 'currency_id': self.currency_id.id, 'partner_id': invoices[0].commercial_partner_id.id, 'partner_type': MAP_INVOICE_TYPE_PARTNER_TYPE[invoices[0].type], + 'multi': False, } @api.multi From 8c81eaabe6b451b112f6af5b2bb06afe9ed91839 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 31 Jul 2018 19:36:30 +0200 Subject: [PATCH 16/24] Revert "[FIX] models: make `onchange` return a smaller diff" This reverts commit 2054b5928574affbb7efcd8a9ab146ee4fa34938 which already has been fixed multiple times [0]. However this change does not correctly handle successive onchange calls on ony2many fields which alter existing rows. i.e., in saas~11.4, an onchange has been added on move lines [1] in order to create and/or update lines containing taxes amounts. However, with diff-only onchange, a second call to onchange will discard changes made by a first one as nothing change between the 2 calls. Scenario: On an existing account.move, add a new credit line with a tax set. The first onchange will update the tax line with new amount. Add a second line (with debit amount balanced). The onchange will not change the tax line, resulting as it value being reset to initial value. As a result, the move is not balanced and cannot be saved. [0] cd2ccc4110274e23607521c18309f07cca68476a, 5e58ac16c3cae2d5c45e7c9f746ed810b835a65d, 07023137cd17d8917673fd6ba7809b2870bd8cc0 [1] d49ab568a2cc5231ac12267a9e74eaf16ca45f9e --- .../test_new_api/tests/test_onchange.py | 64 +++++---- odoo/models.py | 135 ++++-------------- 2 files changed, 67 insertions(+), 132 deletions(-) diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index a1b2e4edfee..1bfdee908a7 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -139,10 +139,14 @@ class TestOnChange(common.TransactionCase): self.env.cache.invalidate() result = self.Discussion.onchange(values, 'name', field_onchange) self.assertIn('messages', result['value']) - self.assertEqual(result['value']['messages'], [ + self.assertItemsEqual(result['value']['messages'], [ (5,), (1, message.id, { 'name': "[%s] %s" % ("Foo", USER.name), + 'body': message.body, + 'author': message.author.name_get()[0], + 'size': message.size, + 'important': message.important, }), (0, 0, { 'name': "[%s] %s" % ("Foo", USER.name), @@ -252,7 +256,8 @@ class TestOnChange(common.TransactionCase): 'lines': [ (5,), (1, line1.id, {'name': partner2.name, - 'partner': (partner2.id, partner2.name)}), + 'partner': (partner2.id, partner2.name), + 'tags': [(5,)]}), (0, 0, {'name': partner2.name, 'partner': (partner2.id, partner2.name), 'tags': [(5,)]}), @@ -260,17 +265,6 @@ class TestOnChange(common.TransactionCase): }) # do it again, but this time with a new tag on the second line - expected_new_tag_result = { - 'name': partner2.name, - 'lines': [ - (5,), - (1, line1.id, {'name': partner2.name, - 'partner': (partner2.id, partner2.name)}), - (0, 0, {'name': partner2.name, - 'partner': (partner2.id, partner2.name), - 'tags': [(5,), (0, 0, {'name': 'Tag'})]}), - ], - } values = { 'name': partner1.name, 'partner': partner2.id, # this one just changed @@ -282,13 +276,18 @@ class TestOnChange(common.TransactionCase): self.env.cache.invalidate() result = multi.onchange(values, 'partner', field_onchange) - self.assertEqual(result['value'], expected_new_tag_result) - - # ensure ID is not returned when asked and a many2many record is set to be created - self.env.cache.invalidate() - - result = multi.onchange(values, 'partner', dict(field_onchange, **{'lines.tags.id': None})) - self.assertEqual(result['value'], expected_new_tag_result) + self.assertEqual(result['value'], { + 'name': partner2.name, + 'lines': [ + (5,), + (1, line1.id, {'name': partner2.name, + 'partner': (partner2.id, partner2.name), + 'tags': [(5,)]}), + (0, 0, {'name': partner2.name, + 'partner': (partner2.id, partner2.name), + 'tags': [(5,), (0, 0, {'name': 'Tag'})]}), + ], + }) def test_onchange_specific(self): """ test the effect of field-specific onchange method """ @@ -320,7 +319,8 @@ class TestOnChange(common.TransactionCase): self.assertIn('participants', result['value']) self.assertItemsEqual( result['value']['participants'], - [(5,)] + [(4, user.id) for user in discussion.participants + demo], + [(5,)] + [(1, user.id, {'display_name': user.display_name}) + for user in discussion.participants + demo], ) def test_onchange_default(self): @@ -356,8 +356,6 @@ class TestOnChange(common.TransactionCase): self.assertEqual(len(discussion.messages), 3) messages = [(4, msg.id) for msg in discussion.messages] messages[0] = (1, messages[0][1], {'body': 'test onchange'}) - lines = ["%s:%s" % (m.name, m.body) for m in discussion.messages] - lines[0] = "%s:%s" % (discussion.messages[0].name, 'test onchange') values = { 'name': discussion.name, 'moderator': demo.id, @@ -368,7 +366,8 @@ class TestOnChange(common.TransactionCase): } result = discussion.onchange(values, 'messages', field_onchange) self.assertIn('message_concat', result['value']) - self.assertEqual(result['value']['message_concat'], "\n".join(lines)) + self.assertEqual(result['value']['message_concat'], + "\n".join(["%s:%s" % (m.name, m.body) for m in discussion.messages])) def test_onchange_one2many_with_domain_on_related_field(self): """ test the value of the one2many field when defined with a domain on a related field""" @@ -414,15 +413,28 @@ class TestOnChange(common.TransactionCase): 'categories': [(4, cat.id) for cat in discussion.categories], 'messages': [(4, msg.id) for msg in discussion.messages], 'participants': [(4, usr.id) for usr in discussion.participants], + 'message_changes': 0, 'important_messages': [(4, msg.id) for msg in discussion.important_messages], 'important_emails': [(4, eml.id) for eml in discussion.important_emails], } - self.env.cache.invalidate() result = discussion.onchange(values, 'name', field_onchange) + # When one2many domain contains non-computed field, things are ok + self.assertEqual(result['value']['important_messages'], + [(5,)] + [(4, msg.id) for msg in discussion.important_messages]) + + # But here with commit 5676d81, we get value of: [(2, email.id)] self.assertEqual( result['value']['important_emails'], - [(5,), (1, email.id, {'name': u'[Foo Bar] %s' % USER.name})], + [(5,), + (1, email.id, { + 'name': u'[Foo Bar] %s' % USER.name, + 'body': email.body, + 'author': USER.name_get()[0], + 'important': True, + 'email_to': demo.email, + 'size': email.size, + })] ) def test_onchange_related(self): diff --git a/odoo/models.py b/odoo/models.py index a716a429f0d..964dbcbf5d9 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -5040,114 +5040,28 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): if not all(name in self._fields for name in names): return {} - class PrefixTree(OrderedDict): - """ A prefix tree for sequences of field names. The tree is a - dictionary that associates each given field name to its - corresponding subtree (in fields order):: - - # tree corresponding to dotnames - # ['name', 'line_ids.product_id', 'line_ids.tags_ids.name'] - { - 'name': {}, - 'line_ids': { - 'product_id': {}, - 'tags_ids': { - 'name': {}, - }, - }, - } - """ - def __init__(self, model, dotnames): - super(PrefixTree, self).__init__() - if not dotnames: - return - # group dotnames by prefix - suffixes = defaultdict(list) - for dotname in dotnames: - names = dotname.split('.', 1) - name_suffixes = suffixes[names[0]] - if len(names) > 1: - name_suffixes.append(names[1]) - # fill in self in fields order - for name in model._fields: - if name in suffixes: - self[name] = PrefixTree(model[name], suffixes[name]) - - def dotnames(self): - """ Iterate over the sequences of field names. """ - for name, subnames in self.items(): - yield name - for dotname in subnames.dotnames(): - yield "%s.%s" % (name, dotname) - - nametree = PrefixTree(self.browse(), field_onchange) - dotnames = list(nametree.dotnames()) - - def snapshot(record, tree=nametree): - """ Return a dict with the values of record, following nametree. """ - vals = {} - for name, subnames in tree.items(): - if subnames: - # x2many fields as {line: snapshot(line), ...} - vals[name] = OrderedDict( - (line, snapshot(line, subnames)) - for line in record[name] - ) - else: - vals[name] = record[name] - return vals - - def diff(record, old, new, tree=nametree): - """ Return the values that differ between snapshots. - The snapshot ``old`` may be empty (for new records). - """ - result = {} - for name, subnames in tree.items(): - if name == 'id': - continue - if old and old[name] == new[name]: - continue - field = record._fields[name] - if not subnames: - result[name] = field.convert_to_onchange(new[name], record, {}) - continue - # x2many fields: serialize value as commands - result[name] = commands = [(5,)] - old_val = old.get(name) or {} - for line, vals in new[name].items(): - vals0 = (old_val.get(line) or snapshot(line, subnames)) if line.id else {} - line_diff = diff(line, vals0, vals, subnames) - if not line.id: - commands.append((0, line.id.ref or 0, line_diff)) - elif line_diff: - commands.append((1, line.id, line_diff)) - else: - commands.append((4, line.id)) - return result - - # prefetch x2many lines without data (for the initial snapshot) - for name, subnames in nametree.items(): - if subnames and values.get(name): - # retrieve all ids in commands, and read the expected fields - line_ids = [] - for cmd in values[name]: - if cmd[0] in (1, 4): - line_ids.append(cmd[1]) - elif cmd[0] == 6: - line_ids.extend(cmd[2]) - lines = self.browse()[name].browse(line_ids) - lines.read(list(subnames), load='_classic_write') + # filter out keys in field_onchange that do not refer to actual fields + dotnames = [] + for dotname in field_onchange: + try: + model = self.browse() + for name in dotname.split('.'): + model = model[name] + dotnames.append(dotname) + except Exception: + pass # create a new record with values, and attach ``self`` to it with env.do_in_onchange(): record = self.new(values) - values = {name: record[name] for name in nametree} + values = {name: record[name] for name in record._cache} # attach ``self`` with a different context (for cache consistency) record._origin = self.with_context(__onchange=True) - # make a snapshot based on the initial values of record + # load fields on secondary records, to avoid false changes with env.do_in_onchange(): - before = snapshot(record) + for dotname in dotnames: + record.mapped(dotname) # determine which field(s) should be triggered an onchange todo = list(names) or list(values) @@ -5166,6 +5080,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): record[name] = value result = {} + dirty = set() # process names in order (or the keys of values if no name given) while todo: @@ -5191,14 +5106,22 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): field.type in ('one2many', 'many2many') and newval._is_dirty() ): todo.append(name) + dirty.add(name) - # make a snapshot based on the final values of record + # determine subfields for field.convert_to_onchange() below + Tree = lambda: defaultdict(Tree) + subnames = Tree() + for dotname in dotnames: + subtree = subnames + for name in dotname.split('.'): + subtree = subtree[name] + + # collect values from dirty fields with env.do_in_onchange(): - after = snapshot(record) - - # determine values that have changed by comparing snapshots - self.invalidate_cache() - result['value'] = diff(record, before, after) + result['value'] = { + name: self._fields[name].convert_to_onchange(record[name], record, subnames[name]) + for name in dirty + } return result From cc0baa086afc35cc2ef9eca72c3d7abba43550da Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 31 Jul 2018 20:31:46 +0200 Subject: [PATCH 17/24] [FIX] base: adapt test expectation to python 3.7 Compare exception message to the exact one raised in all versions. --- odoo/addons/base/tests/test_qweb.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py index 136ad02e250..ab2d0fa4dd0 100644 --- a/odoo/addons/base/tests/test_qweb.py +++ b/odoo/addons/base/tests/test_qweb.py @@ -5,7 +5,6 @@ import collections import json import os.path import re -import sys from lxml import etree @@ -481,12 +480,16 @@ class TestQWebNS(TransactionCase):
""" }) - error_msg = "Can't convert 'int' object to str implicitly" - if sys.version_info >= (3, 6): - error_msg = "must be str, not int" - with self.assertRaisesRegexp(QWebException, error_msg): + + try: + "" + 0 + except TypeError as e: + error_msg = e.args[0] + + with self.assertRaises(QWebException, msg=error_msg): view1.render() + from copy import deepcopy class FileSystemLoader(object): def __init__(self, path): From 06de947b6b16f4237c95f9710e1d68f7ce92f70d Mon Sep 17 00:00:00 2001 From: Jothimani Date: Wed, 1 Aug 2018 12:57:18 +0530 Subject: [PATCH 18/24] [CLA] signature for jothimani-r Closes #26079 --- doc/cla/individual/jothimani-r.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 doc/cla/individual/jothimani-r.md diff --git a/doc/cla/individual/jothimani-r.md b/doc/cla/individual/jothimani-r.md new file mode 100644 index 00000000000..b8049074c4c --- /dev/null +++ b/doc/cla/individual/jothimani-r.md @@ -0,0 +1,11 @@ +India, 2018-07-31 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Jothimani Rajagopal jothimani1991@gmail.com https://github.com/jothimani-r From 1686ef8c047efebb79cb962c8e730e0e2a63da69 Mon Sep 17 00:00:00 2001 From: Olivier Colson Date: Wed, 1 Aug 2018 09:42:07 +0200 Subject: [PATCH 19/24] Revert "[FIX] account: set 'multi' field to False for payments generated when choosing to register payment for multiple invoices with distinct partners" This reverts commit 11a0dd58a7c6f874388f06d2ece33cb1237f79d1. It was made in wrong version. --- addons/account/models/account_payment.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index 50387ded587..e0b6864b0f7 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -197,7 +197,6 @@ class account_register_payments(models.TransientModel): 'currency_id': self.currency_id.id, 'partner_id': invoices[0].commercial_partner_id.id, 'partner_type': MAP_INVOICE_TYPE_PARTNER_TYPE[invoices[0].type], - 'multi': False, } @api.multi From eb35ea557a12553188030936d652dce888d1a8dc Mon Sep 17 00:00:00 2001 From: Olivier Colson Date: Wed, 1 Aug 2018 10:34:30 +0200 Subject: [PATCH 20/24] [FIX] account: set 'multi' field to False for payments generated when choosing to register payment for multiple invoices with distinct partners This field is used by the multiple payment wizard; the payments it generates are always individual and should never have multi=True. Before this commit, they did, because of the values given in context when calling the payment wizard. --- addons/account/models/account_payment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index e3f03a48952..ebfa4de4e5d 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -259,6 +259,7 @@ class account_register_payments(models.TransientModel): 'currency_id': self.currency_id.id, 'partner_id': invoices[0].commercial_partner_id.id, 'partner_type': MAP_INVOICE_TYPE_PARTNER_TYPE[invoices[0].type], + 'multi': False, } @api.multi From 60353cf46369a43217f4f2b63d7e64bcb11c8f62 Mon Sep 17 00:00:00 2001 From: Adrian Torres Date: Mon, 27 Nov 2017 11:12:27 +0100 Subject: [PATCH 21/24] [FIX] server: do not restart if phoenix is True (#21209) Before this commit, saving a file being watched by watchdog (--dev=reload) with vim (and possibly other text editors) would crash the server via a KeyboardInterrupt error. This happens because vim, emacs cause multiple filesystem events to happen when saving a single file, the FSWatcher registers these events as multiple SIGHUPs which in turn calls restart() multiple times in a very small amount of time which makes the KeyboardInterrupts completely shut down the server This is fixed by only calling restart() if odoo.phoenix is False, since catching a SIGHUP sets it to true. Fixes #21178 Special thanks to @odony for the help :) --- odoo/service/server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/odoo/service/server.py b/odoo/service/server.py index b1fb4068d88..c0deb3989d7 100644 --- a/odoo/service/server.py +++ b/odoo/service/server.py @@ -137,8 +137,9 @@ class FSWatcher(object): except SyntaxError: _logger.error('autoreload: python code change detected, SyntaxError in %s', path) else: - _logger.info('autoreload: python code updated, autoreload activated') - restart() + if not getattr(odoo, 'phoenix', False): + _logger.info('autoreload: python code updated, autoreload activated') + restart() def start(self): self.observer.start() From e372ca5cd88e714283bd3b2b5918bdc21c0ab6a5 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Wed, 1 Aug 2018 10:12:26 +0200 Subject: [PATCH 22/24] [FIX] account: aged partner balance report consistent return Before this commit, the function that computes the aged partner balance could return a list instead of a dict if no partner were found After this commit, we make the function's signature consistent closes #26095 --- addons/account/report/account_aged_partner_balance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index 909c8d2cd39..317da02a0af 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -68,7 +68,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): partner_ids = [partner['partner_id'] for partner in partners if partner['partner_id']] lines = dict((partner['partner_id'] or False, []) for partner in partners) if not partner_ids: - return [], [], [] + return [], [], {} # This dictionary will store the not due amount of all partners undue_amounts = {} From ea3d1397fcc50aa6601a985e368bbff90130a28f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 1 Aug 2018 15:29:04 +0200 Subject: [PATCH 23/24] [FIX] account: use full xmlid of view to use --- addons/account/views/account_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index a98e08c2c19..40f01b1e1bc 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -339,7 +339,7 @@ - + From 691dd65e0ecca5ef1ab4fa1ff363562a9349c1d4 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 1 Aug 2018 16:29:57 +0200 Subject: [PATCH 24/24] [FIX] account: adapt new test to actual api Oversight of previous forward-port --- addons/account/static/tests/reconciliation_tests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index 4f0032b52b6..93a8a1818b4 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -1737,14 +1737,14 @@ QUnit.module('account', { testUtils.addMockEnvironment(clientAction, { data: this.params.data, mockRPC: function (route, args) { - if (args.method === 'process_reconciliations') { + if (args.method === 'process_move_lines') { assert.deepEqual(args.args, [ [{id: null, type: null, mv_line_ids: [399, 402], new_mv_line_dicts: []} ] - ], "should call process_reconciliations without the new mv line dict"); + ], "should call process_move_lines without the new mv line dict"); } return this._super(route, args);