diff --git a/addons/sale/models/sale_analytic.py b/addons/sale/models/sale_analytic.py index 5849845e660..0475fa3b82a 100644 --- a/addons/sale/models/sale_analytic.py +++ b/addons/sale/models/sale_analytic.py @@ -109,7 +109,11 @@ class AccountAnalyticLine(models.Model): result.update({'so_line': so_lines[0].id}) else: if order.state != 'sale': - raise UserError(_('The Sales Order %s linked to the Analytic Account must be validated before registering expenses.') % order.name) + message_unconfirmed = _('The Sales Order %s linked to the Analytic Account %s must be validated before registering expenses.') + messages = {'draft': message_unconfirmed, 'sent': message_unconfirmed, + 'done': _('The Sales Order %s linked to the Analytic Account %s is currently locked. You cannot register an expense on a locked Sales Order. Please create a new SO linked to this Analytic Account.'), + 'cancel': _('The Sales Order %s linked to the Analytic Account %s is cancelled. You cannot register an expense on a cancelled Sales Order.')} + raise UserError(messages[order.state] % (order.name, self.account_id.name)) order_line_vals = self._get_sale_order_line_vals(order, price) if order_line_vals: so_line = self.env['sale.order.line'].create(order_line_vals) diff --git a/addons/sale_timesheet/models/account.py b/addons/sale_timesheet/models/account.py index 2c15a829172..3c4e60b9d7c 100644 --- a/addons/sale_timesheet/models/account.py +++ b/addons/sale_timesheet/models/account.py @@ -41,7 +41,7 @@ class AccountAnalyticLine(models.Model): emp = self.env['hr.employee'].search([('user_id', '=', user_id)], limit=1) account = values.get('account_id') and self.env['account.analytic.account'].browse([values['account_id']]) or self.account_id or emp.account_id cost = emp and emp.timesheet_cost or 0.0 - uom = account.company_id.sudo().project_time_mode_id + uom = account.sudo().company_id.project_time_mode_id # Nominal employee cost = 1 * company project UoM (project_time_mode_id) return { 'amount': -unit_amount * cost, diff --git a/addons/web_editor/static/src/js/rte.js b/addons/web_editor/static/src/js/rte.js index 564857966b5..da2c2acd5e0 100644 --- a/addons/web_editor/static/src/js/rte.js +++ b/addons/web_editor/static/src/js/rte.js @@ -159,7 +159,7 @@ var History = function History ($editable) { if (aUndo[pos]) { pos = Math.min(pos, aUndo.length); - aUndo.splice(Math.max(pos,1), aUndo.length); + aUndo.splice(pos, aUndo.length); } // => make a snap when the user change editable zone (because: don't make snap for each keydown) diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js index bae44f1998c..e52ea66614d 100644 --- a/addons/web_editor/static/src/js/summernote.js +++ b/addons/web_editor/static/src/js/summernote.js @@ -1115,7 +1115,14 @@ $.summernote.pluginEvents.untab = function (event, editor, layoutInfo) { $.summernote.pluginEvents.up = function (event, editor, layoutInfo) { var r = range.create(); var node = dom.firstChild(r.sc.childNodes[r.so] || r.sc); - if (!r.isOnCell() || (!dom.isCell(node) && dom.hasContentBefore(node) && (!dom.isBR(dom.hasContentBefore(node)) || !dom.isText(node) || dom.isVisibleText(node) || dom.hasContentBefore(dom.hasContentBefore(node))))) { + if (!r.isOnCell()) { + return; + } + // check if an ancestor between node and cell has content before + var ancestor = dom.ancestor(node, function (ancestorNode) { + return dom.hasContentBefore(ancestorNode) || dom.isCell(ancestorNode); + }); + if (!dom.isCell(ancestor) && (!dom.isBR(dom.hasContentBefore(ancestor)) || !dom.isText(node) || dom.isVisibleText(node) || dom.hasContentBefore(dom.hasContentBefore(ancestor)))) { return; } event.preventDefault(); @@ -1132,7 +1139,14 @@ $.summernote.pluginEvents.up = function (event, editor, layoutInfo) { $.summernote.pluginEvents.down = function (event, editor, layoutInfo) { var r = range.create(); var node = dom.firstChild(r.sc.childNodes[r.so] || r.sc); - if (!r.isOnCell() || (!dom.isCell(node) && dom.hasContentAfter(node) && (!dom.isBR(dom.hasContentAfter(node)) || !dom.isText(node) || dom.isVisibleText(node) || dom.hasContentAfter(dom.hasContentAfter(node))))) { + if (!r.isOnCell()) { + return; + } + // check if an ancestor between node and cell has content after + var ancestor = dom.ancestor(node, function (ancestorNode) { + return dom.hasContentAfter(ancestorNode) || dom.isCell(ancestorNode); + }); + if (!dom.isCell(ancestor) && (!dom.isBR(dom.hasContentAfter(ancestor)) || !dom.isText(node) || dom.isVisibleText(node) || dom.hasContentAfter(dom.hasContentAfter(ancestor)))) { return; } event.preventDefault(); diff --git a/odoo/addons/base/res/res_users.py b/odoo/addons/base/res/res_users.py index 8b3a9fd5549..83c75ae99d7 100644 --- a/odoo/addons/base/res/res_users.py +++ b/odoo/addons/base/res/res_users.py @@ -926,9 +926,12 @@ class UsersView(models.Model): # add reified groups fields for app, kind, gs in self.env['res.groups'].sudo().get_groups_by_application(): if kind == 'selection': + field_name = name_selection_groups(gs.ids) + if allfields and field_name not in allfields: + continue # selection group field tips = ['%s: %s' % (g.name, g.comment) for g in gs if g.comment] - res[name_selection_groups(gs.ids)] = { + res[field_name] = { 'type': 'selection', 'string': app.name or _('Other'), 'selection': [(False, '')] + [(g.id, g.name) for g in gs], @@ -939,7 +942,10 @@ class UsersView(models.Model): else: # boolean group fields for g in gs: - res[name_boolean_group(g.id)] = { + field_name = name_boolean_group(g.id) + if allfields and field_name not in allfields: + continue + res[field_name] = { 'type': 'boolean', 'string': g.name, 'help': g.comment,