diff --git a/addons/account/views/report_journal.xml b/addons/account/views/report_journal.xml index 06dbab99ae4..c642b89347a 100644 --- a/addons/account/views/report_journal.xml +++ b/addons/account/views/report_journal.xml @@ -50,7 +50,7 @@ - + diff --git a/addons/event/models/res_partner.py b/addons/event/models/res_partner.py index 727de940fa1..009b182c1ae 100644 --- a/addons/event/models/res_partner.py +++ b/addons/event/models/res_partner.py @@ -9,8 +9,10 @@ class ResPartner(models.Model): event_count = fields.Integer("Events", compute='_compute_event_count', help="Number of events the partner has participated.") def _compute_event_count(self): + if not self.user_has_groups('event.group_event_user'): + return for partner in self: - partner.event_count = self.env['event.event'].sudo().search_count([('registration_ids.partner_id', 'child_of', partner.ids)]) + partner.event_count = self.env['event.event'].search_count([('registration_ids.partner_id', 'child_of', partner.ids)]) @api.multi def action_event_view(self): diff --git a/addons/event/views/res_partner_views.xml b/addons/event/views/res_partner_views.xml index 59d096efcd1..22aeba8686a 100644 --- a/addons/event/views/res_partner_views.xml +++ b/addons/event/views/res_partner_views.xml @@ -11,6 +11,7 @@ diff --git a/addons/mail/static/src/js/chat_manager.js b/addons/mail/static/src/js/chat_manager.js index aed6186f9a8..d83054e0f0a 100644 --- a/addons/mail/static/src/js/chat_manager.js +++ b/addons/mail/static/src/js/chat_manager.js @@ -483,7 +483,7 @@ function on_partner_notification (data) { } remove_channel(channel); chat_manager.bus.trigger("unsubscribe_from_channel", data.id); - web_client.do_notify(_("Unsubscribed"), msg); + web_client.do_notify(_t("Unsubscribed"), msg); } } else if (data.type === 'toggle_star') { on_toggle_star_notification(data); diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index bb0dd9366fc..fd8350fe102 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -654,7 +654,7 @@ class StockMove(models.Model): self.product_uom = product.uom_id.id return {'domain': {'product_uom': [('category_id', '=', product.uom_id.category_id.id)]}} - @api.onchange('date') + @api.onchange('date_expected') def onchange_date(self): if self.date_expected: self.date = self.date_expected diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Editor.js b/addons/web_editor/static/lib/summernote/src/js/module/Editor.js index b7ba30bfcd1..99947c346cf 100644 --- a/addons/web_editor/static/lib/summernote/src/js/module/Editor.js +++ b/addons/web_editor/static/lib/summernote/src/js/module/Editor.js @@ -628,9 +628,9 @@ define([ } var anchors = []; - // ODOO: adding this branch to modify existing anchor + // ODOO: adding this branch to modify existing anchor if it fully contains the range var ancestor_anchor = dom.ancestor(rng.sc, dom.isAnchor); - if(ancestor_anchor) { + if(ancestor_anchor && ancestor_anchor === dom.ancestor(rng.ec, dom.isAnchor)) { anchors.push($(ancestor_anchor).html(linkText).get(0)); } else if (isTextChanged) { // Create a new link when text changed. diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js index 7289359290e..2b1f516af84 100644 --- a/addons/web_editor/static/src/js/editor/rte.summernote.js +++ b/addons/web_editor/static/src/js/editor/rte.summernote.js @@ -472,7 +472,7 @@ function prettify_html(html) { while (i--) space += ' '; return space; }, - reg = /^<\/?(a|span|font|strong|u|i|strong|b)(\s|>)/i, + reg = /^<\/?(a|span|font|u|em|i|strong|b)(\s|>)/i, inline_level = Infinity, tokens = _.compact(_.flatten(_.map(html.split(//); diff --git a/addons/web_editor/static/src/js/widgets/widgets.js b/addons/web_editor/static/src/js/widgets/widgets.js index 7854c1852c6..4bad378490d 100644 --- a/addons/web_editor/static/src/js/widgets/widgets.js +++ b/addons/web_editor/static/src/js/widgets/widgets.js @@ -190,8 +190,7 @@ var ImageDialog = Widget.extend({ var img = this.images[0]; if (!img) { - var id = this.$(".existing-attachments [data-src]:first").data('id'); - img = _.find(this.images, function (img) { return img.id === id;}); + return this.media; } var def = $.when(); @@ -1196,6 +1195,8 @@ var LinkDialog = Dialog.extend({ if (dom.ancestor(nodes[i], dom.isImg)) { this.data.images.push(dom.ancestor(nodes[i], dom.isImg)); text += '[IMG]'; + } else if (!is_link && nodes[i].nodeType === 1) { + // just use text nodes from listBetween } else if (!is_link && i===0) { text += nodes[i].textContent.slice(so, Infinity); } else if (!is_link && i===nodes.length-1) { diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py index 0e5443ad79e..aa703071d9b 100644 --- a/addons/website/models/ir_http.py +++ b/addons/website/models/ir_http.py @@ -6,6 +6,7 @@ import traceback import os import unittest +import pytz import werkzeug import werkzeug.routing import werkzeug.utils @@ -74,6 +75,10 @@ class Http(models.AbstractModel): context = {} if not request.context.get('tz'): context['tz'] = request.session.get('geoip', {}).get('time_zone') + try: + pytz.timezone(context['tz'] or '') + except pytz.UnknownTimeZoneError: + context.pop('tz') request.website = request.env['website'].get_current_website() # can use `request.env` since auth methods are called context['website_id'] = request.website.id diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py index b9c08b8232e..7e4a9c227a6 100644 --- a/addons/website_event/controllers/main.py +++ b/addons/website_event/controllers/main.py @@ -259,6 +259,6 @@ class WebsiteEventController(http.Controller): Attendees._prepare_attendee_values(registration)) return request.render("website_event.registration_complete", { - 'attendees': Attendees, + 'attendees': Attendees.sudo(), 'event': event, }) diff --git a/doc/reference/cmdline.rst b/doc/reference/cmdline.rst index 4171f12c5e1..12cd5f7a9d8 100644 --- a/doc/reference/cmdline.rst +++ b/doc/reference/cmdline.rst @@ -221,6 +221,45 @@ database 'verify-ca' or 'verify-full' Default value is 'prefer' +.. _reference/cmdline/server/internationalisation: + +Internationalisation +-------------------- + +Use these options to translate Odoo to another language. See i18n section of +the user manual. Option '-d' is mandatory. Option '-l' is mandatory in case +of importation + +.. option:: --load-language + + specifies the languages (separated by commas) for the translations you + want to be loaded + +.. option:: -l, --language + + specify the language of the translation file. Use it with --i18n-export + or --i18n-import + +.. option:: --i18n-export + + export all sentences to be translated to a CSV file, a PO file or a TGZ + archive and exit. + +.. option:: --i18n-import + + import a CSV or a PO file with translations and exit. The '-l' option is + required. + +.. option:: --i18n-overwrite + + overwrites existing translation terms on updating a module or importing + a CSV or a PO file. + +.. option:: --modules + + specify modules to export. Use in combination with --i18n-export + + built-in HTTP ------------- diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index 1cbe67bd5c3..8122ae4100a 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -153,9 +153,7 @@ class Registry(Mapping): """ Delete the registry linked to a given database. """ with cls._lock: if db_name in cls.registries: - registry = cls.registries.pop(db_name) - registry.clear_caches() - registry.registry_invalidated = True + cls.registries.pop(db_name) @classmethod def delete_all(cls): diff --git a/odoo/service/server.py b/odoo/service/server.py index 259bad913fa..a11e7a503a0 100644 --- a/odoo/service/server.py +++ b/odoo/service/server.py @@ -828,7 +828,6 @@ class WorkerCron(Worker): from odoo.addons import base base.ir.ir_cron.ir_cron._acquire_job(db_name) - odoo.modules.registry.Registry.delete(db_name) # dont keep cursors in multi database mode if len(db_names) > 1: