diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index da20b325a3b..2f734dde9ba 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -756,7 +756,7 @@ class WizardMultiChartsAccounts(models.TransientModel): if company_id: company = self.env['res.company'].browse(company_id) currency_id = company.on_change_country(company.country_id.id)['value']['currency_id'] - res.update({'currency_id': currency_id}) + res.update({'currency_id': currency_id.id}) chart_templates = account_chart_template.search([('visible', '=', True)]) if chart_templates: diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py index e9588516a0c..3422edd8cb5 100644 --- a/addons/mrp/wizard/change_production_qty.py +++ b/addons/mrp/wizard/change_production_qty.py @@ -68,7 +68,7 @@ class ChangeProductionQty(models.TransientModel): cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency) quantity = wo.qty_production - wo.qty_produced if production.product_id.tracking == 'serial': - quantity = 1.0 if float_is_zero(quantity, precision_digits=precision) else 0.0 + quantity = 1.0 if not float_is_zero(quantity, precision_digits=precision) else 0.0 else: quantity = quantity if (quantity > 0) else 0 if float_is_zero(quantity, precision_digits=precision): diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 8cf2f5d9a7d..65e4de7faa1 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -1125,12 +1125,15 @@ var ClientListScreenWidget = ScreenWidget.extend({ var self = this; var order = this.pos.get_order(); if( this.has_client_changed() ){ - if ( this.new_client ) { + var default_fiscal_position_id = _.find(this.pos.fiscal_positions, function(fp) { + return fp.id === self.pos.config.default_fiscal_position_id[0]; + }); + if ( this.new_client && this.new_client.property_account_position_id ) { order.fiscal_position = _.find(this.pos.fiscal_positions, function (fp) { return fp.id === self.new_client.property_account_position_id[0]; - }); + }) || default_fiscal_position_id; } else { - order.fiscal_position = undefined; + order.fiscal_position = default_fiscal_position_id; } order.set_client(this.new_client); diff --git a/addons/product/models/product.py b/addons/product/models/product.py index fc21bb7c4bd..d7e9f71705d 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -46,10 +46,13 @@ class ProductCategory(models.Model): category.complete_name = category.name def _compute_product_count(self): - read_group_res = self.env['product.template'].read_group([('categ_id', 'in', self.ids)], ['categ_id'], ['categ_id']) + read_group_res = self.env['product.template'].read_group([('categ_id', 'child_of', self.ids)], ['categ_id'], ['categ_id']) group_data = dict((data['categ_id'][0], data['categ_id_count']) for data in read_group_res) for categ in self: - categ.product_count = group_data.get(categ.id, 0) + product_count = 0 + for sub_categ_id in categ.search([('id', 'child_of', categ.id)]).ids: + product_count += group_data.get(sub_categ_id, 0) + categ.product_count = product_count @api.constrains('parent_id') def _check_category_recursion(self): diff --git a/addons/product/views/product_views.xml b/addons/product/views/product_views.xml index 31eeba88bde..6393f99d003 100644 --- a/addons/product/views/product_views.xml +++ b/addons/product/views/product_views.xml @@ -112,7 +112,7 @@ - + diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 2e108e94e3d..bfeb11ccd7f 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -245,7 +245,8 @@ class Project(models.Model): project = super(Project, self).copy(default) for follower in self.message_follower_ids: project.message_subscribe(partner_ids=follower.partner_id.ids, subtype_ids=follower.subtype_ids.ids) - self.map_tasks(project.id) + if 'tasks' not in default: + self.map_tasks(project.id) return project @api.model @@ -269,6 +270,8 @@ class Project(models.Model): if 'active' in vals: # archiving/unarchiving a project does it on its tasks, too self.with_context(active_test=False).mapped('tasks').write({'active': vals['active']}) + # archiving/unarchiving a project implies that we don't want to use the analytic account anymore + self.with_context(active_test=False).mapped('analytic_account_id').write({'active': vals['active']}) if vals.get('partner_id') or vals.get('privacy_visibility'): for project in self.filtered(lambda project: project.privacy_visibility == 'portal'): project.message_subscribe(project.partner_id.ids) diff --git a/addons/web/static/src/js/chrome/search_inputs.js b/addons/web/static/src/js/chrome/search_inputs.js index d567551873f..a2923d1a607 100644 --- a/addons/web/static/src/js/chrome/search_inputs.js +++ b/addons/web/static/src/js/chrome/search_inputs.js @@ -153,7 +153,7 @@ var Field = Input.extend( /** @lends instance.web.search.Field# */ { value_to_domain = function (facetValue) { return Domain.prototype.stringToArray( domain, - {self: self.value_from(facetValue)} + {self: self.value_from(facetValue), raw_value: facetValue.attributes.value} ); }; } else { diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index ce1a305277f..069e004c702 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -1176,7 +1176,7 @@ var FieldBinaryFile = AbstractFieldBinary.extend({ template: 'FieldBinaryFile', events: _.extend({}, AbstractFieldBinary.prototype.events, { 'click': function (event) { - if (this.mode === 'readonly' && this.value) { + if (this.mode === 'readonly' && this.value && this.recordData.id) { this.on_save_as(event); } }, @@ -1193,6 +1193,11 @@ var FieldBinaryFile = AbstractFieldBinary.extend({ this.do_toggle(!!this.value); if (this.value) { this.$el.empty().append($("").addClass('fa fa-download')); + if (this.recordData.id) { + this.$el.css('cursor', 'pointer'); + } else { + this.$el.css('cursor', 'not-allowed'); + } if (this.filename_value) { this.$el.append(" " + this.filename_value); } diff --git a/addons/web/static/src/js/views/graph/graph_renderer.js b/addons/web/static/src/js/views/graph/graph_renderer.js index 6a976c3a588..4e6c3692aad 100644 --- a/addons/web/static/src/js/views/graph/graph_renderer.js +++ b/addons/web/static/src/js/views/graph/graph_renderer.js @@ -81,7 +81,7 @@ return AbstractRenderer.extend({ setTimeout(function () { self.$el.empty(); var chart = self['_render' + _.str.capitalize(self.state.mode) + 'Chart'](); - if (chart) { + if (chart && chart.tooltip.chartContainer) { self.to_remove = chart.update; nv.utils.onWindowResize(chart.update); chart.tooltip.chartContainer(self.el); diff --git a/addons/web_editor/static/src/js/rte.js b/addons/web_editor/static/src/js/rte.js index f2fb2753642..3f813367ca3 100644 --- a/addons/web_editor/static/src/js/rte.js +++ b/addons/web_editor/static/src/js/rte.js @@ -355,8 +355,8 @@ var RTE = Widget.extend({ var $el = $(this); $el.find('[class]').filter(function () { - if (!this.className.match(/\S/)) { - this.removeAttribute("class"); + if (!this.getAttribute('class').match(/\S/)) { + this.removeAttribute('class'); } }); diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js index 1213b986472..bed19b0acde 100644 --- a/addons/website/static/src/js/website.snippets.animation.js +++ b/addons/website/static/src/js/website.snippets.animation.js @@ -415,16 +415,35 @@ animation.registry.media_video = animation.Class.extend({ start: function () { // TODO: this code should be refactored to make more sense and be better // integrated with Odoo (this refactoring should be done in master). - this.$target.find('iframe').remove(); - if (!this.$target.has('.media_iframe_video_size').length) { - var editor = '
 
'; - var size = '
 
'; - this.$target.html(editor+size); + var def = this._super.apply(this, arguments); + if (this.$target.children('iframe').length) { + // There already is an '); - return this._super.apply(this, arguments); + + // Bug fix / compatibility: empty the
element as all information + // to rebuild the iframe should have been saved on the
element + this.$target.empty(); + + // Add extra content for size / edition + this.$target.append( + '
 
' + + '
 
' + ); + + // Rebuild the iframe. Depending on version / compatibility / instance, + // the src is saved in the 'data-src' attribute or the + // 'data-oe-expression' one (the latter is used as a workaround in 10.0 + // system but should obviously be reviewed in master). + this.$target.append($('