diff --git a/addons/point_of_sale/models/res_partner.py b/addons/point_of_sale/models/res_partner.py index 8ac23e6bf1a..e094d68cf21 100644 --- a/addons/point_of_sale/models/res_partner.py +++ b/addons/point_of_sale/models/res_partner.py @@ -30,5 +30,6 @@ class ResPartner(models.Model): if partner_id: # Modifying existing partner self.browse(partner_id).write(partner) else: + partner['lang'] = self.env.user.lang partner_id = self.create(partner).id return partner_id diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index a88cdc1ef4e..d413b232c54 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -645,7 +645,7 @@ class StockMove(models.Model): (move.picking_id.picking_type_id.use_existing_lots or move.picking_id.picking_type_id.use_create_lots) and \ move.product_id.tracking != 'none' and \ not (move_line and (move_line.product_id and move_line.pack_lot_ids)) or (move_line and not move_line.product_id): - raise UserError(_('You need to provide a Lot/Serial Number for product %s') % move.product_id.name) + raise UserError(_('You need to provide a Lot/Serial Number for product %s') % ("%s (%s)" % (move.product_id.name, move.picking_id.name))) def _prepare_move_line_vals(self, quantity=None, reserved_quant=None): self.ensure_one() diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index b06b654aefc..fd2d596a4b2 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1016,8 +1016,8 @@ class Binary(http.Controller): elif status != 200 and download: return request.not_found() - height = int(height) - width = int(width) + height = int(height or 0) + width = int(width or 0) if content and (width or height): # resize maximum 500*500 if width > 500: diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js index b61236131c6..4f5719063ff 100644 --- a/addons/web/static/src/js/views/calendar/calendar_renderer.js +++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js @@ -330,11 +330,12 @@ return AbstractRenderer.extend({ } element.find('.fc-content .fc-time').text(display_hour); }, - height: 'auto', + height: 'parent', unselectAuto: false, }); this.$calendar.fullCalendar(fc_options); + window.dispatchEvent(new Event('resize')); }, /** * Initialize the mini calendar in the sidebar diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index fe53bb6cf8a..3674046d5ea 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -114,18 +114,20 @@ var FormRenderer = BasicRenderer.extend({ }); }, /** - * Disable stat buttons so that they can't be clicked anymore + * Disable statusbar buttons and stat buttons so that they can't be clicked anymore * */ disableButtons: function() { - this.$('.oe_button_box button').attr('disabled', true); + this.$('.o_statusbar_buttons button, .oe_button_box button') + .attr('disabled', true); }, /** - * Enable stat buttons so they can be clicked again + * Enable statusbar buttons and stat buttons so they can be clicked again * */ enableButtons: function() { - this.$('.oe_button_box button').removeAttr('disabled'); + this.$('.o_statusbar_buttons button, .oe_button_box button') + .removeAttr('disabled'); }, /** * returns the active tab pages for each notebook diff --git a/addons/web/static/src/less/views.less b/addons/web/static/src/less/views.less index 102d50e7590..876ad01a6e7 100644 --- a/addons/web/static/src/less/views.less +++ b/addons/web/static/src/less/views.less @@ -4,6 +4,9 @@ */ // No content helper +.o_view_manager_content > div { + height: 100%; +} .oe_view_nocontent { a { cursor: pointer; diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 8910316eb21..21464cdd845 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -981,6 +981,37 @@ QUnit.module('Views', { calendar.destroy(); }); + QUnit.test('ensure calendar adapts to screen size', function (assert) { + assert.expect(2); + + // We want to be able to restore changes on 'body' + var bodyStyle = $('body').attr('style'); + + // Force the view height to be smaller than the natural calendar height + // (FullCalendar requires that the height be modified on body not $target) + var height = 500; + $('body').height(height); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: '', + }); + + var $scroller = calendar.$('.fc-scroller') + assert.strictEqual($scroller.height() < height, true, + "the scroller should be smaller than the view height"); + assert.strictEqual($scroller.prop('scrollHeight') > height, true, + "the scroller should have a scrollbar"); + calendar.destroy(); + + $('body').removeAttr('style'); + if (bodyStyle) { + $('body').attr('style', bodyStyle); + } + }); + }); }); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index dbb81967cf9..2198177e43e 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -4946,8 +4946,8 @@ QUnit.module('Views', { _t.database.multi_lang = multi_lang; }); - QUnit.test('buttons are disabled until action is resolved', function (assert) { - assert.expect(3); + QUnit.test('buttons are disabled until status bar action is resolved', function (assert) { + assert.expect(9); var def = $.Deferred(); @@ -4956,6 +4956,10 @@ QUnit.module('Views', { model: 'partner', data: this.data, arch: '
' + + '
' + + '
' + '' + '
' + '' + + '
' + + '' + + '' + + '' + + '
' + + '
', + res_id: 1, + intercepts: { + execute_action: function (event) { + return def.then(function() { + event.data.on_success(); + }); + } + }, + }); + + assert.strictEqual(form.$buttons.find('button:not(:disabled)').length, 4, + "control panel buttons should be enabled"); + assert.strictEqual(form.$('.o_form_statusbar button:not(:disabled)').length, 2, + "status bar buttons should be enabled"); + assert.strictEqual(form.$('.oe_button_box button:not(:disabled)').length, 1, "stat buttons should be enabled"); form.$('.oe_button_box button').click(); // The unresolved deferred lets us check the state of the buttons - assert.ok(form.$('.oe_button_box button').attr('disabled'), + assert.strictEqual(form.$buttons.find('button:disabled').length, 4, + "control panel buttons should be disabled"); + assert.strictEqual(form.$('.o_form_statusbar button:disabled').length, 2, + "status bar buttons should be disabled"); + assert.strictEqual(form.$('.oe_button_box button:disabled').length, 1, "stat buttons should be disabled"); def.resolve(); - assert.notOk(form.$('.oe_button_box button').attr('disabled'), + assert.strictEqual(form.$buttons.find('button:not(:disabled)').length, 4, + "control panel buttons should be enabled"); + assert.strictEqual(form.$('.o_form_statusbar button:not(:disabled)').length, 2, + "status bar buttons should be enabled"); + assert.strictEqual(form.$('.oe_button_box button:not(:disabled)').length, 1, "stat buttons should be enabled"); form.destroy(); diff --git a/addons/website_slides/models/slides.py b/addons/website_slides/models/slides.py index 83252665e96..7a0ee51caf1 100644 --- a/addons/website_slides/models/slides.py +++ b/addons/website_slides/models/slides.py @@ -366,7 +366,10 @@ class Slide(models.Model): if slide.id: # avoid to perform a slug on a not yet saved record in case of an onchange. # link_tracker is not in dependencies, so use it to shorten url only if installed. if self.env.registry.get('link.tracker'): - url = self.env['link.tracker'].sudo().create({'url': '%s/slides/slide/%s' % (base_url, slug(slide))}).short_url + url = self.env['link.tracker'].sudo().create({ + 'url': '%s/slides/slide/%s' % (base_url, slug(slide)), + 'title': slide.name, + }).short_url else: url = '%s/slides/slide/%s' % (base_url, slug(slide)) slide.website_url = url diff --git a/odoo/cli/server.py b/odoo/cli/server.py index afb172b7f3c..180efcfb70f 100644 --- a/odoo/cli/server.py +++ b/odoo/cli/server.py @@ -21,6 +21,8 @@ import threading import traceback import time +from psycopg2 import ProgrammingError, errorcodes + import odoo from . import Command @@ -136,6 +138,15 @@ def main(args): for db_name in preload: try: odoo.service.db._create_empty_database(db_name) + except ProgrammingError as err: + if err.pgcode == errorcodes.INSUFFICIENT_PRIVILEGE: + # We use an INFO loglevel on purpose in order to avoid + # reporting unnecessary warnings on build environment + # using restricted database access. + _logger.info("Could not determine if database %s exists, " + "skipping auto-creation: %s", db_name, err) + else: + raise err except odoo.service.db.DatabaseExists: pass