Skip to content
Browse files

[MERGE] forward port branch 11.0 up to 1e4de19

  • Loading branch information...
KangOl committed Aug 19, 2019
2 parents 76a52bd + 1e4de19 commit 121034f79a6a4e57ed936c8672fc5f8472ca2cfd
@@ -1673,7 +1673,7 @@ def _onchange_account_id(self):
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:

@@ -1509,7 +1509,7 @@ def message_parse(self, message, save_original=False):
# 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'))
@@ -40,7 +40,7 @@ def create(self, vals):
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 @@ def product_compare(self, **post):
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 = or _('Uncategorized')
res.setdefault(cat_name, OrderedDict()).setdefault(, [' - '] * 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 = or _('Uncategorized')
att_name =
if not var.attribute_id.create_variant:
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( or _('Uncategorized'), []).append(var)
return res
@@ -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``
<t t-extend="base.template">
@@ -42,7 +42,9 @@ def _eval_context_for_combinations(self):
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}

def _compute_global(self):
@@ -1,3 +1,4 @@
@@ -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,17 +8,25 @@ 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
'name': 'Forbid negatives',
'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
'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 @@ def test_many2many(self):
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

# record1 is food and is accessible with an empy context
records =[('id', '=', self.id1)])

# it should also be accessible as the context is not used when
# searching for SomeObjs
records = SomeObj.with_context(only_media=True).search([('id', '=', self.id1)])

0 comments on commit 121034f

Please sign in to comment.
You can’t perform that action at this time.