diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-08-19 16:38:30 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-08-19 16:38:30 +0200 |
| commit | aac8e0c96032c16eeff293216828cbbfc6772dd1 (patch) | |
| tree | 449e2d0dcc5546c18529009cac2bfb510945a87f | |
| parent | f9f288cd476f3ba95887cf1c625d3285d0a051b1 (diff) | |
| parent | 121034f79a6a4e57ed936c8672fc5f8472ca2cfd (diff) | |
[MERGE] forward port branch saas-11.3 up to 121034f79a6
| -rw-r--r-- | addons/account/models/account_invoice.py | 2 | ||||
| -rw-r--r-- | addons/mail/models/mail_thread.py | 2 | ||||
| -rw-r--r-- | addons/stock/models/stock_production_lot.py | 2 | ||||
| -rw-r--r-- | addons/website_sale_comparison/controllers/main.py | 11 | ||||
| -rw-r--r-- | doc/reference/qweb.rst | 8 | ||||
| -rw-r--r-- | odoo/addons/base/models/ir_rule.py | 4 | ||||
| -rw-r--r-- | odoo/addons/test_access_rights/ir.model.access.csv | 1 | ||||
| -rw-r--r-- | odoo/addons/test_access_rights/models.py | 12 | ||||
| -rw-r--r-- | odoo/addons/test_access_rights/tests/test_ir_rules.py | 38 |
9 files changed, 65 insertions, 15 deletions
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index cc2a5a90a81..4caeb61d2ee 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -1853,7 +1853,7 @@ class AccountInvoiceLine(models.Model): default_tax = self.invoice_id.company_id.account_sale_tax_id else: default_tax = self.invoice_id.company_id.account_purchase_tax_id - self.invoice_line_tax_ids = fpos.map_tax(self.account_id.tax_ids or default_tax, partner=self.partner_id).ids + self.invoice_line_tax_ids = fpos.map_tax(self.account_id.tax_ids or default_tax, partner=self.partner_id) elif not self.price_unit: self._set_taxes() diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 27386fce958..4aee83a9d2f 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -1642,7 +1642,7 @@ class MailThread(models.AbstractModel): # Very unusual situation, be we should be fault-tolerant here message_id = "<%s@localhost>" % time.time() _logger.debug('Parsing Message without message-id, generating a random one: %s', message_id) - msg_dict['message_id'] = message_id + msg_dict['message_id'] = message_id.strip() if message.get('Subject'): msg_dict['subject'] = tools.decode_smtp_header(message.get('Subject')) diff --git a/addons/stock/models/stock_production_lot.py b/addons/stock/models/stock_production_lot.py index 584215620e6..d42ab799baf 100644 --- a/addons/stock/models/stock_production_lot.py +++ b/addons/stock/models/stock_production_lot.py @@ -39,7 +39,7 @@ class ProductionLot(models.Model): @api.multi def write(self, vals): if 'product_id' in vals and any([vals['product_id'] != lot.product_id.id for lot in self]): - move_lines = self.env['stock.move.line'].search([('lot_id', 'in', self.ids)]) + move_lines = self.env['stock.move.line'].search([('lot_id', 'in', self.ids), ('product_id', '!=', vals['product_id'])]) if move_lines: raise UserError(_( 'You are not allowed to change the product linked to a serial or lot number ' + diff --git a/addons/website_sale_comparison/controllers/main.py b/addons/website_sale_comparison/controllers/main.py index f6cb6cfc0fe..a2dac3d4904 100644 --- a/addons/website_sale_comparison/controllers/main.py +++ b/addons/website_sale_comparison/controllers/main.py @@ -18,14 +18,15 @@ class WebsiteSaleProductComparison(WebsiteSale): products = request.env['product.product'].search([('id', 'in', product_ids)]) values['products'] = products.with_context(display_default_code=False) - res = {} + res = OrderedDict() + attrs = products.mapped('product_tmpl_id.valid_product_template_attribute_line_ids.attribute_id').filtered(lambda x: x.create_variant) + for attr in attrs.sorted(lambda att: (att.category_id.sequence, att.sequence)): + cat_name = attr.category_id.name or _('Uncategorized') + res.setdefault(cat_name, OrderedDict()).setdefault(attr.name, [' - '] * len(products)) for num, product in enumerate(products): - for var in product.product_tmpl_id._get_valid_product_template_attribute_lines(): + for var in product.product_tmpl_id.valid_product_template_attribute_line_ids.filtered(lambda x: x.attribute_id.create_variant): cat_name = var.attribute_id.category_id.name or _('Uncategorized') att_name = var.attribute_id.name - if not var.attribute_id.create_variant: - continue - res.setdefault(cat_name, OrderedDict()).setdefault(att_name, [' - '] * len(products)) val = product.attribute_value_ids.filtered(lambda x: x.attribute_id == var.attribute_id) if val: res[cat_name][att_name][num] = val[0].name diff --git a/doc/reference/qweb.rst b/doc/reference/qweb.rst index f4f464f7aa9..5d910d3b061 100644 --- a/doc/reference/qweb.rst +++ b/doc/reference/qweb.rst @@ -458,12 +458,16 @@ template inheritance '''''''''''''''''''' Template inheritance is used to alter existing templates in-place, e.g. to -add information to templates created by an other modules. +add information to templates created by other modules. Template inheritance is performed via the ``t-extend`` directive which takes the name of the template to alter as parameter. -The alteration is then performed with any number of ``t-jquery`` +When ``t-extend`` is combined with ``t-name`` a new template with the given name +is created. In this case the extended template is not altered, instead the +directives define how to create the new template. + +In both cases the alteration is then performed with any number of ``t-jquery`` sub-directives:: <t t-extend="base.template"> diff --git a/odoo/addons/base/models/ir_rule.py b/odoo/addons/base/models/ir_rule.py index 9f63a415892..db319a8a32e 100644 --- a/odoo/addons/base/models/ir_rule.py +++ b/odoo/addons/base/models/ir_rule.py @@ -44,7 +44,9 @@ class IrRule(models.Model): def _eval_context(self): """Returns a dictionary to use as evaluation context for ir.rule domains.""" - return {'user': self.env.user, 'time': time} + # use an empty context for 'user' to make the domain evaluation + # independent from the context + return {'user': self.env.user.with_context({}), 'time': time} @api.depends('groups') def _compute_global(self): diff --git a/odoo/addons/test_access_rights/ir.model.access.csv b/odoo/addons/test_access_rights/ir.model.access.csv index eda40f960d9..4bbc5b37c59 100644 --- a/odoo/addons/test_access_rights/ir.model.access.csv +++ b/odoo/addons/test_access_rights/ir.model.access.csv @@ -1,3 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_test_access_right_some_obj,access_test_access_right_some_obj,model_test_access_right_some_obj,,1,1,1,1 access_test_access_right_container,access_test_access_right_container,model_test_access_right_container,,1,1,1,1 +access_test_access_right_obj_categ,access_test_access_right_obj_categ,model_test_access_right_obj_categ,,1,1,1,1 diff --git a/odoo/addons/test_access_rights/models.py b/odoo/addons/test_access_rights/models.py index f0660776d70..5af1feb855b 100644 --- a/odoo/addons/test_access_rights/models.py +++ b/odoo/addons/test_access_rights/models.py @@ -8,6 +8,7 @@ class SomeObj(models.Model): _description = 'Object For Test Access Right' val = fields.Integer() + categ_id = fields.Many2one('test_access_right.obj_categ') class Container(models.Model): @@ -15,3 +16,14 @@ class Container(models.Model): _description = 'Test Access Right Container' some_ids = fields.Many2many('test_access_right.some_obj', 'test_access_right_rel', 'container_id', 'some_id') + + +class ObjCateg(models.Model): + _name = 'test_access_right.obj_categ' + + name = fields.Char(required=True) + + def search(self, args, **kwargs): + if self.env.context.get('only_media'): + args += [('name', '=', 'Media')] + return super(ObjCateg, self).search(args, **kwargs) diff --git a/odoo/addons/test_access_rights/tests/test_ir_rules.py b/odoo/addons/test_access_rights/tests/test_ir_rules.py index 6724bdbf1e4..249918462d1 100644 --- a/odoo/addons/test_access_rights/tests/test_ir_rules.py +++ b/odoo/addons/test_access_rights/tests/test_ir_rules.py @@ -8,10 +8,11 @@ class TestRules(TransactionCase): def setUp(self): super(TestRules, self).setUp() - self.id1 = self.env['test_access_right.some_obj']\ - .create({'val': 1}).id - self.id2 = self.env['test_access_right.some_obj']\ - .create({'val': -1}).id + ObjCateg = self.env['test_access_right.obj_categ'] + SomeObj = self.env['test_access_right.some_obj'] + self.categ1 = ObjCateg.create({'name': 'Food'}).id + self.id1 = SomeObj.create({'val': 1, 'categ_id': self.categ1}).id + self.id2 = SomeObj.create({'val': -1, 'categ_id': self.categ1}).id # create a global rule forbidding access to records with a negative # (or zero) val self.env['ir.rule'].create({ @@ -19,6 +20,13 @@ class TestRules(TransactionCase): 'model_id': self.browse_ref('test_access_rights.model_test_access_right_some_obj').id, 'domain_force': "[('val', '>', 0)]" }) + # create a global rule that forbid access to records without + # categories, the search is part of the test + self.env['ir.rule'].create({ + 'name': 'See all categories', + 'model_id': self.browse_ref('test_access_rights.model_test_access_right_some_obj').id, + 'domain_force': "[('categ_id', 'in', user.env['test_access_right.obj_categ'].search([]).ids)]" + }) def test_basic_access(self): env = self.env(user=self.browse_ref('base.public_user')) @@ -76,3 +84,25 @@ class TestRules(TransactionCase): container_user.write({'some_ids': [(5,)]}) self.assertItemsEqual(container_user.some_ids.ids, []) self.assertItemsEqual(container_admin.some_ids.ids, [self.id2]) + + def test_no_context_in_ir_rules(self): + """ The context should not impact the ir rules. """ + env = self.env(user=self.browse_ref('base.public_user')) + ObjCateg = self.env['test_access_right.obj_categ'] + SomeObj = self.env['test_access_right.some_obj'] + + # validate the effect of context on category search, there are + # no existing media category + self.assertTrue(ObjCateg.search([])) + self.assertFalse(ObjCateg.with_context(only_media=True).search([])) + + # record1 is food and is accessible with an empy context + ObjCateg.clear_caches() + records = SomeObj.search([('id', '=', self.id1)]) + self.assertTrue(records) + + # it should also be accessible as the context is not used when + # searching for SomeObjs + ObjCateg.clear_caches() + records = SomeObj.with_context(only_media=True).search([('id', '=', self.id1)]) + self.assertTrue(records) |
