From 54d1b38844a79724a77268dc577b771b8c9f6321 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Wed, 16 May 2018 14:46:37 +0200 Subject: [PATCH 1/8] [FIX] point_of_sale: repair cashier from localStorage on refresh page open a pos, change cashier hit F5 Before this commit, the previous user was set as cashier, forgetting about the change we made This was because of two things: - The original fix to do just this use case was pushed in v9.0 as e14ab69 - In v10.0 the commit 475027b (For v11.0: a9caef0) Was intended to update the res.users objects at their loading to ensure that their access rights were loaded too But it did this using the wrong condition After this commit, it reworks fine OPW 1844006 related #24762 closes #24764 --- addons/point_of_sale/static/src/js/models.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 37c115973c4..7cbef6c99dc 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -255,6 +255,7 @@ exports.PosModel = Backbone.Model.extend({ // we attribute a role to the user, 'cashier' or 'manager', depending // on the group the user belongs. var pos_users = []; + var current_cashier = self.get_cashier(); for (var i = 0; i < users.length; i++) { var user = users[i]; for (var j = 0; j < user.groups_id.length; j++) { @@ -272,6 +273,8 @@ exports.PosModel = Backbone.Model.extend({ // replace the current user with its updated version if (user.id === self.user.id) { self.user = user; + } + if (user.id === current_cashier.id) { self.set_cashier(user); } } From cd26eb8e7c3b6062c0c52888fcee0e25d3573728 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Tue, 15 May 2018 13:24:25 +0200 Subject: [PATCH 2/8] [FIX] l10n_fr_fec: EcritureLib should not be empty Make an account move with two move lines. In those lines' label, just hit the space bar, and post your entry. Now, get the FEC report. Before this commit, the EcritureLib field was empty After, it has the value '/' closes #24734 --- addons/l10n_fr_fec/wizard/fec.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/l10n_fr_fec/wizard/fec.py b/addons/l10n_fr_fec/wizard/fec.py index 673b450b789..2d159f96d86 100644 --- a/addons/l10n_fr_fec/wizard/fec.py +++ b/addons/l10n_fr_fec/wizard/fec.py @@ -288,7 +288,9 @@ class AccountFrFec(models.TransientModel): END AS PieceRef, TO_CHAR(am.date, 'YYYYMMDD') AS PieceDate, - CASE WHEN aml.name IS NULL THEN '/' ELSE replace(aml.name, '|', '/') END AS EcritureLib, + CASE WHEN aml.name IS NULL THEN '/' + WHEN aml.name SIMILAR TO '[\t|\s|\n]*' THEN '/' + ELSE replace(aml.name, '|', '/') END AS EcritureLib, replace(CASE WHEN aml.debit = 0 THEN '0,00' ELSE to_char(aml.debit, '000000000000000D99') END, '.', ',') AS Debit, replace(CASE WHEN aml.credit = 0 THEN '0,00' ELSE to_char(aml.credit, '000000000000000D99') END, '.', ',') AS Credit, CASE WHEN rec.name IS NULL THEN '' ELSE rec.name END AS EcritureLet, From a16114efb43da7a14113b061b2ed0f110b668c74 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Wed, 16 May 2018 16:41:07 +0200 Subject: [PATCH 3/8] [FIX] mrp: Two fields with the same label on stock.move The field quantity_done_store had the same label as the field product_uom_qty on model "stock.move" and there were confusions in the pivot view of "stock.move". opw:1841097 --- addons/mrp/i18n/mrp.pot | 5 +++++ addons/mrp/models/stock_move.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/mrp/i18n/mrp.pot b/addons/mrp/i18n/mrp.pot index f5d87479f26..ffa62334b2a 100644 --- a/addons/mrp/i18n/mrp.pot +++ b/addons/mrp/i18n/mrp.pot @@ -2161,6 +2161,11 @@ msgstr "" msgid "Quantity To Produce" msgstr "" +#. module: mrp +#: model:ir.model.fields,field_description:mrp.field_stock_move_quantity_done_store +msgid "Quantity done store" +msgstr "" + #. module: mrp #: model:ir.model.fields,field_description:mrp.field_mrp_routing_workcenter_batch_size msgid "Quantity to Process" diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index c831f49d63d..8fb99e526e9 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -91,7 +91,7 @@ class StockMove(models.Model): quantity_available = fields.Float( 'Quantity Available', compute="_qty_available", digits=dp.get_precision('Product Unit of Measure')) - quantity_done_store = fields.Float('Quantity', digits=0) + quantity_done_store = fields.Float('Quantity done store', digits=0) quantity_done = fields.Float( 'Quantity', compute='_qty_done_compute', inverse='_qty_done_set', digits=dp.get_precision('Product Unit of Measure')) From 866d1e71900fc395a50340dc2ecc645782ad24c5 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 17 May 2018 12:51:29 +0200 Subject: [PATCH 4/8] [FIX] server: fix support for systemd socket activation in threaded server This patches fixes the untested and broken draft of inetd and systemd activation support in the threaded server. This patch also fixes the loss of the process environment in the `_reexec()` function when Odoo is respawning during the following events: - SIGHUP signal is received - one click install has been triggered - code reload needed when using `--dev=reload` --- openerp/service/server.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/openerp/service/server.py b/openerp/service/server.py index c3baace20dc..af01ea9d54f 100644 --- a/openerp/service/server.py +++ b/openerp/service/server.py @@ -91,9 +91,6 @@ class RequestHandler(werkzeug.serving.WSGIRequestHandler): me = threading.currentThread() me.name = 'openerp.service.http.request.%s' % (me.ident,) -# _reexec() should set LISTEN_* to avoid connection refused during reload time. It -# should also work with systemd socket activation. This is currently untested -# and not yet used. class ThreadedWSGIServerReloadable(LoggingBaseWSGIServerMixIn, werkzeug.serving.ThreadedWSGIServer): """ werkzeug Threaded WSGI Server patched to allow reusing a listen socket @@ -105,14 +102,15 @@ class ThreadedWSGIServerReloadable(LoggingBaseWSGIServerMixIn, werkzeug.serving. handler=RequestHandler) def server_bind(self): - envfd = os.environ.get('LISTEN_FDS') - if envfd and os.environ.get('LISTEN_PID') == str(os.getpid()): + SD_LISTEN_FDS_START = 3 + if os.environ.get('LISTEN_FDS') == '1' and os.environ.get('LISTEN_PID') == str(os.getpid()): self.reload_socket = True - self.socket = socket.fromfd(int(envfd), socket.AF_INET, socket.SOCK_STREAM) - # should we os.close(int(envfd)) ? it seem python duplicate the fd. + self.socket = socket.fromfd(SD_LISTEN_FDS_START, socket.AF_INET, socket.SOCK_STREAM) + _logger.info('HTTP service (werkzeug) running through socket activation') else: self.reload_socket = False super(ThreadedWSGIServerReloadable, self).server_bind() + _logger.info('HTTP service (werkzeug) running on %s:%s', self.server_name, self.server_port) def server_activate(self): if not self.reload_socket: @@ -254,7 +252,6 @@ class ThreadedServer(CommonServer): t = threading.Thread(target=self.http_thread, name="openerp.service.httpd") t.setDaemon(True) t.start() - _logger.info('HTTP service (werkzeug) running on %s:%s', self.interface, self.port) def start(self, stop=False): _logger.debug("Setting signal handlers") @@ -853,7 +850,8 @@ def _reexec(updated_modules=None): args += ["-u", ','.join(updated_modules)] if not args or args[0] != exe: args.insert(0, exe) - os.execv(sys.executable, args) + # We should keep the LISTEN_* environment variabled in order to support socket activation on reexec + os.execve(sys.executable, args, os.environ) def load_test_file_yml(registry, test_file): with registry.cursor() as cr: From abda3464edc40b624ee070a92ff506e708f13dc3 Mon Sep 17 00:00:00 2001 From: "Lucas Perais (lpe)" Date: Thu, 17 May 2018 17:33:52 +0200 Subject: [PATCH 5/8] [FIX] web: get_file handles arbitrary AND serialized exceptions Commit bcd4c90 was intendend to make get_file handle uncaught/unserialized exceptions in the context of a http request The drawback is that when get_file received a serialized exception (route: /report/download) the JS modal was empty in that case This commit handles both the cases OPW 1848606 closes #24794 --- addons/web/static/src/js/framework/ajax.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/addons/web/static/src/js/framework/ajax.js b/addons/web/static/src/js/framework/ajax.js index 8f4138a6208..cac9a34a009 100644 --- a/addons/web/static/src/js/framework/ajax.js +++ b/addons/web/static/src/js/framework/ajax.js @@ -232,12 +232,20 @@ function get_file(options) { if (options.error) { var body = this.contentDocument.body; var nodes = body.children.length === 0 ? body.childNodes : body.children; - options.error({ - message: nodes.length > 1 ? nodes[1].textContent : '', - data: { - title: nodes.length > 0 ? nodes[0].textContent : '', - }, - }); + var errorParams = {}; + + try { // Case of a serialized Odoo Exception: It is Json Parsable + var node = nodes[1] || nodes[0]; + errorParams = JSON.parse(node.textContent); + } catch (e) { // Arbitrary uncaught python side exception + errorParams = { + message: nodes.length > 1 ? nodes[1].textContent : '', + data: { + title: nodes.length > 0 ? nodes[0].textContent : '', + } + } + } + options.error(errorParams); } } finally { complete(); From c60b22335be6358307facbe665bbdb3d7f8a435e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Fri, 26 Jan 2018 18:31:50 +0100 Subject: [PATCH 6/8] [FIX] base: honor registry/cache signaling for multiple threaded servers Before this patch the registry and cache signaling was only activated for PreforkServer. In case Odoo was deployed in a multi process/multi threaded architecture the signaling was not ensured, causing registry de-synchronisation amongst threaded servers. --- odoo/modules/registry.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index 50a0be95986..1d05ec466d5 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -127,7 +127,7 @@ class Registry(Mapping): # Indicates that the registry is self.ready = False - # Inter-process signaling (used only when odoo.multi_process is True): + # Inter-process signaling: # The `base_registry_signaling` sequence indicates the whole registry # must be reloaded. # The `base_cache_signaling sequence` indicates all caches must be @@ -357,7 +357,7 @@ class Registry(Mapping): def setup_signaling(self): """ Setup the inter-process signaling on this registry. """ - if not odoo.multi_process: + if self.in_test_mode(): return with self.cursor() as cr: @@ -383,7 +383,7 @@ class Registry(Mapping): """ Check whether the registry has changed, and performs all necessary operations to update the registry. Return an up-to-date registry. """ - if not odoo.multi_process: + if self.in_test_mode(): return self with closing(self.cursor()) as cr: @@ -409,7 +409,7 @@ class Registry(Mapping): def signal_registry_change(self): """ Notifies other processes that the registry has changed. """ - if odoo.multi_process: + if not self.in_test_mode(): _logger.info("Registry changed, signaling through the database") with closing(self.cursor()) as cr: cr.execute("select nextval('base_registry_signaling')") @@ -417,7 +417,7 @@ class Registry(Mapping): def signal_caches_change(self): """ Notifies other processes if caches have been invalidated. """ - if odoo.multi_process and self.cache_cleared: + if self.cache_cleared and not self.in_test_mode(): # signal it through the database to other processes _logger.info("At least one model cache has been invalidated, signaling through the database.") with closing(self.cursor()) as cr: From 612fd33fb136d41cad6d9f9a10e52fdc6556533d Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Fri, 18 May 2018 16:15:55 +0200 Subject: [PATCH 7/8] [FIX] http: correct protocol parsing --- openerp/http.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/http.py b/openerp/http.py index c4c1f95fabf..05778f0d290 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -160,6 +160,7 @@ def redirect_with_hash(url, code=303): # See extensive test page at http://greenbytes.de/tech/tc/httpredirects/ if request.httprequest.user_agent.browser in ('firefox',): return werkzeug.utils.redirect(url, code) + url = url.strip() if urlparse.urlparse(url, scheme='http').scheme not in ('http', 'https'): url = 'http://' + url url = url.replace("'", "%27").replace("<", "%3C") From 9001a75f23c014e744fc1853190297eed4c47438 Mon Sep 17 00:00:00 2001 From: Carlos Dauden Date: Fri, 18 May 2018 17:38:26 +0200 Subject: [PATCH 8/8] [IMP] analytic: Performance on _compute_debit_credit_balance Courtesy of Carlos Dauden. Was PR #24660 --- addons/analytic/models/analytic_account.py | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/addons/analytic/models/analytic_account.py b/addons/analytic/models/analytic_account.py index 0a35ec1fc2a..8350e1a52fa 100644 --- a/addons/analytic/models/analytic_account.py +++ b/addons/analytic/models/analytic_account.py @@ -20,21 +20,24 @@ class AccountAnalyticAccount(models.Model): @api.multi def _compute_debit_credit_balance(self): analytic_line_obj = self.env['account.analytic.line'] - domain = [('account_id', 'in', self.mapped('id'))] + domain = [('account_id', 'in', self.ids)] if self._context.get('from_date', False): domain.append(('date', '>=', self._context['from_date'])) if self._context.get('to_date', False): domain.append(('date', '<=', self._context['to_date'])) - account_amounts = analytic_line_obj.search_read(domain, ['account_id', 'amount']) - account_ids = set([line['account_id'][0] for line in account_amounts]) - data_debit = {account_id: 0.0 for account_id in account_ids} - data_credit = {account_id: 0.0 for account_id in account_ids} - for account_amount in account_amounts: - if account_amount['amount'] < 0.0: - data_debit[account_amount['account_id'][0]] += account_amount['amount'] - else: - data_credit[account_amount['account_id'][0]] += account_amount['amount'] + credit_groups = analytic_line_obj.read_group( + domain=domain + [('amount', '>=', 0.0)], + fields=['account_id', 'amount'], + groupby=['account_id'] + ) + data_credit = {l['account_id'][0]: l['amount'] for l in credit_groups} + debit_groups = analytic_line_obj.read_group( + domain=domain + [('amount', '<', 0.0)], + fields=['account_id', 'amount'], + groupby=['account_id'] + ) + data_debit = {l['account_id'][0]: l['amount'] for l in debit_groups} for account in self: account.debit = abs(data_debit.get(account.id, 0.0))