[MERGE] forward port branch 11.0 up to 1e4de19cd4

This commit is contained in:
Christophe Simonis
2019-08-19 14:43:31 +02:00
10 changed files with 66 additions and 16 deletions
+1 -1
View File
@@ -1673,7 +1673,7 @@ class AccountInvoiceLine(models.Model):
return
if not self.product_id:
fpos = self.invoice_id.fiscal_position_id
self.invoice_line_tax_ids = fpos.map_tax(self.account_id.tax_ids, partner=self.partner_id).ids
self.invoice_line_tax_ids = fpos.map_tax(self.account_id.tax_ids, partner=self.partner_id)
elif not self.price_unit:
self._set_taxes()
+1 -1
View File
@@ -1509,7 +1509,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'))
+1 -1
View File
@@ -40,7 +40,7 @@ class ProductionLot(models.Model):
@api.multi
def write(self, vals):
if 'product_id' in vals:
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 ' +
@@ -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('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.attribute_line_ids.sorted(lambda x: x.attribute_id.sequence):
for var in product.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)
res[cat_name][att_name][num] = val[0].name
values['specs'] = res
@@ -26,6 +26,6 @@ class ProductTemplate(models.Model):
def get_variant_groups(self):
res = OrderedDict()
for var in self.attribute_line_ids.sorted(lambda x: x.attribute_id.sequence):
for var in self.attribute_line_ids.sorted(lambda x: (x.attribute_id.category_id.sequence, x.attribute_id.sequence)):
res.setdefault(var.attribute_id.category_id.name or _('Uncategorized'), []).append(var)
return res
+6 -2
View File
@@ -455,12 +455,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">
+3 -1
View File
@@ -42,7 +42,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):
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_access_right_some_obj access_test_access_right_some_obj model_test_access_right_some_obj 1 1 1 1
3 access_test_access_right_container access_test_access_right_container model_test_access_right_container 1 1 1 1
4 access_test_access_right_obj_categ access_test_access_right_obj_categ model_test_access_right_obj_categ 1 1 1 1
+12
View File
@@ -7,9 +7,21 @@ class SomeObj(models.Model):
_name = 'test_access_right.some_obj'
val = fields.Integer()
categ_id = fields.Many2one('test_access_right.obj_categ')
class Container(models.Model):
_name = '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)
@@ -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'))
@@ -56,3 +64,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)