diff --git a/addons/board/static/src/scss/dashboard.scss b/addons/board/static/src/scss/dashboard.scss
index ad718403495..7bd942eb0e3 100644
--- a/addons/board/static/src/scss/dashboard.scss
+++ b/addons/board/static/src/scss/dashboard.scss
@@ -123,8 +123,8 @@
}
// Override height of graph. min-height doesn't do the trick
- .o_graph_controller {
- height: 500px;
+ .o_graph_svg_container {
+ height: 250px;
}
}
}
diff --git a/addons/calendar/models/res_partner.py b/addons/calendar/models/res_partner.py
index 403d70b18fc..261b955fc8f 100644
--- a/addons/calendar/models/res_partner.py
+++ b/addons/calendar/models/res_partner.py
@@ -11,7 +11,7 @@ from odoo.addons.calendar.models.calendar import get_real_ids
class Partner(models.Model):
_inherit = 'res.partner'
- calendar_last_notif_ack = fields.Datetime('Last notification marked as read from base Calendar')
+ calendar_last_notif_ack = fields.Datetime('Last notification marked as read from base Calendar', default=fields.Datetime.now)
@api.multi
def get_attendee_detail(self, meeting_id):
diff --git a/addons/mail/models/ir_attachment.py b/addons/mail/models/ir_attachment.py
index 4330059c495..527b22409d6 100644
--- a/addons/mail/models/ir_attachment.py
+++ b/addons/mail/models/ir_attachment.py
@@ -13,9 +13,22 @@ class IrAttachment(models.Model):
"""
super(IrAttachment, self)._post_add_create()
for record in self:
- record.register_as_main_attachment()
+ record.register_as_main_attachment(force=False)
- def register_as_main_attachment(self):
+ @api.multi
+ def unlink(self):
+ self.remove_as_main_attachment()
+ super(IrAttachment, self).unlink()
+
+ @api.multi
+ def remove_as_main_attachment(self):
+ for attachment in self:
+ related_record = self.env[attachment.res_model].browse(attachment.res_id)
+ if related_record and hasattr(related_record, 'message_main_attachment_id'):
+ if related_record.message_main_attachment_id == attachment:
+ related_record.message_main_attachment_id = False
+
+ def register_as_main_attachment(self, force=True):
""" Registers this attachment as the main one of the model it is
attached to.
"""
@@ -24,4 +37,5 @@ class IrAttachment(models.Model):
# message_main_attachment_id field can be empty, that's why we compare to False;
# we are just checking that it exists on the model before writing it
if related_record and hasattr(related_record, 'message_main_attachment_id'):
- related_record.message_main_attachment_id = self
+ if force or not related_record.message_main_attachment_id:
+ related_record.message_main_attachment_id = self
diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js
index 72971fbeee9..5f9b11198e3 100644
--- a/addons/mail/static/src/js/chatter.js
+++ b/addons/mail/static/src/js/chatter.js
@@ -81,6 +81,7 @@ var Chatter = Widget.extend({
var nodeOptions = fieldsInfo[mailFields.mail_thread].options || {};
this.hasLogButton = options.display_log_button || nodeOptions.display_log_button;
this.postRefresh = nodeOptions.post_refresh || 'never';
+ this.reloadOnUploadAttachment = this.postRefresh === 'always';
}
},
/**
@@ -572,6 +573,9 @@ var Chatter = Widget.extend({
* @private
*/
_onReloadAttachmentBox: function () {
+ if (this.reloadOnUploadAttachment) {
+ this.trigger_up('reload');
+ }
this._reloadAttachmentBox();
},
/**
diff --git a/addons/mrp/wizard/mrp_product_produce.py b/addons/mrp/wizard/mrp_product_produce.py
index b88b7a45eda..d29fc0c140d 100644
--- a/addons/mrp/wizard/mrp_product_produce.py
+++ b/addons/mrp/wizard/mrp_product_produce.py
@@ -189,7 +189,7 @@ class MrpProductProduceLine(models.TransientModel):
product_produce_id = fields.Many2one('mrp.product.produce')
product_id = fields.Many2one('product.product', 'Product')
- product_tracking = fields.Selection(related="product_id.tracking", readonly=False)
+ product_tracking = fields.Selection(related="product_id.tracking")
lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
qty_to_consume = fields.Float('To Consume', digits=dp.get_precision('Product Unit of Measure'))
product_uom_id = fields.Many2one('uom.uom', 'Unit of Measure')
diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py
index 0928aab1815..08b1aa26a8c 100644
--- a/addons/product/models/product_template.py
+++ b/addons/product/models/product_template.py
@@ -523,6 +523,7 @@ class ProductTemplate(models.Model):
variants_to_create.append({
'product_tmpl_id': tmpl_id.id,
'attribute_value_ids': [(6, 0, list(value_ids))],
+ 'active': tmpl_id.active,
})
if len(variants_to_create) > 1000:
raise UserError(_(
@@ -962,8 +963,10 @@ class ProductTemplate(models.Model):
if not self.active:
return _("The product template is archived so no combination is possible.")
- ptal_stack = [self._get_valid_product_template_attribute_lines()]
- combination_stack = [self.env['product.template.attribute.value']]
+ necessary_values = necessary_values or self.env['product.template.attribute.value']
+ necessary_attributes = necessary_values.mapped('attribute_id')
+ ptal_stack = [self.valid_product_template_attribute_line_ids.filtered(lambda ptal: ptal.attribute_id not in necessary_attributes)]
+ combination_stack = [necessary_values]
# keep going while we have attribute lines to test
while len(ptal_stack):
@@ -972,7 +975,7 @@ class ProductTemplate(models.Model):
if not attribute_lines:
# full combination, if it's possible return it, otherwise skip it
- if self._is_combination_possible(combination, parent_combination) and all(v in combination for v in (necessary_values or [])):
+ if self._is_combination_possible(combination, parent_combination):
yield(combination)
else:
# we have remaining attribute lines to consider
diff --git a/addons/product/tests/test_product_attribute_value_config.py b/addons/product/tests/test_product_attribute_value_config.py
index aa1de67d16b..e966adbdbdc 100644
--- a/addons/product/tests/test_product_attribute_value_config.py
+++ b/addons/product/tests/test_product_attribute_value_config.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import time
+
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
@@ -423,6 +425,47 @@ class TestProductAttributeValueConfig(TestProductAttributeValueSetup):
self.assertEqual(self.computer._get_closest_possible_combination(computer_ssd_256 + computer_ram_8 + computer_hdd_4 + computer_hdd_2),
computer_ssd_256 + computer_ram_8 + computer_hdd_4)
+ # Make sure this is not extremely slow:
+ product_template = self.env['product.template'].create({
+ 'name': 'many combinations',
+ })
+
+ for i in range(10):
+ # create the attributes
+ product_attribute = self.env['product.attribute'].create({
+ 'name': "att %s" % i,
+ 'create_variant': 'dynamic',
+ 'sequence': i,
+ })
+
+ for j in range(10):
+ # create the attribute values
+ self.env['product.attribute.value'].create([{
+ 'name': "val %s/%s" % (i, j),
+ 'attribute_id': product_attribute.id,
+ 'sequence': j,
+ }])
+
+ # set attribute and attribute values on the template
+ self.env['product.template.attribute.line'].create([{
+ 'attribute_id': product_attribute.id,
+ 'product_tmpl_id': product_template.id,
+ 'value_ids': [(6, 0, product_attribute.value_ids.ids)]
+ }])
+
+ # Get a value in the middle for each attribute to make sure it would
+ # take time to reach it (if looping one by one like before the fix).
+ combination = self.env['product.template.attribute.value']
+ for ptal in product_template.attribute_line_ids:
+ combination += ptal.product_template_value_ids[5]
+
+ started_at = time.time()
+ self.assertEqual(product_template._get_closest_possible_combination(combination), combination)
+ elapsed = time.time() - started_at
+ # It should take around 10ms, but to avoid false positives we check an
+ # higher value. Before the fix it would take hours.
+ self.assertLess(elapsed, 0.5)
+
def test_clear_caches(self):
"""The goal of this test is to make sure the cache is invalidated when
it should be."""
diff --git a/addons/sale/report/sale_report_templates.xml b/addons/sale/report/sale_report_templates.xml
index 380596eb181..c8c9612326a 100644
--- a/addons/sale/report/sale_report_templates.xml
+++ b/addons/sale/report/sale_report_templates.xml
@@ -70,11 +70,15 @@