'res/res_partner_image_demo.xml',
],
'test': [
- 'test/base_test.yml',
- 'test/test_osv_expression.yml',
- 'test/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules.
+ 'tests/base_test.yml',
+ 'tests/test_osv_expression.yml',
+ 'tests/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules.
],
'installable': True,
'auto_install': True,
_defaults = {
'company_id': _get_company_id,
}
-ir_default()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
'export_fields': fields.one2many('ir.exports.line', 'export_id',
'Export ID'),
}
-ir_exports()
class ir_exports_line(osv.osv):
'name': fields.char('Field Name', size=64),
'export_id': fields.many2one('ir.exports', 'Export', select=True, ondelete='cascade'),
}
-ir_exports_line()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
'is_default': False
}
-ir_filters()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
self.clear_cache(cr,uid)
return res
-ir_rule()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
'|', ('company_id', '=', cid), ('company_id', '=', False)]
return domain
-ir_property()
-
-
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
result.append((bank.id, (bank.bic and (bank.bic + ' - ') or '') + bank.name))
return result
-Bank()
-
-
class res_partner_bank_type(osv.osv):
_description='Bank Account Type'
_name = 'res.partner.bank.type'
_defaults = {
'format_layout': lambda *args: "%(bank_name)s: %(acc_number)s"
}
-res_partner_bank_type()
class res_partner_bank_type_fields(osv.osv):
_description='Bank type fields'
'readonly': fields.boolean('Readonly'),
'size': fields.integer('Max. Size'),
}
-res_partner_bank_type_fields()
-
class res_partner_bank(osv.osv):
'''Bank Accounts'''
result['state_id'] = part.state_id.id
return {'value': result}
-res_partner_bank()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
else:
return from_amount * rate
-res_currency()
-
class res_currency_rate_type(osv.osv):
_name = "res.currency.rate.type"
_description = "Currency Rate Type"
'name': fields.char('Name', size=64, required=True, translate=True),
}
-res_currency_rate_type()
-
class res_currency_rate(osv.osv):
_name = "res.currency.rate"
_description = "Currency Rate"
}
_order = "name desc"
-res_currency_rate()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+++ /dev/null
-- |
- To check that common dangerous operations are not allowed by the safe_eval mechanism, attempt to
- evaluate unauthorized expressions, and verify that they trigger an error.
--
- 1. Try a few common expressions to verify they work with safe_eval
--
- !python {model: ir.model}: |
- from openerp.tools.safe_eval import safe_eval
- expected = (1, {"a": 9 * 2}, (True, False, None))
- actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
- assert actual == expected, "Simple python expressions are not working with safe_eval"
--
- 2. Try simple literal definition to verify it works with literal_eval
--
- !python {model: ir.model}: |
- import ast
- expected = (1, {"a": 9}, (True, False, None))
- actual = ast.literal_eval('(1, {"a": 9}, (True, False, None))')
- assert actual == expected, "Simple python expressions are not working with literal_eval"
--
- 3. Try arithmetic expression in literal_eval to verify it does not work
--
- !python {model: ir.model}: |
- import ast
- try:
- ast.literal_eval('(1, {"a": 2*9}, (True, False, None))')
- assert False, "literal_eval should not accept arithmetic expressions"
- except ValueError:
- pass
--
- 4. Try forbidden expressions in literal_eval to verify they are not allowed
--
- !python {model: ir.model}: |
- import ast
- try:
- ast.literal_eval('{"a": True.__class__}')
- assert False, "literal_eval should accept only literals"
- except ValueError:
- pass
--
- 5. Try forbidden expressions in safe_eval to verify they are not allowed (open)
--
- !python {model: ir.model}: |
- from openerp.tools.safe_eval import safe_eval
- from openerp.tools.misc import mute_logger
- try:
- with mute_logger('openerp.tools.safe_eval'):
- safe_eval('open("/etc/passwd","r")')
- assert False, "safe_eval should not allow calling open() builtin"
- except ValueError:
- pass
-
--
- "ORM test: verify that parent_store computation are going right"
--
- 0. Emulate normal behavior of tree structure storing
--
- !python {model: res.partner.category}: |
- # pretend the pool has finished loading to avoid deferring parent_store computation
- self.pool._init = False
--
- "1.0 Setup test partner categories: parent root"
--
- !record {model: res.partner.category, id: test_categ_root}:
- name: Root category
--
- "1.1 Setup test partner categories: parent category"
--
- !record {model: res.partner.category, id: test_categ_0}:
- name: Parent category
- parent_id: test_categ_root
--
- "1.2 Setup test partner categories: child 1"
--
- !record {model: res.partner.category, id: test_categ_1}:
- name: Child 1
- parent_id: test_categ_0
--
- "1.3 Setup test partner categories: child 2"
--
- !record {model: res.partner.category, id: test_categ_2}:
- name: Child 2
- parent_id: test_categ_0
--
- "1.4 Setup test partner categories: child 2-1"
--
- !record {model: res.partner.category, id: test_categ_21}:
- name: Child 2-1
- parent_id: test_categ_2
--
- 2. Duplicate the parent category and verify that the children have been duplicated too and are below the new parent
--
- !python {model: res.partner.category}: |
- new_id = self.copy(cr, uid, ref('test_categ_0'))
- new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
- assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
- old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
- assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
- assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
--
- 3. Duplicate the children then reassign them to the new parent (1st method) and check the parent_store structure.
--
- !python {model: res.partner.category}: |
- new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
- new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
- new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []})
- self.write(cr, uid, [new_child1_id, new_child2_id], {'parent_id': new_id})
- new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
- assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
- old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
- assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
- assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
--
- 4. Duplicate the children then reassign them to the new parent (2nd method) and check the parent_store structure.
--
- !python {model: res.partner.category}: |
- new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
- new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
- old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
- new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': [(6,0,[new_child1_id, new_child2_id])]})
- new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
- assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
- old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
- assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
- assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
--
- 5. Duplicate the children then reassign them to the new parent (3rd method) and make sure the parent_store structure is still right.
--
- !python {model: res.partner.category}: |
- new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
- new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
- new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []})
- self.write(cr, uid, [new_id], {'child_ids': [(4,new_child1_id), (4,new_child2_id)]})
- new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
- assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
- old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
- assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
- assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
--
- 6. Restore pool state after the test
--
- !python {model: res.partner.category}: |
- self.pool._init = True
-
--
- "Float precision tests: verify that float rounding methods are working correctly via res.currency"
--
- !python {model: res.currency}: |
- from openerp.tools import float_repr
- from math import log10
- currency = self.browse(cr, uid, ref('base.EUR'))
- def try_round(amount, expected, self=self, cr=cr, currency=currency, float_repr=float_repr,
- log10=log10):
- digits = max(0,-int(log10(currency.rounding)))
- result = float_repr(self.round(cr, 1, currency, amount), precision_digits=digits)
- assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
- try_round(2.674,'2.67')
- try_round(2.675,'2.68') # in Python 2.7.2, round(2.675,2) gives 2.67
- try_round(-2.675,'-2.68') # in Python 2.7.2, round(2.675,2) gives 2.67
- try_round(0.001,'0.00')
- try_round(-0.001,'-0.00')
- try_round(0.0049,'0.00') # 0.0049 is closer to 0 than to 0.01, so should round down
- try_round(0.005,'0.01') # the rule is to round half away from zero
- try_round(-0.005,'-0.01') # the rule is to round half away from zero
-
- def try_zero(amount, expected, self=self, cr=cr, currency=currency):
- assert self.is_zero(cr, 1, currency, amount) == expected, "Rounding error: %s should be zero!" % amount
- try_zero(0.01, False)
- try_zero(-0.01, False)
- try_zero(0.001, True)
- try_zero(-0.001, True)
- try_zero(0.0046, True)
- try_zero(-0.0046, True)
- try_zero(2.68-2.675, False) # 2.68 - 2.675 = 0.005 -> rounds to 0.01
- try_zero(2.68-2.676, True) # 2.68 - 2.675 = 0.004 -> rounds to 0.0
- try_zero(2.676-2.68, True) # 2.675 - 2.68 = -0.004 -> rounds to -0.0
- try_zero(2.675-2.68, False) # 2.675 - 2.68 = -0.005 -> rounds to -0.01
-
- def try_compare(amount1, amount2, expected, self=self, cr=cr, currency=currency):
- assert self.compare_amounts(cr, 1, currency, amount1, amount2) == expected, \
- "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)
- try_compare(0.001, 0.001, 0)
- try_compare(-0.001, -0.001, 0)
- try_compare(0.001, 0.002, 0)
- try_compare(-0.001, -0.002, 0)
- try_compare(2.675, 2.68, 0)
- try_compare(2.676, 2.68, 0)
- try_compare(-2.676, -2.68, 0)
- try_compare(2.674, 2.68, -1)
- try_compare(-2.674, -2.68, 1)
- try_compare(3, 2.68, 1)
- try_compare(-3, -2.68, -1)
- try_compare(0.01, 0, 1)
- try_compare(-0.01, 0, -1)
-
--
- "Float precision tests: verify that float rounding methods are working correctly via tools"
--
- !python {model: res.currency}: |
- from openerp.tools import float_compare, float_is_zero, float_round, float_repr
- def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr):
- result = float_repr(float_round(amount, precision_digits=precision_digits),
- precision_digits=precision_digits)
- assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
- try_round(2.6745, '2.675')
- try_round(-2.6745, '-2.675')
- try_round(2.6744, '2.674')
- try_round(-2.6744, '-2.674')
- try_round(0.0004, '0.000')
- try_round(-0.0004, '-0.000')
- try_round(357.4555, '357.456')
- try_round(-357.4555, '-357.456')
- try_round(457.4554, '457.455')
- try_round(-457.4554, '-457.455')
-
- # Extended float range test, inspired by Cloves Almeida's test on bug #882036.
- fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
- expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']
- precisions = [2, 2, 2, 2, 2, 2, 3, 4]
- # Note: max precision for double floats is 53 bits of precision or
- # 17 significant decimal digits
- for magnitude in range(7):
- for i in xrange(len(fractions)):
- frac, exp, prec = fractions[i], expecteds[i], precisions[i]
- for sign in [-1,1]:
- for x in xrange(0,10000,97):
- n = x * 10**magnitude
- f = sign * (n + frac)
- f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
- try_round(f, f_exp, precision_digits=prec)
-
-
- def try_zero(amount, expected, float_is_zero=float_is_zero):
- assert float_is_zero(amount, precision_digits=3) == expected, "Rounding error: %s should be zero!" % amount
- try_zero(0.0002, True)
- try_zero(-0.0002, True)
- try_zero(0.00034, True)
- try_zero(0.0005, False)
- try_zero(-0.0005, False)
- try_zero(0.0008, False)
- try_zero(-0.0008, False)
-
- def try_compare(amount1, amount2, expected, float_compare=float_compare):
- assert float_compare(amount1, amount2, precision_digits=3) == expected, \
- "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)
- try_compare(0.0003, 0.0004, 0)
- try_compare(-0.0003, -0.0004, 0)
- try_compare(0.0002, 0.0005, -1)
- try_compare(-0.0002, -0.0005, 1)
- try_compare(0.0009, 0.0004, 1)
- try_compare(-0.0009, -0.0004, -1)
- try_compare(557.4555, 557.4556, 0)
- try_compare(-557.4555, -557.4556, 0)
- try_compare(657.4444, 657.445, -1)
- try_compare(-657.4444, -657.445, 1)
-
- # Rounding to unusual rounding units (e.g. coin values)
- def try_round(amount, expected, precision_rounding=None, float_round=float_round, float_repr=float_repr):
- result = float_repr(float_round(amount, precision_rounding=precision_rounding),
- precision_digits=2)
- assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
- try_round(-457.4554, '-457.45', precision_rounding=0.05)
- try_round(457.444, '457.50', precision_rounding=0.5)
- try_round(457.3, '455.00', precision_rounding=5)
- try_round(457.5, '460.00', precision_rounding=5)
- try_round(457.1, '456.00', precision_rounding=3)
-
--
- "Float precision tests: check that proper rounding is performed for float persistence"
--
- !python {model: res.currency}: |
- currency = self.browse(cr, uid, ref('base.EUR'))
- res_currency_rate = self.pool.get('res.currency.rate')
- from openerp.tools import float_compare, float_is_zero, float_round, float_repr
- def try_roundtrip(value, expected, self=self, cr=cr, currency=currency,
- res_currency_rate=res_currency_rate):
- rate_id = res_currency_rate.create(cr, 1, {'name':'2000-01-01',
- 'rate': value,
- 'currency_id': currency.id})
- rate = res_currency_rate.read(cr, 1, rate_id, ['rate'])['rate']
- assert rate == expected, 'Roundtrip error: got %s back from db, expected %s' % (rate, expected)
- # res.currency.rate uses 6 digits of precision by default
- try_roundtrip(2.6748955, 2.674896)
- try_roundtrip(-2.6748955, -2.674896)
- try_roundtrip(10000.999999, 10000.999999)
- try_roundtrip(-10000.999999, -10000.999999)
-
--
- "Float precision tests: verify that invalid parameters are forbidden"
--
- !python {model: res.currency}: |
- from openerp.tools import float_compare, float_is_zero, float_round
- try:
- float_is_zero(0.01, precision_digits=3, precision_rounding=0.01)
- except AssertionError:
- pass
- try:
- float_compare(0.01, 0.02, precision_digits=3, precision_rounding=0.01)
- except AssertionError:
- pass
- try:
- float_round(0.01, precision_digits=3, precision_rounding=0.01)
- except AssertionError:
- pass
--
- Test res.groups name search
--
- !python {model: res.groups}: |
- all_groups = self.search(cr, uid, [])
- full_names = [(group.id, group.full_name) for group in self.browse(cr, uid, all_groups)]
- group_ids = self.search(cr, uid, [('full_name', 'like', '%Sale%')])
- assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sale' in full_name]), "did not match search for 'Sale'"
- group_ids = self.search(cr, uid, [('full_name', 'like', '%Technical%')])
- assert set(group_ids) == set([id for (id, full_name) in full_names if 'Technical' in full_name]), "did not match search for 'Technical'"
- group_ids = self.search(cr, uid, [('full_name', 'like', '%Sales /%')])
- assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sales /' in full_name]), "did not match search for 'Sales /'"
- group_ids = self.search(cr, uid, [('full_name', 'in', ['Administration / Access Rights','Contact Creation'])])
- assert group_ids, "did not match search for 'Administration / Access Rights' and 'Contact Creation'"
+++ /dev/null
--
- I will now stress the authentication layer of the ORM
--
- I create a test user.
--
- !record {model: res.users, id: res_user_test_a1}:
- name: Test Auth User 1
- login: test_base_a1
- password: 'base-test-passwd'
- active: True
--
- I will prepare the context
--
- !python {model: res.users }: |
- from openerp.tools import config
- host = config.get_misc('httpd', 'interface')
- port = config.get_misc('httpd', 'port', 8069)
- if not host:
- host = config.get('xmlrpc_interface')
- port = config.get('xmlrpc_port') or self.port
- if host == '0.0.0.0' or not host:
- host = '127.0.0.1'
- port = int(port)
- context['test_xmlrpc_url'] = 'http://%s:%d/xmlrpc/' % (host, port)
--
- I will commit the cursor and try to login.
--
- !python {model: res.users }: |
- from xmlrpclib import ServerProxy
- cr.commit()
- try:
- logsock = ServerProxy(context['test_xmlrpc_url']+'common')
- luid = logsock.login(cr.dbname, 'test_base_a1', 'base-test-passwd')
- assert luid, "User is not activated after res.users commit!"
- except Exception:
- raise
--
- I will just try to read something as that user
--
- !python {model: res.users }: |
- from xmlrpclib import ServerProxy
- cr.commit()
- try:
- logsock = ServerProxy(context['test_xmlrpc_url']+'object')
- luid = ref('res_user_test_a1')
- res = logsock.execute(cr.dbname, luid, 'base-test-passwd', 'res.users', 'read', luid, ['name',])
- assert res and res['name'], "User cannot read its name!"
- except Exception:
- raise
--
- I will now disable the user.
--
- !record {model: res.users, id: res_user_test_a1}:
- active: False
--
- I will commit the cursor.
--
- !python {model: res.users }: |
- cr.commit()
--
- I will try to read again, connecting as the disabled user.
--
- !python {model: res.users }: |
- from xmlrpclib import ServerProxy
- cr.commit()
- try:
- logsock = ServerProxy(context['test_xmlrpc_url']+'object')
- luid = ref('res_user_test_a1')
- res = logsock.execute(cr.dbname, luid, 'base-test-passwd', 'res.users', 'read', luid, ['name',])
- raise AssertionError("User should not be enabled!")
- except Fault, e:
- if e.faultCode != 'AccessDenied':
- raise
+++ /dev/null
--
- Exercise ir_rule.py code (and indirectly expression.py).
--
- Create an ir_rule for the Employee group (called base.group_user)
- with an blank domain.
--
- !record {model: ir.rule, id: test_rule}:
- model_id: base.model_res_partner
- domain_force: False
- name: test_rule
- groups:
- - base.group_user
- perm_unlink: 1
- perm_write: 1
- perm_read: 1
- perm_create: 1
--
- Read as demo user the partners (one blank domain).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Domain is not empty.
--
- !record {model: ir.rule, id: test_rule}:
- model_id: base.model_res_partner
- domain_force: "[(1,'=',1)]"
--
- Read as demo user the partners (one 1=1 domain).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Domain is an empty list.
--
- !record {model: ir.rule, id: test_rule}:
- model_id: base.model_res_partner
- domain_force: "[]"
--
- Read as demo user the partners (one [] domain).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Create another ir_rule for the Employee group (to test rules from
- multiple groups).
--
- !record {model: ir.rule, id: test_rule2}:
- model_id: base.model_res_partner
- domain_force: False
- name: test_rule2
- groups:
- - base.group_user
- perm_unlink: 1
- perm_write: 1
- perm_read: 1
- perm_create: 1
--
- Read as demo user the partners (blank and [] domains).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Domain is not empty.
--
- !record {model: ir.rule, id: test_rule}:
- model_id: base.model_res_partner
- domain_force: "[(1,'=',1)]"
--
- Read as demo user the partners (1=1 and blank domain).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Domain is not empty.
--
- !record {model: ir.rule, id: test_rule2}:
- model_id: base.model_res_partner
- domain_force: "[(1,'=',1)]"
--
- Read as demo user the partners (two 1=1 domains).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Create another ir_rule for the Employee group (to test rules from
- multiple groups).
--
- !record {model: ir.rule, id: test_rule3}:
- model_id: base.model_res_partner
- domain_force: False
- name: test_rule3
- groups:
- - base.group_user
- perm_unlink: 1
- perm_write: 1
- perm_read: 1
- perm_create: 1
--
- Read as demo user the partners.
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Domain is not empty.
--
- !record {model: ir.rule, id: test_rule3}:
- model_id: base.model_res_partner
- domain_force: "[(1,'=',1)]"
--
- Read as demo user the partners (three 1=1 domains).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Modify the global rule on res_company which triggers a recursive check
- of the rules on company.
--
- !record {model: ir.rule, id: base.res_company_rule}:
- domain_force: "[('id','child_of',[user.company_id.id])]"
--
- Read as demo user the partners (exercising the global company rule).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Modify the ir_rule for employee to have a rule that fordids
- seeing any record.
- We use a domain with implicit AND operator for later tests
- on normalization.
--
- !record {model: ir.rule, id: test_rule2}:
- domain_force: "[('id','=',False),('name','=',False)]"
--
- Check that demo user still sees partners, because group-rules are OR'ed.
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
--
- Create a new group with demo user in it, and a complex rule.
- Demo should still see partners.
--
- !record {model: res.groups, id: test_group}:
- name: Test Group
- users:
- - base.user_demo
--
- Add the rule to the new group, with a domain containing an implicit AND operator,
- which is more tricky because it will have to be normalized before combining it.
--
- !record {model: ir.rule, id: test_rule3}:
- model_id: base.model_res_partner
- domain_force: "[('name', '!=', False),('id', '!=', False)]"
- name: test_rule4
- groups:
- - test_group
- perm_unlink: 1
- perm_write: 1
- perm_read: 1
- perm_create: 1
--
- Read the partners again as demo user, which should give results.
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see partners even with the combined rules."
--
- Delete global domains (to combine only group domains).
--
- !python {model: ir.rule}: |
- ids = self.search(cr, uid, [('groups','=',False)])
- assert ids, "Demo user should see some partner."
- self.unlink(cr, uid, ids)
--
- Read as demo user the partners (several group domains, no global domain).
--
- !python {model: res.partner }: |
- ids = self.search(cr, ref('base.user_demo'), [])
- assert ids, "Demo user should see some partner."
+++ /dev/null
--
- Testing for hierarchical search in M2M
--
- !python {model: res.partner }: |
- ids = self.search(cr, uid, [('category_id', 'child_of',ref('res_partner_category_0'))])
- assert len(ids) >= 1, ids
--
- "1.0 Setup test partner categories: parent root"
--
- !record {model: res.partner.category, id: categ_root}:
- name: Root category
--
- "1.1 Setup test partner categories: parent category"
--
- !record {model: res.partner.category, id: categ_0}:
- name: Parent category
- parent_id: categ_root
--
- "1.2 Setup test partner categories: child 1"
--
- !record {model: res.partner.category, id: categ_1}:
- name: Child 1
- parent_id: categ_0
--
- Test hierarchical search in M2M with child ID (list of ids)
--
- !python {model: res.partner.category }: |
- ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_root')])])
- assert len(ids) == 3, ids
--
- Test hierarchical search in M2M with child ID (single id)
--
- !python {model: res.partner.category }: |
- ids = self.search(cr, uid, [('id', 'child_of',ref('categ_root'))])
- assert len(ids) == 3, ids
--
- Test hierarchical search in M2M with child IDs
--
- !python {model: res.partner.category }: |
- ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1'), ref('categ_0')])])
- assert len(ids) == 2, ids
--
- Test hierarchical search in M2M with child IDs
--
- !python {model: res.partner.category }: |
- ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_0')])])
- assert len(ids) == 2, ids
--
- Test hierarchical search in M2M with child IDs
--
- !python {model: res.partner.category }: |
- ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1')])])
- assert len(ids) == 1, ids
--
- Testing that some domain expressions work
--
- !python {model: res.partner }: |
- ids = self.search(cr, uid, [('parent_id','=','Agrolait')])
- assert len(ids) >= 1, ids
--
- Trying the "in" operator, for scalar value
--
- !python {model: res.partner }: |
- ids = self.search(cr, uid, [('parent_id','in','Agrolait')])
- assert len(ids) >= 1, ids
--
- Trying the "in" operator for list value
--
- !python {model: res.partner }: |
- ids = self.search(cr, uid, [('parent_id','in',['Agrolait','ASUStek'])])
- assert len(ids) >= 1, ids
--
- Check we can use "in" operator for plain fields.
--
- !python {model: ir.ui.menu }: |
- ids = self.search(cr, uid, [('sequence','in',[1, 2, 10, 20])])
- assert len(ids) >= 1, ids
--
- Test one2many operator with empty search list
--
- !assert {model: res.partner, search: "[('child_ids', 'in', [])]", count: 0, string: "Ids should be empty"}
--
- Test one2many operator with False
--
- !assert {model: res.partner, search: "[('child_ids', '=', False)]"}:
- - child_ids in (False, None, [])
--
- Test many2many operator with empty search list
--
- !assert {model: res.partner, search: "[('category_id', 'in', [])]", count: 0, string: "Ids should be empty"}
--
- Test many2many operator with False
--
- !assert {model: res.partner, search: "[('category_id', '=', False)]"}:
- - category_id in (False, None, [])
--
- Filtering on invalid value across x2many relationship should return an empty set
--
- !assert {model: res.partner, search: "[('child_ids.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"}
--
- Check if many2one works with empty search list
--
- !assert {model: res.partner, search: "[('company_id','in', [])]", count: 0, string: "Searching for company_id in [] should be empty!" }
--
- For the sake of the following tests, I will create a second company
--
- !record {model: res.company, id: ymltest_company2}:
- name: Acme 2
--
- And create a few partners with that company or no company
--
- !python {model: res.partner }: |
- for r in range(4):
- self.create(cr, uid, { 'name': 'P of Acme %d' % r,
- 'company_id': ref('ymltest_company2') })
- for r in range(4):
- self.create(cr, uid, { 'name': 'P of All %d' % r,
- 'company_id': False })
--
- Check if many2one works with negative empty list
--
- !python {model: res.partner }: |
- all_ids = self.search(cr, uid, [])
- all_ids.sort()
- res_ids = self.search(cr, uid,['|',('company_id','not in', []), ('company_id','=',False)])
- res_ids.sort()
- assert all_ids == res_ids, "not in [] fails"
--
- Check that many2one will pick the correct records with a list
--
- !python {model: res.partner }: |
- res_ids = self.search(cr, uid, [('company_id', 'in', [False,])])
- assert len(res_ids) >= 4, "We created 4 partners w/company, why find %d? %r" % \
- (len(res_ids), res_ids)
--
- Check that many2one will exclude the correct records with a list
--
- !python {model: res.partner }: |
- # assuming that the default company is #1
- res_ids = self.search(cr, uid, [('company_id', 'not in', [1])])
- assert len(res_ids) >= 4, "We should have found 4 records at least, only have %d! %r" % \
- (len(res_ids), res_ids)
--
- Check that we exclude the correct records, + False
--
- !python {model: res.partner }: |
- # assuming that the default company is #1
- res_ids = self.search(cr, uid, ['|', ('company_id', 'not in', [1]), ('company_id', '=', False)])
- assert len(res_ids) >= 8, "We should have found 8 records at least, only have %d! %r" % \
- (len(res_ids), res_ids)
--
- Check that multi-level expressions also work
--
- !python {model: res.partner }: |
- res_ids = self.search(cr, uid, [('company_id.partner_id', 'in', [])])
- assert res_ids == [], "Searching an empty set should return empty result, not %r" % res_ids
--
- Check that multi-level expressions with negative op work
--
- !python {model: res.partner }: |
- all_ids = self.search(cr, uid, [('company_id', '!=', False)])
- all_ids.sort()
- res_ids = self.search(cr, uid, [('company_id.partner_id', 'not in', [])])
- res_ids.sort()
- assert res_ids == all_ids, "Searching against empty set failed, returns %r" % res_ids
--
- Test the '(not) like/in' behavior. res.partner and its parent_id column are used because
- parent_id is a many2one, allowing to test the Null value, and there are actually some
- null and non-null values in the demo data.
--
- !python {model: res.partner }: |
- partner_ids = self.search(cr, uid, [])
- partner_ids.sort()
- max_partner_id = max(partner_ids)
-
- # Grab test sample data without using a normal
- # search domain, because we want to test these later,
- # so we can't rely on them!
- partners = self.browse(cr, uid, partner_ids)
- with_parent = []
- without_parent = []
- with_website = []
- for x in partners:
- if x.parent_id:
- with_parent.append(x.id)
- else:
- without_parent.append(x.id)
- if x.website:
- with_website.append(x.id)
- with_parent.sort()
- without_parent.sort()
- with_website.sort()
-
- # We treat null values differently than in SQL. For instance in SQL:
- # SELECT id FROM res_partner WHERE parent_id NOT IN (0)
- # will return only the records with non-null parent_id.
- # SELECT id FROM res_partner WHERE parent_id IN (0)
- # will return expectedly nothing (our ids always begin at 1).
- # This means the union of those two results will give only some
- # records, but not all present in database.
- #
- # When using domains and the ORM's search method, we think it is
- # more intuitive that the union returns all the records, and that
- # a domain like ('parent_id', 'not in', [0]) will return all
- # the records. For instance, if you perform a search for the companies
- # that don't have OpenERP has a parent company, you expect to find,
- # among others, the companies that don't have parent company.
- #
-
- # existing values be treated similarly if we simply check that some
- # existing value belongs to them.
-
- res_0 = self.search(cr, uid, [('parent_id', 'not like', 'probably_unexisting_name')]) # get all rows, included null parent_id
- res_0.sort()
- res_1 = self.search(cr, uid, [('parent_id', 'not in', [max_partner_id + 1])]) # get all rows, included null parent_id
- res_1.sort()
- res_2 = self.search(cr, uid, [('parent_id', '!=', False)]) # get rows with not null parent_id, deprecated syntax
- res_2.sort()
- res_3 = self.search(cr, uid, [('parent_id', 'not in', [])]) # get all rows, included null parent_id
- res_3.sort()
- res_4 = self.search(cr, uid, [('parent_id', 'not in', [False])]) # get rows with not null parent_id
- res_4.sort()
- res_4b = self.search(cr, uid, [('parent_id', 'not ilike', '')]) # get only rows without parent
- res_4b.sort()
- assert res_0 == partner_ids, 'res0: expected %r, got %r' % (partner_ids, res_0)
- assert res_1 == partner_ids, 'res1: expected %r, got %r' % (partner_ids, res_1)
- assert res_2 == with_parent, 'res2: expected %r, got %r' % (with_parent, res_2)
- assert res_3 == partner_ids, 'res3: expected %r, got %r' % (partner_ids, res_3)
- assert res_4 == with_parent, 'res4: expected %r, got %r' % (with_parent, res_4)
- assert res_4b == without_parent, 'res4b: expected %r, got %r' % (without_parent, res_4b)
- # The results of these queries, when combined with queries 0..4 must
- # give the whole set of ids.
- res_5 = self.search(cr, uid, [('parent_id', 'like', 'probably_unexisting_name')])
- res_5.sort()
- res_6 = self.search(cr, uid, [('parent_id', 'in', [max_partner_id + 1])])
- res_6.sort()
- res_7 = self.search(cr, uid, [('parent_id', '=', False)])
- res_7.sort()
- res_8 = self.search(cr, uid, [('parent_id', 'in', [])])
- res_8.sort()
- res_9 = self.search(cr, uid, [('parent_id', 'in', [False])])
- res_9.sort()
- res_9b = self.search(cr, uid, [('parent_id', 'ilike', '')]) # get those with a parent
- res_9b.sort()
-
- assert res_5 == [], 'res5: expected %r, got %r' % ([], res_5)
- assert res_6 == [], 'res6: expected %r, got %r' % ([], res_6)
- assert res_7 == without_parent, 'res7: expected %r, got %r' % (without_parent, res_7)
- assert res_8 == [], 'res8: expected %r, got %r' % ([], res_8)
- assert res_9 == without_parent, 'res9: expected %r, got %r' % (without_parent, res_9)
- assert res_9b == with_parent, 'res9b: expected %r, got %r' % (with_parent, res_9b)
- # These queries must return exactly the results than the queries 0..4,
- # i.e. not ... in ... must be the same as ... not in ... .
- res_10 = self.search(cr, uid, ['!', ('parent_id', 'like', 'probably_unexisting_name')])
- res_10.sort()
- res_11 = self.search(cr, uid, ['!', ('parent_id', 'in', [max_partner_id + 1])])
- res_11.sort()
- res_12 = self.search(cr, uid, ['!', ('parent_id', '=', False)])
- res_12.sort()
- res_13 = self.search(cr, uid, ['!', ('parent_id', 'in', [])])
- res_13.sort()
- res_14 = self.search(cr, uid, ['!', ('parent_id', 'in', [False])])
- res_14.sort()
- assert res_0 == res_10
- assert res_1 == res_11
- assert res_2 == res_12
- assert res_3 == res_13
- assert res_4 == res_14
-
- # Testing many2one field is not enough, a regular char field is tested
- # with in [] and must not return any result.
- res_15 = self.search(cr, uid, [('website', 'in', [])])
- assert res_15 == []
- # not in [] must return everything.
- res_16 = self.search(cr, uid, [('website', 'not in', [])])
- res_16.sort()
- assert res_16 == partner_ids
-
- res_17 = self.search(cr, uid, [('website', '!=', False)])
- res_17.sort()
- assert res_17 == with_website
-
--
- Check behavior for required many2one fields
--
- !python {model: res.company }: |
- company_ids = sorted(self.search(cr, uid, []))
- # currency_id is required
- res_101 = sorted(self.search(cr, uid, [('currency_id', 'not ilike', '')])) # get no companies
- res_102 = sorted(self.search(cr, uid, [('currency_id', 'ilike', '')])) # get all companies
- assert res_101 == [], 'res_101: expected %r, got %r' % ([], res_101)
- assert res_102 == company_ids, 'res_102: expected %r, got %r' % (company_ids, res_102)
--
- Verify domain evaluation for `one2many != False`
--
- !python {model: res.partner.category }: |
- all_ids = self.search(cr, uid, [])
- parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
- result = set(self.search(cr, uid, [('child_ids', '!=', False)]))
- assert result and result == parent_categs, "Got %r, expected %r" % (result, parent_categs)
--
- Verify domain evaluation for `one2many == False`
--
- !python {model: res.partner.category }: |
- all_ids = self.search(cr, uid, [])
- parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
- leaf_categs = set(all_ids) - parent_categs
- result = set(self.search(cr, uid, [('child_ids', '=', False)]))
- assert result and result == leaf_categs, "Got %r, expected %r" % (result, leaf_categs)
--
- Equivalent queries.
--
- !python {model: res.currency }: |
- max_currency_id = max(self.search(cr, uid, []))
- res_0 = self.search(cr, uid, [])
- res_1 = self.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')])
- res_2 = self.search(cr, uid, [('id', 'not in', [max_currency_id + 1003])])
- res_3 = self.search(cr, uid, [('id', 'not in', [])])
- res_4 = self.search(cr, uid, [('id', '!=', False)])
- res_0.sort()
- res_1.sort()
- res_2.sort()
- res_3.sort()
- res_4.sort()
- assert res_0 == res_1
- assert res_0 == res_2
- assert res_0 == res_3
- assert res_0 == res_4
--
- Equivalent queries, integer and string.
--
- !python {model: res.partner }: |
- all_ids = self.search(cr, uid, [])
- if len(all_ids) > 1:
- one = all_ids[0]
- record = self.browse(cr, uid, one)
- others = all_ids[1:]
- res_1 = self.search(cr, uid, [('id', '=', one)])
- # self.search(cr, uid, [('id', '!=', others)]) # not permitted
- res_2 = self.search(cr, uid, [('id', 'not in', others)])
- res_3 = self.search(cr, uid, ['!', ('id', '!=', one)])
- res_4 = self.search(cr, uid, ['!', ('id', 'in', others)])
- # res_5 = self.search(cr, uid, [('id', 'in', one)]) # TODO make it permitted, just like for child_of
- res_6 = self.search(cr, uid, [('id', 'in', [one])])
- res_7 = self.search(cr, uid, [('name', '=', record.name)])
- res_8 = self.search(cr, uid, [('name', 'in', [record.name])])
- # res_9 = self.search(cr, uid, [('name', 'in', record.name)]) # TODO
- assert [one] == res_1
- assert [one] == res_2
- assert [one] == res_3
- assert [one] == res_4
- #assert [one] == res_5
- assert [one] == res_6
- assert [one] == res_7
--
- Need a company with a parent_id.
--
- !record {model: res.company, id: ymltest_company3}:
- name: Acme 3
--
- Need a company with a parent_id.
--
- !record {model: res.company, id: ymltest_company4}:
- name: Acme 4
- parent_id: ymltest_company3
--
- Equivalent queries, one2many.
--
- !python {model: res.company }: |
- # Search the company via its one2many (the one2many must point back at the company).
- company = self.browse(cr, uid, ref('ymltest_company3'))
- max_currency_id = max(self.pool.get('res.currency').search(cr, uid, []))
- currency_ids1 = self.pool.get('res.currency').search(cr, uid, [('name', 'not like', 'probably_unexisting_name')])
- currency_ids2 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [max_currency_id + 1003])])
- currency_ids3 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [])])
- assert currency_ids1 == currency_ids2 == currency_ids3, 'All 3 results should have be the same: all currencies'
- default_company = self.browse(cr, uid, 1)
-
- # Due to currency data definition change (in relation with bug 1111298), this test now needs
- # a manual setup where all currencies are assigned to the default company.
- self.pool['res.currency'].write(cr, uid, currency_ids1, {'company_id': default_company.id})
-
- # one2many towards same model
- res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child
- res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child
- # one2many towards another model
- res_3 = self.search(cr, uid, [('currency_ids', 'in', [x.id for x in default_company.currency_ids])]) # companies having a currency of main company
- res_4 = self.search(cr, uid, [('currency_ids', 'in', [default_company.currency_ids[0].id])]) # companies having first currency of main company
- res_5 = self.search(cr, uid, [('currency_ids', 'in', default_company.currency_ids[0].id)]) # companies having first currency of main company
- # res_6 = self.search(cr, uid, [('currency_ids', 'in', [default_company.currency_ids[0].name])]) # TODO
- res_7 = self.search(cr, uid, [('currency_ids', '=', default_company.currency_ids[0].name)])
- res_8 = self.search(cr, uid, [('currency_ids', 'like', default_company.currency_ids[0].name)])
- res_9 = self.search(cr, uid, [('currency_ids', 'like', 'probably_unexisting_name')])
- # self.search(cr, uid, [('currency_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception
- assert res_1 == [ref('ymltest_company3')]
- assert res_2 == [ref('ymltest_company3')]
- assert res_3 == [1]
- assert res_4 == [1]
- assert res_5 == [1]
- assert res_7 == [1]
- assert res_8 == [1]
- assert res_9 == []
-
- # get the companies referenced by some currency (this is normally the main company) using a weird negative domain
- res_10 = self.search(cr, uid, [('currency_ids', 'not like', 'probably_unexisting_name')])
- res_11 = self.search(cr, uid, [('currency_ids', 'not in', [max_currency_id + 1])])
- res_12 = self.search(cr, uid, [('currency_ids', '!=', False)])
- res_13 = self.search(cr, uid, [('currency_ids', 'not in', [])])
- res_10.sort()
- res_11.sort()
- res_12.sort()
- res_13.sort()
- assert res_10 == res_11
- assert res_10 == res_12
- assert res_10 == res_13
-
- # try testing real subsets with IN/NOT IN
- res_partner = self.pool.get('res.partner')
- res_users = self.pool.get('res.users')
- p1, _ = res_partner.name_create(cr, uid, "Dédé Boitaclou")
- p2, _ = res_partner.name_create(cr, uid, "Raoulette Pizza O'poil")
- u1a = res_users.create(cr, uid, {'login': 'dbo', 'partner_id': p1})
- u1b = res_users.create(cr, uid, {'login': 'dbo2', 'partner_id': p1})
- u2 = res_users.create(cr, uid, {'login': 'rpo', 'partner_id': p2})
- assert [p1] == res_partner.search(cr, uid, [('user_ids', 'in', u1a)]), "o2m IN accept single int on right side"
- assert [p1,p2] == res_partner.search(cr, uid, [('user_ids', 'in', [u1a,u2])]), "o2m IN matches any on the right side"
- all_partners = res_partner.search(cr, uid, [])
- assert (set(all_partners) - set([p1])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', u1a)])), "o2m NOT IN matches none on the right side"
- assert (set(all_partners) - set([p1,p2])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', [u1b, u2])])), "o2m NOT IN matches none on the right side"
-
- # child_of x returns x and its children (direct or not).
- company = self.browse(cr, uid, ref('ymltest_company3'))
- expected = [ref('ymltest_company3'), ref('ymltest_company4')]
- expected.sort()
- res_1 = self.search(cr, uid, [('id', 'child_of', [ref('ymltest_company3')])])
- res_1.sort()
- res_2 = self.search(cr, uid, [('id', 'child_of', ref('ymltest_company3'))])
- res_2.sort()
- res_3 = self.search(cr, uid, [('id', 'child_of', [company.name])])
- res_3.sort()
- res_4 = self.search(cr, uid, [('id', 'child_of', company.name)])
- res_4.sort()
- assert res_1 == expected
- assert res_2 == expected
- assert res_3 == expected
- assert res_4 == expected
--
- Unaccent. Create a company with an accent in its name.
--
- !record {model: res.company, id: ymltest_unaccent_company}:
- name: Hélène
--
- Test the unaccent-enabled 'ilike'.
--
- !python {model: res.company}: |
- if self.pool.has_unaccent:
- ids = self.search(cr, uid, [('name','ilike','Helene')], {})
- assert ids == [ref('ymltest_unaccent_company')]
- ids = self.search(cr, uid, [('name','ilike','hélène')], {})
- assert ids == [ref('ymltest_unaccent_company')]
- ids = self.search(cr, uid, [('name','not ilike','Helene')], {})
- assert ref('ymltest_unaccent_company') not in ids
- ids = self.search(cr, uid, [('name','not ilike','hélène')], {})
- assert ref('ymltest_unaccent_company') not in ids
--
- Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on an untranslated field.
--
- !python {model: res.partner }: |
- all_ids = self.search(cr, uid, [('name', '=like', 'A_e_or')])
- assert len(all_ids) == 1, "Must match one partner (Axelor), got %r"%all_ids
- all_ids = self.search(cr, uid, [('name', '=ilike', 'v%')])
- assert len(all_ids) >= 1, "Must match one partner (Vicking Direct), got %r"%all_ids
--
- Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on translated field.
--
- !python {model: res.country }: |
- all_ids = self.search(cr, uid, [('name', '=like', 'Ind__')])
- assert len(all_ids) == 1, "Must match India only, got %r"%all_ids
- all_ids = self.search(cr, uid, [('name', '=ilike', 'z%')])
- assert len(all_ids) == 3, "Must match only countries with names starting with Z (currently 3), got %r"%all_ids
--
- Use the create_date column on res.country (which doesn't declare it in _columns).
--
- !python {model: res.country }: |
- ids = self.search(cr, uid, [('create_date', '<', '2001-01-01 12:00:00')])
-
-
--
- Verify that invalid expressions are refused, even for magic fields
--
- !python {model: res.country }: |
- try:
- self.search(cr, uid, [('does_not_exist', '=', 'foo')])
- raise AssertionError('Invalid fields should not be accepted')
- except ValueError:
- pass
-
- try:
- self.search(cr, uid, [('create_date', '>>', 'foo')])
- raise AssertionError('Invalid operators should not be accepted')
- except ValueError:
- pass
-
- import psycopg2
- try:
- cr._default_log_exceptions = False
- cr.execute('SAVEPOINT expression_failure_test')
- self.search(cr, uid, [('create_date', '=', "1970-01-01'); --")])
- # if the above search gives no error, the operand was not escaped!
- cr.execute('RELEASE SAVEPOINT expression_failure_test')
- raise AssertionError('Operands should always be SQL escaped')
- except psycopg2.DataError:
- # Should give: 'DataError: invalid input syntax for type timestamp' or similar
- cr.execute('ROLLBACK TO SAVEPOINT expression_failure_test')
--
- Testing for Many2Many field with category supplier and active=False
--
- !python {model: res.partner }: |
- vals = {'category_id': [(6, 0, [ref("base.res_partner_category_1")])],
- 'name': 'OpenERP Test',
- 'active': False,
- 'child_ids': [(0, 0, {'name': 'address of OpenERP Test', 'country_id': ref("base.be")})]
- }
- self.create(cr, uid, vals, context=context)
- res_ids = self.search(cr, uid, [('category_id', 'ilike', 'supplier'), ('active', '=', False)])
- assert len(res_ids) != 0, "Record not Found with category supplier and active False."
--
- Testing for One2Many field with country Belgium and active=False
--
- !python {model: res.partner }: |
- res_ids = self.search(cr, uid, [('child_ids.country_id','=','Belgium'),('active','=',False)])
- assert len(res_ids) != 0, "Record not Found with country Belgium and active False."
--
- Check that we can exclude translated fields (bug lp:1071710)
--
- !python {model: res.country}: |
- # first install french language
- Modules = self.pool.get('ir.module.module')
- base = Modules.browse(cr, uid, Modules.search(cr, uid, [('name', '=', 'base')])[0])
-
- # hack: mark module as installed to allow install of the translation
- base_state = base.state
- base.write({'state': 'installed'})
- base.update_translations('fr_FR')
- base.write({'state': base_state})
-
- # tests
- be_id = self.search(cr, uid, [('name', '=', 'Belgium')])[0]
-
- ctx = {'lang': 'fr_FR'}
- not_be = self.search(cr, uid, [('name', '!=', 'Belgique')], context=ctx)
-
- assert be_id not in not_be, "Search match failed"
-
- # indirect search via m2o
- Partners = self.pool.get('res.partner')
- agrolait = Partners.search(cr, uid, [('name', '=', 'Agrolait')])[0]
-
- not_be = Partners.search(cr, uid, [('country_id', '!=', 'Belgium')])
- assert agrolait not in not_be, "Search match failed (m2o)"
-
- not_be = Partners.search(cr, uid, [('country_id', '!=', 'Belgique')], context=ctx)
- assert agrolait not in not_be, "Search match failed (m2o)"
--- /dev/null
+- |
+ To check that common dangerous operations are not allowed by the safe_eval mechanism, attempt to
+ evaluate unauthorized expressions, and verify that they trigger an error.
+-
+ 1. Try a few common expressions to verify they work with safe_eval
+-
+ !python {model: ir.model}: |
+ from openerp.tools.safe_eval import safe_eval
+ expected = (1, {"a": 9 * 2}, (True, False, None))
+ actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
+ assert actual == expected, "Simple python expressions are not working with safe_eval"
+-
+ 2. Try simple literal definition to verify it works with literal_eval
+-
+ !python {model: ir.model}: |
+ import ast
+ expected = (1, {"a": 9}, (True, False, None))
+ actual = ast.literal_eval('(1, {"a": 9}, (True, False, None))')
+ assert actual == expected, "Simple python expressions are not working with literal_eval"
+-
+ 3. Try arithmetic expression in literal_eval to verify it does not work
+-
+ !python {model: ir.model}: |
+ import ast
+ try:
+ ast.literal_eval('(1, {"a": 2*9}, (True, False, None))')
+ assert False, "literal_eval should not accept arithmetic expressions"
+ except ValueError:
+ pass
+-
+ 4. Try forbidden expressions in literal_eval to verify they are not allowed
+-
+ !python {model: ir.model}: |
+ import ast
+ try:
+ ast.literal_eval('{"a": True.__class__}')
+ assert False, "literal_eval should accept only literals"
+ except ValueError:
+ pass
+-
+ 5. Try forbidden expressions in safe_eval to verify they are not allowed (open)
+-
+ !python {model: ir.model}: |
+ from openerp.tools.safe_eval import safe_eval
+ from openerp.tools.misc import mute_logger
+ try:
+ with mute_logger('openerp.tools.safe_eval'):
+ safe_eval('open("/etc/passwd","r")')
+ assert False, "safe_eval should not allow calling open() builtin"
+ except ValueError:
+ pass
+
+-
+ "ORM test: verify that parent_store computation are going right"
+-
+ 0. Emulate normal behavior of tree structure storing
+-
+ !python {model: res.partner.category}: |
+ # pretend the pool has finished loading to avoid deferring parent_store computation
+ self.pool._init = False
+-
+ "1.0 Setup test partner categories: parent root"
+-
+ !record {model: res.partner.category, id: test_categ_root}:
+ name: Root category
+-
+ "1.1 Setup test partner categories: parent category"
+-
+ !record {model: res.partner.category, id: test_categ_0}:
+ name: Parent category
+ parent_id: test_categ_root
+-
+ "1.2 Setup test partner categories: child 1"
+-
+ !record {model: res.partner.category, id: test_categ_1}:
+ name: Child 1
+ parent_id: test_categ_0
+-
+ "1.3 Setup test partner categories: child 2"
+-
+ !record {model: res.partner.category, id: test_categ_2}:
+ name: Child 2
+ parent_id: test_categ_0
+-
+ "1.4 Setup test partner categories: child 2-1"
+-
+ !record {model: res.partner.category, id: test_categ_21}:
+ name: Child 2-1
+ parent_id: test_categ_2
+-
+ 2. Duplicate the parent category and verify that the children have been duplicated too and are below the new parent
+-
+ !python {model: res.partner.category}: |
+ new_id = self.copy(cr, uid, ref('test_categ_0'))
+ new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
+ assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
+ old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
+ assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
+ assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
+-
+ 3. Duplicate the children then reassign them to the new parent (1st method) and check the parent_store structure.
+-
+ !python {model: res.partner.category}: |
+ new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
+ new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
+ new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []})
+ self.write(cr, uid, [new_child1_id, new_child2_id], {'parent_id': new_id})
+ new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
+ assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
+ old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
+ assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
+ assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
+-
+ 4. Duplicate the children then reassign them to the new parent (2nd method) and check the parent_store structure.
+-
+ !python {model: res.partner.category}: |
+ new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
+ new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
+ old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
+ new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': [(6,0,[new_child1_id, new_child2_id])]})
+ new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
+ assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
+ old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
+ assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
+ assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
+-
+ 5. Duplicate the children then reassign them to the new parent (3rd method) and make sure the parent_store structure is still right.
+-
+ !python {model: res.partner.category}: |
+ new_child1_id = self.copy(cr, uid, ref('test_categ_1'))
+ new_child2_id = self.copy(cr, uid, ref('test_categ_2'))
+ new_id = self.copy(cr, uid, ref('test_categ_0'), {'child_ids': []})
+ self.write(cr, uid, [new_id], {'child_ids': [(4,new_child1_id), (4,new_child2_id)]})
+ new_struct = self.search(cr, uid, [('parent_id', 'child_of', new_id)])
+ assert len(new_struct) == 4, "After duplication, the new object must have the childs records"
+ old_struct = self.search(cr, uid, [('parent_id', 'child_of', ref('test_categ_0'))])
+ assert len(old_struct) == 4, "After duplication, previous record must have old childs records only"
+ assert (not set(new_struct).intersection(old_struct)), "After duplication, nodes should not be mixed"
+-
+ 6. Restore pool state after the test
+-
+ !python {model: res.partner.category}: |
+ self.pool._init = True
+
+-
+ "Float precision tests: verify that float rounding methods are working correctly via res.currency"
+-
+ !python {model: res.currency}: |
+ from openerp.tools import float_repr
+ from math import log10
+ currency = self.browse(cr, uid, ref('base.EUR'))
+ def try_round(amount, expected, self=self, cr=cr, currency=currency, float_repr=float_repr,
+ log10=log10):
+ digits = max(0,-int(log10(currency.rounding)))
+ result = float_repr(self.round(cr, 1, currency, amount), precision_digits=digits)
+ assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
+ try_round(2.674,'2.67')
+ try_round(2.675,'2.68') # in Python 2.7.2, round(2.675,2) gives 2.67
+ try_round(-2.675,'-2.68') # in Python 2.7.2, round(2.675,2) gives 2.67
+ try_round(0.001,'0.00')
+ try_round(-0.001,'-0.00')
+ try_round(0.0049,'0.00') # 0.0049 is closer to 0 than to 0.01, so should round down
+ try_round(0.005,'0.01') # the rule is to round half away from zero
+ try_round(-0.005,'-0.01') # the rule is to round half away from zero
+
+ def try_zero(amount, expected, self=self, cr=cr, currency=currency):
+ assert self.is_zero(cr, 1, currency, amount) == expected, "Rounding error: %s should be zero!" % amount
+ try_zero(0.01, False)
+ try_zero(-0.01, False)
+ try_zero(0.001, True)
+ try_zero(-0.001, True)
+ try_zero(0.0046, True)
+ try_zero(-0.0046, True)
+ try_zero(2.68-2.675, False) # 2.68 - 2.675 = 0.005 -> rounds to 0.01
+ try_zero(2.68-2.676, True) # 2.68 - 2.675 = 0.004 -> rounds to 0.0
+ try_zero(2.676-2.68, True) # 2.675 - 2.68 = -0.004 -> rounds to -0.0
+ try_zero(2.675-2.68, False) # 2.675 - 2.68 = -0.005 -> rounds to -0.01
+
+ def try_compare(amount1, amount2, expected, self=self, cr=cr, currency=currency):
+ assert self.compare_amounts(cr, 1, currency, amount1, amount2) == expected, \
+ "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)
+ try_compare(0.001, 0.001, 0)
+ try_compare(-0.001, -0.001, 0)
+ try_compare(0.001, 0.002, 0)
+ try_compare(-0.001, -0.002, 0)
+ try_compare(2.675, 2.68, 0)
+ try_compare(2.676, 2.68, 0)
+ try_compare(-2.676, -2.68, 0)
+ try_compare(2.674, 2.68, -1)
+ try_compare(-2.674, -2.68, 1)
+ try_compare(3, 2.68, 1)
+ try_compare(-3, -2.68, -1)
+ try_compare(0.01, 0, 1)
+ try_compare(-0.01, 0, -1)
+
+-
+ "Float precision tests: verify that float rounding methods are working correctly via tools"
+-
+ !python {model: res.currency}: |
+ from openerp.tools import float_compare, float_is_zero, float_round, float_repr
+ def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr):
+ result = float_repr(float_round(amount, precision_digits=precision_digits),
+ precision_digits=precision_digits)
+ assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
+ try_round(2.6745, '2.675')
+ try_round(-2.6745, '-2.675')
+ try_round(2.6744, '2.674')
+ try_round(-2.6744, '-2.674')
+ try_round(0.0004, '0.000')
+ try_round(-0.0004, '-0.000')
+ try_round(357.4555, '357.456')
+ try_round(-357.4555, '-357.456')
+ try_round(457.4554, '457.455')
+ try_round(-457.4554, '-457.455')
+
+ # Extended float range test, inspired by Cloves Almeida's test on bug #882036.
+ fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
+ expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']
+ precisions = [2, 2, 2, 2, 2, 2, 3, 4]
+ # Note: max precision for double floats is 53 bits of precision or
+ # 17 significant decimal digits
+ for magnitude in range(7):
+ for i in xrange(len(fractions)):
+ frac, exp, prec = fractions[i], expecteds[i], precisions[i]
+ for sign in [-1,1]:
+ for x in xrange(0,10000,97):
+ n = x * 10**magnitude
+ f = sign * (n + frac)
+ f_exp = ('-' if f != 0 and sign == -1 else '') + str(n) + exp
+ try_round(f, f_exp, precision_digits=prec)
+
+
+ def try_zero(amount, expected, float_is_zero=float_is_zero):
+ assert float_is_zero(amount, precision_digits=3) == expected, "Rounding error: %s should be zero!" % amount
+ try_zero(0.0002, True)
+ try_zero(-0.0002, True)
+ try_zero(0.00034, True)
+ try_zero(0.0005, False)
+ try_zero(-0.0005, False)
+ try_zero(0.0008, False)
+ try_zero(-0.0008, False)
+
+ def try_compare(amount1, amount2, expected, float_compare=float_compare):
+ assert float_compare(amount1, amount2, precision_digits=3) == expected, \
+ "Rounding error, compare_amounts(%s,%s) should be %s" % (amount1, amount2, expected)
+ try_compare(0.0003, 0.0004, 0)
+ try_compare(-0.0003, -0.0004, 0)
+ try_compare(0.0002, 0.0005, -1)
+ try_compare(-0.0002, -0.0005, 1)
+ try_compare(0.0009, 0.0004, 1)
+ try_compare(-0.0009, -0.0004, -1)
+ try_compare(557.4555, 557.4556, 0)
+ try_compare(-557.4555, -557.4556, 0)
+ try_compare(657.4444, 657.445, -1)
+ try_compare(-657.4444, -657.445, 1)
+
+ # Rounding to unusual rounding units (e.g. coin values)
+ def try_round(amount, expected, precision_rounding=None, float_round=float_round, float_repr=float_repr):
+ result = float_repr(float_round(amount, precision_rounding=precision_rounding),
+ precision_digits=2)
+ assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
+ try_round(-457.4554, '-457.45', precision_rounding=0.05)
+ try_round(457.444, '457.50', precision_rounding=0.5)
+ try_round(457.3, '455.00', precision_rounding=5)
+ try_round(457.5, '460.00', precision_rounding=5)
+ try_round(457.1, '456.00', precision_rounding=3)
+
+-
+ "Float precision tests: check that proper rounding is performed for float persistence"
+-
+ !python {model: res.currency}: |
+ currency = self.browse(cr, uid, ref('base.EUR'))
+ res_currency_rate = self.pool.get('res.currency.rate')
+ from openerp.tools import float_compare, float_is_zero, float_round, float_repr
+ def try_roundtrip(value, expected, self=self, cr=cr, currency=currency,
+ res_currency_rate=res_currency_rate):
+ rate_id = res_currency_rate.create(cr, 1, {'name':'2000-01-01',
+ 'rate': value,
+ 'currency_id': currency.id})
+ rate = res_currency_rate.read(cr, 1, rate_id, ['rate'])['rate']
+ assert rate == expected, 'Roundtrip error: got %s back from db, expected %s' % (rate, expected)
+ # res.currency.rate uses 6 digits of precision by default
+ try_roundtrip(2.6748955, 2.674896)
+ try_roundtrip(-2.6748955, -2.674896)
+ try_roundtrip(10000.999999, 10000.999999)
+ try_roundtrip(-10000.999999, -10000.999999)
+
+-
+ "Float precision tests: verify that invalid parameters are forbidden"
+-
+ !python {model: res.currency}: |
+ from openerp.tools import float_compare, float_is_zero, float_round
+ try:
+ float_is_zero(0.01, precision_digits=3, precision_rounding=0.01)
+ except AssertionError:
+ pass
+ try:
+ float_compare(0.01, 0.02, precision_digits=3, precision_rounding=0.01)
+ except AssertionError:
+ pass
+ try:
+ float_round(0.01, precision_digits=3, precision_rounding=0.01)
+ except AssertionError:
+ pass
+-
+ Test res.groups name search
+-
+ !python {model: res.groups}: |
+ all_groups = self.search(cr, uid, [])
+ full_names = [(group.id, group.full_name) for group in self.browse(cr, uid, all_groups)]
+ group_ids = self.search(cr, uid, [('full_name', 'like', '%Sale%')])
+ assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sale' in full_name]), "did not match search for 'Sale'"
+ group_ids = self.search(cr, uid, [('full_name', 'like', '%Technical%')])
+ assert set(group_ids) == set([id for (id, full_name) in full_names if 'Technical' in full_name]), "did not match search for 'Technical'"
+ group_ids = self.search(cr, uid, [('full_name', 'like', '%Sales /%')])
+ assert set(group_ids) == set([id for (id, full_name) in full_names if 'Sales /' in full_name]), "did not match search for 'Sales /'"
+ group_ids = self.search(cr, uid, [('full_name', 'in', ['Administration / Access Rights','Contact Creation'])])
+ assert group_ids, "did not match search for 'Administration / Access Rights' and 'Contact Creation'"
--- /dev/null
+-
+ Exercise ir_rule.py code (and indirectly expression.py).
+-
+ Create an ir_rule for the Employee group (called base.group_user)
+ with an blank domain.
+-
+ !record {model: ir.rule, id: test_rule}:
+ model_id: base.model_res_partner
+ domain_force: False
+ name: test_rule
+ groups:
+ - base.group_user
+ perm_unlink: 1
+ perm_write: 1
+ perm_read: 1
+ perm_create: 1
+-
+ Read as demo user the partners (one blank domain).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Domain is not empty.
+-
+ !record {model: ir.rule, id: test_rule}:
+ model_id: base.model_res_partner
+ domain_force: "[(1,'=',1)]"
+-
+ Read as demo user the partners (one 1=1 domain).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Domain is an empty list.
+-
+ !record {model: ir.rule, id: test_rule}:
+ model_id: base.model_res_partner
+ domain_force: "[]"
+-
+ Read as demo user the partners (one [] domain).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Create another ir_rule for the Employee group (to test rules from
+ multiple groups).
+-
+ !record {model: ir.rule, id: test_rule2}:
+ model_id: base.model_res_partner
+ domain_force: False
+ name: test_rule2
+ groups:
+ - base.group_user
+ perm_unlink: 1
+ perm_write: 1
+ perm_read: 1
+ perm_create: 1
+-
+ Read as demo user the partners (blank and [] domains).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Domain is not empty.
+-
+ !record {model: ir.rule, id: test_rule}:
+ model_id: base.model_res_partner
+ domain_force: "[(1,'=',1)]"
+-
+ Read as demo user the partners (1=1 and blank domain).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Domain is not empty.
+-
+ !record {model: ir.rule, id: test_rule2}:
+ model_id: base.model_res_partner
+ domain_force: "[(1,'=',1)]"
+-
+ Read as demo user the partners (two 1=1 domains).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Create another ir_rule for the Employee group (to test rules from
+ multiple groups).
+-
+ !record {model: ir.rule, id: test_rule3}:
+ model_id: base.model_res_partner
+ domain_force: False
+ name: test_rule3
+ groups:
+ - base.group_user
+ perm_unlink: 1
+ perm_write: 1
+ perm_read: 1
+ perm_create: 1
+-
+ Read as demo user the partners.
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Domain is not empty.
+-
+ !record {model: ir.rule, id: test_rule3}:
+ model_id: base.model_res_partner
+ domain_force: "[(1,'=',1)]"
+-
+ Read as demo user the partners (three 1=1 domains).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Modify the global rule on res_company which triggers a recursive check
+ of the rules on company.
+-
+ !record {model: ir.rule, id: base.res_company_rule}:
+ domain_force: "[('id','child_of',[user.company_id.id])]"
+-
+ Read as demo user the partners (exercising the global company rule).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Modify the ir_rule for employee to have a rule that fordids
+ seeing any record.
+ We use a domain with implicit AND operator for later tests
+ on normalization.
+-
+ !record {model: ir.rule, id: test_rule2}:
+ domain_force: "[('id','=',False),('name','=',False)]"
+-
+ Check that demo user still sees partners, because group-rules are OR'ed.
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
+-
+ Create a new group with demo user in it, and a complex rule.
+ Demo should still see partners.
+-
+ !record {model: res.groups, id: test_group}:
+ name: Test Group
+ users:
+ - base.user_demo
+-
+ Add the rule to the new group, with a domain containing an implicit AND operator,
+ which is more tricky because it will have to be normalized before combining it.
+-
+ !record {model: ir.rule, id: test_rule3}:
+ model_id: base.model_res_partner
+ domain_force: "[('name', '!=', False),('id', '!=', False)]"
+ name: test_rule4
+ groups:
+ - test_group
+ perm_unlink: 1
+ perm_write: 1
+ perm_read: 1
+ perm_create: 1
+-
+ Read the partners again as demo user, which should give results.
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see partners even with the combined rules."
+-
+ Delete global domains (to combine only group domains).
+-
+ !python {model: ir.rule}: |
+ ids = self.search(cr, uid, [('groups','=',False)])
+ assert ids, "Demo user should see some partner."
+ self.unlink(cr, uid, ids)
+-
+ Read as demo user the partners (several group domains, no global domain).
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, ref('base.user_demo'), [])
+ assert ids, "Demo user should see some partner."
--- /dev/null
+-
+ Testing for hierarchical search in M2M
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, uid, [('category_id', 'child_of',ref('res_partner_category_0'))])
+ assert len(ids) >= 1, ids
+-
+ "1.0 Setup test partner categories: parent root"
+-
+ !record {model: res.partner.category, id: categ_root}:
+ name: Root category
+-
+ "1.1 Setup test partner categories: parent category"
+-
+ !record {model: res.partner.category, id: categ_0}:
+ name: Parent category
+ parent_id: categ_root
+-
+ "1.2 Setup test partner categories: child 1"
+-
+ !record {model: res.partner.category, id: categ_1}:
+ name: Child 1
+ parent_id: categ_0
+-
+ Test hierarchical search in M2M with child ID (list of ids)
+-
+ !python {model: res.partner.category }: |
+ ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_root')])])
+ assert len(ids) == 3, ids
+-
+ Test hierarchical search in M2M with child ID (single id)
+-
+ !python {model: res.partner.category }: |
+ ids = self.search(cr, uid, [('id', 'child_of',ref('categ_root'))])
+ assert len(ids) == 3, ids
+-
+ Test hierarchical search in M2M with child IDs
+-
+ !python {model: res.partner.category }: |
+ ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1'), ref('categ_0')])])
+ assert len(ids) == 2, ids
+-
+ Test hierarchical search in M2M with child IDs
+-
+ !python {model: res.partner.category }: |
+ ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_0')])])
+ assert len(ids) == 2, ids
+-
+ Test hierarchical search in M2M with child IDs
+-
+ !python {model: res.partner.category }: |
+ ids = self.search(cr, uid, [('id', 'child_of',[ref('categ_1')])])
+ assert len(ids) == 1, ids
+-
+ Testing that some domain expressions work
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, uid, [('parent_id','=','Agrolait')])
+ assert len(ids) >= 1, ids
+-
+ Trying the "in" operator, for scalar value
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, uid, [('parent_id','in','Agrolait')])
+ assert len(ids) >= 1, ids
+-
+ Trying the "in" operator for list value
+-
+ !python {model: res.partner }: |
+ ids = self.search(cr, uid, [('parent_id','in',['Agrolait','ASUStek'])])
+ assert len(ids) >= 1, ids
+-
+ Check we can use "in" operator for plain fields.
+-
+ !python {model: ir.ui.menu }: |
+ ids = self.search(cr, uid, [('sequence','in',[1, 2, 10, 20])])
+ assert len(ids) >= 1, ids
+-
+ Test one2many operator with empty search list
+-
+ !assert {model: res.partner, search: "[('child_ids', 'in', [])]", count: 0, string: "Ids should be empty"}
+-
+ Test one2many operator with False
+-
+ !assert {model: res.partner, search: "[('child_ids', '=', False)]"}:
+ - child_ids in (False, None, [])
+-
+ Test many2many operator with empty search list
+-
+ !assert {model: res.partner, search: "[('category_id', 'in', [])]", count: 0, string: "Ids should be empty"}
+-
+ Test many2many operator with False
+-
+ !assert {model: res.partner, search: "[('category_id', '=', False)]"}:
+ - category_id in (False, None, [])
+-
+ Filtering on invalid value across x2many relationship should return an empty set
+-
+ !assert {model: res.partner, search: "[('child_ids.city','=','foo')]", count: 0, string: "Searching for address.city = foo should give empty results"}
+-
+ Check if many2one works with empty search list
+-
+ !assert {model: res.partner, search: "[('company_id','in', [])]", count: 0, string: "Searching for company_id in [] should be empty!" }
+-
+ For the sake of the following tests, I will create a second company
+-
+ !record {model: res.company, id: ymltest_company2}:
+ name: Acme 2
+-
+ And create a few partners with that company or no company
+-
+ !python {model: res.partner }: |
+ for r in range(4):
+ self.create(cr, uid, { 'name': 'P of Acme %d' % r,
+ 'company_id': ref('ymltest_company2') })
+ for r in range(4):
+ self.create(cr, uid, { 'name': 'P of All %d' % r,
+ 'company_id': False })
+-
+ Check if many2one works with negative empty list
+-
+ !python {model: res.partner }: |
+ all_ids = self.search(cr, uid, [])
+ all_ids.sort()
+ res_ids = self.search(cr, uid,['|',('company_id','not in', []), ('company_id','=',False)])
+ res_ids.sort()
+ assert all_ids == res_ids, "not in [] fails"
+-
+ Check that many2one will pick the correct records with a list
+-
+ !python {model: res.partner }: |
+ res_ids = self.search(cr, uid, [('company_id', 'in', [False,])])
+ assert len(res_ids) >= 4, "We created 4 partners w/company, why find %d? %r" % \
+ (len(res_ids), res_ids)
+-
+ Check that many2one will exclude the correct records with a list
+-
+ !python {model: res.partner }: |
+ # assuming that the default company is #1
+ res_ids = self.search(cr, uid, [('company_id', 'not in', [1])])
+ assert len(res_ids) >= 4, "We should have found 4 records at least, only have %d! %r" % \
+ (len(res_ids), res_ids)
+-
+ Check that we exclude the correct records, + False
+-
+ !python {model: res.partner }: |
+ # assuming that the default company is #1
+ res_ids = self.search(cr, uid, ['|', ('company_id', 'not in', [1]), ('company_id', '=', False)])
+ assert len(res_ids) >= 8, "We should have found 8 records at least, only have %d! %r" % \
+ (len(res_ids), res_ids)
+-
+ Check that multi-level expressions also work
+-
+ !python {model: res.partner }: |
+ res_ids = self.search(cr, uid, [('company_id.partner_id', 'in', [])])
+ assert res_ids == [], "Searching an empty set should return empty result, not %r" % res_ids
+-
+ Check that multi-level expressions with negative op work
+-
+ !python {model: res.partner }: |
+ all_ids = self.search(cr, uid, [('company_id', '!=', False)])
+ all_ids.sort()
+ res_ids = self.search(cr, uid, [('company_id.partner_id', 'not in', [])])
+ res_ids.sort()
+ assert res_ids == all_ids, "Searching against empty set failed, returns %r" % res_ids
+-
+ Test the '(not) like/in' behavior. res.partner and its parent_id column are used because
+ parent_id is a many2one, allowing to test the Null value, and there are actually some
+ null and non-null values in the demo data.
+-
+ !python {model: res.partner }: |
+ partner_ids = self.search(cr, uid, [])
+ partner_ids.sort()
+ max_partner_id = max(partner_ids)
+
+ # Grab test sample data without using a normal
+ # search domain, because we want to test these later,
+ # so we can't rely on them!
+ partners = self.browse(cr, uid, partner_ids)
+ with_parent = []
+ without_parent = []
+ with_website = []
+ for x in partners:
+ if x.parent_id:
+ with_parent.append(x.id)
+ else:
+ without_parent.append(x.id)
+ if x.website:
+ with_website.append(x.id)
+ with_parent.sort()
+ without_parent.sort()
+ with_website.sort()
+
+ # We treat null values differently than in SQL. For instance in SQL:
+ # SELECT id FROM res_partner WHERE parent_id NOT IN (0)
+ # will return only the records with non-null parent_id.
+ # SELECT id FROM res_partner WHERE parent_id IN (0)
+ # will return expectedly nothing (our ids always begin at 1).
+ # This means the union of those two results will give only some
+ # records, but not all present in database.
+ #
+ # When using domains and the ORM's search method, we think it is
+ # more intuitive that the union returns all the records, and that
+ # a domain like ('parent_id', 'not in', [0]) will return all
+ # the records. For instance, if you perform a search for the companies
+ # that don't have OpenERP has a parent company, you expect to find,
+ # among others, the companies that don't have parent company.
+ #
+
+ # existing values be treated similarly if we simply check that some
+ # existing value belongs to them.
+
+ res_0 = self.search(cr, uid, [('parent_id', 'not like', 'probably_unexisting_name')]) # get all rows, included null parent_id
+ res_0.sort()
+ res_1 = self.search(cr, uid, [('parent_id', 'not in', [max_partner_id + 1])]) # get all rows, included null parent_id
+ res_1.sort()
+ res_2 = self.search(cr, uid, [('parent_id', '!=', False)]) # get rows with not null parent_id, deprecated syntax
+ res_2.sort()
+ res_3 = self.search(cr, uid, [('parent_id', 'not in', [])]) # get all rows, included null parent_id
+ res_3.sort()
+ res_4 = self.search(cr, uid, [('parent_id', 'not in', [False])]) # get rows with not null parent_id
+ res_4.sort()
+ res_4b = self.search(cr, uid, [('parent_id', 'not ilike', '')]) # get only rows without parent
+ res_4b.sort()
+ assert res_0 == partner_ids, 'res0: expected %r, got %r' % (partner_ids, res_0)
+ assert res_1 == partner_ids, 'res1: expected %r, got %r' % (partner_ids, res_1)
+ assert res_2 == with_parent, 'res2: expected %r, got %r' % (with_parent, res_2)
+ assert res_3 == partner_ids, 'res3: expected %r, got %r' % (partner_ids, res_3)
+ assert res_4 == with_parent, 'res4: expected %r, got %r' % (with_parent, res_4)
+ assert res_4b == without_parent, 'res4b: expected %r, got %r' % (without_parent, res_4b)
+ # The results of these queries, when combined with queries 0..4 must
+ # give the whole set of ids.
+ res_5 = self.search(cr, uid, [('parent_id', 'like', 'probably_unexisting_name')])
+ res_5.sort()
+ res_6 = self.search(cr, uid, [('parent_id', 'in', [max_partner_id + 1])])
+ res_6.sort()
+ res_7 = self.search(cr, uid, [('parent_id', '=', False)])
+ res_7.sort()
+ res_8 = self.search(cr, uid, [('parent_id', 'in', [])])
+ res_8.sort()
+ res_9 = self.search(cr, uid, [('parent_id', 'in', [False])])
+ res_9.sort()
+ res_9b = self.search(cr, uid, [('parent_id', 'ilike', '')]) # get those with a parent
+ res_9b.sort()
+
+ assert res_5 == [], 'res5: expected %r, got %r' % ([], res_5)
+ assert res_6 == [], 'res6: expected %r, got %r' % ([], res_6)
+ assert res_7 == without_parent, 'res7: expected %r, got %r' % (without_parent, res_7)
+ assert res_8 == [], 'res8: expected %r, got %r' % ([], res_8)
+ assert res_9 == without_parent, 'res9: expected %r, got %r' % (without_parent, res_9)
+ assert res_9b == with_parent, 'res9b: expected %r, got %r' % (with_parent, res_9b)
+ # These queries must return exactly the results than the queries 0..4,
+ # i.e. not ... in ... must be the same as ... not in ... .
+ res_10 = self.search(cr, uid, ['!', ('parent_id', 'like', 'probably_unexisting_name')])
+ res_10.sort()
+ res_11 = self.search(cr, uid, ['!', ('parent_id', 'in', [max_partner_id + 1])])
+ res_11.sort()
+ res_12 = self.search(cr, uid, ['!', ('parent_id', '=', False)])
+ res_12.sort()
+ res_13 = self.search(cr, uid, ['!', ('parent_id', 'in', [])])
+ res_13.sort()
+ res_14 = self.search(cr, uid, ['!', ('parent_id', 'in', [False])])
+ res_14.sort()
+ assert res_0 == res_10
+ assert res_1 == res_11
+ assert res_2 == res_12
+ assert res_3 == res_13
+ assert res_4 == res_14
+
+ # Testing many2one field is not enough, a regular char field is tested
+ # with in [] and must not return any result.
+ res_15 = self.search(cr, uid, [('website', 'in', [])])
+ assert res_15 == []
+ # not in [] must return everything.
+ res_16 = self.search(cr, uid, [('website', 'not in', [])])
+ res_16.sort()
+ assert res_16 == partner_ids
+
+ res_17 = self.search(cr, uid, [('website', '!=', False)])
+ res_17.sort()
+ assert res_17 == with_website
+
+-
+ Check behavior for required many2one fields
+-
+ !python {model: res.company }: |
+ company_ids = sorted(self.search(cr, uid, []))
+ # currency_id is required
+ res_101 = sorted(self.search(cr, uid, [('currency_id', 'not ilike', '')])) # get no companies
+ res_102 = sorted(self.search(cr, uid, [('currency_id', 'ilike', '')])) # get all companies
+ assert res_101 == [], 'res_101: expected %r, got %r' % ([], res_101)
+ assert res_102 == company_ids, 'res_102: expected %r, got %r' % (company_ids, res_102)
+-
+ Verify domain evaluation for `one2many != False`
+-
+ !python {model: res.partner.category }: |
+ all_ids = self.search(cr, uid, [])
+ parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
+ result = set(self.search(cr, uid, [('child_ids', '!=', False)]))
+ assert result and result == parent_categs, "Got %r, expected %r" % (result, parent_categs)
+-
+ Verify domain evaluation for `one2many == False`
+-
+ !python {model: res.partner.category }: |
+ all_ids = self.search(cr, uid, [])
+ parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
+ leaf_categs = set(all_ids) - parent_categs
+ result = set(self.search(cr, uid, [('child_ids', '=', False)]))
+ assert result and result == leaf_categs, "Got %r, expected %r" % (result, leaf_categs)
+-
+ Equivalent queries.
+-
+ !python {model: res.currency }: |
+ max_currency_id = max(self.search(cr, uid, []))
+ res_0 = self.search(cr, uid, [])
+ res_1 = self.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')])
+ res_2 = self.search(cr, uid, [('id', 'not in', [max_currency_id + 1003])])
+ res_3 = self.search(cr, uid, [('id', 'not in', [])])
+ res_4 = self.search(cr, uid, [('id', '!=', False)])
+ res_0.sort()
+ res_1.sort()
+ res_2.sort()
+ res_3.sort()
+ res_4.sort()
+ assert res_0 == res_1
+ assert res_0 == res_2
+ assert res_0 == res_3
+ assert res_0 == res_4
+-
+ Equivalent queries, integer and string.
+-
+ !python {model: res.partner }: |
+ all_ids = self.search(cr, uid, [])
+ if len(all_ids) > 1:
+ one = all_ids[0]
+ record = self.browse(cr, uid, one)
+ others = all_ids[1:]
+ res_1 = self.search(cr, uid, [('id', '=', one)])
+ # self.search(cr, uid, [('id', '!=', others)]) # not permitted
+ res_2 = self.search(cr, uid, [('id', 'not in', others)])
+ res_3 = self.search(cr, uid, ['!', ('id', '!=', one)])
+ res_4 = self.search(cr, uid, ['!', ('id', 'in', others)])
+ # res_5 = self.search(cr, uid, [('id', 'in', one)]) # TODO make it permitted, just like for child_of
+ res_6 = self.search(cr, uid, [('id', 'in', [one])])
+ res_7 = self.search(cr, uid, [('name', '=', record.name)])
+ res_8 = self.search(cr, uid, [('name', 'in', [record.name])])
+ # res_9 = self.search(cr, uid, [('name', 'in', record.name)]) # TODO
+ assert [one] == res_1
+ assert [one] == res_2
+ assert [one] == res_3
+ assert [one] == res_4
+ #assert [one] == res_5
+ assert [one] == res_6
+ assert [one] == res_7
+-
+ Need a company with a parent_id.
+-
+ !record {model: res.company, id: ymltest_company3}:
+ name: Acme 3
+-
+ Need a company with a parent_id.
+-
+ !record {model: res.company, id: ymltest_company4}:
+ name: Acme 4
+ parent_id: ymltest_company3
+-
+ Equivalent queries, one2many.
+-
+ !python {model: res.company }: |
+ # Search the company via its one2many (the one2many must point back at the company).
+ company = self.browse(cr, uid, ref('ymltest_company3'))
+ max_currency_id = max(self.pool.get('res.currency').search(cr, uid, []))
+ currency_ids1 = self.pool.get('res.currency').search(cr, uid, [('name', 'not like', 'probably_unexisting_name')])
+ currency_ids2 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [max_currency_id + 1003])])
+ currency_ids3 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [])])
+ assert currency_ids1 == currency_ids2 == currency_ids3, 'All 3 results should have be the same: all currencies'
+ default_company = self.browse(cr, uid, 1)
+
+ # Due to currency data definition change (in relation with bug 1111298), this test now needs
+ # a manual setup where all currencies are assigned to the default company.
+ self.pool['res.currency'].write(cr, uid, currency_ids1, {'company_id': default_company.id})
+
+ # one2many towards same model
+ res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child
+ res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child
+ # one2many towards another model
+ res_3 = self.search(cr, uid, [('currency_ids', 'in', [x.id for x in default_company.currency_ids])]) # companies having a currency of main company
+ res_4 = self.search(cr, uid, [('currency_ids', 'in', [default_company.currency_ids[0].id])]) # companies having first currency of main company
+ res_5 = self.search(cr, uid, [('currency_ids', 'in', default_company.currency_ids[0].id)]) # companies having first currency of main company
+ # res_6 = self.search(cr, uid, [('currency_ids', 'in', [default_company.currency_ids[0].name])]) # TODO
+ res_7 = self.search(cr, uid, [('currency_ids', '=', default_company.currency_ids[0].name)])
+ res_8 = self.search(cr, uid, [('currency_ids', 'like', default_company.currency_ids[0].name)])
+ res_9 = self.search(cr, uid, [('currency_ids', 'like', 'probably_unexisting_name')])
+ # self.search(cr, uid, [('currency_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception
+ assert res_1 == [ref('ymltest_company3')]
+ assert res_2 == [ref('ymltest_company3')]
+ assert res_3 == [1]
+ assert res_4 == [1]
+ assert res_5 == [1]
+ assert res_7 == [1]
+ assert res_8 == [1]
+ assert res_9 == []
+
+ # get the companies referenced by some currency (this is normally the main company) using a weird negative domain
+ res_10 = self.search(cr, uid, [('currency_ids', 'not like', 'probably_unexisting_name')])
+ res_11 = self.search(cr, uid, [('currency_ids', 'not in', [max_currency_id + 1])])
+ res_12 = self.search(cr, uid, [('currency_ids', '!=', False)])
+ res_13 = self.search(cr, uid, [('currency_ids', 'not in', [])])
+ res_10.sort()
+ res_11.sort()
+ res_12.sort()
+ res_13.sort()
+ assert res_10 == res_11
+ assert res_10 == res_12
+ assert res_10 == res_13
+
+ # try testing real subsets with IN/NOT IN
+ res_partner = self.pool.get('res.partner')
+ res_users = self.pool.get('res.users')
+ p1, _ = res_partner.name_create(cr, uid, "Dédé Boitaclou")
+ p2, _ = res_partner.name_create(cr, uid, "Raoulette Pizza O'poil")
+ u1a = res_users.create(cr, uid, {'login': 'dbo', 'partner_id': p1})
+ u1b = res_users.create(cr, uid, {'login': 'dbo2', 'partner_id': p1})
+ u2 = res_users.create(cr, uid, {'login': 'rpo', 'partner_id': p2})
+ assert [p1] == res_partner.search(cr, uid, [('user_ids', 'in', u1a)]), "o2m IN accept single int on right side"
+ assert [p1,p2] == res_partner.search(cr, uid, [('user_ids', 'in', [u1a,u2])]), "o2m IN matches any on the right side"
+ all_partners = res_partner.search(cr, uid, [])
+ assert (set(all_partners) - set([p1])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', u1a)])), "o2m NOT IN matches none on the right side"
+ assert (set(all_partners) - set([p1,p2])) == set(res_partner.search(cr, uid, [('user_ids', 'not in', [u1b, u2])])), "o2m NOT IN matches none on the right side"
+
+ # child_of x returns x and its children (direct or not).
+ company = self.browse(cr, uid, ref('ymltest_company3'))
+ expected = [ref('ymltest_company3'), ref('ymltest_company4')]
+ expected.sort()
+ res_1 = self.search(cr, uid, [('id', 'child_of', [ref('ymltest_company3')])])
+ res_1.sort()
+ res_2 = self.search(cr, uid, [('id', 'child_of', ref('ymltest_company3'))])
+ res_2.sort()
+ res_3 = self.search(cr, uid, [('id', 'child_of', [company.name])])
+ res_3.sort()
+ res_4 = self.search(cr, uid, [('id', 'child_of', company.name)])
+ res_4.sort()
+ assert res_1 == expected
+ assert res_2 == expected
+ assert res_3 == expected
+ assert res_4 == expected
+-
+ Unaccent. Create a company with an accent in its name.
+-
+ !record {model: res.company, id: ymltest_unaccent_company}:
+ name: Hélène
+-
+ Test the unaccent-enabled 'ilike'.
+-
+ !python {model: res.company}: |
+ if self.pool.has_unaccent:
+ ids = self.search(cr, uid, [('name','ilike','Helene')], {})
+ assert ids == [ref('ymltest_unaccent_company')]
+ ids = self.search(cr, uid, [('name','ilike','hélène')], {})
+ assert ids == [ref('ymltest_unaccent_company')]
+ ids = self.search(cr, uid, [('name','not ilike','Helene')], {})
+ assert ref('ymltest_unaccent_company') not in ids
+ ids = self.search(cr, uid, [('name','not ilike','hélène')], {})
+ assert ref('ymltest_unaccent_company') not in ids
+-
+ Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on an untranslated field.
+-
+ !python {model: res.partner }: |
+ all_ids = self.search(cr, uid, [('name', '=like', 'A_e_or')])
+ assert len(all_ids) == 1, "Must match one partner (Axelor), got %r"%all_ids
+ all_ids = self.search(cr, uid, [('name', '=ilike', 'v%')])
+ assert len(all_ids) >= 1, "Must match one partner (Vicking Direct), got %r"%all_ids
+-
+ Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on translated field.
+-
+ !python {model: res.country }: |
+ all_ids = self.search(cr, uid, [('name', '=like', 'Ind__')])
+ assert len(all_ids) == 1, "Must match India only, got %r"%all_ids
+ all_ids = self.search(cr, uid, [('name', '=ilike', 'z%')])
+ assert len(all_ids) == 3, "Must match only countries with names starting with Z (currently 3), got %r"%all_ids
+-
+ Use the create_date column on res.country (which doesn't declare it in _columns).
+-
+ !python {model: res.country }: |
+ ids = self.search(cr, uid, [('create_date', '<', '2001-01-01 12:00:00')])
+
+
+-
+ Verify that invalid expressions are refused, even for magic fields
+-
+ !python {model: res.country }: |
+ try:
+ self.search(cr, uid, [('does_not_exist', '=', 'foo')])
+ raise AssertionError('Invalid fields should not be accepted')
+ except ValueError:
+ pass
+
+ try:
+ self.search(cr, uid, [('create_date', '>>', 'foo')])
+ raise AssertionError('Invalid operators should not be accepted')
+ except ValueError:
+ pass
+
+ import psycopg2
+ try:
+ cr._default_log_exceptions = False
+ cr.execute('SAVEPOINT expression_failure_test')
+ self.search(cr, uid, [('create_date', '=', "1970-01-01'); --")])
+ # if the above search gives no error, the operand was not escaped!
+ cr.execute('RELEASE SAVEPOINT expression_failure_test')
+ raise AssertionError('Operands should always be SQL escaped')
+ except psycopg2.DataError:
+ # Should give: 'DataError: invalid input syntax for type timestamp' or similar
+ cr.execute('ROLLBACK TO SAVEPOINT expression_failure_test')
+-
+ Testing for Many2Many field with category supplier and active=False
+-
+ !python {model: res.partner }: |
+ vals = {'category_id': [(6, 0, [ref("base.res_partner_category_1")])],
+ 'name': 'OpenERP Test',
+ 'active': False,
+ 'child_ids': [(0, 0, {'name': 'address of OpenERP Test', 'country_id': ref("base.be")})]
+ }
+ self.create(cr, uid, vals, context=context)
+ res_ids = self.search(cr, uid, [('category_id', 'ilike', 'supplier'), ('active', '=', False)])
+ assert len(res_ids) != 0, "Record not Found with category supplier and active False."
+-
+ Testing for One2Many field with country Belgium and active=False
+-
+ !python {model: res.partner }: |
+ res_ids = self.search(cr, uid, [('child_ids.country_id','=','Belgium'),('active','=',False)])
+ assert len(res_ids) != 0, "Record not Found with country Belgium and active False."
+-
+ Check that we can exclude translated fields (bug lp:1071710)
+-
+ !python {model: res.country}: |
+ # first install french language
+ Modules = self.pool.get('ir.module.module')
+ base = Modules.browse(cr, uid, Modules.search(cr, uid, [('name', '=', 'base')])[0])
+
+ # hack: mark module as installed to allow install of the translation
+ base_state = base.state
+ base.write({'state': 'installed'})
+ base.update_translations('fr_FR')
+ base.write({'state': base_state})
+
+ # tests
+ be_id = self.search(cr, uid, [('name', '=', 'Belgium')])[0]
+
+ ctx = {'lang': 'fr_FR'}
+ not_be = self.search(cr, uid, [('name', '!=', 'Belgique')], context=ctx)
+
+ assert be_id not in not_be, "Search match failed"
+
+ # indirect search via m2o
+ Partners = self.pool.get('res.partner')
+ agrolait = Partners.search(cr, uid, [('name', '=', 'Agrolait')])[0]
+
+ not_be = Partners.search(cr, uid, [('country_id', '!=', 'Belgium')])
+ assert agrolait not in not_be, "Search match failed (m2o)"
+
+ not_be = Partners.search(cr, uid, [('country_id', '!=', 'Belgique')], context=ctx)
+ assert agrolait not in not_be, "Search match failed (m2o)"