[MIG] base/tests
Convert YAML tests into Python tests: - translation tests moved to test_translate.py - test phases tests moved to test_phase.py - safe_eval tests moved to test_base.py - parent_store tests moved to test_base.py - float rounding tests moved to test_float.py - `ir.rule` tests moved to test_acl.py - search tests moved to test_expression.py
This commit is contained in:
@@ -12,18 +12,17 @@ class TestServerActionsEmail(TestServerActionsBase):
|
||||
'name': 'TestTemplate',
|
||||
'email_from': 'myself@example.com',
|
||||
'email_to': 'brigitte@example.com',
|
||||
'partner_to': '%s' % self.test_partner_id,
|
||||
'model_id': self.res_partner_model_id,
|
||||
'partner_to': '%s' % self.test_partner.id,
|
||||
'model_id': self.res_partner_model.id,
|
||||
'subject': 'About ${object.name}',
|
||||
'body_html': '<p>Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}</p>',
|
||||
})
|
||||
action = self.env['ir.actions.server'].browse(self.act_id)
|
||||
action.write({'state': 'email', 'template_id': email_template.id})
|
||||
run_res = action.with_context(self.context).run()
|
||||
self.action.write({'state': 'email', 'template_id': email_template.id})
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: email server action correctly finished should return False')
|
||||
# check an email is waiting for sending
|
||||
mail = self.env['mail.mail'].search([('subject', '=', 'About TestingPartner')])
|
||||
self.assertEqual(len(mail.ids), 1, 'ir_actions_server: TODO')
|
||||
self.assertEqual(len(mail), 1, 'ir_actions_server: TODO')
|
||||
# check email content
|
||||
self.assertEqual(mail.body, '<p>Dear TestingPartner, your parent is False</p>',
|
||||
'ir_actions_server: TODO')
|
||||
|
||||
@@ -72,11 +72,7 @@ The kernel of Odoo, needed for all installation.
|
||||
'res/res_partner_demo.yml',
|
||||
'res/res_partner_image_demo.xml',
|
||||
],
|
||||
'test': [
|
||||
'tests/base_test.yml',
|
||||
'tests/test_osv_expression.yml',
|
||||
'tests/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules.
|
||||
],
|
||||
'test': [],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'post_init_hook': 'post_init',
|
||||
|
||||
@@ -4,6 +4,7 @@ import test_base
|
||||
import test_basecase
|
||||
import test_db_cursor
|
||||
import test_expression
|
||||
import test_float
|
||||
import test_func
|
||||
import test_ir_actions
|
||||
import test_ir_attachment
|
||||
@@ -16,6 +17,7 @@ import test_menu
|
||||
import test_orm
|
||||
import test_ormcache
|
||||
import test_osv
|
||||
import test_phase
|
||||
import test_qweb
|
||||
import test_res_config
|
||||
import test_res_lang
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
- |
|
||||
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
|
||||
|
||||
# Force partner_categ.copy() to copy children
|
||||
self._fields['child_ids'].copy = True
|
||||
self._columns['child_ids'].copy = True
|
||||
-
|
||||
"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}: |
|
||||
self._columns['child_ids'].copy = True # force copying children for test
|
||||
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
|
||||
self._fields['child_ids'].copy = False
|
||||
self._columns['child_ids'].copy = False
|
||||
|
||||
-
|
||||
"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, rounding_method='HALF-UP'):
|
||||
result = float_repr(float_round(amount, precision_digits=precision_digits, rounding_method=rounding_method),
|
||||
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')
|
||||
|
||||
# Try some rounding value with rounding method UP instead of HALF-UP
|
||||
# We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives
|
||||
# us 8175,0000000001234 as value, and if not handle correctly the rounding UP
|
||||
# value will be incorrect (should be 8,175 and not 8,176)
|
||||
try_round(8.175, '8.175', rounding_method='UP')
|
||||
try_round(8.1751, '8.176', rounding_method='UP')
|
||||
try_round(-8.175, '-8.175', rounding_method='UP')
|
||||
try_round(-8.1751, '-8.176', rounding_method='UP')
|
||||
try_round(-6.000, '-6.000', rounding_method='UP')
|
||||
try_round(1.8, '2', 0, rounding_method='UP')
|
||||
try_round(-1.8, '-2', 0, rounding_method='UP')
|
||||
|
||||
# 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'])[0]['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'"
|
||||
@@ -1,26 +1,23 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from openerp.exceptions import AccessError
|
||||
from openerp.tools.misc import mute_logger
|
||||
from openerp.tests import common
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools.misc import mute_logger
|
||||
|
||||
# test group that demo user should not have
|
||||
USER_DEMO = 'base.user_demo'
|
||||
GROUP_SYSTEM = 'base.group_system'
|
||||
GROUP_ERP_MANAGER = 'base.group_erp_manager'
|
||||
|
||||
|
||||
class TestACL(common.TransactionCase):
|
||||
class TestACL(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestACL, self).setUp()
|
||||
self.res_currency = self.registry('res.currency')
|
||||
self.res_partner = self.registry('res.partner')
|
||||
self.res_users = self.registry('res.users')
|
||||
self.res_company = self.registry('res.company')
|
||||
self.demo_uid = self.env.ref('base.user_demo').id
|
||||
self.demo_user = self.env.ref(USER_DEMO)
|
||||
self.erp_system_group = self.env.ref(GROUP_SYSTEM)
|
||||
self.erp_manager_group = self.env.ref(GROUP_ERP_MANAGER)
|
||||
|
||||
def _set_field_groups(self, model, field_name, groups):
|
||||
field = model._fields[field_name]
|
||||
@@ -32,109 +29,103 @@ class TestACL(common.TransactionCase):
|
||||
def test_field_visibility_restriction(self):
|
||||
"""Check that model-level ``groups`` parameter effectively restricts access to that
|
||||
field for users who do not belong to one of the explicitly allowed groups"""
|
||||
currency = self.env['res.currency'].sudo(self.demo_user)
|
||||
|
||||
# Verify the test environment first
|
||||
original_fields = self.res_currency.fields_get(self.cr, self.demo_uid, [])
|
||||
form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
original_fields = currency.fields_get([])
|
||||
form_view = currency.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(form_view.get('arch'))
|
||||
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
|
||||
has_group_system = self.demo_user.has_group(GROUP_SYSTEM)
|
||||
self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group before the test")
|
||||
self.assertTrue('decimal_places' in original_fields, "'decimal_places' field must be properly visible before the test")
|
||||
self.assertIn('decimal_places', original_fields, "'decimal_places' field must be properly visible before the test")
|
||||
self.assertNotEquals(view_arch.xpath("//field[@name='decimal_places']"), [],
|
||||
"Field 'decimal_places' must be found in view definition before the test")
|
||||
|
||||
# restrict access to the field and check it's gone
|
||||
self._set_field_groups(self.res_currency, 'decimal_places', GROUP_SYSTEM)
|
||||
self._set_field_groups(currency, 'decimal_places', GROUP_SYSTEM)
|
||||
|
||||
fields = self.res_currency.fields_get(self.cr, self.demo_uid, [])
|
||||
form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
fields = currency.fields_get([])
|
||||
form_view = currency.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(form_view.get('arch'))
|
||||
self.assertFalse('decimal_places' in fields, "'decimal_places' field should be gone")
|
||||
self.assertNotIn('decimal_places', fields, "'decimal_places' field should be gone")
|
||||
self.assertEquals(view_arch.xpath("//field[@name='decimal_places']"), [],
|
||||
"Field 'decimal_places' must not be found in view definition")
|
||||
|
||||
# Make demo user a member of the restricted group and check that the field is back
|
||||
self.erp_system_group.write({'users': [(4, self.demo_uid)]})
|
||||
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
|
||||
fields = self.res_currency.fields_get(self.cr, self.demo_uid, [])
|
||||
form_view = self.res_currency.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
self.erp_system_group.users += self.demo_user
|
||||
has_group_system = self.demo_user.has_group(GROUP_SYSTEM)
|
||||
fields = currency.fields_get([])
|
||||
form_view = currency.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(form_view.get('arch'))
|
||||
#import pprint; pprint.pprint(fields); pprint.pprint(form_view)
|
||||
self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group")
|
||||
self.assertTrue('decimal_places' in fields, "'decimal_places' field must be properly visible again")
|
||||
self.assertIn('decimal_places', fields, "'decimal_places' field must be properly visible again")
|
||||
self.assertNotEquals(view_arch.xpath("//field[@name='decimal_places']"), [],
|
||||
"Field 'decimal_places' must be found in view definition again")
|
||||
|
||||
#cleanup
|
||||
self.erp_system_group.write({'users': [(3, self.demo_uid)]})
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_field_crud_restriction(self):
|
||||
"Read/Write RPC access to restricted field should be forbidden"
|
||||
partner = self.env['res.partner'].browse(1).sudo(self.demo_user)
|
||||
|
||||
# Verify the test environment first
|
||||
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
|
||||
has_group_system = self.demo_user.has_group(GROUP_SYSTEM)
|
||||
self.assertFalse(has_group_system, "`demo` user should not belong to the restricted group")
|
||||
self.assert_(self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids']))
|
||||
self.assert_(self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []}))
|
||||
self.assert_(partner.read(['bank_ids']))
|
||||
self.assert_(partner.write({'bank_ids': []}))
|
||||
|
||||
# Now restrict access to the field and check it's forbidden
|
||||
self._set_field_groups(self.res_partner, 'bank_ids', GROUP_SYSTEM)
|
||||
self._set_field_groups(partner, 'bank_ids', GROUP_SYSTEM)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids'])
|
||||
partner.read(['bank_ids'])
|
||||
with self.assertRaises(AccessError):
|
||||
self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []})
|
||||
partner.write({'bank_ids': []})
|
||||
|
||||
# Add the restricted group, and check that it works again
|
||||
self.erp_system_group.write({'users': [(4, self.demo_uid)]})
|
||||
has_group_system = self.res_users.has_group(self.cr, self.demo_uid, GROUP_SYSTEM)
|
||||
self.erp_system_group.users += self.demo_user
|
||||
has_group_system = self.demo_user.has_group(GROUP_SYSTEM)
|
||||
self.assertTrue(has_group_system, "`demo` user should now belong to the restricted group")
|
||||
self.assert_(self.res_partner.read(self.cr, self.demo_uid, [1], ['bank_ids']))
|
||||
self.assert_(self.res_partner.write(self.cr, self.demo_uid, [1], {'bank_ids': []}))
|
||||
|
||||
#cleanup
|
||||
self.erp_system_group.write({'users': [(3, self.demo_uid)]})
|
||||
self.assert_(partner.read(['bank_ids']))
|
||||
self.assert_(partner.write({'bank_ids': []}))
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_fields_browse_restriction(self):
|
||||
"""Test access to records having restricted fields"""
|
||||
self._set_field_groups(self.res_partner, 'email', GROUP_SYSTEM)
|
||||
partner = self.env['res.partner'].sudo(self.demo_user)
|
||||
self._set_field_groups(partner, 'email', GROUP_SYSTEM)
|
||||
|
||||
pid = self.res_partner.search(self.cr, self.demo_uid, [], limit=1)[0]
|
||||
part = self.res_partner.browse(self.cr, self.demo_uid, pid)
|
||||
# accessing fields must no raise exceptions...
|
||||
part.name
|
||||
partner = partner.search([], limit=1)
|
||||
partner.name
|
||||
# ... except if they are restricted
|
||||
with self.assertRaises(AccessError) as cm:
|
||||
with self.assertRaises(AccessError):
|
||||
with mute_logger('openerp.models'):
|
||||
part.email
|
||||
|
||||
#Useless because we get the title in the client side now in the chrome.js file(map_title)
|
||||
#self.assertEqual(cm.exception.args[0], 'Access Error')
|
||||
partner.email
|
||||
|
||||
def test_view_create_edit_button_invisibility(self):
|
||||
""" Test form view Create, Edit, Delete button visibility based on access right of model"""
|
||||
methods = ['create', 'edit', 'delete']
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
company = self.env['res.company'].sudo(self.demo_user)
|
||||
company_view = company.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
for method in methods:
|
||||
self.assertEqual(view_arch.get(method), 'false')
|
||||
|
||||
def test_view_create_edit_button_visibility(self):
|
||||
""" Test form view Create, Edit, Delete button visibility based on access right of model"""
|
||||
self.erp_system_group.users += self.demo_user
|
||||
methods = ['create', 'edit', 'delete']
|
||||
self.erp_manager_group.write({'users': [(4, self.demo_uid)]})
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
company = self.env['res.company'].sudo(self.demo_user)
|
||||
company_view = company.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
for method in methods:
|
||||
self.assertIsNone(view_arch.get(method))
|
||||
# cleanup
|
||||
self.erp_manager_group.write({'users': [(3, self.demo_uid)]})
|
||||
|
||||
def test_m2o_field_create_edit_invisibility(self):
|
||||
""" Test many2one field Create and Edit option visibility based on access rights of relation field"""
|
||||
methods = ['create', 'write']
|
||||
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
company = self.env['res.company'].sudo(self.demo_user)
|
||||
company_view = company.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
field_node = view_arch.xpath("//field[@name='currency_id']")
|
||||
self.assertTrue(len(field_node), "currency_id field should be in company from view")
|
||||
@@ -143,17 +134,125 @@ class TestACL(common.TransactionCase):
|
||||
|
||||
def test_m2o_field_create_edit_visibility(self):
|
||||
""" Test many2one field Create and Edit option visibility based on access rights of relation field"""
|
||||
self.erp_system_group.users += self.demo_user
|
||||
methods = ['create', 'write']
|
||||
|
||||
self.erp_system_group.write({'users': [(4, self.demo_uid)]})
|
||||
company_view = self.res_company.fields_view_get(self.cr, self.demo_uid, False, 'form')
|
||||
company = self.env['res.company'].sudo(self.demo_user)
|
||||
company_view = company.fields_view_get(False, 'form')
|
||||
view_arch = etree.fromstring(company_view['arch'])
|
||||
field_node = view_arch.xpath("//field[@name='currency_id']")
|
||||
self.assertTrue(len(field_node), "currency_id field should be in company from view")
|
||||
for method in methods:
|
||||
self.assertEqual(field_node[0].get('can_' + method), 'true')
|
||||
# cleanup
|
||||
self.erp_manager_group.write({'users': [(3, self.demo_uid)]})
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
class TestIrRule(TransactionCase):
|
||||
|
||||
def test_ir_rule(self):
|
||||
model_res_partner = self.env.ref('base.model_res_partner')
|
||||
group_user = self.env.ref('base.group_user')
|
||||
user_demo = self.env.ref('base.user_demo')
|
||||
|
||||
# create an ir_rule for the Employee group with an blank domain
|
||||
rule1 = self.env['ir.rule'].create({
|
||||
'name': 'test_rule1',
|
||||
'model_id': model_res_partner.id,
|
||||
'domain_force': False,
|
||||
'groups': [(6, 0, group_user.ids)],
|
||||
})
|
||||
|
||||
# read as demo user the partners (one blank domain)
|
||||
partners_demo = self.env['res.partner'].sudo(user_demo)
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# same with domain 1=1
|
||||
rule1.domain_force = "[(1,'=',1)]"
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# same with domain []
|
||||
rule1.domain_force = "[]"
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# create another ir_rule for the Employee group (to test multiple rules)
|
||||
rule2 = self.env['ir.rule'].create({
|
||||
'name': 'test_rule2',
|
||||
'model_id': model_res_partner.id,
|
||||
'domain_force': False,
|
||||
'groups': [(6, 0, group_user.ids)],
|
||||
})
|
||||
|
||||
# read as demo user with domains [] and blank
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# same with domains 1=1 and blank
|
||||
rule1.domain_force = "[(1,'=',1)]"
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# same with domains 1=1 and 1=1
|
||||
rule2.domain_force = "[(1,'=',1)]"
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# create another ir_rule for the Employee group (to test multiple rules)
|
||||
rule3 = self.env['ir.rule'].create({
|
||||
'name': 'test_rule3',
|
||||
'model_id': model_res_partner.id,
|
||||
'domain_force': False,
|
||||
'groups': [(6, 0, group_user.ids)],
|
||||
})
|
||||
|
||||
# read the partners as demo user
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# same with domains 1=1, 1=1 and 1=1
|
||||
rule3.domain_force = "[(1,'=',1)]"
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# modify the global rule on res_company which triggers a recursive check
|
||||
# of the rules on company
|
||||
global_rule = self.env.ref('base.res_company_rule_employee')
|
||||
global_rule.domain_force = "[('id','child_of',[user.company_id.id])]"
|
||||
|
||||
# read as demo user (exercising the global company rule)
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "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.
|
||||
rule2.domain_force = "[('id','=',False),('name','=',False)]"
|
||||
|
||||
# check that demo user still sees partners, because group-rules are OR'ed
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partner.")
|
||||
|
||||
# create a new group with demo user in it, and a complex rule
|
||||
group_test = self.env['res.groups'].create({
|
||||
'name': 'Test Group',
|
||||
'users': [(6, 0, user_demo.ids)],
|
||||
})
|
||||
|
||||
# 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
|
||||
rule3.write({
|
||||
'domain_force': "[('name','!=',False),('id','!=',False)]",
|
||||
'groups': [(6, 0, group_test.ids)],
|
||||
})
|
||||
|
||||
# read the partners again as demo user, which should give results
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see partners even with the combined rules.")
|
||||
|
||||
# delete global domains (to combine only group domains)
|
||||
self.env['ir.rule'].search([('groups', '=', False)]).unlink()
|
||||
|
||||
# read the partners as demo user (several group domains, no global domain)
|
||||
partners = partners_demo.search([])
|
||||
self.assertTrue(partners, "Demo user should see some partners.")
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import models
|
||||
from openerp.tools import mute_logger
|
||||
from openerp.tests import common
|
||||
from openerp.exceptions import AccessError
|
||||
from odoo import models
|
||||
from odoo.tools import mute_logger
|
||||
from odoo.tests import common
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
|
||||
class TestAPI(common.TransactionCase):
|
||||
@@ -84,7 +86,7 @@ class TestAPI(common.TransactionCase):
|
||||
ids = map(int, partners)
|
||||
|
||||
# modify those partners, and check that partners has not changed
|
||||
self.registry('res.partner').write(self.cr, self.uid, ids, {'active': False})
|
||||
partners.write({'active': False})
|
||||
self.assertEqual(ids, map(int, partners))
|
||||
|
||||
# redo the search, and check that the result is now empty
|
||||
@@ -94,7 +96,7 @@ class TestAPI(common.TransactionCase):
|
||||
@mute_logger('openerp.models')
|
||||
def test_06_fields(self):
|
||||
""" Check that relation fields return records, recordsets or nulls. """
|
||||
user = self.registry('res.users').browse(self.cr, self.uid, self.uid)
|
||||
user = self.env.user
|
||||
self.assertIsRecord(user, 'res.users')
|
||||
self.assertIsRecord(user.partner_id, 'res.partner')
|
||||
self.assertIsRecordset(user.groups_id, 'res.groups')
|
||||
|
||||
@@ -1,80 +1,113 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import ast
|
||||
import unittest
|
||||
|
||||
import openerp.tests.common as common
|
||||
from openerp.exceptions import ValidationError
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import mute_logger
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
class test_base(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(test_base,self).setUp()
|
||||
self.res_partner = self.registry('res.partner')
|
||||
self.res_users = self.registry('res.users')
|
||||
self.res_partner_title = self.registry('res.partner.title')
|
||||
class TestSafeEval(unittest.TestCase):
|
||||
|
||||
# samples use effective TLDs from the Mozilla public suffix
|
||||
# list at http://publicsuffix.org
|
||||
self.samples = [
|
||||
('"Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr> ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'),
|
||||
('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'),
|
||||
('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''),
|
||||
(" Raoul O'hara <!@historicalsociety.museum>", "Raoul O'hara", '!@historicalsociety.museum')
|
||||
]
|
||||
def test_01_safe_eval(self):
|
||||
""" Try a few common expressions to verify they work with safe_eval """
|
||||
expected = (1, {"a": 9 * 2}, (True, False, None))
|
||||
actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
|
||||
self.assertEqual(actual, expected, "Simple python expressions are not working with safe_eval")
|
||||
|
||||
def test_02_literal_eval(self):
|
||||
""" Try simple literal definition to verify it works with literal_eval """
|
||||
expected = (1, {"a": 9}, (True, False, None))
|
||||
actual = ast.literal_eval('(1, {"a": 9}, (True, False, None))')
|
||||
self.assertEqual(actual, expected, "Simple python expressions are not working with literal_eval")
|
||||
|
||||
def test_03_literal_eval_arithmetic(self):
|
||||
""" Try arithmetic expression in literal_eval to verify it does not work """
|
||||
with self.assertRaises(ValueError):
|
||||
ast.literal_eval('(1, {"a": 2*9}, (True, False, None))')
|
||||
|
||||
def test_04_literal_eval_forbidden(self):
|
||||
""" Try forbidden expressions in literal_eval to verify they are not allowed """
|
||||
with self.assertRaises(ValueError):
|
||||
ast.literal_eval('{"a": True.__class__}')
|
||||
|
||||
@mute_logger('openerp.tools.safe_eval')
|
||||
def test_05_safe_eval_forbiddon(self):
|
||||
""" Try forbidden expressions in safe_eval to verify they are not allowed (open) """
|
||||
with self.assertRaises(ValueError):
|
||||
safe_eval('open("/etc/passwd","r")')
|
||||
|
||||
|
||||
# samples use effective TLDs from the Mozilla public suffix
|
||||
# list at http://publicsuffix.org
|
||||
SAMPLES = [
|
||||
('"Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr> ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'),
|
||||
('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'),
|
||||
('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''),
|
||||
(" Raoul O'hara <!@historicalsociety.museum>", "Raoul O'hara", '!@historicalsociety.museum'),
|
||||
]
|
||||
|
||||
class TestBase(TransactionCase):
|
||||
|
||||
def test_00_res_partner_name_create(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
parse = self.res_partner._parse_partner_name
|
||||
for text, name, mail in self.samples:
|
||||
self.assertEqual((name,mail), parse(text), 'Partner name parsing failed')
|
||||
partner_id, dummy = self.res_partner.name_create(cr, uid, text)
|
||||
partner = self.res_partner.browse(cr, uid, partner_id)
|
||||
res_partner = self.env['res.partner']
|
||||
parse = res_partner._parse_partner_name
|
||||
for text, name, mail in SAMPLES:
|
||||
self.assertEqual((name, mail), parse(text), 'Partner name parsing failed')
|
||||
partner_id, dummy = res_partner.name_create(text)
|
||||
partner = res_partner.browse(partner_id)
|
||||
self.assertEqual(name or mail, partner.name, 'Partner name incorrect')
|
||||
self.assertEqual(mail or False, partner.email, 'Partner email incorrect')
|
||||
|
||||
def test_10_res_partner_find_or_create(self):
|
||||
cr,uid = self.cr, self.uid
|
||||
email = self.samples[0][0]
|
||||
partner_id, dummy = self.res_partner.name_create(cr, uid, email)
|
||||
found_id = self.res_partner.find_or_create(cr, uid, email)
|
||||
res_partner = self.env['res.partner']
|
||||
email = SAMPLES[0][0]
|
||||
partner_id, dummy = res_partner.name_create(email)
|
||||
found_id = res_partner.find_or_create(email)
|
||||
self.assertEqual(partner_id, found_id, 'find_or_create failed')
|
||||
partner_id2, dummy2 = self.res_partner.name_create(cr, uid, 'sarah.john@connor.com')
|
||||
found_id2 = self.res_partner.find_or_create(cr, uid, 'john@connor.com')
|
||||
partner_id2, dummy2 = res_partner.name_create('sarah.john@connor.com')
|
||||
found_id2 = res_partner.find_or_create('john@connor.com')
|
||||
self.assertNotEqual(partner_id2, found_id2, 'john@connor.com match sarah.john@connor.com')
|
||||
new_id = self.res_partner.find_or_create(cr, uid, self.samples[1][0])
|
||||
new_id = res_partner.find_or_create(SAMPLES[1][0])
|
||||
self.assertTrue(new_id > partner_id, 'find_or_create failed - should have created new one')
|
||||
new_id2 = self.res_partner.find_or_create(cr, uid, self.samples[2][0])
|
||||
new_id2 = res_partner.find_or_create(SAMPLES[2][0])
|
||||
self.assertTrue(new_id2 > new_id, 'find_or_create failed - should have created new one again')
|
||||
|
||||
def test_15_res_partner_name_search(self):
|
||||
cr,uid = self.cr, self.uid
|
||||
for name, active in [
|
||||
res_partner = self.env['res.partner']
|
||||
DATA = [
|
||||
('"A Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr>', False),
|
||||
('B Raoul chirurgiens-dentistes.fr', True),
|
||||
("C Raoul O'hara <!@historicalsociety.museum>", True),
|
||||
('ryu+giga-Sushi@aizubange.fukushima.jp', True),
|
||||
]:
|
||||
partner_id, dummy = self.res_partner.name_create(cr, uid, name, context={'default_active': active})
|
||||
partners = self.res_partner.name_search(cr, uid, 'Raoul')
|
||||
]
|
||||
for name, active in DATA:
|
||||
partner_id, dummy = res_partner.with_context(default_active=active).name_create(name)
|
||||
partners = res_partner.name_search('Raoul')
|
||||
self.assertEqual(len(partners), 2, 'Incorrect search number result for name_search')
|
||||
partners = self.res_partner.name_search(cr, uid, 'Raoul', limit=1)
|
||||
partners = res_partner.name_search('Raoul', limit=1)
|
||||
self.assertEqual(len(partners), 1, 'Incorrect search number result for name_search with a limit')
|
||||
self.assertEqual(partners[0][1], 'B Raoul chirurgiens-dentistes.fr', 'Incorrect partner returned, should be the first active')
|
||||
|
||||
def test_20_res_partner_address_sync(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
ghoststep = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
|
||||
{'name': 'GhostStep',
|
||||
'is_company': True,
|
||||
'street': 'Main Street, 10',
|
||||
'phone': '123456789',
|
||||
'email': 'info@ghoststep.com',
|
||||
'vat': 'BE0477472701',
|
||||
'type': 'contact'}))
|
||||
p1 = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Denis Bladesmith <denis.bladesmith@ghoststep.com>')[0])
|
||||
res_partner = self.env['res.partner']
|
||||
ghoststep = res_partner.create({
|
||||
'name': 'GhostStep',
|
||||
'is_company': True,
|
||||
'street': 'Main Street, 10',
|
||||
'phone': '123456789',
|
||||
'email': 'info@ghoststep.com',
|
||||
'vat': 'BE0477472701',
|
||||
'type': 'contact',
|
||||
})
|
||||
p1 = res_partner.browse(res_partner.name_create('Denis Bladesmith <denis.bladesmith@ghoststep.com>')[0])
|
||||
self.assertEqual(p1.type, 'contact', 'Default type must be "contact"')
|
||||
p1phone = '123456789#34'
|
||||
p1.write({'phone': p1phone,
|
||||
'parent_id': ghoststep.id})
|
||||
p1.refresh()
|
||||
self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced')
|
||||
self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync')
|
||||
self.assertEqual(p1.type, 'contact', 'Type should be preserved after address sync')
|
||||
@@ -84,13 +117,11 @@ class test_base(common.TransactionCase):
|
||||
p1street = 'Different street, 42'
|
||||
p1.write({'street': p1street,
|
||||
'type': 'invoice'})
|
||||
p1.refresh(), ghoststep.refresh()
|
||||
self.assertEqual(p1.street, p1street, 'Address fields must not be synced after turning sync off')
|
||||
self.assertNotEqual(ghoststep.street, p1street, 'Parent address must never be touched')
|
||||
|
||||
# turn on sync again
|
||||
p1.write({'type': 'contact'})
|
||||
p1.refresh()
|
||||
self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced again')
|
||||
self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync')
|
||||
self.assertEqual(p1.type, 'contact', 'Type should be preserved after address sync')
|
||||
@@ -99,213 +130,197 @@ class test_base(common.TransactionCase):
|
||||
# Modify parent, sync to children
|
||||
ghoststreet = 'South Street, 25'
|
||||
ghoststep.write({'street': ghoststreet})
|
||||
p1.refresh()
|
||||
self.assertEqual(p1.street, ghoststreet, 'Address fields must be synced automatically')
|
||||
self.assertEqual(p1.phone, p1phone, 'Phone should not be synced')
|
||||
self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync')
|
||||
|
||||
p1street = 'My Street, 11'
|
||||
p1.write({'street': p1street})
|
||||
ghoststep.refresh()
|
||||
self.assertEqual(ghoststep.street, ghoststreet, 'Touching contact should never alter parent')
|
||||
|
||||
def test_30_res_partner_first_contact_sync(self):
|
||||
""" Test initial creation of company/contact pair where contact address gets copied to
|
||||
company """
|
||||
cr, uid = self.cr, self.uid
|
||||
ironshield = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'IronShield')[0])
|
||||
res_partner = self.env['res.partner']
|
||||
ironshield = res_partner.browse(res_partner.name_create('IronShield')[0])
|
||||
self.assertFalse(ironshield.is_company, 'Partners are not companies by default')
|
||||
self.assertEqual(ironshield.type, 'contact', 'Default type must be "contact"')
|
||||
ironshield.write({'type': 'contact'})
|
||||
p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
|
||||
{'name': 'Isen Hardearth',
|
||||
'street': 'Strongarm Avenue, 12',
|
||||
'parent_id': ironshield.id}))
|
||||
|
||||
p1 = res_partner.create({
|
||||
'name': 'Isen Hardearth',
|
||||
'street': 'Strongarm Avenue, 12',
|
||||
'parent_id': ironshield.id,
|
||||
})
|
||||
self.assertEquals(p1.type, 'contact', 'Default type must be "contact", not the copied parent type')
|
||||
ironshield.refresh()
|
||||
self.assertEqual(ironshield.street, p1.street, 'Address fields should be copied to company')
|
||||
|
||||
def test_40_res_partner_address_getc(self):
|
||||
def test_40_res_partner_address_get(self):
|
||||
""" Test address_get address resolution mechanism: it should first go down through descendants,
|
||||
stopping when encountering another is_copmany entity, then go up, stopping again at the first
|
||||
is_company entity or the root ancestor and if nothing matches, it should use the provided partner
|
||||
itself """
|
||||
cr, uid = self.cr, self.uid
|
||||
elmtree = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Elmtree')[0])
|
||||
branch1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 1',
|
||||
'parent_id': elmtree.id,
|
||||
'is_company': True}))
|
||||
leaf10 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 10',
|
||||
'parent_id': branch1.id,
|
||||
'type': 'invoice'}))
|
||||
branch11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 11',
|
||||
'parent_id': branch1.id,
|
||||
'type': 'other'}))
|
||||
leaf111 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 111',
|
||||
'parent_id': branch11.id,
|
||||
'type': 'delivery'}))
|
||||
res_partner = self.env['res.partner']
|
||||
elmtree = res_partner.browse(res_partner.name_create('Elmtree')[0])
|
||||
branch1 = res_partner.create({'name': 'Branch 1',
|
||||
'parent_id': elmtree.id,
|
||||
'is_company': True})
|
||||
leaf10 = res_partner.create({'name': 'Leaf 10',
|
||||
'parent_id': branch1.id,
|
||||
'type': 'invoice'})
|
||||
branch11 = res_partner.create({'name': 'Branch 11',
|
||||
'parent_id': branch1.id,
|
||||
'type': 'other'})
|
||||
leaf111 = res_partner.create({'name': 'Leaf 111',
|
||||
'parent_id': branch11.id,
|
||||
'type': 'delivery'})
|
||||
branch11.write({'is_company': False}) # force is_company after creating 1rst child
|
||||
branch2 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 2',
|
||||
'parent_id': elmtree.id,
|
||||
'is_company': True}))
|
||||
leaf21 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 21',
|
||||
'parent_id': branch2.id,
|
||||
'type': 'delivery'}))
|
||||
leaf22 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 22',
|
||||
'parent_id': branch2.id}))
|
||||
leaf23 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 23',
|
||||
'parent_id': branch2.id,
|
||||
'type': 'contact'}))
|
||||
branch2 = res_partner.create({'name': 'Branch 2',
|
||||
'parent_id': elmtree.id,
|
||||
'is_company': True})
|
||||
leaf21 = res_partner.create({'name': 'Leaf 21',
|
||||
'parent_id': branch2.id,
|
||||
'type': 'delivery'})
|
||||
leaf22 = res_partner.create({'name': 'Leaf 22',
|
||||
'parent_id': branch2.id})
|
||||
leaf23 = res_partner.create({'name': 'Leaf 23',
|
||||
'parent_id': branch2.id,
|
||||
'type': 'contact'})
|
||||
|
||||
# go up, stop at branch1
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(leaf111.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf111.id,
|
||||
'invoice': leaf10.id,
|
||||
'contact': branch1.id,
|
||||
'other': branch11.id}, 'Invalid address resolution')
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [branch11.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(branch11.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf111.id,
|
||||
'invoice': leaf10.id,
|
||||
'contact': branch1.id,
|
||||
'other': branch11.id}, 'Invalid address resolution')
|
||||
|
||||
# go down, stop at at all child companies
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(elmtree.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': elmtree.id,
|
||||
'invoice': elmtree.id,
|
||||
'contact': elmtree.id,
|
||||
'other': elmtree.id}, 'Invalid address resolution')
|
||||
|
||||
# go down through children
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [branch1.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(branch1.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf111.id,
|
||||
'invoice': leaf10.id,
|
||||
'contact': branch1.id,
|
||||
'other': branch11.id}, 'Invalid address resolution')
|
||||
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [branch2.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(branch2.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf21.id,
|
||||
'invoice': branch2.id,
|
||||
'contact': branch2.id,
|
||||
'other': branch2.id}, 'Invalid address resolution. Company is the first encountered contact, therefore default for unfound addresses.')
|
||||
|
||||
# go up then down through siblings
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [leaf21.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(leaf21.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf21.id,
|
||||
'invoice': branch2.id,
|
||||
'contact': branch2.id,
|
||||
'other': branch2.id}, 'Invalid address resolution, should scan commercial entity ancestor and its descendants')
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [leaf22.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(leaf22.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf21.id,
|
||||
'invoice': leaf22.id,
|
||||
'contact': leaf22.id,
|
||||
'other': leaf22.id}, 'Invalid address resolution, should scan commercial entity ancestor and its descendants')
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [leaf23.id], ['delivery', 'invoice', 'contact', 'other']),
|
||||
self.assertEqual(leaf23.address_get(['delivery', 'invoice', 'contact', 'other']),
|
||||
{'delivery': leaf21.id,
|
||||
'invoice': leaf23.id,
|
||||
'contact': leaf23.id,
|
||||
'other': leaf23.id}, 'Invalid address resolution, `default` should only override if no partner with specific type exists')
|
||||
|
||||
# empty adr_pref means only 'contact'
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], []),
|
||||
self.assertEqual(elmtree.address_get([]),
|
||||
{'contact': elmtree.id}, 'Invalid address resolution, no contact means commercial entity ancestor')
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []),
|
||||
self.assertEqual(leaf111.address_get([]),
|
||||
{'contact': branch1.id}, 'Invalid address resolution, no contact means finding contact in ancestors')
|
||||
branch11.write({'type': 'contact'})
|
||||
self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []),
|
||||
self.assertEqual(leaf111.address_get([]),
|
||||
{'contact': branch11.id}, 'Invalid address resolution, branch11 should now be contact')
|
||||
|
||||
|
||||
def test_50_res_partner_commercial_sync(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
p0 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
|
||||
{'name': 'Sigurd Sunknife',
|
||||
'email': 'ssunknife@gmail.com'}))
|
||||
sunhelm = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
|
||||
{'name': 'Sunhelm',
|
||||
'is_company': True,
|
||||
'street': 'Rainbow Street, 13',
|
||||
'phone': '1122334455',
|
||||
'email': 'info@sunhelm.com',
|
||||
'vat': 'BE0477472701',
|
||||
'child_ids': [(4, p0.id),
|
||||
(0, 0, {'name': 'Alrik Greenthorn',
|
||||
'email': 'agr@sunhelm.com'})],
|
||||
}))
|
||||
p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
|
||||
{'name': 'Otto Blackwood',
|
||||
'email': 'otto.blackwood@sunhelm.com',
|
||||
'parent_id': sunhelm.id}))
|
||||
p11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
|
||||
{'name': 'Gini Graywool',
|
||||
'email': 'ggr@sunhelm.com',
|
||||
'parent_id': p1.id}))
|
||||
p2 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid,
|
||||
[('email', '=', 'agr@sunhelm.com')])[0])
|
||||
self.res_partner.write(cr, uid, sunhelm.id, {'child_ids': [(0, 0, {'name': 'Ulrik Greenthorn',
|
||||
'email': 'ugr@sunhelm.com'})]})
|
||||
p3 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid,
|
||||
[('email', '=', 'ugr@sunhelm.com')])[0])
|
||||
def test_50_res_partner_commercial_sync(self):
|
||||
res_partner = self.env['res.partner']
|
||||
p0 = res_partner.create({'name': 'Sigurd Sunknife',
|
||||
'email': 'ssunknife@gmail.com'})
|
||||
sunhelm = res_partner.create({'name': 'Sunhelm',
|
||||
'is_company': True,
|
||||
'street': 'Rainbow Street, 13',
|
||||
'phone': '1122334455',
|
||||
'email': 'info@sunhelm.com',
|
||||
'vat': 'BE0477472701',
|
||||
'child_ids': [(4, p0.id),
|
||||
(0, 0, {'name': 'Alrik Greenthorn',
|
||||
'email': 'agr@sunhelm.com'})]})
|
||||
p1 = res_partner.create({'name': 'Otto Blackwood',
|
||||
'email': 'otto.blackwood@sunhelm.com',
|
||||
'parent_id': sunhelm.id})
|
||||
p11 = res_partner.create({'name': 'Gini Graywool',
|
||||
'email': 'ggr@sunhelm.com',
|
||||
'parent_id': p1.id})
|
||||
p2 = res_partner.search([('email', '=', 'agr@sunhelm.com')], limit=1)
|
||||
sunhelm.write({'child_ids': [(0, 0, {'name': 'Ulrik Greenthorn',
|
||||
'email': 'ugr@sunhelm.com'})]})
|
||||
p3 = res_partner.search([('email', '=', 'ugr@sunhelm.com')], limit=1)
|
||||
|
||||
for p in (p0, p1, p11, p2, p3):
|
||||
p.refresh()
|
||||
self.assertEquals(p.commercial_partner_id, sunhelm, 'Incorrect commercial entity resolution')
|
||||
self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced')
|
||||
sunhelmvat = 'BE0123456789'
|
||||
sunhelm.write({'vat': sunhelmvat})
|
||||
for p in (p0, p1, p11, p2, p3):
|
||||
p.refresh()
|
||||
self.assertEquals(p.vat, sunhelmvat, 'Commercial fields must be automatically and recursively synced')
|
||||
|
||||
p1vat = 'BE0987654321'
|
||||
p1.write({'vat': p1vat})
|
||||
for p in (sunhelm, p0, p11, p2, p3):
|
||||
p.refresh()
|
||||
self.assertEquals(p.vat, sunhelmvat, 'Sync to children should only work downstream and on commercial entities')
|
||||
|
||||
# promote p1 to commercial entity
|
||||
p1.write({
|
||||
'parent_id': sunhelm.id,
|
||||
'is_company': True,
|
||||
'name': 'Sunhelm Subsidiary'})
|
||||
p1.refresh()
|
||||
p1.write({'parent_id': sunhelm.id,
|
||||
'is_company': True,
|
||||
'name': 'Sunhelm Subsidiary'})
|
||||
self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields')
|
||||
self.assertEquals(p1.commercial_partner_id, p1, 'Incorrect commercial entity resolution after setting is_company')
|
||||
|
||||
# writing on parent should not touch child commercial entities
|
||||
sunhelmvat2 = 'BE0112233445'
|
||||
sunhelm.write({'vat': sunhelmvat2})
|
||||
p1.refresh()
|
||||
self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields')
|
||||
p0.refresh()
|
||||
self.assertEquals(p0.vat, sunhelmvat2, 'Commercial fields must be automatically synced')
|
||||
|
||||
def test_60_read_group(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
title_sir = self.res_partner_title.create(cr, uid, {'name': 'Sir...'})
|
||||
title_lady = self.res_partner_title.create(cr, uid, {'name': 'Lady...'})
|
||||
title_sir = self.env['res.partner.title'].create({'name': 'Sir...'})
|
||||
title_lady = self.env['res.partner.title'].create({'name': 'Lady...'})
|
||||
test_users = [
|
||||
{'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend', 'date': '2015-03-28', 'title': title_lady},
|
||||
{'name': 'Alice', 'login': 'alice2', 'color': 0, 'function': 'Friend', 'date': '2015-01-28', 'title': title_lady},
|
||||
{'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend', 'date': '2015-03-02', 'title': title_sir},
|
||||
{'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper', 'date': '2015-03-20', 'title': title_lady},
|
||||
{'name': 'Nab', 'login': 'nab', 'color': -3, 'function': '5$ Wrench', 'date': '2014-09-10', 'title': title_sir},
|
||||
{'name': 'Nab', 'login': 'nab-she', 'color': 6, 'function': '5$ Wrench', 'date': '2014-01-02', 'title': title_lady},
|
||||
{'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend', 'date': '2015-03-28', 'title': title_lady.id},
|
||||
{'name': 'Alice', 'login': 'alice2', 'color': 0, 'function': 'Friend', 'date': '2015-01-28', 'title': title_lady.id},
|
||||
{'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend', 'date': '2015-03-02', 'title': title_sir.id},
|
||||
{'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper', 'date': '2015-03-20', 'title': title_lady.id},
|
||||
{'name': 'Nab', 'login': 'nab', 'color': -3, 'function': '5$ Wrench', 'date': '2014-09-10', 'title': title_sir.id},
|
||||
{'name': 'Nab', 'login': 'nab-she', 'color': 6, 'function': '5$ Wrench', 'date': '2014-01-02', 'title': title_lady.id},
|
||||
]
|
||||
ids = [self.res_users.create(cr, uid, u) for u in test_users]
|
||||
domain = [('id', 'in', ids)]
|
||||
res_users = self.env['res.users']
|
||||
user_ids = [res_users.create(vals).id for vals in test_users]
|
||||
domain = [('id', 'in', user_ids)]
|
||||
|
||||
# group on local char field without domain and without active_test (-> empty WHERE clause)
|
||||
groups_data = self.res_users.read_group(cr, uid, [], fields=['login'], groupby=['login'], orderby='login DESC', context={'active_test': False})
|
||||
groups_data = res_users.with_context(active_test=False).read_group([], fields=['login'], groupby=['login'], orderby='login DESC')
|
||||
self.assertGreater(len(groups_data), 6, "Incorrect number of results when grouping on a field")
|
||||
|
||||
# group on local char field with limit
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['login'], groupby=['login'], orderby='login DESC', limit=3, offset=3)
|
||||
groups_data = res_users.read_group(domain, fields=['login'], groupby=['login'], orderby='login DESC', limit=3, offset=3)
|
||||
self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field with limit")
|
||||
self.assertEqual(['bob', 'alice2', 'alice'], [g['login'] for g in groups_data], 'Result mismatch')
|
||||
|
||||
# group on inherited char field, aggregate on int field (second groupby ignored on purpose)
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color', 'function'], groupby=['function', 'login'])
|
||||
groups_data = res_users.read_group(domain, fields=['name', 'color', 'function'], groupby=['function', 'login'])
|
||||
self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field")
|
||||
self.assertEqual(['5$ Wrench', 'Eavesdropper', 'Friend'], [g['function'] for g in groups_data], 'incorrect read_group order')
|
||||
for group_data in groups_data:
|
||||
@@ -313,210 +328,186 @@ class test_base(common.TransactionCase):
|
||||
self.assertEqual(group_data['color'], 3, "Incorrect sum for aggregated data for the column 'color'")
|
||||
|
||||
# group on inherited char field, reverse order
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby='name', orderby='name DESC')
|
||||
groups_data = res_users.read_group(domain, fields=['name', 'color'], groupby='name', orderby='name DESC')
|
||||
self.assertEqual(['Nab', 'Eve', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
|
||||
# group on int field, default ordering
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['color'], groupby='color')
|
||||
groups_data = res_users.read_group(domain, fields=['color'], groupby='color')
|
||||
self.assertEqual([-3, 0, 1, 2, 3, 6], [g['color'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
|
||||
# multi group, second level is int field, should still be summed in first level grouping
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby=['name', 'color'], orderby='name DESC')
|
||||
groups_data = res_users.read_group(domain, fields=['name', 'color'], groupby=['name', 'color'], orderby='name DESC')
|
||||
self.assertEqual(['Nab', 'Eve', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([3, 3, 2, 1], [g['color'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
|
||||
# group on inherited char field, multiple orders with directions
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby='name', orderby='color DESC, name')
|
||||
groups_data = res_users.read_group(domain, fields=['name', 'color'], groupby='name', orderby='color DESC, name')
|
||||
self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field")
|
||||
self.assertEqual(['Eve', 'Nab', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([1, 2, 1, 2], [g['name_count'] for g in groups_data], 'Incorrect number of results')
|
||||
|
||||
# group on inherited date column (res_partner.date) -> Year-Month, default ordering
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'date'], groupby=['date'])
|
||||
groups_data = res_users.read_group(domain, fields=['function', 'color', 'date'], groupby=['date'])
|
||||
self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field")
|
||||
self.assertEqual(['January 2014', 'September 2014', 'January 2015', 'March 2015'], [g['date'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([1, 1, 1, 3], [g['date_count'] for g in groups_data], 'Incorrect number of results')
|
||||
|
||||
# group on inherited date column (res_partner.date) -> Year-Month, custom order
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'date'], groupby=['date'], orderby='date DESC')
|
||||
groups_data = res_users.read_group(domain, fields=['function', 'color', 'date'], groupby=['date'], orderby='date DESC')
|
||||
self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field")
|
||||
self.assertEqual(['March 2015', 'January 2015', 'September 2014', 'January 2014'], [g['date'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([3, 1, 1, 1], [g['date_count'] for g in groups_data], 'Incorrect number of results')
|
||||
|
||||
# group on inherited many2one (res_partner.title), default order
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'])
|
||||
groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'])
|
||||
self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field")
|
||||
# m2o is returned as a (id, label) pair
|
||||
self.assertEqual([(title_lady, 'Lady...'), (title_sir, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([(title_lady.id, 'Lady...'), (title_sir.id, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([4, 2], [g['title_count'] for g in groups_data], 'Incorrect number of results')
|
||||
self.assertEqual([10, -1], [g['color'] for g in groups_data], 'Incorrect aggregation of int column')
|
||||
|
||||
# group on inherited many2one (res_partner.title), reversed natural order
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="title desc")
|
||||
groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="title desc")
|
||||
self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field")
|
||||
# m2o is returned as a (id, label) pair
|
||||
self.assertEqual([(title_sir, 'Sir...'), (title_lady, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([(title_sir.id, 'Sir...'), (title_lady.id, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([2, 4], [g['title_count'] for g in groups_data], 'Incorrect number of results')
|
||||
self.assertEqual([-1, 10], [g['color'] for g in groups_data], 'Incorrect aggregation of int column')
|
||||
|
||||
# group on inherited many2one (res_partner.title), multiple orders with m2o in second position
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="color desc, title desc")
|
||||
groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="color desc, title desc")
|
||||
self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field")
|
||||
# m2o is returned as a (id, label) pair
|
||||
self.assertEqual([(title_lady, 'Lady...'), (title_sir, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the result')
|
||||
self.assertEqual([(title_lady.id, 'Lady...'), (title_sir.id, 'Sir...')], [g['title'] for g in groups_data], 'Incorrect ordering of the result')
|
||||
self.assertEqual([4, 2], [g['title_count'] for g in groups_data], 'Incorrect number of results')
|
||||
self.assertEqual([10, -1], [g['color'] for g in groups_data], 'Incorrect aggregation of int column')
|
||||
|
||||
# group on inherited many2one (res_partner.title), ordered by other inherited field (color)
|
||||
groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby='color')
|
||||
groups_data = res_users.read_group(domain, fields=['function', 'color', 'title'], groupby=['title'], orderby='color')
|
||||
self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field")
|
||||
# m2o is returned as a (id, label) pair
|
||||
self.assertEqual([(title_sir, 'Sir...'), (title_lady, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([(title_sir.id, 'Sir...'), (title_lady.id, 'Lady...')], [g['title'] for g in groups_data], 'Incorrect ordering of the list')
|
||||
self.assertEqual([2, 4], [g['title_count'] for g in groups_data], 'Incorrect number of results')
|
||||
self.assertEqual([-1, 10], [g['color'] for g in groups_data], 'Incorrect aggregation of int column')
|
||||
|
||||
|
||||
class test_partner_recursion(common.TransactionCase):
|
||||
class TestPartnerRecursion(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(test_partner_recursion,self).setUp()
|
||||
self.res_partner = self.registry('res.partner')
|
||||
cr, uid = self.cr, self.uid
|
||||
self.p1 = self.res_partner.name_create(cr, uid, 'Elmtree')[0]
|
||||
self.p2 = self.res_partner.create(cr, uid, {'name': 'Elmtree Child 1', 'parent_id': self.p1})
|
||||
self.p3 = self.res_partner.create(cr, uid, {'name': 'Elmtree Grand-Child 1.1', 'parent_id': self.p2})
|
||||
super(TestPartnerRecursion,self).setUp()
|
||||
res_partner = self.env['res.partner']
|
||||
self.p1 = res_partner.browse(res_partner.name_create('Elmtree')[0])
|
||||
self.p2 = res_partner.create({'name': 'Elmtree Child 1', 'parent_id': self.p1.id})
|
||||
self.p3 = res_partner.create({'name': 'Elmtree Grand-Child 1.1', 'parent_id': self.p2.id})
|
||||
|
||||
# split 101, 102, 103 tests to force SQL rollback between them
|
||||
|
||||
def test_101_res_partner_recursion(self):
|
||||
cr, uid, p1, p3 = self.cr, self.uid, self.p1, self.p3
|
||||
self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p1], {'parent_id': p3})
|
||||
with self.assertRaises(ValidationError):
|
||||
self.p1.write({'parent_id': self.p3.id})
|
||||
|
||||
def test_102_res_partner_recursion(self):
|
||||
cr, uid, p2, p3 = self.cr, self.uid, self.p2, self.p3
|
||||
self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p2], {'parent_id': p3})
|
||||
with self.assertRaises(ValidationError):
|
||||
self.p2.write({'parent_id': self.p3.id})
|
||||
|
||||
def test_103_res_partner_recursion(self):
|
||||
cr, uid, p3 = self.cr, self.uid, self.p3
|
||||
self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p3], {'parent_id': p3})
|
||||
with self.assertRaises(ValidationError):
|
||||
self.p3.write({'parent_id': self.p3.id})
|
||||
|
||||
def test_104_res_partner_recursion_indirect_cycle(self):
|
||||
""" Indirect hacky write to create cycle in children """
|
||||
cr, uid, p2, p3 = self.cr, self.uid, self.p2, self.p3
|
||||
p3b = self.res_partner.create(cr, uid, {'name': 'Elmtree Grand-Child 1.2', 'parent_id': self.p2})
|
||||
self.assertRaises(ValidationError, self.res_partner.write, cr, uid, [p2],
|
||||
{'child_ids': [(1, p3, {'parent_id': p3b}), (1, p3b, {'parent_id': p3})]})
|
||||
p3b = self.p1.create({'name': 'Elmtree Grand-Child 1.2', 'parent_id': self.p2.id})
|
||||
with self.assertRaises(ValidationError):
|
||||
self.p2.write({'child_ids': [(1, self.p3.id, {'parent_id': p3b.id}),
|
||||
(1, p3b.id, {'parent_id': self.p3.id})]})
|
||||
|
||||
def test_110_res_partner_recursion_multi_update(self):
|
||||
""" multi-write on several partners in same hierarchy must not trigger a false cycle detection """
|
||||
cr, uid, p1, p2, p3 = self.cr, self.uid, self.p1, self.p2, self.p3
|
||||
self.assertTrue(self.res_partner.write(cr, uid, [p1,p2,p3], {'phone': '123456'}))
|
||||
ps = self.p1 + self.p2 + self.p3
|
||||
self.assertTrue(ps.write({'phone': '123456'}))
|
||||
|
||||
class test_translation(common.TransactionCase):
|
||||
|
||||
class TestParentStore(TransactionCase):
|
||||
""" Verify that parent_store computation is done right """
|
||||
|
||||
def setUp(self):
|
||||
super(test_translation, self).setUp()
|
||||
self.res_category = self.registry('res.partner.category')
|
||||
self.ir_translation = self.registry('ir.translation')
|
||||
cr, uid = self.cr, self.uid
|
||||
self.registry('ir.translation').load_module_terms(cr, ['base'], ['fr_FR'])
|
||||
self.cat_id = self.res_category.create(cr, uid, {'name': 'Customers'})
|
||||
self.ir_translation.create(cr, uid, {'name': 'res.partner.category,name', 'module':'base',
|
||||
'value': 'Clients', 'res_id': self.cat_id, 'lang':'fr_FR', 'state':'translated', 'type': 'model'})
|
||||
super(TestParentStore, self).setUp()
|
||||
# pretend the pool has finished loading to avoid deferring parent_store computation
|
||||
self.patch(self.registry, '_init', False)
|
||||
|
||||
def test_101_create_translated_record(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
no_context_cat = self.res_category.browse(cr, uid, self.cat_id)
|
||||
self.assertEqual(no_context_cat.name, 'Customers', "Error in basic name_get")
|
||||
# force res_partner_category.copy() to copy children
|
||||
category = self.env['res.partner.category']
|
||||
self.patch(category._fields['child_ids'], 'copy', True)
|
||||
self.patch(category._columns['child_ids'], 'copy', True)
|
||||
|
||||
fr_context_cat = self.res_category.browse(cr, uid, self.cat_id, context={'lang':'fr_FR'})
|
||||
self.assertEqual(fr_context_cat.name, 'Clients', "Translation not found")
|
||||
# setup categories
|
||||
self.root = category.create({'name': 'Root category'})
|
||||
self.cat0 = category.create({'name': 'Parent category', 'parent_id': self.root.id})
|
||||
self.cat1 = category.create({'name': 'Child 1', 'parent_id': self.cat0.id})
|
||||
self.cat2 = category.create({'name': 'Child 2', 'parent_id': self.cat0.id})
|
||||
self.cat21 = category.create({'name': 'Child 2-1', 'parent_id': self.cat2.id})
|
||||
|
||||
def test_102_duplicate_record(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
self.new_cat_id = self.res_category.copy(cr, uid, self.cat_id, context={'lang':'fr_FR'})
|
||||
def test_duplicate_parent(self):
|
||||
""" Duplicate the parent category and verify that the children have been duplicated too """
|
||||
new_cat0 = self.cat0.copy()
|
||||
new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)])
|
||||
self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records")
|
||||
old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)])
|
||||
self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only")
|
||||
self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed")
|
||||
|
||||
no_context_cat = self.res_category.browse(cr, uid, self.new_cat_id)
|
||||
self.assertEqual(no_context_cat.name, 'Customers', "Duplication did not set untranslated value")
|
||||
def test_duplicate_children_01(self):
|
||||
""" Duplicate the children then reassign them to the new parent (1st method). """
|
||||
new_cat1 = self.cat1.copy()
|
||||
new_cat2 = self.cat2.copy()
|
||||
new_cat0 = self.cat0.copy({'child_ids': []})
|
||||
(new_cat1 + new_cat2).write({'parent_id': new_cat0.id})
|
||||
new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)])
|
||||
self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records")
|
||||
old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)])
|
||||
self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only")
|
||||
self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed")
|
||||
|
||||
fr_context_cat = self.res_category.browse(cr, uid, self.new_cat_id, context={'lang':'fr_FR'})
|
||||
self.assertEqual(fr_context_cat.name, 'Clients', "Did not found translation for initial value")
|
||||
def test_duplicate_children_02(self):
|
||||
""" Duplicate the children then reassign them to the new parent (2nd method). """
|
||||
new_cat1 = self.cat1.copy()
|
||||
new_cat2 = self.cat2.copy()
|
||||
new_cat0 = self.cat0.copy({'child_ids': [(6, 0, (new_cat1 + new_cat2).ids)]})
|
||||
new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)])
|
||||
self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records")
|
||||
old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)])
|
||||
self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only")
|
||||
self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed")
|
||||
|
||||
def test_103_duplicate_record_fr(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
self.new_fr_cat_id = self.res_category.copy(cr, uid, self.cat_id, default={'name': 'Clients (copie)'}, context={'lang':'fr_FR'})
|
||||
def test_duplicate_children_03(self):
|
||||
""" Duplicate the children then reassign them to the new parent (3rd method). """
|
||||
new_cat1 = self.cat1.copy()
|
||||
new_cat2 = self.cat2.copy()
|
||||
new_cat0 = self.cat0.copy({'child_ids': []})
|
||||
new_cat0.write({'child_ids': [(4, new_cat1.id), (4, new_cat2.id)]})
|
||||
new_struct = new_cat0.search([('parent_id', 'child_of', new_cat0.id)])
|
||||
self.assertEqual(len(new_struct), 4, "After duplication, the new object must have the childs records")
|
||||
old_struct = new_cat0.search([('parent_id', 'child_of', self.cat0.id)])
|
||||
self.assertEqual(len(old_struct), 4, "After duplication, previous record must have old childs records only")
|
||||
self.assertFalse(new_struct & old_struct, "After duplication, nodes should not be mixed")
|
||||
|
||||
no_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id)
|
||||
self.assertEqual(no_context_cat.name, 'Customers', "Duplication erased original untranslated value")
|
||||
|
||||
fr_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id, context={'lang':'fr_FR'})
|
||||
self.assertEqual(fr_context_cat.name, 'Clients (copie)', "Did not used default value for translated value")
|
||||
class TestGroups(TransactionCase):
|
||||
|
||||
def test_104_orderby_translated_field(self):
|
||||
""" Test search ordered by a translated field. """
|
||||
# create a category with a French translation
|
||||
category = self.env['res.partner.category'].create({'name': 'Padawans'})
|
||||
category_fr = category.with_context(lang='fr_FR')
|
||||
category_fr.write({'name': 'Apprentis'})
|
||||
# search for categories, and sort them by (translated) name
|
||||
categories = category_fr.search([('id', 'in', [self.cat_id, category.id])], order='name')
|
||||
self.assertEqual(categories.ids, [category.id, self.cat_id],
|
||||
"Search ordered by translated name should return Padawans (Apprentis) before Customers (Clients)")
|
||||
def test_res_groups_fullname_search(self):
|
||||
all_groups = self.env['res.groups'].search([])
|
||||
|
||||
test_state = None
|
||||
#: Stores state information across multiple test classes
|
||||
def setUpModule():
|
||||
global test_state
|
||||
test_state = {}
|
||||
def tearDownModule():
|
||||
global test_state
|
||||
test_state = None
|
||||
groups = all_groups.search([('full_name', 'like', '%Sale%')])
|
||||
self.assertItemsEqual(groups.ids, [g.id for g in all_groups if 'Sale' in g.full_name],
|
||||
"did not match search for 'Sale'")
|
||||
|
||||
class TestPhaseInstall00(unittest.TestCase):
|
||||
"""
|
||||
WARNING: Relies on tests being run in alphabetical order
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.state = None
|
||||
groups = all_groups.search([('full_name', 'like', '%Technical%')])
|
||||
self.assertItemsEqual(groups.ids, [g.id for g in all_groups if 'Technical' in g.full_name],
|
||||
"did not match search for 'Technical'")
|
||||
|
||||
def test_00_setup(self):
|
||||
type(self).state = 'init'
|
||||
groups = all_groups.search([('full_name', 'like', '%Sales /%')])
|
||||
self.assertItemsEqual(groups.ids, [g.id for g in all_groups if 'Sales /' in g.full_name],
|
||||
"did not match search for 'Sales /'")
|
||||
|
||||
@common.at_install(False)
|
||||
def test_01_no_install(self):
|
||||
type(self).state = 'error'
|
||||
|
||||
def test_02_check(self):
|
||||
self.assertEqual(
|
||||
self.state, 'init',
|
||||
"Testcase state should not have been transitioned from 00")
|
||||
|
||||
class TestPhaseInstall01(unittest.TestCase):
|
||||
at_install = False
|
||||
|
||||
def test_default_norun(self):
|
||||
self.fail("An unmarket test in a non-at-install case should not run")
|
||||
|
||||
@common.at_install(True)
|
||||
def test_set_run(self):
|
||||
test_state['set_at_install'] = True
|
||||
|
||||
class TestPhaseInstall02(unittest.TestCase):
|
||||
"""
|
||||
Can't put the check for test_set_run in the same class: if
|
||||
@common.at_install does not work for test_set_run, it won't work for
|
||||
the other one either. Thus move checking of whether test_set_run has
|
||||
correctly run indeed to a separate class.
|
||||
|
||||
Warning: relies on *classes* being run in alphabetical order in test
|
||||
modules
|
||||
"""
|
||||
def test_check_state(self):
|
||||
self.assertTrue(
|
||||
test_state.get('set_at_install'),
|
||||
"The flag should be set if local overriding of runstate")
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
groups = all_groups.search([('full_name', 'in', ['Administration / Access Rights','Contact Creation'])])
|
||||
self.assertTrue(groups, "did not match search for 'Administration / Access Rights' and 'Contact Creation'")
|
||||
|
||||
@@ -1,86 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import unittest
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.tests import common
|
||||
from odoo.tests import common
|
||||
|
||||
class test_single_transaction_case(common.SingleTransactionCase):
|
||||
|
||||
class TestSingleTransactionCase(common.SingleTransactionCase):
|
||||
"""
|
||||
Check the whole-class transaction behavior of SingleTransactionCase.
|
||||
"""
|
||||
|
||||
def test_00(self):
|
||||
"""Create a partner."""
|
||||
cr, uid = self.cr, self.uid
|
||||
self.registry('res.partner').create(cr, uid, {'name': 'test_per_class_teardown_partner'})
|
||||
ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(1, len(ids), "Test partner not found.")
|
||||
""" Create a partner. """
|
||||
self.env['res.partner'].create({'name': 'test_per_class_teardown_partner'})
|
||||
partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(1, len(partners), "Test partner not found.")
|
||||
|
||||
def test_01(self):
|
||||
"""Find the created partner."""
|
||||
cr, uid = self.cr, self.uid
|
||||
ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(1, len(ids), "Test partner not found.")
|
||||
""" Find the created partner. """
|
||||
partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(1, len(partners), "Test partner not found.")
|
||||
|
||||
def test_20a(self):
|
||||
""" Create a partner with a XML ID """
|
||||
cr, uid = self.cr, self.uid
|
||||
res_partner = self.registry('res.partner')
|
||||
ir_model_data = self.registry('ir.model.data')
|
||||
pid, _ = res_partner.name_create(cr, uid, 'Mr Blue')
|
||||
ir_model_data.create(cr, uid, {'name': 'test_partner_blue',
|
||||
'module': 'base',
|
||||
'model': 'res.partner',
|
||||
'res_id': pid})
|
||||
pid, _ = self.env['res.partner'].name_create('Mr Blue')
|
||||
self.env['ir.model.data'].create({'name': 'test_partner_blue',
|
||||
'module': 'base',
|
||||
'model': 'res.partner',
|
||||
'res_id': pid})
|
||||
|
||||
def test_20b(self):
|
||||
""" Resolve xml id with ref() and browse_ref() """
|
||||
cr, uid = self.cr, self.uid
|
||||
res_partner = self.registry('res.partner')
|
||||
xid = 'base.test_partner_blue'
|
||||
p_ref = self.ref(xid)
|
||||
self.assertTrue(p_ref, "ref() should resolve xid to database ID")
|
||||
partner = res_partner.browse(cr, uid, p_ref)
|
||||
p_browse_ref = self.browse_ref(xid)
|
||||
self.assertEqual(partner, p_browse_ref, "browse_ref() should resolve xid to browse records")
|
||||
|
||||
partner = self.env.ref(xid)
|
||||
pid = self.ref(xid)
|
||||
self.assertTrue(pid, "ref() should resolve xid to database ID")
|
||||
self.assertEqual(pid, partner.id, "ref() is not consistent with env.ref()")
|
||||
partner2 = self.browse_ref(xid)
|
||||
self.assertEqual(partner, partner2, "browse_ref() should resolve xid to browse records")
|
||||
|
||||
|
||||
class test_transaction_case(common.TransactionCase):
|
||||
class TestTransactionCase(common.TransactionCase):
|
||||
"""
|
||||
Check the per-method transaction behavior of TransactionCase.
|
||||
"""
|
||||
|
||||
def test_00(self):
|
||||
"""Create a partner."""
|
||||
cr, uid = self.cr, self.uid
|
||||
ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(0, len(ids), "Test partner found.")
|
||||
self.registry('res.partner').create(cr, uid, {'name': 'test_per_class_teardown_partner'})
|
||||
ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(1, len(ids), "Test partner not found.")
|
||||
""" Create a partner. """
|
||||
partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(0, len(partners), "Test partner found.")
|
||||
self.env['res.partner'].create({'name': 'test_per_class_teardown_partner'})
|
||||
partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(1, len(partners), "Test partner not found.")
|
||||
|
||||
def test_01(self):
|
||||
"""Don't find the created partner."""
|
||||
cr, uid = self.cr, self.uid
|
||||
ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(0, len(ids), "Test partner found.")
|
||||
|
||||
""" Don't find the created partner. """
|
||||
partners = self.env['res.partner'].search([('name', '=', 'test_per_class_teardown_partner')])
|
||||
self.assertEqual(0, len(partners), "Test partner found.")
|
||||
|
||||
def test_20a(self):
|
||||
""" Create a partner with a XML ID then resolve xml id with ref() and browse_ref() """
|
||||
cr, uid = self.cr, self.uid
|
||||
res_partner = self.registry('res.partner')
|
||||
ir_model_data = self.registry('ir.model.data')
|
||||
pid, _ = res_partner.name_create(cr, uid, 'Mr Yellow')
|
||||
ir_model_data.create(cr, uid, {'name': 'test_partner_yellow',
|
||||
'module': 'base',
|
||||
'model': 'res.partner',
|
||||
'res_id': pid})
|
||||
pid, _ = self.env['res.partner'].name_create('Mr Yellow')
|
||||
self.env['ir.model.data'].create({'name': 'test_partner_yellow',
|
||||
'module': 'base',
|
||||
'model': 'res.partner',
|
||||
'res_id': pid})
|
||||
xid = 'base.test_partner_yellow'
|
||||
p_ref = self.ref(xid)
|
||||
self.assertEquals(p_ref, pid, "ref() should resolve xid to database ID")
|
||||
partner = res_partner.browse(cr, uid, pid)
|
||||
p_browse_ref = self.browse_ref(xid)
|
||||
self.assertEqual(partner, p_browse_ref, "browse_ref() should resolve xid to browse records")
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
partner = self.env.ref(xid)
|
||||
pid = self.ref(xid)
|
||||
self.assertEquals(pid, partner.id, "ref() should resolve xid to database ID")
|
||||
partner2 = self.browse_ref(xid)
|
||||
self.assertEqual(partner, partner2, "browse_ref() should resolve xid to browse records")
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import unittest
|
||||
|
||||
import openerp
|
||||
from openerp.tools.misc import mute_logger
|
||||
from openerp.tests import common
|
||||
import odoo
|
||||
from odoo.tests import common
|
||||
from odoo.tools.misc import mute_logger
|
||||
|
||||
ADMIN_USER_ID = common.ADMIN_USER_ID
|
||||
|
||||
def registry():
|
||||
return openerp.modules.registry.RegistryManager.get(common.get_db_name())
|
||||
return odoo.registry(common.get_db_name())
|
||||
|
||||
|
||||
class test_cr_execute(unittest.TestCase):
|
||||
class TestExecute(unittest.TestCase):
|
||||
""" Try cr.execute with wrong parameters """
|
||||
|
||||
@mute_logger('openerp.sql_db')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,177 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from math import log10
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import float_compare, float_is_zero, float_repr, float_round
|
||||
|
||||
|
||||
class TestFloatPrecision(TransactionCase):
|
||||
""" Tests on float precision. """
|
||||
|
||||
def test_rounding_02(self):
|
||||
""" Test rounding methods with 2 digits. """
|
||||
currency = self.env.ref('base.EUR')
|
||||
|
||||
def try_round(amount, expected):
|
||||
digits = max(0, -int(log10(currency.rounding)))
|
||||
result = float_repr(currency.round(amount), precision_digits=digits)
|
||||
self.assertEqual(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.assertEqual(currency.is_zero(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.assertEqual(currency.compare_amounts(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)
|
||||
|
||||
def test_rounding_03(self):
|
||||
""" Test rounding methods with 3 digits. """
|
||||
|
||||
def try_round(amount, expected, digits=3, method='HALF-UP'):
|
||||
value = float_round(amount, precision_digits=digits, rounding_method=method)
|
||||
result = float_repr(value, precision_digits=digits)
|
||||
self.assertEqual(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')
|
||||
|
||||
# Try some rounding value with rounding method UP instead of HALF-UP
|
||||
# We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives
|
||||
# us 8175,0000000001234 as value, and if not handle correctly the rounding UP
|
||||
# value will be incorrect (should be 8,175 and not 8,176)
|
||||
try_round(8.175, '8.175', method='UP')
|
||||
try_round(8.1751, '8.176', method='UP')
|
||||
try_round(-8.175, '-8.175', method='UP')
|
||||
try_round(-8.1751, '-8.176', method='UP')
|
||||
try_round(-6.000, '-6.000', method='UP')
|
||||
try_round(1.8, '2', 0, method='UP')
|
||||
try_round(-1.8, '-2', 0, method='UP')
|
||||
|
||||
# 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, digits=prec)
|
||||
|
||||
def try_zero(amount, expected):
|
||||
self.assertEqual(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):
|
||||
self.assertEqual(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):
|
||||
value = float_round(amount, precision_rounding=precision_rounding)
|
||||
result = float_repr(value, precision_digits=2)
|
||||
self.assertEqual(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)
|
||||
|
||||
def test_rounding_04(self):
|
||||
""" check that proper rounding is performed for float persistence """
|
||||
currency = self.env.ref('base.EUR')
|
||||
currency_rate = self.env['res.currency.rate']
|
||||
|
||||
def try_roundtrip(value, expected):
|
||||
rate = currency_rate.create({'name':'2000-01-01',
|
||||
'rate': value,
|
||||
'currency_id': currency.id})
|
||||
self.assertEqual(rate.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)
|
||||
|
||||
def test_rounding_invalid(self):
|
||||
""" verify that invalid parameters are forbidden """
|
||||
with self.assertRaises(AssertionError):
|
||||
float_is_zero(0.01, precision_digits=3, precision_rounding=0.01)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
float_compare(0.01, 0.02, precision_digits=3, precision_rounding=0.01)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
float_round(0.01, precision_digits=3, precision_rounding=0.01)
|
||||
@@ -1,16 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import functools
|
||||
import unittest
|
||||
|
||||
from openerp.tools.func import compose
|
||||
from openerp.tools import frozendict
|
||||
from odoo.tools import frozendict
|
||||
from odoo.tools.func import compose
|
||||
|
||||
|
||||
class TestCompose(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
str_add = compose(str, lambda a, b: a + b)
|
||||
self.assertEqual(
|
||||
str_add(1, 2),
|
||||
"3")
|
||||
self.assertEqual(str_add(1, 2), "3")
|
||||
|
||||
def test_decorator(self):
|
||||
""" ensure compose() can be partially applied as a decorator
|
||||
@@ -21,6 +22,7 @@ class TestCompose(unittest.TestCase):
|
||||
|
||||
self.assertEqual(mul(5, 42), u"210")
|
||||
|
||||
|
||||
class TestFrozendict(unittest.TestCase):
|
||||
def test_frozendict_immutable(self):
|
||||
""" Ensure that a frozendict is immutable. """
|
||||
|
||||
@@ -1,58 +1,50 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.exceptions import ValidationError
|
||||
import openerp.tests.common as common
|
||||
from openerp.tools import mute_logger
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import mute_logger
|
||||
import odoo.tests.common as common
|
||||
import odoo.workflow
|
||||
|
||||
|
||||
class TestServerActionsBase(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestServerActionsBase, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Models
|
||||
self.ir_actions_server = self.registry('ir.actions.server')
|
||||
self.ir_actions_client = self.registry('ir.actions.client')
|
||||
self.ir_values = self.registry('ir.values')
|
||||
self.ir_model = self.registry('ir.model')
|
||||
self.ir_model_fields = self.registry('ir.model.fields')
|
||||
self.res_partner = self.registry('res.partner')
|
||||
self.res_country = self.registry('res.country')
|
||||
|
||||
# Data on which we will run the server action
|
||||
self.test_country_id = self.res_country.create(cr, uid, {
|
||||
self.test_country = self.env['res.country'].create({
|
||||
'name': 'TestingCountry',
|
||||
'code': 'TY',
|
||||
'address_format': 'SuperFormat',
|
||||
})
|
||||
self.test_country = self.res_country.browse(cr, uid, self.test_country_id)
|
||||
self.test_partner_id = self.res_partner.create(cr, uid, {
|
||||
self.test_partner = self.env['res.partner'].create({
|
||||
'name': 'TestingPartner',
|
||||
'city': 'OrigCity',
|
||||
'country_id': self.test_country_id,
|
||||
'country_id': self.test_country.id,
|
||||
})
|
||||
self.test_partner = self.res_partner.browse(cr, uid, self.test_partner_id)
|
||||
self.context = {
|
||||
'active_id': self.test_partner_id,
|
||||
'active_model': 'res.partner',
|
||||
'active_id': self.test_partner.id,
|
||||
}
|
||||
|
||||
# Model data
|
||||
self.res_partner_model_id = self.ir_model.search(cr, uid, [('model', '=', 'res.partner')])[0]
|
||||
self.res_partner_name_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'name')])[0]
|
||||
self.res_partner_city_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'city')])[0]
|
||||
self.res_partner_country_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'country_id')])[0]
|
||||
self.res_partner_parent_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.partner'), ('name', '=', 'parent_id')])[0]
|
||||
self.res_country_model_id = self.ir_model.search(cr, uid, [('model', '=', 'res.country')])[0]
|
||||
self.res_country_name_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.country'), ('name', '=', 'name')])[0]
|
||||
self.res_country_code_field_id = self.ir_model_fields.search(cr, uid, [('model', '=', 'res.country'), ('name', '=', 'code')])[0]
|
||||
Model = self.env['ir.model']
|
||||
Fields = self.env['ir.model.fields']
|
||||
self.res_partner_model = Model.search([('model', '=', 'res.partner')])
|
||||
self.res_partner_name_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'name')])
|
||||
self.res_partner_city_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'city')])
|
||||
self.res_partner_country_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'country_id')])
|
||||
self.res_partner_parent_field = Fields.search([('model', '=', 'res.partner'), ('name', '=', 'parent_id')])
|
||||
self.res_country_model = Model.search([('model', '=', 'res.country')])
|
||||
self.res_country_name_field = Fields.search([('model', '=', 'res.country'), ('name', '=', 'name')])
|
||||
self.res_country_code_field = Fields.search([('model', '=', 'res.country'), ('name', '=', 'code')])
|
||||
|
||||
# create server action to
|
||||
self.act_id = self.ir_actions_server.create(cr, uid, {
|
||||
self.action = self.env['ir.actions.server'].create({
|
||||
'name': 'TestAction',
|
||||
'condition': 'True',
|
||||
'model_id': self.res_partner_model_id,
|
||||
'model_id': self.res_partner_model.id,
|
||||
'state': 'code',
|
||||
'code': 'obj.write({"comment": "MyComment"})',
|
||||
})
|
||||
@@ -61,346 +53,318 @@ class TestServerActionsBase(common.TransactionCase):
|
||||
class TestServerActions(TestServerActionsBase):
|
||||
|
||||
def test_00_action(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Do: eval 'True' condition
|
||||
self.ir_actions_server.run(cr, uid, [self.act_id], self.context)
|
||||
self.test_partner.refresh()
|
||||
self.action.with_context(self.context).run()
|
||||
self.assertEqual(self.test_partner.comment, 'MyComment', 'ir_actions_server: invalid condition check')
|
||||
self.test_partner.write({'comment': False})
|
||||
|
||||
# Do: eval False condition, that should be considered as True (void = True)
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {'condition': False})
|
||||
self.ir_actions_server.run(cr, uid, [self.act_id], self.context)
|
||||
self.test_partner.refresh()
|
||||
self.action.write({'condition': False})
|
||||
self.action.with_context(self.context).run()
|
||||
self.assertEqual(self.test_partner.comment, 'MyComment', 'ir_actions_server: invalid condition check')
|
||||
|
||||
# Do: create contextual action
|
||||
self.ir_actions_server.create_action(cr, uid, [self.act_id])
|
||||
self.action.create_action()
|
||||
|
||||
# Test: ir_values created
|
||||
ir_values_ids = self.ir_values.search(cr, uid, [('name', '=', 'Run TestAction')])
|
||||
self.assertEqual(len(ir_values_ids), 1, 'ir_actions_server: create_action should have created an entry in ir_values')
|
||||
ir_value = self.ir_values.browse(cr, uid, ir_values_ids[0])
|
||||
self.assertEqual(ir_value.value, 'ir.actions.server,%s' % self.act_id, 'ir_actions_server: created ir_values should reference the server action')
|
||||
self.assertEqual(ir_value.model, 'res.partner', 'ir_actions_server: created ir_values should be linked to the action base model')
|
||||
ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')])
|
||||
self.assertEqual(len(ir_values), 1, 'ir_actions_server: create_action should have created an entry in ir_values')
|
||||
self.assertEqual(ir_values.value, 'ir.actions.server,%s' % self.action.id, 'ir_actions_server: created ir_values should reference the server action')
|
||||
self.assertEqual(ir_values.model, 'res.partner', 'ir_actions_server: created ir_values should be linked to the action base model')
|
||||
|
||||
# Do: remove contextual action
|
||||
self.ir_actions_server.unlink_action(cr, uid, [self.act_id])
|
||||
self.action.unlink_action()
|
||||
|
||||
# Test: ir_values removed
|
||||
ir_values_ids = self.ir_values.search(cr, uid, [('name', '=', 'Run TestAction')])
|
||||
self.assertEqual(len(ir_values_ids), 0, 'ir_actions_server: unlink_action should remove the ir_values record')
|
||||
ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')])
|
||||
self.assertEqual(len(ir_values), 0, 'ir_actions_server: unlink_action should remove the ir_values record')
|
||||
|
||||
def test_10_code(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
self.ir_actions_server.write(cr, uid, self.act_id, {
|
||||
self.action.write({
|
||||
'state': 'code',
|
||||
'code': """partner_name = obj.name + '_code'
|
||||
self.pool["res.partner"].create(cr, uid, {"name": partner_name}, context=context)
|
||||
workflow"""
|
||||
'code': ("partner_name = obj.name + '_code'\n"
|
||||
"obj.env['res.partner'].create({'name': partner_name})\n"
|
||||
"workflow"),
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: code server action correctly finished should return False')
|
||||
|
||||
pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner_code')])
|
||||
self.assertEqual(len(pids), 1, 'ir_actions_server: 1 new partner should have been created')
|
||||
partners = self.test_partner.search([('name', 'ilike', 'TestingPartner_code')])
|
||||
self.assertEqual(len(partners), 1, 'ir_actions_server: 1 new partner should have been created')
|
||||
|
||||
def test_20_trigger(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
Workflow = self.env['workflow']
|
||||
WorkflowActivity = self.env['workflow.activity']
|
||||
WorkflowTransition = self.env['workflow.transition']
|
||||
|
||||
# Data: code server action (at this point code-based actions should work)
|
||||
act_id2 = self.ir_actions_server.create(cr, uid, {
|
||||
action2 = self.action.create({
|
||||
'name': 'TestAction2',
|
||||
'type': 'ir.actions.server',
|
||||
'condition': 'True',
|
||||
'model_id': self.res_partner_model_id,
|
||||
'model_id': self.res_partner_model.id,
|
||||
'state': 'code',
|
||||
'code': 'obj.write({"comment": "MyComment"})',
|
||||
})
|
||||
act_id3 = self.ir_actions_server.create(cr, uid, {
|
||||
action3 = self.action.create({
|
||||
'name': 'TestAction3',
|
||||
'type': 'ir.actions.server',
|
||||
'condition': 'True',
|
||||
'model_id': self.res_country_model_id,
|
||||
'model_id': self.res_country_model.id,
|
||||
'state': 'code',
|
||||
'code': 'obj.write({"code": "ZZ"})',
|
||||
})
|
||||
|
||||
# Data: create workflows
|
||||
partner_wf_id = self.registry('workflow').create(cr, uid, {
|
||||
partner_workflow = Workflow.create({
|
||||
'name': 'TestWorkflow',
|
||||
'osv': 'res.partner',
|
||||
'on_create': True,
|
||||
})
|
||||
partner_act1_id = self.registry('workflow.activity').create(cr, uid, {
|
||||
partner_activity1 = WorkflowActivity.create({
|
||||
'name': 'PartnerStart',
|
||||
'wkf_id': partner_wf_id,
|
||||
'flow_start': True
|
||||
'wkf_id': partner_workflow.id,
|
||||
'flow_start': True,
|
||||
})
|
||||
partner_act2_id = self.registry('workflow.activity').create(cr, uid, {
|
||||
partner_activity2 = WorkflowActivity.create({
|
||||
'name': 'PartnerTwo',
|
||||
'wkf_id': partner_wf_id,
|
||||
'wkf_id': partner_workflow.id,
|
||||
'kind': 'function',
|
||||
'action': 'True',
|
||||
'action_id': act_id2,
|
||||
'action_id': action2.id,
|
||||
})
|
||||
partner_trs1_id = self.registry('workflow.transition').create(cr, uid, {
|
||||
partner_transition1 = WorkflowTransition.create({
|
||||
'signal': 'partner_trans',
|
||||
'act_from': partner_act1_id,
|
||||
'act_to': partner_act2_id
|
||||
'act_from': partner_activity1.id,
|
||||
'act_to': partner_activity2.id,
|
||||
})
|
||||
country_wf_id = self.registry('workflow').create(cr, uid, {
|
||||
country_workflow = Workflow.create({
|
||||
'name': 'TestWorkflow',
|
||||
'osv': 'res.country',
|
||||
'on_create': True,
|
||||
})
|
||||
country_act1_id = self.registry('workflow.activity').create(cr, uid, {
|
||||
country_activity1 = WorkflowActivity.create({
|
||||
'name': 'CountryStart',
|
||||
'wkf_id': country_wf_id,
|
||||
'flow_start': True
|
||||
'wkf_id': country_workflow.id,
|
||||
'flow_start': True,
|
||||
})
|
||||
country_act2_id = self.registry('workflow.activity').create(cr, uid, {
|
||||
country_activity2 = WorkflowActivity.create({
|
||||
'name': 'CountryTwo',
|
||||
'wkf_id': country_wf_id,
|
||||
'wkf_id': country_workflow.id,
|
||||
'kind': 'function',
|
||||
'action': 'True',
|
||||
'action_id': act_id3,
|
||||
'action_id': action3.id,
|
||||
})
|
||||
country_trs1_id = self.registry('workflow.transition').create(cr, uid, {
|
||||
country_transition1 = WorkflowTransition.create({
|
||||
'signal': 'country_trans',
|
||||
'act_from': country_act1_id,
|
||||
'act_to': country_act2_id
|
||||
'act_from': country_activity1.id,
|
||||
'act_to': country_activity2.id,
|
||||
})
|
||||
|
||||
# Data: re-create country and partner to benefit from the workflows
|
||||
self.test_country_id = self.res_country.create(cr, uid, {
|
||||
country = self.test_country.create({
|
||||
'name': 'TestingCountry2',
|
||||
'code': 'T2',
|
||||
})
|
||||
self.test_country = self.res_country.browse(cr, uid, self.test_country_id)
|
||||
self.test_partner_id = self.res_partner.create(cr, uid, {
|
||||
partner = self.test_partner.create({
|
||||
'name': 'TestingPartner2',
|
||||
'country_id': self.test_country_id,
|
||||
'country_id': country.id,
|
||||
})
|
||||
self.test_partner = self.res_partner.browse(cr, uid, self.test_partner_id)
|
||||
self.context = {
|
||||
'active_id': self.test_partner_id,
|
||||
'active_model': 'res.partner',
|
||||
}
|
||||
context = dict(self.context, active_id=partner.id)
|
||||
|
||||
# Run the action on partner object itself ('base')
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'trigger',
|
||||
'use_relational_model': 'base',
|
||||
'wkf_model_id': self.res_partner_model_id,
|
||||
'wkf_transition_id': partner_trs1_id,
|
||||
'wkf_model_id': self.res_partner_model.id,
|
||||
'wkf_transition_id': partner_transition1.id,
|
||||
})
|
||||
self.ir_actions_server.run(cr, uid, [self.act_id], self.context)
|
||||
self.test_partner.refresh()
|
||||
self.assertEqual(self.test_partner.comment, 'MyComment', 'ir_actions_server: incorrect signal trigger')
|
||||
self.action.with_context(context).run()
|
||||
self.assertEqual(partner.comment, 'MyComment', 'ir_actions_server: incorrect signal trigger')
|
||||
|
||||
# Run the action on related country object ('relational')
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'use_relational_model': 'relational',
|
||||
'wkf_model_id': self.res_country_model_id,
|
||||
'wkf_field_id': self.res_partner_country_field_id,
|
||||
'wkf_transition_id': country_trs1_id,
|
||||
'wkf_model_id': self.res_country_model.id,
|
||||
'wkf_field_id': self.res_partner_country_field.id,
|
||||
'wkf_transition_id': country_transition1.id,
|
||||
})
|
||||
self.ir_actions_server.run(cr, uid, [self.act_id], self.context)
|
||||
self.test_country.refresh()
|
||||
self.assertEqual(self.test_country.code, 'ZZ', 'ir_actions_server: incorrect signal trigger')
|
||||
self.action.with_context(context).run()
|
||||
self.assertEqual(country.code, 'ZZ', 'ir_actions_server: incorrect signal trigger')
|
||||
|
||||
# Clear workflow cache, otherwise openerp will try to create workflows even if it has been deleted
|
||||
from openerp.workflow import clear_cache
|
||||
clear_cache(cr, uid)
|
||||
# Clear workflow cache, otherwise odoo will try to create workflows even if it has been deleted
|
||||
odoo.workflow.clear_cache(self.cr, self.uid)
|
||||
|
||||
def test_30_client(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
client_action_id = self.registry('ir.actions.client').create(cr, uid, {
|
||||
client_action = self.env['ir.actions.client'].create({
|
||||
'name': 'TestAction2',
|
||||
'tag': 'Test',
|
||||
})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'client_action',
|
||||
'action_id': client_action_id,
|
||||
'action_id': client_action.id,
|
||||
})
|
||||
res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
res = self.action.with_context(self.context).run()
|
||||
self.assertEqual(res['name'], 'TestAction2', 'ir_actions_server: incorrect return result for a client action')
|
||||
|
||||
def test_40_crud_create(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
_city = 'TestCity'
|
||||
_name = 'TestNew'
|
||||
|
||||
# Do: create a new record in the same model and link it
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'object_create',
|
||||
'use_create': 'new',
|
||||
'link_new_record': True,
|
||||
'link_field_id': self.res_partner_parent_field_id,
|
||||
'fields_lines': [(0, 0, {'col1': self.res_partner_name_field_id, 'value': _name}),
|
||||
(0, 0, {'col1': self.res_partner_city_field_id, 'value': _city})],
|
||||
'link_field_id': self.res_partner_parent_field.id,
|
||||
'fields_lines': [(0, 0, {'col1': self.res_partner_name_field.id, 'value': _name}),
|
||||
(0, 0, {'col1': self.res_partner_city_field.id, 'value': _city})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new partner created
|
||||
pids = self.res_partner.search(cr, uid, [('name', 'ilike', _name)])
|
||||
self.assertEqual(len(pids), 1, 'ir_actions_server: TODO')
|
||||
partner = self.res_partner.browse(cr, uid, pids[0])
|
||||
partner = self.test_partner.search([('name', 'ilike', _name)])
|
||||
self.assertEqual(len(partner), 1, 'ir_actions_server: TODO')
|
||||
self.assertEqual(partner.city, _city, 'ir_actions_server: TODO')
|
||||
# Test: new partner linked
|
||||
self.test_partner.refresh()
|
||||
self.assertEqual(self.test_partner.parent_id.id, pids[0], 'ir_actions_server: TODO')
|
||||
self.assertEqual(self.test_partner.parent_id, partner, 'ir_actions_server: TODO')
|
||||
|
||||
# Do: copy current record
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'object_create',
|
||||
'use_create': 'copy_current',
|
||||
'link_new_record': False,
|
||||
'fields_lines': [(0, 0, {'col1': self.res_partner_name_field_id, 'value': 'TestCopyCurrent'}),
|
||||
(0, 0, {'col1': self.res_partner_city_field_id, 'value': 'TestCity'})],
|
||||
'fields_lines': [(5,),
|
||||
(0, 0, {'col1': self.res_partner_name_field.id, 'value': 'TestCopyCurrent'}),
|
||||
(0, 0, {'col1': self.res_partner_city_field.id, 'value': 'TestCity'})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new partner created
|
||||
pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value
|
||||
self.assertEqual(len(pids), 1, 'ir_actions_server: TODO')
|
||||
partner = self.res_partner.browse(cr, uid, pids[0])
|
||||
partner = self.test_partner.search([('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value
|
||||
self.assertEqual(len(partner), 1, 'ir_actions_server: TODO')
|
||||
self.assertEqual(partner.city, 'TestCity', 'ir_actions_server: TODO')
|
||||
self.assertEqual(partner.country_id.id, self.test_partner.country_id.id, 'ir_actions_server: TODO')
|
||||
self.assertEqual(partner.country_id, self.test_partner.country_id, 'ir_actions_server: TODO')
|
||||
|
||||
# Do: create a new record in another model
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'object_create',
|
||||
'use_create': 'new_other',
|
||||
'crud_model_id': self.res_country_model_id,
|
||||
'crud_model_id': self.res_country_model.id,
|
||||
'link_new_record': False,
|
||||
'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'obj.name', 'type': 'equation'}),
|
||||
(0, 0, {'col1': self.res_country_code_field_id, 'value': 'obj.name[0:2]', 'type': 'equation'})],
|
||||
'fields_lines': [(5,),
|
||||
(0, 0, {'col1': self.res_country_name_field.id, 'value': 'obj.name', 'type': 'equation'}),
|
||||
(0, 0, {'col1': self.res_country_code_field.id, 'value': 'obj.name[0:2]', 'type': 'equation'})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new country created
|
||||
cids = self.res_country.search(cr, uid, [('name', 'ilike', 'TestingPartner')])
|
||||
self.assertEqual(len(cids), 1, 'ir_actions_server: TODO')
|
||||
country = self.res_country.browse(cr, uid, cids[0])
|
||||
country = self.test_country.search([('name', 'ilike', 'TestingPartner')])
|
||||
self.assertEqual(len(country), 1, 'ir_actions_server: TODO')
|
||||
self.assertEqual(country.code, 'TE', 'ir_actions_server: TODO')
|
||||
|
||||
# Do: copy a record in another model
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'object_create',
|
||||
'use_create': 'copy_other',
|
||||
'crud_model_id': self.res_country_model_id,
|
||||
'crud_model_id': self.res_country_model.id,
|
||||
'link_new_record': False,
|
||||
'ref_object': 'res.country,%s' % self.test_country_id,
|
||||
'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'NewCountry', 'type': 'value'}),
|
||||
(0, 0, {'col1': self.res_country_code_field_id, 'value': 'NY', 'type': 'value'})],
|
||||
'ref_object': 'res.country,%s' % self.test_country.id,
|
||||
'fields_lines': [(5,),
|
||||
(0, 0, {'col1': self.res_country_name_field.id, 'value': 'NewCountry', 'type': 'value'}),
|
||||
(0, 0, {'col1': self.res_country_code_field.id, 'value': 'NY', 'type': 'value'})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new country created
|
||||
cids = self.res_country.search(cr, uid, [('name', 'ilike', 'NewCountry')])
|
||||
self.assertEqual(len(cids), 1, 'ir_actions_server: TODO')
|
||||
country = self.res_country.browse(cr, uid, cids[0])
|
||||
country = self.test_country.search([('name', 'ilike', 'NewCountry')])
|
||||
self.assertEqual(len(country), 1, 'ir_actions_server: TODO')
|
||||
self.assertEqual(country.code, 'NY', 'ir_actions_server: TODO')
|
||||
self.assertEqual(country.address_format, 'SuperFormat', 'ir_actions_server: TODO')
|
||||
|
||||
def test_50_crud_write(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
_name = 'TestNew'
|
||||
|
||||
# Do: create a new record in the same model and link it
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'object_write',
|
||||
'use_write': 'current',
|
||||
'fields_lines': [(0, 0, {'col1': self.res_partner_name_field_id, 'value': _name})],
|
||||
'fields_lines': [(0, 0, {'col1': self.res_partner_name_field.id, 'value': _name})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new partner created
|
||||
pids = self.res_partner.search(cr, uid, [('name', 'ilike', _name)])
|
||||
self.assertEqual(len(pids), 1, 'ir_actions_server: TODO')
|
||||
partner = self.res_partner.browse(cr, uid, pids[0])
|
||||
partner = self.test_partner.search([('name', 'ilike', _name)])
|
||||
self.assertEqual(len(partner), 1, 'ir_actions_server: TODO')
|
||||
self.assertEqual(partner.city, 'OrigCity', 'ir_actions_server: TODO')
|
||||
|
||||
# Do: copy current record
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'use_write': 'other',
|
||||
'crud_model_id': self.res_country_model_id,
|
||||
'ref_object': 'res.country,%s' % self.test_country_id,
|
||||
'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'obj.name', 'type': 'equation'})],
|
||||
'crud_model_id': self.res_country_model.id,
|
||||
'ref_object': 'res.country,%s' % self.test_country.id,
|
||||
'fields_lines': [(5,), (0, 0, {'col1': self.res_country_name_field.id, 'value': 'obj.name', 'type': 'equation'})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new country created
|
||||
cids = self.res_country.search(cr, uid, [('name', 'ilike', 'TestNew')])
|
||||
self.assertEqual(len(cids), 1, 'ir_actions_server: TODO')
|
||||
country = self.test_country.search([('name', 'ilike', 'TestNew')])
|
||||
self.assertEqual(len(country), 1, 'ir_actions_server: TODO')
|
||||
|
||||
# Do: copy a record in another model
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {'fields_lines': [[5]]})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'use_write': 'expression',
|
||||
'crud_model_id': self.res_country_model_id,
|
||||
'crud_model_id': self.res_country_model.id,
|
||||
'write_expression': 'object.country_id',
|
||||
'fields_lines': [(0, 0, {'col1': self.res_country_name_field_id, 'value': 'NewCountry', 'type': 'value'})],
|
||||
'fields_lines': [(5,), (0, 0, {'col1': self.res_country_name_field.id, 'value': 'NewCountry', 'type': 'value'})],
|
||||
})
|
||||
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
run_res = self.action.with_context(self.context).run()
|
||||
self.assertFalse(run_res, 'ir_actions_server: create record action correctly finished should return False')
|
||||
# Test: new country created
|
||||
cids = self.res_country.search(cr, uid, [('name', 'ilike', 'NewCountry')])
|
||||
self.assertEqual(len(cids), 1, 'ir_actions_server: TODO')
|
||||
country = self.test_country.search([('name', 'ilike', 'NewCountry')])
|
||||
self.assertEqual(len(country), 1, 'ir_actions_server: TODO')
|
||||
|
||||
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
|
||||
def test_60_multi(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Data: 2 server actions that will be nested
|
||||
act1_id = self.ir_actions_server.create(cr, uid, {
|
||||
action1 = self.action.create({
|
||||
'name': 'Subaction1',
|
||||
'sequence': 1,
|
||||
'model_id': self.res_partner_model_id,
|
||||
'model_id': self.res_partner_model.id,
|
||||
'state': 'code',
|
||||
'code': 'action = {"type": "ir.actions.act_window"}',
|
||||
})
|
||||
act2_id = self.ir_actions_server.create(cr, uid, {
|
||||
action2 = self.action.create({
|
||||
'name': 'Subaction2',
|
||||
'sequence': 2,
|
||||
'model_id': self.res_partner_model_id,
|
||||
'model_id': self.res_partner_model.id,
|
||||
'state': 'object_create',
|
||||
'use_create': 'copy_current',
|
||||
})
|
||||
act3_id = self.ir_actions_server.create(cr, uid, {
|
||||
action3 = self.action.create({
|
||||
'name': 'Subaction3',
|
||||
'sequence': 3,
|
||||
'model_id': self.res_partner_model_id,
|
||||
'model_id': self.res_partner_model.id,
|
||||
'state': 'code',
|
||||
'code': 'action = {"type": "ir.actions.act_url"}',
|
||||
})
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
self.action.write({
|
||||
'state': 'multi',
|
||||
'child_ids': [(6, 0, [act1_id, act2_id, act3_id])],
|
||||
'child_ids': [(6, 0, [action1.id, action2.id, action3.id])],
|
||||
})
|
||||
|
||||
# Do: run the action
|
||||
res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
|
||||
res = self.action.with_context(self.context).run()
|
||||
|
||||
# Test: new partner created
|
||||
pids = self.res_partner.search(cr, uid, [('name', 'ilike', 'TestingPartner (copy)')]) # currently res_partner overrides default['name'] whatever its value
|
||||
self.assertEqual(len(pids), 1, 'ir_actions_server: TODO')
|
||||
# currently res_partner overrides default['name'] whatever its value
|
||||
partner = self.test_partner.search([('name', 'ilike', 'TestingPartner (copy)')])
|
||||
self.assertEqual(len(partner), 1, 'ir_actions_server: TODO')
|
||||
# Test: action returned
|
||||
self.assertEqual(res.get('type'), 'ir.actions.act_url')
|
||||
|
||||
# Test loops
|
||||
with self.assertRaises(ValidationError):
|
||||
self.ir_actions_server.write(cr, uid, [self.act_id], {
|
||||
'child_ids': [(6, 0, [self.act_id])]
|
||||
self.action.write({
|
||||
'child_ids': [(6, 0, [self.action.id])]
|
||||
})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
import openerp
|
||||
import openerp.tests.common
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
HASH_SPLIT = 2 # FIXME: testing implementations detail is not a good idea
|
||||
|
||||
class test_ir_attachment(openerp.tests.common.TransactionCase):
|
||||
|
||||
class TestIrAttachment(TransactionCase):
|
||||
def setUp(self):
|
||||
super(test_ir_attachment, self).setUp()
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
self.ira = registry('ir.attachment')
|
||||
self.filestore = self.ira._filestore(cr, uid)
|
||||
super(TestIrAttachment, self).setUp()
|
||||
self.Attachment = self.env['ir.attachment']
|
||||
self.ira = self.Attachment._model
|
||||
self.filestore = self.Attachment._filestore()
|
||||
|
||||
# Blob1
|
||||
self.blob1 = 'blob1'
|
||||
@@ -20,73 +23,55 @@ class test_ir_attachment(openerp.tests.common.TransactionCase):
|
||||
self.blob1_fname = blob1_hash[:HASH_SPLIT] + '/' + blob1_hash
|
||||
|
||||
# Blob2
|
||||
blob2 = 'blob2'
|
||||
self.blob2_b64 = blob2.encode('base64')
|
||||
self.blob2 = 'blob2'
|
||||
self.blob2_b64 = self.blob2.encode('base64')
|
||||
|
||||
def test_01_store_in_db(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
# force storing in database
|
||||
registry('ir.config_parameter').set_param(cr, uid, 'ir_attachment.location', 'db')
|
||||
self.env['ir.config_parameter'].set_param('ir_attachment.location', 'db')
|
||||
|
||||
# 'ir_attachment.location' is undefined test database storage
|
||||
a1 = self.ira.create(cr, uid, {'name': 'a1', 'datas': self.blob1_b64})
|
||||
a1_read = self.ira.read(cr, uid, [a1], ['datas'])
|
||||
self.assertEqual(a1_read[0]['datas'], self.blob1_b64)
|
||||
a1 = self.Attachment.create({'name': 'a1', 'datas': self.blob1_b64})
|
||||
self.assertEqual(a1.datas, self.blob1_b64)
|
||||
|
||||
a1_db_datas = self.ira.browse(cr, uid, a1).db_datas
|
||||
a1_db_datas = a1.db_datas
|
||||
self.assertEqual(a1_db_datas, self.blob1_b64)
|
||||
|
||||
def test_02_store_on_disk(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
|
||||
a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
|
||||
|
||||
self.assertEqual(a2_store_fname, self.blob1_fname)
|
||||
self.assertTrue(os.path.isfile(os.path.join(self.filestore, a2_store_fname)))
|
||||
a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64})
|
||||
self.assertEqual(a2.store_fname, self.blob1_fname)
|
||||
self.assertTrue(os.path.isfile(os.path.join(self.filestore, a2.store_fname)))
|
||||
|
||||
def test_03_no_duplication(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
|
||||
a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
|
||||
|
||||
a3 = self.ira.create(cr, uid, {'name': 'a3', 'datas': self.blob1_b64})
|
||||
a3_store_fname = self.ira.browse(cr, uid, a3).store_fname
|
||||
|
||||
self.assertEqual(a3_store_fname, a2_store_fname)
|
||||
a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64})
|
||||
a3 = self.Attachment.create({'name': 'a3', 'datas': self.blob1_b64})
|
||||
self.assertEqual(a3.store_fname, a2.store_fname)
|
||||
|
||||
def test_04_keep_file(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64})
|
||||
a3 = self.Attachment.create({'name': 'a3', 'datas': self.blob1_b64})
|
||||
|
||||
a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
|
||||
a3 = self.ira.create(cr, uid, {'name': 'a3', 'datas': self.blob1_b64})
|
||||
a2_fn = os.path.join(self.filestore, a2.store_fname)
|
||||
|
||||
a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
|
||||
a2_fn = os.path.join(self.filestore, a2_store_fname)
|
||||
|
||||
self.ira.unlink(cr, uid, [a3])
|
||||
a3.unlink()
|
||||
self.assertTrue(os.path.isfile(a2_fn))
|
||||
|
||||
# delete a2 it is unlinked
|
||||
self.ira.unlink(cr, uid, [a2])
|
||||
a2.unlink()
|
||||
self.assertFalse(os.path.isfile(a2_fn))
|
||||
|
||||
def test_05_change_data_change_file(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
a2 = self.ira.create(cr, uid, {'name': 'a2', 'datas': self.blob1_b64})
|
||||
a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
|
||||
a2_fn = os.path.join(self.filestore, a2_store_fname)
|
||||
a2 = self.Attachment.create({'name': 'a2', 'datas': self.blob1_b64})
|
||||
a2_store_fname1 = a2.store_fname
|
||||
a2_fn = os.path.join(self.filestore, a2_store_fname1)
|
||||
|
||||
self.assertTrue(os.path.isfile(a2_fn))
|
||||
|
||||
self.ira.write(cr, uid, [a2], {'datas': self.blob2_b64})
|
||||
a2.write({'datas': self.blob2_b64})
|
||||
self.assertFalse(os.path.isfile(a2_fn))
|
||||
|
||||
new_a2_store_fname = self.ira.browse(cr, uid, a2).store_fname
|
||||
self.assertNotEqual(a2_store_fname, new_a2_store_fname)
|
||||
a2_store_fname2 = a2.store_fname
|
||||
self.assertNotEqual(a2_store_fname1, a2_store_fname2)
|
||||
|
||||
new_a2_fn = os.path.join(self.filestore, new_a2_store_fname)
|
||||
self.assertTrue(os.path.isfile(new_a2_fn))
|
||||
a2_fn = os.path.join(self.filestore, a2_store_fname2)
|
||||
self.assertTrue(os.path.isfile(a2_fn))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import functools
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp import exceptions
|
||||
from openerp.tests import common
|
||||
from odoo import exceptions
|
||||
from odoo.tests.common import TransactionCase, ADMIN_USER_ID
|
||||
|
||||
def noid(d):
|
||||
""" Removes values that are not relevant for the test comparisons """
|
||||
@@ -10,17 +10,19 @@ def noid(d):
|
||||
d.pop('action_id', None)
|
||||
return d
|
||||
|
||||
class FiltersCase(common.TransactionCase):
|
||||
|
||||
class FiltersCase(TransactionCase):
|
||||
def build(self, model, *args):
|
||||
Model = self.registry(model)
|
||||
for vars in args:
|
||||
Model.create(self.cr, common.ADMIN_USER_ID, vars, {})
|
||||
Model = self.env[model].sudo(ADMIN_USER_ID)
|
||||
for vals in args:
|
||||
Model.create(vals)
|
||||
|
||||
|
||||
class TestGetFilters(FiltersCase):
|
||||
def setUp(self):
|
||||
super(TestGetFilters, self).setUp()
|
||||
self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0]
|
||||
self.USER_ID = self.USER[0]
|
||||
self.USER_NG = self.env['res.users'].name_search('demo')[0]
|
||||
self.USER_ID = self.USER_NG[0]
|
||||
|
||||
def test_own_filters(self):
|
||||
self.build(
|
||||
@@ -30,14 +32,13 @@ class TestGetFilters(FiltersCase):
|
||||
dict(name='c', user_id=self.USER_ID, model_id='ir.filters'),
|
||||
dict(name='d', user_id=self.USER_ID, model_id='ir.filters'))
|
||||
|
||||
filters = self.registry('ir.filters').get_filters(
|
||||
self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='d', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='a', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='d', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
|
||||
])
|
||||
|
||||
def test_global_filters(self):
|
||||
@@ -49,8 +50,7 @@ class TestGetFilters(FiltersCase):
|
||||
dict(name='d', user_id=False, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
filters = self.registry('ir.filters').get_filters(
|
||||
self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'),
|
||||
@@ -63,40 +63,40 @@ class TestGetFilters(FiltersCase):
|
||||
self.build(
|
||||
'ir.filters',
|
||||
dict(name='a', user_id=False, model_id='ir.filters'),
|
||||
dict(name='b', user_id=common.ADMIN_USER_ID, model_id='ir.filters'),
|
||||
dict(name='b', user_id=ADMIN_USER_ID, model_id='ir.filters'),
|
||||
dict(name='c', user_id=self.USER_ID, model_id='ir.filters'),
|
||||
dict(name='d', user_id=common.ADMIN_USER_ID, model_id='ir.filters') )
|
||||
dict(name='d', user_id=ADMIN_USER_ID, model_id='ir.filters') )
|
||||
|
||||
filters = self.registry('ir.filters').get_filters(
|
||||
self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = self.env['ir.filters'].sudo(self.USER_ID).get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', is_default=False, user_id=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', is_default=False, user_id=self.USER_NG, domain='[]', context='{}', sort='[]'),
|
||||
])
|
||||
|
||||
|
||||
class TestOwnDefaults(FiltersCase):
|
||||
def setUp(self):
|
||||
super(TestOwnDefaults, self).setUp()
|
||||
self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0]
|
||||
self.USER_ID = self.USER[0]
|
||||
self.USER_NG = self.env['res.users'].name_search('demo')[0]
|
||||
self.USER_ID = self.USER_NG[0]
|
||||
|
||||
def test_new_no_filter(self):
|
||||
"""
|
||||
When creating a @is_default filter with no existing filter, that new
|
||||
filter gets the default flag
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
Filters.create_or_replace({
|
||||
'name': 'a',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = Filters.get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=True,
|
||||
dict(name='a', user_id=self.USER_NG, is_default=True,
|
||||
domain='[]', context='{}', sort='[]')
|
||||
])
|
||||
|
||||
@@ -111,19 +111,19 @@ class TestOwnDefaults(FiltersCase):
|
||||
dict(name='b', user_id=self.USER_ID, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
Filters.create_or_replace({
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = Filters.get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='a', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'),
|
||||
])
|
||||
|
||||
def test_new_filter_existing_default(self):
|
||||
@@ -137,19 +137,19 @@ class TestOwnDefaults(FiltersCase):
|
||||
dict(name='b', is_default=True, user_id=self.USER_ID, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
Filters.create_or_replace({
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = Filters.get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='a', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='c', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'),
|
||||
])
|
||||
|
||||
def test_update_filter_set_default(self):
|
||||
@@ -163,25 +163,26 @@ class TestOwnDefaults(FiltersCase):
|
||||
dict(name='b', is_default=True, user_id=self.USER_ID, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
Filters.create_or_replace({
|
||||
'name': 'a',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = Filters.get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=True, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='a', user_id=self.USER_NG, is_default=True, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=self.USER_NG, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
])
|
||||
|
||||
|
||||
class TestGlobalDefaults(FiltersCase):
|
||||
def setUp(self):
|
||||
super(TestGlobalDefaults, self).setUp()
|
||||
self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0]
|
||||
self.USER_ID = self.USER[0]
|
||||
self.USER_NG = self.env['res.users'].name_search('demo')[0]
|
||||
self.USER_ID = self.USER_NG[0]
|
||||
|
||||
def test_new_filter_not_default(self):
|
||||
"""
|
||||
@@ -194,14 +195,14 @@ class TestGlobalDefaults(FiltersCase):
|
||||
dict(name='b', user_id=False, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
Filters.create_or_replace({
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = Filters.get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
@@ -220,9 +221,9 @@ class TestGlobalDefaults(FiltersCase):
|
||||
dict(name='b', is_default=True, user_id=False, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
with self.assertRaises(exceptions.Warning):
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters.create_or_replace({
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
@@ -240,10 +241,9 @@ class TestGlobalDefaults(FiltersCase):
|
||||
dict(name='b', is_default=True, user_id=False, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
with self.assertRaises(exceptions.Warning):
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters.create_or_replace({
|
||||
'name': 'a',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
@@ -260,42 +260,37 @@ class TestGlobalDefaults(FiltersCase):
|
||||
dict(name='b', is_default=True, user_id=False, model_id='ir.filters'),
|
||||
)
|
||||
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters = self.env['ir.filters'].sudo(self.USER_ID)
|
||||
context_value = "{'some_key': True}"
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
Filters.create_or_replace({
|
||||
'name': 'b',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
'context': context_value,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
filters = Filters.get_filters('ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=False, is_default=False, domain='[]', context='{}', sort='[]'),
|
||||
dict(name='b', user_id=False, is_default=True, domain='[]', context=context_value, sort='[]'),
|
||||
])
|
||||
|
||||
from openerp.tests.common import TransactionCase
|
||||
|
||||
class TestReadGroup(TransactionCase):
|
||||
"""Test function read_group with groupby on a many2one field to a model
|
||||
(in test, "user_id" to "res.users") which is ordered by an inherited not stored field (in
|
||||
test, "name" inherited from "res.partners").
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestReadGroup, self).setUp()
|
||||
self.ir_filters_model = self.env['ir.filters']
|
||||
self.res_partner_model = self.env['res.partner']
|
||||
self.res_users_model = self.env['res.users']
|
||||
|
||||
def test_read_group_1(self):
|
||||
self.assertEqual(self.res_users_model._order, "name, login", "Model res.users must be ordered by name, login")
|
||||
self.assertFalse(self.res_users_model._fields['name'].store, "Field name is not stored in res.users")
|
||||
Users = self.env['res.users']
|
||||
self.assertEqual(Users._order, "name, login", "Model res.users must be ordered by name, login")
|
||||
self.assertFalse(Users._fields['name'].store, "Field name is not stored in res.users")
|
||||
|
||||
filter_a = self.ir_filters_model.create(dict(name="Filter_A", model_id="ir.filters"))
|
||||
filter_b = self.ir_filters_model.create(dict(name="Filter_B", model_id="ir.filters"))
|
||||
Filters = self.env['ir.filters']
|
||||
filter_a = Filters.create(dict(name="Filter_A", model_id="ir.filters"))
|
||||
filter_b = Filters.create(dict(name="Filter_B", model_id="ir.filters"))
|
||||
filter_b.write(dict(user_id=False))
|
||||
res = self.ir_filters_model.read_group([], ['name', 'user_id'], ['user_id'])
|
||||
|
||||
res = Filters.read_group([], ['name', 'user_id'], ['user_id'])
|
||||
self.assertTrue(any(val['user_id'] == False for val in res), "At least one group must contain val['user_id'] == False.")
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
-
|
||||
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: res_company_rule_employee}:
|
||||
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."
|
||||
@@ -1,193 +1,177 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Run with one of these commands:
|
||||
# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \
|
||||
# OPENERP_DATABASE=yy PYTHONPATH=. python tests/test_ir_sequence.py
|
||||
# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \
|
||||
# OPENERP_DATABASE=yy nosetests tests/test_ir_sequence.py
|
||||
# > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \
|
||||
# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence
|
||||
# This assume an existing database.
|
||||
import psycopg2
|
||||
import psycopg2.errorcodes
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from contextlib import contextmanager
|
||||
import unittest
|
||||
|
||||
import openerp
|
||||
from openerp.tests import common
|
||||
import psycopg2
|
||||
import psycopg2.errorcodes
|
||||
|
||||
import odoo
|
||||
from odoo.tests import common
|
||||
|
||||
ADMIN_USER_ID = common.ADMIN_USER_ID
|
||||
|
||||
def registry(model):
|
||||
return openerp.modules.registry.RegistryManager.get(common.get_db_name())[model]
|
||||
|
||||
def cursor():
|
||||
return openerp.modules.registry.RegistryManager.get(common.get_db_name()).cursor()
|
||||
@contextmanager
|
||||
def environment():
|
||||
""" Return an environment with a new cursor for the current database; the
|
||||
cursor is committed and closed after the context block.
|
||||
"""
|
||||
registry = odoo.registry(common.get_db_name())
|
||||
with registry.cursor() as cr:
|
||||
yield odoo.api.Environment(cr, ADMIN_USER_ID, {})
|
||||
cr.commit()
|
||||
|
||||
|
||||
def drop_sequence(code):
|
||||
cr = cursor()
|
||||
s = registry('ir.sequence')
|
||||
ids = s.search(cr, ADMIN_USER_ID, [('code', '=', code)])
|
||||
s.unlink(cr, ADMIN_USER_ID, ids)
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seq = env['ir.sequence'].search([('code', '=', code)])
|
||||
seq.unlink()
|
||||
|
||||
class test_ir_sequence_standard(unittest.TestCase):
|
||||
|
||||
class TestIrSequenceStandard(unittest.TestCase):
|
||||
""" A few tests for a 'Standard' (i.e. PostgreSQL) sequence. """
|
||||
|
||||
def test_ir_sequence_create(self):
|
||||
""" Try to create a sequence object. """
|
||||
cr = cursor()
|
||||
d = dict(code='test_sequence_type', name='Test sequence')
|
||||
c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {})
|
||||
assert c
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seq = env['ir.sequence'].create({
|
||||
'code': 'test_sequence_type',
|
||||
'name': 'Test sequence',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
def test_ir_sequence_search(self):
|
||||
""" Try a search. """
|
||||
cr = cursor()
|
||||
ids = registry('ir.sequence').search(cr, ADMIN_USER_ID, [], {})
|
||||
assert ids
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seqs = env['ir.sequence'].search([])
|
||||
self.assertTrue(seqs)
|
||||
|
||||
def test_ir_sequence_draw(self):
|
||||
""" Try to draw a number. """
|
||||
cr = cursor()
|
||||
n = registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type', {})
|
||||
assert n
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
n = env['ir.sequence'].next_by_code('test_sequence_type')
|
||||
self.assertTrue(n)
|
||||
|
||||
def test_ir_sequence_draw_twice(self):
|
||||
""" Try to draw a number from two transactions. """
|
||||
cr0 = cursor()
|
||||
cr1 = cursor()
|
||||
n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type', {})
|
||||
assert n0
|
||||
n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type', {})
|
||||
assert n1
|
||||
cr0.commit()
|
||||
cr1.commit()
|
||||
cr0.close()
|
||||
cr1.close()
|
||||
with environment() as env0:
|
||||
with environment() as env1:
|
||||
n0 = env0['ir.sequence'].next_by_code('test_sequence_type')
|
||||
self.assertTrue(n0)
|
||||
n1 = env1['ir.sequence'].next_by_code('test_sequence_type')
|
||||
self.assertTrue(n1)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
drop_sequence('test_sequence_type')
|
||||
|
||||
class test_ir_sequence_no_gap(unittest.TestCase):
|
||||
|
||||
class TestIrSequenceNoGap(unittest.TestCase):
|
||||
""" Copy of the previous tests for a 'No gap' sequence. """
|
||||
|
||||
def test_ir_sequence_create_no_gap(self):
|
||||
""" Try to create a sequence object. """
|
||||
cr = cursor()
|
||||
d = dict(code='test_sequence_type_2', name='Test sequence',
|
||||
implementation='no_gap')
|
||||
c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {})
|
||||
assert c
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seq = env['ir.sequence'].create({
|
||||
'code': 'test_sequence_type_2',
|
||||
'name': 'Test sequence',
|
||||
'implementation': 'no_gap',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
def test_ir_sequence_draw_no_gap(self):
|
||||
""" Try to draw a number. """
|
||||
cr = cursor()
|
||||
n = registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type_2', {})
|
||||
assert n
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
n = env['ir.sequence'].next_by_code('test_sequence_type_2')
|
||||
self.assertTrue(n)
|
||||
|
||||
def test_ir_sequence_draw_twice_no_gap(self):
|
||||
""" Try to draw a number from two transactions.
|
||||
This is expected to not work.
|
||||
"""
|
||||
cr0 = cursor()
|
||||
cr1 = cursor()
|
||||
cr1._default_log_exceptions = False # Prevent logging a traceback
|
||||
with self.assertRaises(psycopg2.OperationalError) as e:
|
||||
n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {})
|
||||
assert n0
|
||||
n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {})
|
||||
self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode")
|
||||
cr0.close()
|
||||
cr1.close()
|
||||
with environment() as env0:
|
||||
with environment() as env1:
|
||||
env1.cr._default_log_exceptions = False # Prevent logging a traceback
|
||||
with self.assertRaises(psycopg2.OperationalError) as e:
|
||||
n0 = env0['ir.sequence'].next_by_code('test_sequence_type_2')
|
||||
self.assertTrue(n0)
|
||||
n1 = env1['ir.sequence'].next_by_code('test_sequence_type_2')
|
||||
self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode")
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
drop_sequence('test_sequence_type_2')
|
||||
|
||||
class test_ir_sequence_change_implementation(unittest.TestCase):
|
||||
|
||||
class TestIrSequenceChangeImplementation(unittest.TestCase):
|
||||
""" Create sequence objects and change their ``implementation`` field. """
|
||||
|
||||
def test_ir_sequence_1_create(self):
|
||||
""" Try to create a sequence object. """
|
||||
cr = cursor()
|
||||
d = dict(code='test_sequence_type_3', name='Test sequence')
|
||||
c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {})
|
||||
assert c
|
||||
d = dict(code='test_sequence_type_4', name='Test sequence',
|
||||
implementation='no_gap')
|
||||
c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {})
|
||||
assert c
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seq = env['ir.sequence'].create({
|
||||
'code': 'test_sequence_type_3',
|
||||
'name': 'Test sequence',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
seq = env['ir.sequence'].create({
|
||||
'code': 'test_sequence_type_4',
|
||||
'name': 'Test sequence',
|
||||
'implementation': 'no_gap',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
def test_ir_sequence_2_write(self):
|
||||
cr = cursor()
|
||||
ids = registry('ir.sequence').search(cr, ADMIN_USER_ID,
|
||||
[('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])], {})
|
||||
registry('ir.sequence').write(cr, ADMIN_USER_ID, ids,
|
||||
{'implementation': 'standard'}, {})
|
||||
registry('ir.sequence').write(cr, ADMIN_USER_ID, ids,
|
||||
{'implementation': 'no_gap'}, {})
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
domain = [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])]
|
||||
seqs = env['ir.sequence'].search(domain)
|
||||
seqs.write({'implementation': 'standard'})
|
||||
seqs.write({'implementation': 'no_gap'})
|
||||
|
||||
def test_ir_sequence_3_unlink(self):
|
||||
cr = cursor()
|
||||
ids = registry('ir.sequence').search(cr, ADMIN_USER_ID,
|
||||
[('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])], {})
|
||||
registry('ir.sequence').unlink(cr, ADMIN_USER_ID, ids, {})
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
domain = [('code', 'in', ['test_sequence_type_3', 'test_sequence_type_4'])]
|
||||
seqs = env['ir.sequence'].search(domain)
|
||||
seqs.unlink()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
drop_sequence('test_sequence_type_3')
|
||||
drop_sequence('test_sequence_type_4')
|
||||
|
||||
class test_ir_sequence_generate(unittest.TestCase):
|
||||
|
||||
class TestIrSequenceGenerate(unittest.TestCase):
|
||||
""" Create sequence objects and generate some values. """
|
||||
|
||||
def test_ir_sequence_create(self):
|
||||
""" Try to create a sequence object. """
|
||||
cr = cursor()
|
||||
d = dict(code='test_sequence_type_5', name='Test sequence')
|
||||
c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {})
|
||||
assert c
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seq = env['ir.sequence'].create({
|
||||
'code': 'test_sequence_type_5',
|
||||
'name': 'Test sequence',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
cr = cursor()
|
||||
f = lambda *a: registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type_5', {})
|
||||
assert all(str(x) == f() for x in xrange(1,10))
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
for i in xrange(1, 10):
|
||||
n = env['ir.sequence'].next_by_code('test_sequence_type_5')
|
||||
self.assertEqual(n, str(i))
|
||||
|
||||
def test_ir_sequence_create_no_gap(self):
|
||||
""" Try to create a sequence object. """
|
||||
cr = cursor()
|
||||
d = dict(code='test_sequence_type_6', name='Test sequence', implementation='no_gap')
|
||||
c = registry('ir.sequence').create(cr, ADMIN_USER_ID, d, {})
|
||||
assert c
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
seq = env['ir.sequence'].create({
|
||||
'code': 'test_sequence_type_6',
|
||||
'name': 'Test sequence',
|
||||
'implementation': 'no_gap',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
cr = cursor()
|
||||
f = lambda *a: registry('ir.sequence').next_by_code(cr, ADMIN_USER_ID, 'test_sequence_type_6', {})
|
||||
assert all(str(x) == f() for x in xrange(1,10))
|
||||
cr.commit()
|
||||
cr.close()
|
||||
with environment() as env:
|
||||
for i in xrange(1, 10):
|
||||
n = env['ir.sequence'].next_by_code('test_sequence_type_6')
|
||||
self.assertEqual(n, str(i))
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
@@ -195,33 +179,29 @@ class test_ir_sequence_generate(unittest.TestCase):
|
||||
drop_sequence('test_sequence_type_6')
|
||||
|
||||
|
||||
class Test_ir_sequence_init(common.TransactionCase):
|
||||
class TestIrSequenceInit(common.TransactionCase):
|
||||
|
||||
def test_00(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
# test if read statement return the good number_next value (from postgreSQL sequence and not ir_sequence value)
|
||||
sequence = registry('ir.sequence')
|
||||
""" test whether the read method returns the right number_next value
|
||||
(from postgreSQL sequence and not ir_sequence value)
|
||||
"""
|
||||
# first creation of sequence (normal)
|
||||
values = {'number_next': 1,
|
||||
'company_id': 1,
|
||||
'padding': 4,
|
||||
'number_increment': 1,
|
||||
'implementation': 'standard',
|
||||
'name': 'test-sequence-00'}
|
||||
seq_id = sequence.create(cr, uid, values)
|
||||
# Call get next 4 times
|
||||
sequence.next_by_id(cr, uid, seq_id)
|
||||
sequence.next_by_id(cr, uid, seq_id)
|
||||
sequence.next_by_id(cr, uid, seq_id)
|
||||
read_sequence = sequence.next_by_id(cr, uid, seq_id)
|
||||
seq = self.env['ir.sequence'].create({
|
||||
'number_next': 1,
|
||||
'company_id': 1,
|
||||
'padding': 4,
|
||||
'number_increment': 1,
|
||||
'implementation': 'standard',
|
||||
'name': 'test-sequence-00',
|
||||
})
|
||||
# Call next() 4 times, and check the last returned value
|
||||
seq.next_by_id()
|
||||
seq.next_by_id()
|
||||
seq.next_by_id()
|
||||
n = seq.next_by_id()
|
||||
self.assertEqual(n, "0004", 'The actual sequence value must be 4. reading : %s' % n)
|
||||
# reset sequence to 1 by write()
|
||||
seq.write({'number_next': 1})
|
||||
# Read the value of the current sequence
|
||||
assert read_sequence == "0004", 'The actual sequence value must be 4. reading : %s' % read_sequence
|
||||
# reset sequence to 1 by write method calling
|
||||
sequence.write(cr, uid, [seq_id], {'number_next': 1})
|
||||
# Read the value of the current sequence
|
||||
read_sequence = sequence.next_by_id(cr, uid, seq_id)
|
||||
assert read_sequence == "0001", 'The actual sequence value must be 1. reading : %s' % read_sequence
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
n = seq.next_by_id()
|
||||
self.assertEqual(n, "0001", 'The actual sequence value must be 1. reading : %s' % n)
|
||||
|
||||
@@ -1,122 +1,142 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.tests import common
|
||||
from datetime import date
|
||||
|
||||
from odoo.tests.common import SingleTransactionCase
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
|
||||
|
||||
class test_ir_sequence_date_range_standard(common.SingleTransactionCase):
|
||||
|
||||
class TestIrSequenceDateRangeStandard(SingleTransactionCase):
|
||||
""" A few tests for a 'Standard' (i.e. PostgreSQL) sequence. """
|
||||
|
||||
def test_ir_sequence_date_range_1_create(self):
|
||||
""" Try to create a sequence object with date ranges enabled. """
|
||||
d = dict(code='test_sequence_date_range', name='Test sequence', use_date_range=True)
|
||||
c = self.registry('ir.sequence').create(self.cr, self.uid, d, {})
|
||||
assert c
|
||||
seq = self.env['ir.sequence'].create({
|
||||
'code': 'test_sequence_date_range',
|
||||
'name': 'Test sequence',
|
||||
'use_date_range': True,
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
def test_ir_sequence_date_range_2_change_dates(self):
|
||||
""" Draw numbers to create a first subsequence then change its date range. Then, try to draw a new number adn check a new subsequence was correctly created. """
|
||||
year = str(int(date.today().strftime("%Y")) - 1)
|
||||
dt = "{}-01-16".format(year)
|
||||
n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range', {'ir_sequence_date': dt})
|
||||
year = date.today().year - 1
|
||||
january = lambda d: date(year, 1, d).strftime(DATE_FORMAT)
|
||||
|
||||
seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)})
|
||||
n = seq16.next_by_code('test_sequence_date_range')
|
||||
self.assertEqual(n, '1')
|
||||
n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range', {'ir_sequence_date': dt})
|
||||
n = seq16.next_by_code('test_sequence_date_range')
|
||||
self.assertEqual(n, '2')
|
||||
|
||||
# modify the range of date created
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', '{}-01-01'.format(year))]
|
||||
seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {})
|
||||
self.registry('ir.sequence.date_range').write(self.cr, self.uid, seq_date_range_id, {'date_from': '{}-01-18'.format(year)}, {})
|
||||
n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range', {'ir_sequence_date': dt})
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', january(1))]
|
||||
seq_date_range = self.env['ir.sequence.date_range'].search(domain)
|
||||
seq_date_range.write({'date_from': january(18)})
|
||||
n = seq16.next_by_code('test_sequence_date_range')
|
||||
self.assertEqual(n, '1')
|
||||
|
||||
# check the newly created sequence stops at the 17th of January
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', '{}-01-01'.format(year))]
|
||||
seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {})
|
||||
seq_date_range = self.registry('ir.sequence.date_range').browse(self.cr, self.uid, seq_date_range_id[0])
|
||||
self.assertEqual(seq_date_range.date_to, '{}-01-17'.format(year))
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range'), ('date_from', '=', january(1))]
|
||||
seq_date_range = self.env['ir.sequence.date_range'].search(domain)
|
||||
self.assertEqual(seq_date_range.date_to, january(17))
|
||||
|
||||
def test_ir_sequence_date_range_3_unlink(self):
|
||||
ids = self.registry('ir.sequence').search(self.cr, self.uid, [('code', '=', 'test_sequence_date_range')])
|
||||
self.registry('ir.sequence').unlink(self.cr, self.uid, ids)
|
||||
seq = self.env['ir.sequence'].search([('code', '=', 'test_sequence_date_range')])
|
||||
seq.unlink()
|
||||
|
||||
|
||||
class test_ir_sequence_date_range_no_gap(common.SingleTransactionCase):
|
||||
class TestIrSequenceDateRangeNoGap(SingleTransactionCase):
|
||||
""" Copy of the previous tests for a 'No gap' sequence. """
|
||||
|
||||
def test_ir_sequence_date_range_1_create_no_gap(self):
|
||||
""" Try to create a sequence object. """
|
||||
d = dict(code='test_sequence_date_range_2', name='Test sequence',
|
||||
implementation='no_gap', use_date_range=True)
|
||||
c = self.registry('ir.sequence').create(self.cr, self.uid, d, {})
|
||||
assert c
|
||||
seq = self.env['ir.sequence'].create({
|
||||
'code': 'test_sequence_date_range_2',
|
||||
'name': 'Test sequence',
|
||||
'use_date_range': True,
|
||||
'implementation': 'no_gap',
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
def test_ir_sequence_date_range_2_change_dates(self):
|
||||
""" Draw numbers to create a first subsequence then change its date range. Then, try to draw a new number adn check a new subsequence was correctly created. """
|
||||
year = str(int(date.today().strftime("%Y")) - 1)
|
||||
dt = "{}-01-16".format(year)
|
||||
n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_2', {'ir_sequence_date': dt})
|
||||
year = date.today().year - 1
|
||||
january = lambda d: date(year, 1, d).strftime(DATE_FORMAT)
|
||||
|
||||
seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)})
|
||||
n = seq16.next_by_code('test_sequence_date_range_2')
|
||||
self.assertEqual(n, '1')
|
||||
n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_2', {'ir_sequence_date': dt})
|
||||
n = seq16.next_by_code('test_sequence_date_range_2')
|
||||
self.assertEqual(n, '2')
|
||||
|
||||
# modify the range of date created
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', '{}-01-01'.format(year))]
|
||||
seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {})
|
||||
self.registry('ir.sequence.date_range').write(self.cr, self.uid, seq_date_range_id, {'date_from': '{}-01-18'.format(year)}, {})
|
||||
n = self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_2', {'ir_sequence_date': dt})
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', january(1))]
|
||||
seq_date_range = self.env['ir.sequence.date_range'].search(domain)
|
||||
seq_date_range.write({'date_from': january(18)})
|
||||
n = seq16.next_by_code('test_sequence_date_range_2')
|
||||
self.assertEqual(n, '1')
|
||||
|
||||
# check the newly created sequence stops at the 17th of January
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', '{}-01-01'.format(year))]
|
||||
seq_date_range_id = self.registry('ir.sequence.date_range').search(self.cr, self.uid, domain, {})
|
||||
seq_date_range = self.registry('ir.sequence.date_range').browse(self.cr, self.uid, seq_date_range_id[0])
|
||||
self.assertEqual(seq_date_range.date_to, '{}-01-17'.format(year))
|
||||
domain = [('sequence_id.code', '=', 'test_sequence_date_range_2'), ('date_from', '=', january(1))]
|
||||
seq_date_range = self.env['ir.sequence.date_range'].search(domain)
|
||||
self.assertEqual(seq_date_range.date_to, january(17))
|
||||
|
||||
def test_ir_sequence_date_range_3_unlink(self):
|
||||
ids = self.registry('ir.sequence').search(self.cr, self.uid, [('code', '=', 'test_sequence_date_range_2')])
|
||||
self.registry('ir.sequence').unlink(self.cr, self.uid, ids)
|
||||
seq = self.env['ir.sequence'].search([('code', '=', 'test_sequence_date_range_2')])
|
||||
seq.unlink()
|
||||
|
||||
|
||||
class test_ir_sequence_date_range_change_implementation(common.SingleTransactionCase):
|
||||
class TestIrSequenceDateRangeChangeImplementation(SingleTransactionCase):
|
||||
""" Create sequence objects and change their ``implementation`` field. """
|
||||
|
||||
def test_ir_sequence_date_range_1_create(self):
|
||||
""" Try to create a sequence object. """
|
||||
d = dict(code='test_sequence_date_range_3', name='Test sequence', use_date_range=True)
|
||||
c = self.registry('ir.sequence').create(self.cr, self.uid, d, {})
|
||||
assert c
|
||||
d = {
|
||||
seq = self.env['ir.sequence'].create({
|
||||
'code': 'test_sequence_date_range_3',
|
||||
'name': 'Test sequence',
|
||||
'use_date_range': True,
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
seq = self.env['ir.sequence'].create({
|
||||
'code': 'test_sequence_date_range_4',
|
||||
'name': 'Test sequence',
|
||||
'use_date_range': True,
|
||||
'implementation': 'no_gap',
|
||||
'use_date_range': True
|
||||
}
|
||||
c = self.registry('ir.sequence').create(self.cr, self.uid, d, {})
|
||||
assert c
|
||||
})
|
||||
self.assertTrue(seq)
|
||||
|
||||
def test_ir_sequence_date_range_2_use(self):
|
||||
""" Make some use of the sequences to create some subsequences """
|
||||
year = str(int(date.today().strftime("%Y")) - 1)
|
||||
dt = "{}-01-16".format(year)
|
||||
f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_3', {})
|
||||
assert all(str(x) == f() for x in xrange(1, 5))
|
||||
f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_3', {'ir_sequence_date': dt})
|
||||
assert all(str(x) == f() for x in xrange(1, 5))
|
||||
f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_4', {})
|
||||
assert all(str(x) == f() for x in xrange(1, 5))
|
||||
f = lambda *a: self.registry('ir.sequence').next_by_code(self.cr, self.uid, 'test_sequence_date_range_4', {'ir_sequence_date': dt})
|
||||
assert all(str(x) == f() for x in xrange(1, 5))
|
||||
year = date.today().year - 1
|
||||
january = lambda d: date(year, 1, d).strftime(DATE_FORMAT)
|
||||
|
||||
seq = self.env['ir.sequence']
|
||||
seq16 = self.env['ir.sequence'].with_context({'ir_sequence_date': january(16)})
|
||||
|
||||
for i in xrange(1, 5):
|
||||
n = seq.next_by_code('test_sequence_date_range_3')
|
||||
self.assertEqual(n, str(i))
|
||||
for i in xrange(1, 5):
|
||||
n = seq16.next_by_code('test_sequence_date_range_3')
|
||||
self.assertEqual(n, str(i))
|
||||
for i in xrange(1, 5):
|
||||
n = seq.next_by_code('test_sequence_date_range_4')
|
||||
self.assertEqual(n, str(i))
|
||||
for i in xrange(1, 5):
|
||||
n = seq16.next_by_code('test_sequence_date_range_4')
|
||||
self.assertEqual(n, str(i))
|
||||
|
||||
def test_ir_sequence_date_range_3_write(self):
|
||||
"""swap the implementation method on both"""
|
||||
ids = self.registry('ir.sequence').search(self.cr, self.uid, [
|
||||
('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4'])
|
||||
], {})
|
||||
self.registry('ir.sequence').write(self.cr, self.uid, ids, {'implementation': 'standard'})
|
||||
self.registry('ir.sequence').write(self.cr, self.uid, ids, {'implementation': 'no_gap'})
|
||||
domain = [('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4'])]
|
||||
seqs = self.env['ir.sequence'].search(domain)
|
||||
seqs.write({'implementation': 'standard'})
|
||||
seqs.write({'implementation': 'no_gap'})
|
||||
|
||||
def test_ir_sequence_date_range_4_unlink(self):
|
||||
ids = self.registry('ir.sequence').search(self.cr, self.uid, [
|
||||
('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4'])
|
||||
], {})
|
||||
self.registry('ir.sequence').unlink(self.cr, self.uid, ids, {})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
domain = [('code', 'in', ['test_sequence_date_range_3', 'test_sequence_date_range_4'])]
|
||||
seqs = self.env['ir.sequence'].search(domain)
|
||||
seqs.unlink()
|
||||
|
||||
@@ -1,98 +1,99 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import openerp.tests.common as common
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
class test_ir_values(common.TransactionCase):
|
||||
|
||||
class TestIrValues(TransactionCase):
|
||||
|
||||
def test_00(self):
|
||||
# Create some default value for some (non-existing) model, for all users.
|
||||
|
||||
ir_values = self.registry('ir.values')
|
||||
ir_values = self.env['ir.values']
|
||||
# use the old API
|
||||
ir_values.set(self.cr, self.uid, 'default', False, 'my_test_field',
|
||||
['unexisting_model'], 'global value')
|
||||
ir_values.set('default', False, 'my_test_field', ['unexisting_model'],
|
||||
'global value')
|
||||
# use the new API
|
||||
ir_values.set_default(self.cr, self.uid, 'other_unexisting_model',
|
||||
'my_other_test_field', 'conditional value', condition='foo=bar')
|
||||
|
||||
ir_values.set_default('other_unexisting_model', 'my_other_test_field',
|
||||
'conditional value', condition='foo=bar')
|
||||
|
||||
# Retrieve them.
|
||||
|
||||
ir_values = self.registry('ir.values')
|
||||
# d is a list of triplets (id, name, value)
|
||||
# Old API
|
||||
d = ir_values.get(self.cr, self.uid, 'default', False, ['unexisting_model'])
|
||||
assert len(d) == 1, "Only one single value should be retrieved for this model"
|
||||
assert d[0][1] == 'my_test_field', "Can't retrieve the created default value. (1)"
|
||||
assert d[0][2] == 'global value', "Can't retrieve the created default value. (2)"
|
||||
d = ir_values.get('default', False, ['unexisting_model'])
|
||||
self.assertEqual(len(d), 1, "Only one single value should be retrieved for this model")
|
||||
self.assertEqual(d[0][1], 'my_test_field', "Can't retrieve the created default value. (1)")
|
||||
self.assertEqual(d[0][2], 'global value', "Can't retrieve the created default value. (2)")
|
||||
|
||||
# New API, Conditional version
|
||||
d = ir_values.get_defaults(self.cr, self.uid, 'other_unexisting_model')
|
||||
assert len(d) == 0, "No value should be retrieved, the condition is not met"
|
||||
d = ir_values.get_defaults(self.cr, self.uid, 'other_unexisting_model', condition="foo=eggs")
|
||||
assert len(d) == 0, 'Condition is not met either, no defaults should be returned'
|
||||
d = ir_values.get_defaults(self.cr, self.uid, 'other_unexisting_model', condition="foo=bar")
|
||||
assert len(d) == 1, "Only one single value should be retrieved"
|
||||
assert d[0][1] == 'my_other_test_field', "Can't retrieve the created default value. (5)"
|
||||
assert d[0][2] == 'conditional value', "Can't retrieve the created default value. (6)"
|
||||
d = ir_values.get_defaults('other_unexisting_model')
|
||||
self.assertEqual(len(d), 0, "No value should be retrieved, the condition is not met")
|
||||
d = ir_values.get_defaults('other_unexisting_model', condition="foo=eggs")
|
||||
self.assertEqual(len(d), 0, 'Condition is not met either, no defaults should be returned')
|
||||
d = ir_values.get_defaults('other_unexisting_model', condition="foo=bar")
|
||||
self.assertEqual(len(d), 1, "Only one single value should be retrieved")
|
||||
self.assertEqual(d[0][1], 'my_other_test_field', "Can't retrieve the created default value. (5)")
|
||||
self.assertEqual(d[0][2], 'conditional value', "Can't retrieve the created default value. (6)")
|
||||
|
||||
# Do it again but for a specific user.
|
||||
|
||||
ir_values = self.registry('ir.values')
|
||||
ir_values.set(self.cr, self.uid, 'default', False, 'my_test_field',['unexisting_model'], 'specific value', preserve_user=True)
|
||||
ir_values.set('default', False, 'my_test_field',['unexisting_model'],
|
||||
'specific value', preserve_user=True)
|
||||
|
||||
# Retrieve it and check it is the one for the current user.
|
||||
ir_values = self.registry('ir.values')
|
||||
d = ir_values.get(self.cr, self.uid, 'default', False, ['unexisting_model'])
|
||||
assert len(d) == 1, "Only one default must be returned per field"
|
||||
assert d[0][1] == 'my_test_field', "Can't retrieve the created default value."
|
||||
assert d[0][2] == 'specific value', "Can't retrieve the created default value."
|
||||
|
||||
d = ir_values.get('default', False, ['unexisting_model'])
|
||||
self.assertEqual(len(d), 1, "Only one default must be returned per field")
|
||||
self.assertEqual(d[0][1], 'my_test_field', "Can't retrieve the created default value.")
|
||||
self.assertEqual(d[0][2], 'specific value', "Can't retrieve the created default value.")
|
||||
|
||||
# Create some action bindings for a non-existing model.
|
||||
|
||||
act_id_1 = self.ref('base.act_values_form_action')
|
||||
act_id_2 = self.ref('base.act_values_form_defaults')
|
||||
act_id_3 = self.ref('base.action_res_company_form')
|
||||
|
||||
ir_values = self.registry('ir.values')
|
||||
ir_values.set(self.cr, self.uid, 'action', 'tree_but_open', 'OnDblClick Action', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_1, isobject=True)
|
||||
ir_values.set(self.cr, self.uid, 'action', 'tree_but_open', 'OnDblClick Action 2', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_2, isobject=True)
|
||||
ir_values.set(self.cr, self.uid, 'action', 'client_action_multi', 'Side Wizard', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_3, isobject=True)
|
||||
report_ids = self.registry('ir.actions.report.xml').search(self.cr, self.uid, [], {})
|
||||
reports = self.registry('ir.actions.report.xml').browse(self.cr, self.uid, report_ids, {})
|
||||
report_id = [report.id for report in reports if not report.groups_id][0] # assume at least one
|
||||
ir_values.set(self.cr, self.uid, 'action', 'client_print_multi', 'Nice Report', ['unexisting_model'], 'ir.actions.report.xml,%d' % report_id, isobject=True)
|
||||
ir_values.set('action', 'tree_but_open', 'OnDblClick Action', ['unexisting_model'],
|
||||
'ir.actions.act_window,%d' % act_id_1, isobject=True)
|
||||
ir_values.set('action', 'tree_but_open', 'OnDblClick Action 2', ['unexisting_model'],
|
||||
'ir.actions.act_window,%d' % act_id_2, isobject=True)
|
||||
ir_values.set('action', 'client_action_multi', 'Side Wizard', ['unexisting_model'],
|
||||
'ir.actions.act_window,%d' % act_id_3, isobject=True)
|
||||
reports = self.env['ir.actions.report.xml'].search([])
|
||||
report_id = next(report.id for report in reports if not report.groups_id)
|
||||
ir_values.set('action', 'client_print_multi', 'Nice Report', ['unexisting_model'],
|
||||
'ir.actions.report.xml,%d' % report_id, isobject=True)
|
||||
|
||||
# Replace one action binding to set a new name.
|
||||
|
||||
ir_values = self.registry('ir.values')
|
||||
ir_values.set(self.cr, self.uid, 'action', 'tree_but_open', 'OnDblClick Action New', ['unexisting_model'], 'ir.actions.act_window,%d' % act_id_1, isobject=True)
|
||||
ir_values.set('action', 'tree_but_open', 'OnDblClick Action New', ['unexisting_model'],
|
||||
'ir.actions.act_window,%d' % act_id_1, isobject=True)
|
||||
|
||||
# Retrieve the action bindings and check they're correct
|
||||
|
||||
ir_values = self.registry('ir.values')
|
||||
actions = ir_values.get(self.cr, self.uid, 'action', 'tree_but_open', ['unexisting_model'])
|
||||
assert len(actions) == 2, "Mismatching number of bound actions"
|
||||
actions = ir_values.get('action', 'tree_but_open', ['unexisting_model'])
|
||||
self.assertEqual(len(actions), 2, "Mismatching number of bound actions")
|
||||
#first action
|
||||
assert len(actions[0]) == 3, "Malformed action definition"
|
||||
assert actions[0][1] == 'OnDblClick Action 2', 'Bound action does not match definition'
|
||||
assert isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_2, 'Bound action does not match definition'
|
||||
self.assertEqual(len(actions[0]), 3, "Malformed action definition")
|
||||
self.assertEqual(actions[0][1], 'OnDblClick Action 2', 'Bound action does not match definition')
|
||||
self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_2,
|
||||
'Bound action does not match definition')
|
||||
#second action - this ones comes last because it was re-created with a different name
|
||||
assert len(actions[1]) == 3, "Malformed action definition"
|
||||
assert actions[1][1] == 'OnDblClick Action New', 'Re-Registering an action should replace it'
|
||||
assert isinstance(actions[1][2], dict) and actions[1][2]['id'] == act_id_1, 'Bound action does not match definition'
|
||||
self.assertEqual(len(actions[1]), 3, "Malformed action definition")
|
||||
self.assertEqual(actions[1][1], 'OnDblClick Action New', 'Re-Registering an action should replace it')
|
||||
self.assertTrue(isinstance(actions[1][2], dict) and actions[1][2]['id'] == act_id_1,
|
||||
'Bound action does not match definition')
|
||||
|
||||
actions = ir_values.get(self.cr, self.uid, 'action', 'client_action_multi', ['unexisting_model'])
|
||||
assert len(actions) == 1, "Mismatching number of bound actions"
|
||||
assert len(actions[0]) == 3, "Malformed action definition"
|
||||
assert actions[0][1] == 'Side Wizard', 'Bound action does not match definition'
|
||||
assert isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_3, 'Bound action does not match definition'
|
||||
actions = ir_values.get('action', 'client_action_multi', ['unexisting_model'])
|
||||
self.assertEqual(len(actions), 1, "Mismatching number of bound actions")
|
||||
self.assertEqual(len(actions[0]), 3, "Malformed action definition")
|
||||
self.assertEqual(actions[0][1], 'Side Wizard', 'Bound action does not match definition')
|
||||
self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_3,
|
||||
'Bound action does not match definition')
|
||||
|
||||
actions = ir_values.get(self.cr, self.uid, 'action', 'client_print_multi', ['unexisting_model'])
|
||||
assert len(actions) == 1, "Mismatching number of bound actions"
|
||||
assert len(actions[0]) == 3, "Malformed action definition"
|
||||
assert actions[0][1] == 'Nice Report', 'Bound action does not match definition'
|
||||
assert isinstance(actions[0][2], dict) and actions[0][2]['id'] == report_id, 'Bound action does not match definition'
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
actions = ir_values.get('action', 'client_print_multi', ['unexisting_model'])
|
||||
self.assertEqual(len(actions), 1, "Mismatching number of bound actions")
|
||||
self.assertEqual(len(actions[0]), 3, "Malformed action definition")
|
||||
self.assertEqual(actions[0][1], 'Nice Report', 'Bound action does not match definition')
|
||||
self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == report_id,
|
||||
'Bound action does not match definition')
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# This test can be run stand-alone with something like:
|
||||
# > PYTHONPATH=. python2 openerp/tests/test_misc.py
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import cgi
|
||||
import unittest
|
||||
|
||||
from openerp.tools import html_sanitize, append_content_to_html, plaintext2html, email_split
|
||||
import test_mail_examples
|
||||
from odoo.tools import html_sanitize, append_content_to_html, plaintext2html, email_split
|
||||
from . import test_mail_examples
|
||||
|
||||
|
||||
class TestSanitizer(unittest.TestCase):
|
||||
@@ -325,7 +322,3 @@ class TestEmailTools(unittest.TestCase):
|
||||
]
|
||||
for text, expected in cases:
|
||||
self.assertEqual(email_split(text), expected, 'email_split is broken')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
MISC_HTML_SOURCE = """
|
||||
<font size="2" style="color: rgb(31, 31, 31); font-family: monospace; font-variant: normal; line-height: normal; ">test1</font>
|
||||
@@ -515,4 +515,4 @@ REMOVE_CLASS_IN = [
|
||||
REMOVE_CLASS_OUT = [
|
||||
'<div class="modal-backdrop in">',
|
||||
'<div class="modal-content openerp">',
|
||||
'<div class="modal-header">']
|
||||
'<div class="modal-header">']
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
import openerp.tests.common as common
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
class test_menu(common.TransactionCase):
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
def setUp(self):
|
||||
super(test_menu,self).setUp()
|
||||
self.Menus = self.registry('ir.ui.menu')
|
||||
|
||||
class TestMenu(TransactionCase):
|
||||
|
||||
def test_00_menu_deletion(self):
|
||||
"""Verify that menu deletion works properly when there are child menus, and those
|
||||
are indeed made orphans"""
|
||||
cr, uid, Menus = self.cr, self.uid, self.Menus
|
||||
|
||||
# Generic trick necessary for search() calls to avoid hidden menus
|
||||
ctx = {'ir.ui.menu.full_list': True}
|
||||
|
||||
root_id = Menus.create(cr, uid, {'name': 'Test root'})
|
||||
child1_id = Menus.create(cr, uid, {'name': 'Test child 1', 'parent_id': root_id})
|
||||
child2_id = Menus.create(cr, uid, {'name': 'Test child 2', 'parent_id': root_id})
|
||||
child21_id = Menus.create(cr, uid, {'name': 'Test child 2-1', 'parent_id': child2_id})
|
||||
|
||||
all_ids = [root_id, child1_id, child2_id, child21_id]
|
||||
Menu = self.env['ir.ui.menu']
|
||||
root = Menu.create({'name': 'Test root'})
|
||||
child1 = Menu.create({'name': 'Test child 1', 'parent_id': root.id})
|
||||
child2 = Menu.create({'name': 'Test child 2', 'parent_id': root.id})
|
||||
child21 = Menu.create({'name': 'Test child 2-1', 'parent_id': child2.id})
|
||||
all_ids = [root.id, child1.id, child2.id, child21.id]
|
||||
|
||||
# delete and check that direct children are promoted to top-level
|
||||
# cfr. explanation in menu.unlink()
|
||||
Menus.unlink(cr, uid, [root_id])
|
||||
root.unlink()
|
||||
|
||||
remaining_ids = Menus.search(cr, uid, [('id', 'in', all_ids)], order="id", context=ctx)
|
||||
self.assertEqual([child1_id, child2_id, child21_id], remaining_ids)
|
||||
# Generic trick necessary for search() calls to avoid hidden menus
|
||||
Menu = self.env['ir.ui.menu'].with_context({'ir.ui.menu.full_list': True})
|
||||
|
||||
orphan_ids = Menus.search(cr, uid, [('id', 'in', all_ids), ('parent_id', '=', False)], order="id", context=ctx)
|
||||
self.assertEqual([child1_id, child2_id], orphan_ids)
|
||||
remaining = Menu.search([('id', 'in', all_ids)], order="id")
|
||||
self.assertEqual([child1.id, child2.id, child21.id], remaining.ids)
|
||||
|
||||
orphans = Menu.search([('id', 'in', all_ids), ('parent_id', '=', False)], order="id")
|
||||
self.assertEqual([child1.id, child2.id], orphans.ids)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import unittest
|
||||
|
||||
from openerp.tools import misc
|
||||
from odoo.tools import misc
|
||||
|
||||
|
||||
class test_countingstream(unittest.TestCase):
|
||||
class TestCountingStream(unittest.TestCase):
|
||||
def test_empty_stream(self):
|
||||
s = misc.CountingStream(iter([]))
|
||||
self.assertEqual(s.index, -1)
|
||||
@@ -32,6 +35,3 @@ class test_countingstream(unittest.TestCase):
|
||||
self.assertEqual(s.index, 0)
|
||||
self.assertIsNone(next(s, None))
|
||||
self.assertEqual(s.index, 0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,117 +1,125 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from openerp.tools import mute_logger
|
||||
from openerp.tests import common
|
||||
|
||||
UID = common.ADMIN_USER_ID
|
||||
from odoo.exceptions import AccessError, MissingError
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
class TestORM(common.TransactionCase):
|
||||
""" test special behaviors of ORM CRUD functions
|
||||
|
||||
TODO: use real Exceptions types instead of Exception """
|
||||
|
||||
def setUp(self):
|
||||
super(TestORM, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
self.partner = self.registry('res.partner')
|
||||
self.users = self.registry('res.users')
|
||||
self.p1 = self.partner.name_create(cr, uid, 'W')[0]
|
||||
self.p2 = self.partner.name_create(cr, uid, 'Y')[0]
|
||||
self.ir_rule = self.registry('ir.rule')
|
||||
|
||||
# sample unprivileged user
|
||||
employee_gid = self.ref('base.group_user')
|
||||
self.uid2 = self.users.create(cr, uid, {'name': 'test user', 'login': 'test', 'groups_id': [4,employee_gid]})
|
||||
class TestORM(TransactionCase):
|
||||
""" test special behaviors of ORM CRUD functions """
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def testAccessDeletedRecords(self):
|
||||
def test_access_deleted_records(self):
|
||||
""" Verify that accessing deleted records works as expected """
|
||||
cr, uid, uid2, p1, p2 = self.cr, self.uid, self.uid2, self.p1, self.p2
|
||||
self.partner.unlink(cr, uid, [p1])
|
||||
p1 = self.env['res.partner'].create({'name': 'W'})
|
||||
p2 = self.env['res.partner'].create({'name': 'Y'})
|
||||
p1.unlink()
|
||||
|
||||
# read() is expected to skip deleted records because our API is not
|
||||
# transactional for a sequence of search()->read() performed from the
|
||||
# client-side... a concurrent deletion could therefore cause spurious
|
||||
# exceptions even when simply opening a list view!
|
||||
# /!\ Using unprileged user to detect former side effects of ir.rules!
|
||||
self.assertEqual([{'id': p2, 'name': 'Y'}], self.partner.read(cr, uid2, [p1,p2], ['name']), "read() should skip deleted records")
|
||||
self.assertEqual([], self.partner.read(cr, uid2, [p1], ['name']), "read() should skip deleted records")
|
||||
user = self.env['res.users'].create({
|
||||
'name': 'test user',
|
||||
'login': 'test2',
|
||||
'groups_id': [4, self.ref('base.group_user')],
|
||||
})
|
||||
ps = (p1 + p2).sudo(user)
|
||||
self.assertEqual([{'id': p2.id, 'name': 'Y'}], ps.read(['name']), "read() should skip deleted records")
|
||||
self.assertEqual([], ps[0].read(['name']), "read() should skip deleted records")
|
||||
|
||||
# Deleting an already deleted record should be simply ignored
|
||||
self.assertTrue(self.partner.unlink(cr, uid, [p1]), "Re-deleting should be a no-op")
|
||||
self.assertTrue(p1.unlink(), "Re-deleting should be a no-op")
|
||||
|
||||
# Updating an already deleted record should raise, even as admin
|
||||
with self.assertRaises(Exception):
|
||||
self.partner.write(cr, uid, [p1], {'name': 'foo'})
|
||||
with self.assertRaises(MissingError):
|
||||
p1.write({'name': 'foo'})
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def testAccessFilteredRecords(self):
|
||||
def test_access_filtered_records(self):
|
||||
""" Verify that accessing filtered records works as expected for non-admin user """
|
||||
cr, uid, uid2, p1, p2 = self.cr, self.uid, self.uid2, self.p1, self.p2
|
||||
partner_model = self.registry('ir.model').search(cr, uid, [('model','=','res.partner')])[0]
|
||||
self.ir_rule.create(cr, uid, {'name': 'Y is invisible',
|
||||
'domain_force': [('id', '!=', p1)],
|
||||
'model_id': partner_model})
|
||||
p1 = self.env['res.partner'].create({'name': 'W'})
|
||||
p2 = self.env['res.partner'].create({'name': 'Y'})
|
||||
user = self.env['res.users'].create({
|
||||
'name': 'test user',
|
||||
'login': 'test2',
|
||||
'groups_id': [4, self.ref('base.group_user')],
|
||||
})
|
||||
|
||||
partner_model = self.env['ir.model'].search([('model','=','res.partner')])
|
||||
self.env['ir.rule'].create({
|
||||
'name': 'Y is invisible',
|
||||
'domain_force': [('id', '!=', p1.id)],
|
||||
'model_id': partner_model.id,
|
||||
})
|
||||
|
||||
# search as unprivileged user
|
||||
partners = self.partner.search(cr, uid2, [])
|
||||
self.assertFalse(p1 in partners, "W should not be visible...")
|
||||
self.assertTrue(p2 in partners, "... but Y should be visible")
|
||||
partners = self.env['res.partner'].sudo(user).search([])
|
||||
self.assertNotIn(p1, partners, "W should not be visible...")
|
||||
self.assertIn(p2, partners, "... but Y should be visible")
|
||||
|
||||
# read as unprivileged user
|
||||
with self.assertRaises(Exception):
|
||||
self.partner.read(cr, uid2, [p1], ['name'])
|
||||
with self.assertRaises(AccessError):
|
||||
p1.sudo(user).read(['name'])
|
||||
# write as unprivileged user
|
||||
with self.assertRaises(Exception):
|
||||
self.partner.write(cr, uid2, [p1], {'name': 'foo'})
|
||||
with self.assertRaises(AccessError):
|
||||
p1.sudo(user).write({'name': 'foo'})
|
||||
# unlink as unprivileged user
|
||||
with self.assertRaises(Exception):
|
||||
self.partner.unlink(cr, uid2, [p1])
|
||||
with self.assertRaises(AccessError):
|
||||
p1.sudo(user).unlink()
|
||||
|
||||
# Prepare mixed case
|
||||
self.partner.unlink(cr, uid, [p2])
|
||||
p2.unlink()
|
||||
# read mixed records: some deleted and some filtered
|
||||
with self.assertRaises(Exception):
|
||||
self.partner.read(cr, uid2, [p1,p2], ['name'])
|
||||
with self.assertRaises(AccessError):
|
||||
(p1 + p2).sudo(user).read(['name'])
|
||||
# delete mixed records: some deleted and some filtered
|
||||
with self.assertRaises(Exception):
|
||||
self.partner.unlink(cr, uid2, [p1,p2])
|
||||
with self.assertRaises(AccessError):
|
||||
(p1 + p2).sudo(user).unlink()
|
||||
|
||||
def test_multi_read(self):
|
||||
record_id = self.partner.create(self.cr, UID, {'name': 'MyPartner1'})
|
||||
records = self.partner.read(self.cr, UID, [record_id])
|
||||
self.assertIsInstance(records, list)
|
||||
def test_read(self):
|
||||
partner = self.env['res.partner'].create({'name': 'MyPartner1'})
|
||||
result = partner.read()
|
||||
self.assertIsInstance(result, list)
|
||||
|
||||
def test_one_read(self):
|
||||
record_id = self.partner.create(self.cr, UID, {'name': 'MyPartner1'})
|
||||
record = self.partner.read(self.cr, UID, record_id)
|
||||
self.assertIsInstance(record, dict)
|
||||
# special cases for the old API only
|
||||
result = self.registry('res.partner').read(self.cr, self.uid, [partner.id])
|
||||
self.assertIsInstance(result, list)
|
||||
result = self.registry('res.partner').read(self.cr, self.uid, partner.id)
|
||||
self.assertIsInstance(result, dict)
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_search_read(self):
|
||||
partner = self.env['res.partner']
|
||||
|
||||
# simple search_read
|
||||
self.partner.create(self.cr, UID, {'name': 'MyPartner1'})
|
||||
found = self.partner.search_read(self.cr, UID, [['name', '=', 'MyPartner1']], ['name'])
|
||||
partner.create({'name': 'MyPartner1'})
|
||||
found = partner.search_read([('name', '=', 'MyPartner1')], ['name'])
|
||||
self.assertEqual(len(found), 1)
|
||||
self.assertEqual(found[0]['name'], 'MyPartner1')
|
||||
self.assertTrue('id' in found[0])
|
||||
self.assertIn('id', found[0])
|
||||
|
||||
# search_read correct order
|
||||
self.partner.create(self.cr, UID, {'name': 'MyPartner2'})
|
||||
found = self.partner.search_read(self.cr, UID, [['name', 'like', 'MyPartner']], ['name'], order="name")
|
||||
partner.create({'name': 'MyPartner2'})
|
||||
found = partner.search_read([('name', 'like', 'MyPartner')], ['name'], order="name")
|
||||
self.assertEqual(len(found), 2)
|
||||
self.assertEqual(found[0]['name'], 'MyPartner1')
|
||||
self.assertEqual(found[1]['name'], 'MyPartner2')
|
||||
found = self.partner.search_read(self.cr, UID, [['name', 'like', 'MyPartner']], ['name'], order="name desc")
|
||||
found = partner.search_read([('name', 'like', 'MyPartner')], ['name'], order="name desc")
|
||||
self.assertEqual(len(found), 2)
|
||||
self.assertEqual(found[0]['name'], 'MyPartner2')
|
||||
self.assertEqual(found[1]['name'], 'MyPartner1')
|
||||
|
||||
# search_read that finds nothing
|
||||
found = self.partner.search_read(self.cr, UID, [['name', '=', 'Does not exists']], ['name'])
|
||||
found = partner.search_read([('name', '=', 'Does not exists')], ['name'])
|
||||
self.assertEqual(len(found), 0)
|
||||
|
||||
def test_exists(self):
|
||||
partner = self.partner.browse(self.cr, UID, [])
|
||||
partner = self.env['res.partner']
|
||||
|
||||
# check that records obtained from search exist
|
||||
recs = partner.search([])
|
||||
@@ -123,7 +131,7 @@ class TestORM(common.TransactionCase):
|
||||
self.assertFalse(recs.exists())
|
||||
|
||||
def test_groupby_date(self):
|
||||
partners = dict(
|
||||
partners_data = dict(
|
||||
A='2012-11-19',
|
||||
B='2012-12-17',
|
||||
C='2012-12-31',
|
||||
@@ -133,42 +141,37 @@ class TestORM(common.TransactionCase):
|
||||
G='2013-02-11',
|
||||
)
|
||||
|
||||
all_partners = []
|
||||
partners_by_day = defaultdict(set)
|
||||
partners_by_month = defaultdict(set)
|
||||
partners_by_year = defaultdict(set)
|
||||
partner_ids = []
|
||||
partner_ids_by_day = defaultdict(list)
|
||||
partner_ids_by_month = defaultdict(list)
|
||||
partner_ids_by_year = defaultdict(list)
|
||||
|
||||
for name, date in partners.items():
|
||||
p = self.partner.create(self.cr, UID, dict(name=name, date=date))
|
||||
all_partners.append(p)
|
||||
partners_by_day[date].add(p)
|
||||
partners_by_month[date.rsplit('-', 1)[0]].add(p)
|
||||
partners_by_year[date.split('-', 1)[0]].add(p)
|
||||
partners = self.env['res.partner']
|
||||
for name, date in partners_data.items():
|
||||
p = partners.create(dict(name=name, date=date))
|
||||
partner_ids.append(p.id)
|
||||
partner_ids_by_day[date].append(p.id)
|
||||
partner_ids_by_month[date.rsplit('-', 1)[0]].append(p.id)
|
||||
partner_ids_by_year[date.split('-', 1)[0]].append(p.id)
|
||||
|
||||
def read_group(interval, domain=None):
|
||||
main_domain = [('id', 'in', all_partners)]
|
||||
if domain:
|
||||
domain = ['&'] + main_domain + domain
|
||||
else:
|
||||
domain = main_domain
|
||||
|
||||
rg = self.partner.read_group(self.cr, self.uid, domain, ['date'], 'date' + ':' + interval)
|
||||
def read_group(interval):
|
||||
domain = [('id', 'in', partner_ids)]
|
||||
result = {}
|
||||
for r in rg:
|
||||
result[r['date:' + interval]] = set(self.partner.search(self.cr, self.uid, r['__domain']))
|
||||
for grp in partners.read_group(domain, ['date'], ['date:' + interval]):
|
||||
result[grp['date:' + interval]] = partners.search(grp['__domain'])
|
||||
return result
|
||||
|
||||
self.assertEqual(len(read_group('day')), len(partners_by_day))
|
||||
self.assertEqual(len(read_group('month')), len(partners_by_month))
|
||||
self.assertEqual(len(read_group('year')), len(partners_by_year))
|
||||
self.assertEqual(len(read_group('day')), len(partner_ids_by_day))
|
||||
self.assertEqual(len(read_group('month')), len(partner_ids_by_month))
|
||||
self.assertEqual(len(read_group('year')), len(partner_ids_by_year))
|
||||
|
||||
rg = self.partner.read_group(self.cr, self.uid, [('id', 'in', all_partners)],
|
||||
['date'], ['date:month', 'date:day'], lazy=False)
|
||||
self.assertEqual(len(rg), len(all_partners))
|
||||
res = partners.read_group([('id', 'in', partner_ids)], ['date'],
|
||||
['date:month', 'date:day'], lazy=False)
|
||||
self.assertEqual(len(res), len(partner_ids))
|
||||
|
||||
def test_write_duplicate(self):
|
||||
cr, uid, p1 = self.cr, self.uid, self.p1
|
||||
self.partner.write(cr, uid, [p1, p1], {'name': 'X'})
|
||||
p1 = self.env['res.partner'].create({'name': 'W'})
|
||||
(p1 + p1).write({'name': 'X'})
|
||||
|
||||
def test_m2m_store_trigger(self):
|
||||
group_user = self.env.ref('base.group_user')
|
||||
@@ -187,110 +190,93 @@ class TestORM(common.TransactionCase):
|
||||
self.assertTrue(user.share)
|
||||
|
||||
|
||||
class TestInherits(common.TransactionCase):
|
||||
class TestInherits(TransactionCase):
|
||||
""" test the behavior of the orm for models that use _inherits;
|
||||
specifically: res.users, that inherits from res.partner
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestInherits, self).setUp()
|
||||
self.partner = self.registry('res.partner')
|
||||
self.user = self.registry('res.users')
|
||||
|
||||
def test_default(self):
|
||||
""" `default_get` cannot return a dictionary or a new id """
|
||||
defaults = self.user.default_get(self.cr, UID, ['partner_id'])
|
||||
defaults = self.env['res.users'].default_get(['partner_id'])
|
||||
if 'partner_id' in defaults:
|
||||
self.assertIsInstance(defaults['partner_id'], (bool, int, long))
|
||||
|
||||
def test_create(self):
|
||||
""" creating a user should automatically create a new partner """
|
||||
partners_before = self.partner.search(self.cr, UID, [])
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
|
||||
foo = self.user.browse(self.cr, UID, foo_id)
|
||||
partners_before = self.env['res.partner'].search([])
|
||||
user_foo = self.env['res.users'].create({'name': 'Foo', 'login': 'foo'})
|
||||
|
||||
self.assertNotIn(foo.partner_id.id, partners_before)
|
||||
self.assertNotIn(user_foo.partner_id, partners_before)
|
||||
|
||||
def test_create_with_ancestor(self):
|
||||
""" creating a user with a specific 'partner_id' should not create a new partner """
|
||||
par_id = self.partner.create(self.cr, UID, {'name': 'Foo'})
|
||||
partners_before = self.partner.search(self.cr, UID, [])
|
||||
foo_id = self.user.create(self.cr, UID, {'partner_id': par_id, 'login': 'foo', 'password': 'foo'})
|
||||
partners_after = self.partner.search(self.cr, UID, [])
|
||||
partner_foo = self.env['res.partner'].create({'name': 'Foo'})
|
||||
partners_before = self.env['res.partner'].search([])
|
||||
user_foo = self.env['res.users'].create({'partner_id': partner_foo.id, 'login': 'foo'})
|
||||
partners_after = self.env['res.partner'].search([])
|
||||
|
||||
self.assertEqual(set(partners_before), set(partners_after))
|
||||
|
||||
foo = self.user.browse(self.cr, UID, foo_id)
|
||||
self.assertEqual(foo.name, 'Foo')
|
||||
self.assertEqual(foo.partner_id.id, par_id)
|
||||
self.assertEqual(partners_before, partners_after)
|
||||
self.assertEqual(user_foo.name, 'Foo')
|
||||
self.assertEqual(user_foo.partner_id, partner_foo)
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_read(self):
|
||||
""" inherited fields should be read without any indirection """
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
|
||||
foo_values, = self.user.read(self.cr, UID, [foo_id])
|
||||
partner_id = foo_values['partner_id'][0]
|
||||
partner_values, = self.partner.read(self.cr, UID, [partner_id])
|
||||
self.assertEqual(foo_values['name'], partner_values['name'])
|
||||
user_foo = self.env['res.users'].create({'name': 'Foo', 'login': 'foo'})
|
||||
user_values, = user_foo.read()
|
||||
partner_values, = user_foo.partner_id.read()
|
||||
|
||||
foo = self.user.browse(self.cr, UID, foo_id)
|
||||
self.assertEqual(foo.name, foo.partner_id.name)
|
||||
self.assertEqual(user_values['name'], partner_values['name'])
|
||||
self.assertEqual(user_foo.name, user_foo.partner_id.name)
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_copy(self):
|
||||
""" copying a user should automatically copy its partner, too """
|
||||
foo_id = self.user.create(self.cr, UID, {
|
||||
user_foo = self.env['res.users'].create({
|
||||
'name': 'Foo',
|
||||
'login': 'foo',
|
||||
'password': 'foo',
|
||||
'supplier': True,
|
||||
})
|
||||
foo_before, = self.user.read(self.cr, UID, [foo_id])
|
||||
foo_before, = user_foo.read()
|
||||
del foo_before['__last_update']
|
||||
bar_id = self.user.copy(self.cr, UID, foo_id, {
|
||||
'login': 'bar',
|
||||
'password': 'bar',
|
||||
})
|
||||
foo_after, = self.user.read(self.cr, UID, [foo_id])
|
||||
user_bar = user_foo.copy({'login': 'bar'})
|
||||
foo_after, = user_foo.read()
|
||||
del foo_after['__last_update']
|
||||
|
||||
self.assertEqual(foo_before, foo_after)
|
||||
|
||||
foo, bar = self.user.browse(self.cr, UID, [foo_id, bar_id])
|
||||
self.assertEqual(bar.name, 'Foo (copy)')
|
||||
self.assertEqual(bar.login, 'bar')
|
||||
self.assertEqual(foo.supplier, bar.supplier)
|
||||
self.assertNotEqual(foo.id, bar.id)
|
||||
self.assertNotEqual(foo.partner_id.id, bar.partner_id.id)
|
||||
self.assertEqual(user_bar.name, 'Foo (copy)')
|
||||
self.assertEqual(user_bar.login, 'bar')
|
||||
self.assertEqual(user_foo.supplier, user_bar.supplier)
|
||||
self.assertNotEqual(user_foo.id, user_bar.id)
|
||||
self.assertNotEqual(user_foo.partner_id.id, user_bar.partner_id.id)
|
||||
|
||||
@mute_logger('openerp.models')
|
||||
def test_copy_with_ancestor(self):
|
||||
""" copying a user with 'parent_id' in defaults should not duplicate the partner """
|
||||
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo',
|
||||
user_foo = self.env['res.users'].create({'name': 'Foo', 'login': 'foo', 'password': 'foo',
|
||||
'login_date': '2016-01-01', 'signature': 'XXX'})
|
||||
par_id = self.partner.create(self.cr, UID, {'name': 'Bar'})
|
||||
partner_bar = self.env['res.partner'].create({'name': 'Bar'})
|
||||
|
||||
foo_before, = self.user.read(self.cr, UID, [foo_id])
|
||||
foo_before, = user_foo.read()
|
||||
del foo_before['__last_update']
|
||||
del foo_before['login_date']
|
||||
partners_before = self.partner.search(self.cr, UID, [])
|
||||
bar_id = self.user.copy(self.cr, UID, foo_id, {'partner_id': par_id, 'login': 'bar'})
|
||||
foo_after, = self.user.read(self.cr, UID, [foo_id])
|
||||
partners_before = self.env['res.partner'].search([])
|
||||
user_bar = user_foo.copy({'partner_id': partner_bar.id, 'login': 'bar'})
|
||||
foo_after, = user_foo.read()
|
||||
del foo_after['__last_update']
|
||||
del foo_after['login_date']
|
||||
partners_after = self.partner.search(self.cr, UID, [])
|
||||
partners_after = self.env['res.partner'].search([])
|
||||
|
||||
self.assertEqual(foo_before, foo_after)
|
||||
self.assertEqual(set(partners_before), set(partners_after))
|
||||
|
||||
foo, bar = self.user.browse(self.cr, UID, [foo_id, bar_id])
|
||||
self.assertNotEqual(foo.id, bar.id)
|
||||
self.assertEqual(bar.partner_id.id, par_id)
|
||||
self.assertEqual(bar.login, 'bar', "login is given from copy parameters")
|
||||
self.assertFalse(bar.password, "password should not be copied from original record")
|
||||
self.assertEqual(bar.name, 'Bar', "name is given from specific partner")
|
||||
self.assertEqual(bar.signature, foo.signature, "signature should be copied")
|
||||
self.assertEqual(partners_before, partners_after)
|
||||
|
||||
self.assertNotEqual(user_foo.id, user_bar.id)
|
||||
self.assertEqual(user_bar.partner_id.id, partner_bar.id)
|
||||
self.assertEqual(user_bar.login, 'bar', "login is given from copy parameters")
|
||||
self.assertFalse(user_bar.password, "password should not be copied from original record")
|
||||
self.assertEqual(user_bar.name, 'Bar', "name is given from specific partner")
|
||||
self.assertEqual(user_bar.signature, user_foo.signature, "signature should be copied")
|
||||
|
||||
|
||||
CREATE = lambda values: (0, False, values)
|
||||
@@ -301,11 +287,8 @@ LINK_TO = lambda id: (4, id, False)
|
||||
DELETE_ALL = lambda: (5, False, False)
|
||||
REPLACE_WITH = lambda ids: (6, False, ids)
|
||||
|
||||
def sorted_by_id(list_of_dicts):
|
||||
"sort dictionaries by their 'id' field; useful for comparisons"
|
||||
return sorted(list_of_dicts, key=lambda d: d.get('id'))
|
||||
|
||||
class TestO2MSerialization(common.TransactionCase):
|
||||
class TestO2MSerialization(TransactionCase):
|
||||
""" test the orm method 'write' on one2many fields """
|
||||
|
||||
def setUp(self):
|
||||
@@ -314,136 +297,121 @@ class TestO2MSerialization(common.TransactionCase):
|
||||
|
||||
def test_no_command(self):
|
||||
" empty list of commands yields an empty list of records "
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', [])
|
||||
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', [])
|
||||
self.assertEqual(results, [])
|
||||
|
||||
def test_CREATE_commands(self):
|
||||
" returns the VALUES dict as-is "
|
||||
values = [{'foo': 'bar'}, {'foo': 'baz'}, {'foo': 'baq'}]
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', map(CREATE, values))
|
||||
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', map(CREATE, values))
|
||||
self.assertEqual(results, values)
|
||||
|
||||
def test_LINK_TO_command(self):
|
||||
" reads the records from the database, records are returned with their ids. "
|
||||
ids = [
|
||||
self.partner.create(self.cr, UID, {'name': 'foo'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'bar'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'baz'})
|
||||
self.env['res.partner'].create({'name': 'foo'}).id,
|
||||
self.env['res.partner'].create({'name': 'bar'}).id,
|
||||
self.env['res.partner'].create({'name': 'baz'}).id,
|
||||
]
|
||||
commands = map(LINK_TO, ids)
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', commands, ['name'])
|
||||
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
|
||||
self.assertItemsEqual(results, [
|
||||
{'id': ids[0], 'name': 'foo'},
|
||||
{'id': ids[1], 'name': 'bar'},
|
||||
{'id': ids[2], 'name': 'baz'}
|
||||
]))
|
||||
{'id': ids[2], 'name': 'baz'},
|
||||
])
|
||||
|
||||
def test_bare_ids_command(self):
|
||||
" same as the equivalent LINK_TO commands "
|
||||
ids = [
|
||||
self.partner.create(self.cr, UID, {'name': 'foo'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'bar'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'baz'})
|
||||
self.env['res.partner'].create({'name': 'foo'}).id,
|
||||
self.env['res.partner'].create({'name': 'bar'}).id,
|
||||
self.env['res.partner'].create({'name': 'baz'}).id,
|
||||
]
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', ids, ['name'])
|
||||
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', ids, ['name'])
|
||||
self.assertItemsEqual(results, [
|
||||
{'id': ids[0], 'name': 'foo'},
|
||||
{'id': ids[1], 'name': 'bar'},
|
||||
{'id': ids[2], 'name': 'baz'}
|
||||
]))
|
||||
{'id': ids[2], 'name': 'baz'},
|
||||
])
|
||||
|
||||
def test_UPDATE_command(self):
|
||||
" take the in-db records and merge the provided information in "
|
||||
id_foo = self.partner.create(self.cr, UID, {'name': 'foo'})
|
||||
id_bar = self.partner.create(self.cr, UID, {'name': 'bar'})
|
||||
id_baz = self.partner.create(self.cr, UID, {'name': 'baz', 'city': 'tag'})
|
||||
foo = self.env['res.partner'].create({'name': 'foo'})
|
||||
bar = self.env['res.partner'].create({'name': 'bar'})
|
||||
baz = self.env['res.partner'].create({'name': 'baz', 'city': 'tag'})
|
||||
commands = [
|
||||
LINK_TO(foo.id),
|
||||
UPDATE(bar.id, {'name': 'qux', 'city': 'tagtag'}),
|
||||
UPDATE(baz.id, {'name': 'quux'}),
|
||||
]
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', [
|
||||
LINK_TO(id_foo),
|
||||
UPDATE(id_bar, {'name': 'qux', 'city': 'tagtag'}),
|
||||
UPDATE(id_baz, {'name': 'quux'})
|
||||
], ['name', 'city'])
|
||||
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
{'id': id_foo, 'name': 'foo', 'city': False},
|
||||
{'id': id_bar, 'name': 'qux', 'city': 'tagtag'},
|
||||
{'id': id_baz, 'name': 'quux', 'city': 'tag'}
|
||||
]))
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name', 'city'])
|
||||
self.assertItemsEqual(results, [
|
||||
{'id': foo.id, 'name': 'foo', 'city': False},
|
||||
{'id': bar.id, 'name': 'qux', 'city': 'tagtag'},
|
||||
{'id': baz.id, 'name': 'quux', 'city': 'tag'},
|
||||
])
|
||||
|
||||
def test_DELETE_command(self):
|
||||
" deleted records are not returned at all. "
|
||||
ids = [
|
||||
self.partner.create(self.cr, UID, {'name': 'foo'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'bar'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'baz'})
|
||||
self.env['res.partner'].create({'name': 'foo'}).id,
|
||||
self.env['res.partner'].create({'name': 'bar'}).id,
|
||||
self.env['res.partner'].create({'name': 'baz'}).id,
|
||||
]
|
||||
commands = [DELETE(ids[0]), DELETE(ids[1]), DELETE(ids[2])]
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', commands, ['name'])
|
||||
commands = map(DELETE, ids)
|
||||
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
|
||||
self.assertEqual(results, [])
|
||||
|
||||
def test_mixed_commands(self):
|
||||
ids = [
|
||||
self.partner.create(self.cr, UID, {'name': name})
|
||||
self.env['res.partner'].create({'name': name}).id
|
||||
for name in ['NObar', 'baz', 'qux', 'NOquux', 'NOcorge', 'garply']
|
||||
]
|
||||
commands = [
|
||||
CREATE({'name': 'foo'}),
|
||||
UPDATE(ids[0], {'name': 'bar'}),
|
||||
LINK_TO(ids[1]),
|
||||
DELETE(ids[2]),
|
||||
UPDATE(ids[3], {'name': 'quux',}),
|
||||
UPDATE(ids[4], {'name': 'corge'}),
|
||||
CREATE({'name': 'grault'}),
|
||||
LINK_TO(ids[5]),
|
||||
]
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', [
|
||||
CREATE({'name': 'foo'}),
|
||||
UPDATE(ids[0], {'name': 'bar'}),
|
||||
LINK_TO(ids[1]),
|
||||
DELETE(ids[2]),
|
||||
UPDATE(ids[3], {'name': 'quux',}),
|
||||
UPDATE(ids[4], {'name': 'corge'}),
|
||||
CREATE({'name': 'grault'}),
|
||||
LINK_TO(ids[5])
|
||||
], ['name'])
|
||||
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
|
||||
self.assertItemsEqual(results, [
|
||||
{'name': 'foo'},
|
||||
{'id': ids[0], 'name': 'bar'},
|
||||
{'id': ids[1], 'name': 'baz'},
|
||||
{'id': ids[3], 'name': 'quux'},
|
||||
{'id': ids[4], 'name': 'corge'},
|
||||
{'name': 'grault'},
|
||||
{'id': ids[5], 'name': 'garply'}
|
||||
]))
|
||||
{'id': ids[5], 'name': 'garply'},
|
||||
])
|
||||
|
||||
def test_LINK_TO_pairs(self):
|
||||
"LINK_TO commands can be written as pairs, instead of triplets"
|
||||
ids = [
|
||||
self.partner.create(self.cr, UID, {'name': 'foo'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'bar'}),
|
||||
self.partner.create(self.cr, UID, {'name': 'baz'})
|
||||
self.env['res.partner'].create({'name': 'foo'}).id,
|
||||
self.env['res.partner'].create({'name': 'bar'}).id,
|
||||
self.env['res.partner'].create({'name': 'baz'}).id,
|
||||
]
|
||||
commands = map(lambda id: (4, id), ids)
|
||||
commands = [(4, id) for id in ids]
|
||||
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', commands, ['name'])
|
||||
|
||||
self.assertEqual(sorted_by_id(results), sorted_by_id([
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
|
||||
self.assertItemsEqual(results, [
|
||||
{'id': ids[0], 'name': 'foo'},
|
||||
{'id': ids[1], 'name': 'bar'},
|
||||
{'id': ids[2], 'name': 'baz'}
|
||||
]))
|
||||
{'id': ids[2], 'name': 'baz'},
|
||||
])
|
||||
|
||||
def test_singleton_commands(self):
|
||||
"DELETE_ALL can appear as a singleton"
|
||||
results = self.partner.resolve_2many_commands(
|
||||
self.cr, UID, 'child_ids', [DELETE_ALL()], ['name'])
|
||||
|
||||
commands = [DELETE_ALL()]
|
||||
results = self.env['res.partner'].resolve_2many_commands('child_ids', commands, ['name'])
|
||||
self.assertEqual(results, [])
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.tests import common
|
||||
from openerp.tools import get_cache_key_counter
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools import get_cache_key_counter
|
||||
|
||||
class TestOrmcache(common.TransactionCase):
|
||||
|
||||
class TestOrmcache(TransactionCase):
|
||||
def test_ormcache(self):
|
||||
""" Test the effectiveness of the ormcache() decorator. """
|
||||
IMD = self.env['ir.model.data']
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import unittest
|
||||
from openerp.osv.query import Query
|
||||
|
||||
from odoo.osv.query import Query
|
||||
|
||||
|
||||
class QueryTestCase(unittest.TestCase):
|
||||
|
||||
@@ -1,632 +0,0 @@
|
||||
-
|
||||
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
|
||||
-
|
||||
Test hierarchical search in M2M with parent ID (list of ids)
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_1')])])
|
||||
assert len(ids) == 3, ids
|
||||
-
|
||||
Test hierarchical search in M2M with parent ID (single id)
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'parent_of',ref('categ_1'))])
|
||||
assert len(ids) == 3, ids
|
||||
-
|
||||
Test hierarchical search in M2M with parent IDs
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_root'), ref('categ_0')])])
|
||||
assert len(ids) == 2, ids
|
||||
-
|
||||
Test hierarchical search in M2M with parent IDs
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_0')])])
|
||||
assert len(ids) == 2, ids
|
||||
-
|
||||
Test hierarchical search in M2M with parent IDs
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_1')])])
|
||||
assert len(ids) == 3, ids
|
||||
-
|
||||
Test hierarchical search in M2M with parent IDs
|
||||
-
|
||||
!python {model: res.partner.category }: |
|
||||
ids = self.search(cr, uid, [('id', 'parent_of',[ref('categ_root')])])
|
||||
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)]"}:
|
||||
- list(child_ids) == []
|
||||
-
|
||||
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)]"}:
|
||||
- list(category_id) == []
|
||||
-
|
||||
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 }: |
|
||||
company = self.browse(cr, uid, ref('ymltest_company3'))
|
||||
|
||||
# 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
|
||||
assert res_1 == [ref('ymltest_company3')], "res_1"
|
||||
assert res_2 == [ref('ymltest_company3')], "res_2"
|
||||
|
||||
# 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] == res_partner.search(cr, uid, [('user_ids', '=', 'Dédé Boitaclou')]), "o2m NOT IN matches none on the right side"
|
||||
assert [] == res_partner.search(cr, uid, [('user_ids', 'in', [10000])]), "o2m NOT IN matches none on the 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])) == set(res_partner.search(cr, uid, [('user_ids', '!=', 'Dédé Boitaclou')])), "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
|
||||
|
||||
# parent_of x returns x and its parents (direct or not).
|
||||
company = self.browse(cr, uid, ref('ymltest_company4'))
|
||||
expected = [ref('ymltest_company4'), ref('ymltest_company3')]
|
||||
expected.sort()
|
||||
res_1 = self.search(cr, uid, [('id', 'parent_of', [ref('ymltest_company4')])])
|
||||
res_1.sort()
|
||||
res_2 = self.search(cr, uid, [('id', 'parent_of', ref('ymltest_company4'))])
|
||||
res_2.sort()
|
||||
res_3 = self.search(cr, uid, [('id', 'parent_of', [company.name])])
|
||||
res_3.sort()
|
||||
res_4 = self.search(cr, uid, [('id', 'parent_of', company.name)])
|
||||
res_4.sort()
|
||||
assert res_1 == expected
|
||||
assert res_2 == expected
|
||||
assert res_3 == expected
|
||||
assert res_4 == expected
|
||||
-
|
||||
Equivalent queries, one2many.
|
||||
-
|
||||
!python {model: res.currency }: |
|
||||
# Create a currency and a currency rate
|
||||
res_currency = self.pool['res.currency']
|
||||
res_currency_rate = self.pool['res.currency.rate']
|
||||
currency = res_currency.create(cr, uid, {'name': 'ZZZ', 'symbol': 'ZZZ', 'rounding': 1.0})
|
||||
currency_rate = self.pool['res.currency.rate'].create(cr, uid, {'name': '2010-01-01', 'currency_id': currency, 'rate': 1.0})
|
||||
|
||||
# Search the currency via its rates one2many (the one2many must point back at the currency).
|
||||
max_currency_rate_id = max(res_currency_rate.search(cr, uid, []))
|
||||
currency_rate1 = res_currency_rate.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')])
|
||||
currency_rate2 = res_currency_rate.search(cr, uid, [('id', 'not in', [max_currency_rate_id + 1003])])
|
||||
currency_rate3 = res_currency_rate.search(cr, uid, [('id', 'not in', [])])
|
||||
assert currency_rate1 == currency_rate2 == currency_rate3, 'All 3 results should be the same : empty'
|
||||
default_currency = self.browse(cr, uid, 1)
|
||||
|
||||
# one2many towards another model
|
||||
res_3 = self.search(cr, uid, [('rate_ids', 'in', [x.id for x in default_currency.rate_ids])]) # currencies having a rate of main currency
|
||||
res_4 = self.search(cr, uid, [('rate_ids', 'in', [default_currency.rate_ids[0].id])]) # currencies having first rate of main currency
|
||||
res_5 = self.search(cr, uid, [('rate_ids', 'in', default_currency.rate_ids[0].id)]) # currencies having first rate of main currency
|
||||
# res_6 = self.search(cr, uid, [('rate_ids', 'in', [default_currency.rate_ids[0].name])])
|
||||
# res_7 = self.search(cr, uid, [('rate_ids', '=', default_currency.rate_ids[0].name)])
|
||||
# res_8 = self.search(cr, uid, [('rate_ids', 'like', default_currency.rate_ids[0].name)])
|
||||
|
||||
res_9 = self.search(cr, uid, [('rate_ids', 'like', 'probably_unexisting_name')])
|
||||
# self.search(cr, uid, [('rate_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception
|
||||
assert res_3 == [1], "res_3"
|
||||
assert res_4 == [1], "res_4"
|
||||
assert res_5 == [1], "res_5"
|
||||
# assert res_7 == [1], "res_7"
|
||||
# assert res_8 == [1], "res_8"
|
||||
assert res_9 == [], "res_9"
|
||||
|
||||
# get the currencies referenced by some currency rates using a weird negative domain
|
||||
res_10 = self.search(cr, uid, [('rate_ids', 'not like', 'probably_unexisting_name')])
|
||||
res_11 = self.search(cr, uid, [('rate_ids', 'not in', [max_currency_rate_id + 1])])
|
||||
res_12 = self.search(cr, uid, [('rate_ids', '!=', False)])
|
||||
res_13 = self.search(cr, uid, [('rate_ids', 'not in', [])])
|
||||
res_10.sort()
|
||||
res_11.sort()
|
||||
res_12.sort()
|
||||
res_13.sort()
|
||||
assert res_10 == res_11, 'res_11'
|
||||
assert res_10 == res_12, 'res_12'
|
||||
assert res_10 == res_13, 'res_13'
|
||||
-
|
||||
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_U_TeK')])
|
||||
assert len(all_ids) == 1, "Must match one partner (ASUSTeK), got %r"%all_ids
|
||||
all_ids = self.search(cr, uid, [('name', '=ilike', 'c%')])
|
||||
assert len(all_ids) >= 1, "Must match one partner (China Export), 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 vendor 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', 'vendor'), ('active', '=', False)])
|
||||
assert len(res_ids) != 0, "Record not Found with category vendor 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)"
|
||||
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import unittest
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
#: Stores state information across multiple test classes
|
||||
test_state = None
|
||||
|
||||
def setUpModule():
|
||||
global test_state
|
||||
test_state = {}
|
||||
|
||||
def tearDownModule():
|
||||
global test_state
|
||||
test_state = None
|
||||
|
||||
|
||||
class TestPhaseInstall00(unittest.TestCase):
|
||||
"""
|
||||
WARNING: Relies on tests being run in alphabetical order
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.state = None
|
||||
|
||||
def test_00_setup(self):
|
||||
type(self).state = 'init'
|
||||
|
||||
@common.at_install(False)
|
||||
def test_01_no_install(self):
|
||||
type(self).state = 'error'
|
||||
|
||||
def test_02_check(self):
|
||||
self.assertEqual(self.state, 'init',
|
||||
"Testcase state should not have been transitioned from 00")
|
||||
|
||||
|
||||
class TestPhaseInstall01(unittest.TestCase):
|
||||
at_install = False
|
||||
|
||||
def test_default_norun(self):
|
||||
self.fail("An unmarket test in a non-at-install case should not run")
|
||||
|
||||
@common.at_install(True)
|
||||
def test_set_run(self):
|
||||
test_state['set_at_install'] = True
|
||||
|
||||
|
||||
class TestPhaseInstall02(unittest.TestCase):
|
||||
"""
|
||||
Can't put the check for test_set_run in the same class: if
|
||||
@common.at_install does not work for test_set_run, it won't work for
|
||||
the other one either. Thus move checking of whether test_set_run has
|
||||
correctly run indeed to a separate class.
|
||||
|
||||
Warning: relies on *classes* being run in alphabetical order in test
|
||||
modules
|
||||
"""
|
||||
def test_check_state(self):
|
||||
self.assertTrue(test_state.get('set_at_install'),
|
||||
"The flag should be set if local overriding of runstate")
|
||||
@@ -1,92 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import cgi
|
||||
import collections
|
||||
import json
|
||||
import os.path
|
||||
import glob
|
||||
import re
|
||||
import collections
|
||||
|
||||
from lxml import etree
|
||||
|
||||
import openerp.modules
|
||||
from openerp.addons.base.ir.ir_qweb import QWebContext, FileSystemLoader
|
||||
from openerp.tests import common
|
||||
from odoo.addons.base.ir.ir_qweb import QWebContext, FileSystemLoader
|
||||
from odoo.modules import get_module_resource
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
class TestQWebTField(common.TransactionCase):
|
||||
|
||||
class TestQWebTField(TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestQWebTField, self).setUp()
|
||||
self.env = self.env(context={'inherit_branding': True})
|
||||
self.engine = self.env['ir.qweb']
|
||||
self.env_branding = self.env(context={'inherit_branding': True})
|
||||
self.engine = self.env_branding['ir.qweb']
|
||||
|
||||
def context(self, values):
|
||||
return QWebContext(self.env, values)
|
||||
return QWebContext(self.env_branding, values)
|
||||
|
||||
def test_trivial(self):
|
||||
field = etree.Element('span', {'t-field': u'company.name'})
|
||||
company = self.env['res.company'].create({'name': "My Test Company"})
|
||||
|
||||
Companies = self.registry('res.company')
|
||||
company_id = Companies.create(self.cr, self.uid, {
|
||||
'name': "My Test Company"
|
||||
})
|
||||
result = self.engine.render_node(field, self.context({
|
||||
'company': Companies.browse(self.cr, self.uid, company_id),
|
||||
}))
|
||||
|
||||
result = self.engine.render_node(field, self.context({'company': company}))
|
||||
self.assertEqual(
|
||||
result,
|
||||
'<span data-oe-model="res.company" data-oe-id="%d" '
|
||||
'data-oe-field="name" data-oe-type="char" '
|
||||
'data-oe-expression="company.name">%s</span>' % (
|
||||
company_id,
|
||||
"My Test Company",))
|
||||
company.id,
|
||||
"My Test Company",
|
||||
),
|
||||
)
|
||||
|
||||
def test_i18n(self):
|
||||
field = etree.Element('span', {'t-field': u'company.name'})
|
||||
|
||||
Companies = self.registry('res.company')
|
||||
s = u"Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!"
|
||||
company_id = Companies.create(self.cr, self.uid, {
|
||||
'name': s,
|
||||
})
|
||||
result = self.engine.render_node(field, self.context({
|
||||
'company': Companies.browse(self.cr, self.uid, company_id),
|
||||
}))
|
||||
company = self.env['res.company'].create({'name': s})
|
||||
|
||||
result = self.engine.render_node(field, self.context({'company': company}))
|
||||
self.assertEqual(
|
||||
result,
|
||||
'<span data-oe-model="res.company" data-oe-id="%d" '
|
||||
'data-oe-field="name" data-oe-type="char" '
|
||||
'data-oe-expression="company.name">%s</span>' % (
|
||||
company_id,
|
||||
cgi.escape(s.encode('utf-8')),))
|
||||
company.id,
|
||||
cgi.escape(s.encode('utf-8')),
|
||||
),
|
||||
)
|
||||
|
||||
def test_reject_crummy_tags(self):
|
||||
field = etree.Element('td', {'t-field': u'company.name'})
|
||||
|
||||
with self.assertRaisesRegexp(
|
||||
AssertionError,
|
||||
r'^RTE widgets do not work correctly'):
|
||||
self.engine.render_node(field, self.context({
|
||||
'company': None
|
||||
}))
|
||||
with self.assertRaisesRegexp(AssertionError, r'^RTE widgets do not work correctly'):
|
||||
self.engine.render_node(field, self.context({'company': None}))
|
||||
|
||||
def test_reject_t_tag(self):
|
||||
field = etree.Element('t', {'t-field': u'company.name'})
|
||||
|
||||
with self.assertRaisesRegexp(
|
||||
AssertionError,
|
||||
r'^t-field can not be used on a t element'):
|
||||
self.engine.render_node(field, self.context({
|
||||
'company': None
|
||||
}))
|
||||
with self.assertRaisesRegexp(AssertionError, r'^t-field can not be used on a t element'):
|
||||
self.engine.render_node(field, self.context({'company': None}))
|
||||
|
||||
class TestQWeb(common.TransactionCase):
|
||||
matcher = re.compile('^qweb-test-(.*)\.xml$')
|
||||
|
||||
class TestQWeb(TransactionCase):
|
||||
matcher = re.compile(r'^qweb-test-(.*)\.xml$')
|
||||
|
||||
@classmethod
|
||||
def get_cases(cls):
|
||||
path = cls.qweb_test_file_path()
|
||||
|
||||
return (
|
||||
cls("test_qweb_{}".format(cls.matcher.match(f).group(1)))
|
||||
for f in os.listdir(path)
|
||||
@@ -94,12 +80,10 @@ class TestQWeb(common.TransactionCase):
|
||||
if f != 'qweb-test-extend.xml'
|
||||
if cls.matcher.match(f)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def qweb_test_file_path(cls):
|
||||
path = os.path.dirname(
|
||||
openerp.modules.get_module_resource(
|
||||
'web', 'static', 'lib', 'qweb', 'qweb2.js'))
|
||||
return path
|
||||
return os.path.dirname(get_module_resource('web', 'static', 'lib', 'qweb', 'qweb2.js'))
|
||||
|
||||
def __getattr__(self, item):
|
||||
if not item.startswith('test_qweb_'):
|
||||
@@ -129,9 +113,10 @@ class TestQWeb(common.TransactionCase):
|
||||
self.assertEqual(
|
||||
qweb.render(template, qwebcontext=ctx).strip(),
|
||||
(result or u'').strip().encode('utf-8'),
|
||||
template
|
||||
template,
|
||||
)
|
||||
|
||||
|
||||
def load_tests(loader, suite, _):
|
||||
# can't override TestQWeb.__dir__ because dir() called on *class* not
|
||||
# instance
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import openerp
|
||||
import openerp.tests.common as common
|
||||
from odoo import exceptions
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
class test_res_config(common.TransactionCase):
|
||||
|
||||
class TestResConfig(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(test_res_config, self).setUp()
|
||||
self.res_config = self.registry('res.config.settings')
|
||||
super(TestResConfig, self).setUp()
|
||||
self.ResConfig = self.env['res.config.settings']
|
||||
|
||||
# Define the test values
|
||||
self.menu_xml_id = 'base.menu_action_res_users'
|
||||
@@ -17,15 +19,13 @@ class test_res_config(common.TransactionCase):
|
||||
# Note: see the get_config_warning() doc for a better example
|
||||
|
||||
# Fetch the expected values
|
||||
module_name, menu_xml_id = self.menu_xml_id.split('.')
|
||||
dummy, menu_id = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, module_name, menu_xml_id)
|
||||
ir_ui_menu = self.registry('ir.ui.menu').browse(self.cr, self.uid, menu_id, context=None)
|
||||
menu = self.env.ref(self.menu_xml_id)
|
||||
|
||||
model_name, field_name = self.full_field_name.rsplit('.', 1)
|
||||
|
||||
self.expected_path = ir_ui_menu.complete_name
|
||||
self.expected_action_id = ir_ui_menu.action.id
|
||||
self.expected_name = self.registry(model_name).fields_get(self.cr, self.uid, allfields=[field_name], context=None)[field_name]['string']
|
||||
self.expected_path = menu.complete_name
|
||||
self.expected_action_id = menu.action.id
|
||||
self.expected_name = self.env[model_name].fields_get([field_name])[field_name]['string']
|
||||
self.expected_final_error_msg = self.error_msg % {
|
||||
'field:res.partner.lang': self.expected_name,
|
||||
'menu:base.menu_action_res_users': self.expected_path
|
||||
@@ -36,7 +36,7 @@ class test_res_config(common.TransactionCase):
|
||||
|
||||
def test_00_get_option_path(self):
|
||||
""" The get_option_path() method should return a tuple containing a string and an integer """
|
||||
res = self.res_config.get_option_path(self.cr, self.uid, self.menu_xml_id, context=None)
|
||||
res = self.ResConfig.get_option_path(self.menu_xml_id)
|
||||
|
||||
# Check types
|
||||
self.assertIsInstance(res, tuple)
|
||||
@@ -50,7 +50,7 @@ class test_res_config(common.TransactionCase):
|
||||
|
||||
def test_10_get_option_name(self):
|
||||
""" The get_option_name() method should return a string """
|
||||
res = self.res_config.get_option_name(self.cr, self.uid, self.full_field_name, context=None)
|
||||
res = self.ResConfig.get_option_name(self.full_field_name)
|
||||
|
||||
# Check type
|
||||
self.assertIsInstance(res, basestring)
|
||||
@@ -60,10 +60,10 @@ class test_res_config(common.TransactionCase):
|
||||
|
||||
def test_20_get_config_warning(self):
|
||||
""" The get_config_warning() method should return a RedirectWarning """
|
||||
res = self.res_config.get_config_warning(self.cr, self.error_msg, context=None)
|
||||
res = self.ResConfig.get_config_warning(self.error_msg)
|
||||
|
||||
# Check type
|
||||
self.assertIsInstance(res, openerp.exceptions.RedirectWarning)
|
||||
self.assertIsInstance(res, exceptions.RedirectWarning)
|
||||
|
||||
# Check returned value
|
||||
self.assertEqual(res.args[0], self.expected_final_error_msg)
|
||||
@@ -71,10 +71,10 @@ class test_res_config(common.TransactionCase):
|
||||
|
||||
def test_30_get_config_warning_wo_menu(self):
|
||||
""" The get_config_warning() method should return a Warning exception """
|
||||
res = self.res_config.get_config_warning(self.cr, self.error_msg_wo_menu, context=None)
|
||||
res = self.ResConfig.get_config_warning(self.error_msg_wo_menu)
|
||||
|
||||
# Check type
|
||||
self.assertIsInstance(res, openerp.exceptions.Warning)
|
||||
self.assertIsInstance(res, exceptions.Warning)
|
||||
|
||||
# Check returned value
|
||||
self.assertEqual(res.args[0], self.expected_final_error_msg_wo_menu)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import openerp.tests.common as common
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
class test_res_lang(common.TransactionCase):
|
||||
class test_res_lang(TransactionCase):
|
||||
|
||||
def test_00_intersperse(self):
|
||||
from openerp.addons.base.res.res_lang import intersperse
|
||||
from odoo.addons.base.res.res_lang import intersperse
|
||||
|
||||
assert intersperse("", []) == ("", 0)
|
||||
assert intersperse("0", []) == ("0", 0)
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
# Copyright (c) 2015 ACSONE SA/NV (<http://acsone.eu>)
|
||||
|
||||
from openerp.tests.common import TransactionCase
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestResPartnerBank(TransactionCase):
|
||||
"""Tests acc_number
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
import unittest
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import openerp.tests.common as common
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class test_search(common.TransactionCase):
|
||||
class test_search(TransactionCase):
|
||||
|
||||
def test_00_search_order(self):
|
||||
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
# Create 6 partners with a given name, and a given creation order to
|
||||
# ensure the order of their ID. Some are set as unactive to verify they
|
||||
# ensure the order of their ID. Some are set as inactive to verify they
|
||||
# are by default excluded from the searches and to provide a second
|
||||
# `order` argument.
|
||||
|
||||
partners = registry('res.partner')
|
||||
c = partners.create(cr, uid, {'name': 'test_search_order_C'})
|
||||
d = partners.create(cr, uid, {'name': 'test_search_order_D', 'active': False})
|
||||
a = partners.create(cr, uid, {'name': 'test_search_order_A'})
|
||||
b = partners.create(cr, uid, {'name': 'test_search_order_B'})
|
||||
ab = partners.create(cr, uid, {'name': 'test_search_order_AB'})
|
||||
e = partners.create(cr, uid, {'name': 'test_search_order_E', 'active': False})
|
||||
Partner = self.env['res.partner']
|
||||
c = Partner.create({'name': 'test_search_order_C'})
|
||||
d = Partner.create({'name': 'test_search_order_D', 'active': False})
|
||||
a = Partner.create({'name': 'test_search_order_A'})
|
||||
b = Partner.create({'name': 'test_search_order_B'})
|
||||
ab = Partner.create({'name': 'test_search_order_AB'})
|
||||
e = Partner.create({'name': 'test_search_order_E', 'active': False})
|
||||
|
||||
# The tests.
|
||||
|
||||
@@ -28,116 +26,109 @@ class test_search(common.TransactionCase):
|
||||
# The order of the returned ids should be given by the `order`
|
||||
# parameter of search().
|
||||
|
||||
name_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name asc")
|
||||
self.assertEqual([a, ab, b, c], name_asc, "Search with 'NAME ASC' order failed.")
|
||||
name_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name desc")
|
||||
self.assertEqual([c, b, ab, a], name_desc, "Search with 'NAME DESC' order failed.")
|
||||
id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id asc")
|
||||
self.assertEqual([c, a, b, ab], id_asc, "Search with 'ID ASC' order failed.")
|
||||
id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id desc")
|
||||
self.assertEqual([ab, b, a, c], id_desc, "Search with 'ID DESC' order failed.")
|
||||
name_asc = Partner.search([('name', 'like', 'test_search_order%')], order="name asc")
|
||||
self.assertEqual([a, ab, b, c], list(name_asc), "Search with 'NAME ASC' order failed.")
|
||||
name_desc = Partner.search([('name', 'like', 'test_search_order%')], order="name desc")
|
||||
self.assertEqual([c, b, ab, a], list(name_desc), "Search with 'NAME DESC' order failed.")
|
||||
id_asc = Partner.search([('name', 'like', 'test_search_order%')], order="id asc")
|
||||
self.assertEqual([c, a, b, ab], list(id_asc), "Search with 'ID ASC' order failed.")
|
||||
id_desc = Partner.search([('name', 'like', 'test_search_order%')], order="id desc")
|
||||
self.assertEqual([ab, b, a, c], list(id_desc), "Search with 'ID DESC' order failed.")
|
||||
|
||||
# The inactive records shouldn't be excluded as soon as a condition on
|
||||
# that field is present in the domain. The `order` parameter of
|
||||
# search() should support any legal coma-separated values.
|
||||
|
||||
active_asc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id asc")
|
||||
self.assertEqual([d, e, c, a, b, ab], active_asc_id_asc, "Search with 'ACTIVE ASC, ID ASC' order failed.")
|
||||
active_desc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id asc")
|
||||
self.assertEqual([c, a, b, ab, d, e], active_desc_id_asc, "Search with 'ACTIVE DESC, ID ASC' order failed.")
|
||||
active_asc_id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id desc")
|
||||
self.assertEqual([e, d, ab, b, a, c], active_asc_id_desc, "Search with 'ACTIVE ASC, ID DESC' order failed.")
|
||||
active_desc_id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id desc")
|
||||
self.assertEqual([ab, b, a, c, e, d], active_desc_id_desc, "Search with 'ACTIVE DESC, ID DESC' order failed.")
|
||||
id_asc_active_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active asc")
|
||||
self.assertEqual([c, d, a, b, ab, e], id_asc_active_asc, "Search with 'ID ASC, ACTIVE ASC' order failed.")
|
||||
id_asc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active desc")
|
||||
self.assertEqual([c, d, a, b, ab, e], id_asc_active_desc, "Search with 'ID ASC, ACTIVE DESC' order failed.")
|
||||
id_desc_active_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active asc")
|
||||
self.assertEqual([e, ab, b, a, d, c], id_desc_active_asc, "Search with 'ID DESC, ACTIVE ASC' order failed.")
|
||||
id_desc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc")
|
||||
self.assertEqual([e, ab, b, a, d, c], id_desc_active_desc, "Search with 'ID DESC, ACTIVE DESC' order failed.")
|
||||
active_asc_id_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id asc")
|
||||
self.assertEqual([d, e, c, a, b, ab], list(active_asc_id_asc), "Search with 'ACTIVE ASC, ID ASC' order failed.")
|
||||
active_desc_id_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id asc")
|
||||
self.assertEqual([c, a, b, ab, d, e], list(active_desc_id_asc), "Search with 'ACTIVE DESC, ID ASC' order failed.")
|
||||
active_asc_id_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id desc")
|
||||
self.assertEqual([e, d, ab, b, a, c], list(active_asc_id_desc), "Search with 'ACTIVE ASC, ID DESC' order failed.")
|
||||
active_desc_id_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id desc")
|
||||
self.assertEqual([ab, b, a, c, e, d], list(active_desc_id_desc), "Search with 'ACTIVE DESC, ID DESC' order failed.")
|
||||
id_asc_active_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active asc")
|
||||
self.assertEqual([c, d, a, b, ab, e], list(id_asc_active_asc), "Search with 'ID ASC, ACTIVE ASC' order failed.")
|
||||
id_asc_active_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active desc")
|
||||
self.assertEqual([c, d, a, b, ab, e], list(id_asc_active_desc), "Search with 'ID ASC, ACTIVE DESC' order failed.")
|
||||
id_desc_active_asc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active asc")
|
||||
self.assertEqual([e, ab, b, a, d, c], list(id_desc_active_asc), "Search with 'ID DESC, ACTIVE ASC' order failed.")
|
||||
id_desc_active_desc = Partner.search([('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc")
|
||||
self.assertEqual([e, ab, b, a, d, c], list(id_desc_active_desc), "Search with 'ID DESC, ACTIVE DESC' order failed.")
|
||||
|
||||
def test_10_inherits_m2order(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
users_obj = registry('res.users')
|
||||
Users = self.env['res.users']
|
||||
|
||||
# Find Employee group
|
||||
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
|
||||
group_employee_id = group_employee_ref and group_employee_ref[1] or False
|
||||
group_employee = self.env.ref('base.group_user')
|
||||
|
||||
# Get country/state data
|
||||
country_us_id = registry('res.country').search(cr, uid, [('code', 'like', 'US')])[0]
|
||||
state_ids = registry('res.country.state').search(cr, uid, [('country_id', '=', country_us_id)], limit=2)
|
||||
country_be_id = registry('res.country').search(cr, uid, [('code', 'like', 'BE')])[0]
|
||||
country_be = self.env.ref('base.be')
|
||||
country_us = self.env.ref('base.us')
|
||||
states_us = country_us.state_ids[:2]
|
||||
|
||||
# Create test users
|
||||
search_user = users_obj.create(cr, uid, {'name': '__search', 'login': '__search', 'groups_id': [(6, 0, [group_employee_id])]})
|
||||
a = users_obj.create(cr, uid, {'name': '__test_A', 'login': '__test_A', 'country_id': country_be_id, 'state_id': country_be_id})
|
||||
b = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__a_test_B', 'country_id': country_us_id, 'state_id': state_ids[1]})
|
||||
c = users_obj.create(cr, uid, {'name': '__test_B', 'login': '__z_test_B', 'country_id': country_us_id, 'state_id': state_ids[0]})
|
||||
u = Users.create({'name': '__search', 'login': '__search', 'groups_id': [(6, 0, [group_employee.id])]})
|
||||
a = Users.create({'name': '__test_A', 'login': '__test_A', 'country_id': country_be.id, 'state_id': country_be.id})
|
||||
b = Users.create({'name': '__test_B', 'login': '__a_test_B', 'country_id': country_us.id, 'state_id': states_us[1].id})
|
||||
c = Users.create({'name': '__test_B', 'login': '__z_test_B', 'country_id': country_us.id, 'state_id': states_us[0].id})
|
||||
|
||||
# Search as search user
|
||||
Users = Users.sudo(u)
|
||||
|
||||
# Do: search on res.users, order on a field on res.partner to try inherits'd fields, then res.users
|
||||
user_ids = users_obj.search(cr, search_user, [], order='name asc, login desc')
|
||||
expected_ids = [search_user, a, c, b]
|
||||
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
|
||||
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
expected_ids = [u.id, a.id, c.id, b.id]
|
||||
user_ids = Users.search([('id', 'in', expected_ids)], order='name asc, login desc').ids
|
||||
self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
|
||||
# Do: order on many2one and inherits'd fields
|
||||
user_ids = users_obj.search(cr, search_user, [], order='state_id asc, country_id desc, name asc, login desc')
|
||||
expected_ids = [c, b, a, search_user]
|
||||
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
|
||||
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
expected_ids = [c.id, b.id, a.id, u.id]
|
||||
user_ids = Users.search([('id', 'in', expected_ids)], order='state_id asc, country_id desc, name asc, login desc').ids
|
||||
self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
|
||||
# Do: order on many2one and inherits'd fields
|
||||
user_ids = users_obj.search(cr, search_user, [], order='country_id desc, state_id desc, name asc, login desc')
|
||||
expected_ids = [search_user, b, c, a]
|
||||
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
|
||||
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
expected_ids = [u.id, b.id, c.id, a.id]
|
||||
user_ids = Users.search([('id', 'in', expected_ids)], order='country_id desc, state_id desc, name asc, login desc').ids
|
||||
self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
|
||||
# Do: order on many2one, but not by specifying in order parameter of search, but by overriding _order of res_users
|
||||
self.patch_order('res.users', 'country_id desc, name asc, login desc')
|
||||
user_ids = users_obj.search(cr, search_user, [])
|
||||
expected_ids = [search_user, c, b, a]
|
||||
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
|
||||
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
expected_ids = [u.id, c.id, b.id, a.id]
|
||||
user_ids = Users.search([('id', 'in', expected_ids)]).ids
|
||||
self.assertEqual(user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||
|
||||
def test_11_indirect_inherits_m2o_order(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
Cron = registry('ir.cron')
|
||||
Users = registry('res.users')
|
||||
Cron = self.env['ir.cron']
|
||||
Users = self.env['res.users']
|
||||
|
||||
user_ids = {}
|
||||
cron_ids = {}
|
||||
for u in 'BAC':
|
||||
user_ids[u] = Users.create(cr, uid, {'name': u, 'login': u})
|
||||
cron_ids[u] = Cron.create(cr, uid, {'name': u, 'user_id': user_ids[u]})
|
||||
user_ids[u] = Users.create({'name': u, 'login': u}).id
|
||||
cron_ids[u] = Cron.create({'name': u, 'user_id': user_ids[u]}).id
|
||||
|
||||
ids = Cron.search(cr, uid, [('id', 'in', cron_ids.values())], order='user_id')
|
||||
ids = Cron.search([('id', 'in', cron_ids.values())], order='user_id').ids
|
||||
expected_ids = [cron_ids[l] for l in 'ABC']
|
||||
self.assertEqual(ids, expected_ids)
|
||||
|
||||
def test_12_m2o_order_loop_self(self):
|
||||
registry, cr, uid = self.registry, self.cr, self.uid
|
||||
|
||||
Cats = registry('ir.module.category')
|
||||
ids = {}
|
||||
Cats = self.env['ir.module.category']
|
||||
cat_ids = {}
|
||||
def create(name, **kw):
|
||||
ids[name] = Cats.create(cr, uid, dict(kw, name=name))
|
||||
cat_ids[name] = Cats.create(dict(kw, name=name)).id
|
||||
|
||||
self.patch_order('ir.module.category', 'parent_id desc, name')
|
||||
|
||||
create('A')
|
||||
create('B', parent_id=ids['A'])
|
||||
create('C', parent_id=ids['A'])
|
||||
create('B', parent_id=cat_ids['A'])
|
||||
create('C', parent_id=cat_ids['A'])
|
||||
create('D')
|
||||
create('E', parent_id=ids['D'])
|
||||
create('F', parent_id=ids['D'])
|
||||
create('E', parent_id=cat_ids['D'])
|
||||
create('F', parent_id=cat_ids['D'])
|
||||
|
||||
expected_order = [ids[x] for x in 'ADEFBC']
|
||||
domain = [('id', 'in', ids.values())]
|
||||
search_result = Cats.search(cr, uid, domain)
|
||||
self.assertEqual(search_result, expected_order)
|
||||
expected_ids = [cat_ids[x] for x in 'ADEFBC']
|
||||
found_ids = Cats.search([('id', 'in', cat_ids.values())]).ids
|
||||
self.assertEqual(found_ids, expected_ids)
|
||||
|
||||
def test_13_m2o_order_loop_multi(self):
|
||||
Users = self.env['res.users']
|
||||
@@ -154,11 +145,6 @@ class test_search(common.TransactionCase):
|
||||
u3 = Users.create(dict(name='C', login='c', **kw)).id
|
||||
u4 = Users.sudo(user=u2).create(dict(name='D', login='z', **kw)).id
|
||||
|
||||
expected_order = [u2, u4, u3, u1]
|
||||
|
||||
domain = [('id', 'in', [u1, u2, u3, u4])]
|
||||
search_result = list(Users.search(domain)._ids)
|
||||
self.assertEqual(search_result, expected_order)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
expected_ids = [u2, u4, u3, u1]
|
||||
found_ids = Users.search([('id', 'in', expected_ids)]).ids
|
||||
self.assertEqual(found_ids, expected_ids)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from lxml.etree import XMLSyntaxError
|
||||
import unittest
|
||||
from openerp.tools.translate import quote, unquote, xml_translate, html_translate
|
||||
|
||||
from odoo.tools.translate import quote, unquote, xml_translate, html_translate
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TranslationToolsTestCase(unittest.TestCase):
|
||||
|
||||
@@ -167,3 +169,56 @@ class TranslationToolsTestCase(unittest.TestCase):
|
||||
self.assertEquals(result, """<i class="fa-check"/>""")
|
||||
result = html_translate(lambda term: term, source)
|
||||
self.assertEquals(result, source)
|
||||
|
||||
|
||||
class TestTranslation(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTranslation, self).setUp()
|
||||
self.env['ir.translation'].load_module_terms(['base'], ['fr_FR'])
|
||||
self.customers = self.env['res.partner.category'].create({'name': 'Customers'})
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'res.partner.category,name',
|
||||
'module':'base',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': self.customers.id,
|
||||
'value': 'Clients',
|
||||
'state': 'translated',
|
||||
})
|
||||
|
||||
def test_101_create_translated_record(self):
|
||||
category = self.customers.with_context({})
|
||||
self.assertEqual(category.name, 'Customers', "Error in basic name_get")
|
||||
|
||||
category_fr = category.with_context({'lang': 'fr_FR'})
|
||||
self.assertEqual(category_fr.name, 'Clients', "Translation not found")
|
||||
|
||||
def test_102_duplicate_record(self):
|
||||
category = self.customers.with_context({'lang': 'fr_FR'}).copy()
|
||||
|
||||
category_no = category.with_context({})
|
||||
self.assertEqual(category_no.name, 'Customers', "Duplication did not set untranslated value")
|
||||
|
||||
category_fr = category.with_context({'lang': 'fr_FR'})
|
||||
self.assertEqual(category_fr.name, 'Clients', "Did not found translation for initial value")
|
||||
|
||||
def test_103_duplicate_record_fr(self):
|
||||
category = self.customers.with_context({'lang': 'fr_FR'}).copy({'name': 'Clients (copie)'})
|
||||
|
||||
category_no = category.with_context({})
|
||||
self.assertEqual(category_no.name, 'Customers', "Duplication erased original untranslated value")
|
||||
|
||||
category_fr = category.with_context({'lang': 'fr_FR'})
|
||||
self.assertEqual(category_fr.name, 'Clients (copie)', "Did not used default value for translated value")
|
||||
|
||||
def test_104_orderby_translated_field(self):
|
||||
""" Test search ordered by a translated field. """
|
||||
# create a category with a French translation
|
||||
padawans = self.env['res.partner.category'].create({'name': 'Padawans'})
|
||||
padawans_fr = padawans.with_context(lang='fr_FR')
|
||||
padawans_fr.write({'name': 'Apprentis'})
|
||||
# search for categories, and sort them by (translated) name
|
||||
categories = padawans_fr.search([('id', 'in', [self.customers.id, padawans.id])], order='name')
|
||||
self.assertEqual(categories.ids, [padawans.id, self.customers.id],
|
||||
"Search ordered by translated name should return Padawans (Apprentis) before Customers (Clients)")
|
||||
|
||||
@@ -1,57 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
# This assumes an existing but uninitialized database.
|
||||
|
||||
from contextlib import contextmanager
|
||||
import unittest
|
||||
|
||||
import openerp
|
||||
from openerp import SUPERUSER_ID
|
||||
import common
|
||||
from openerp import api, registry, SUPERUSER_ID
|
||||
from openerp.tests import common
|
||||
from openerp.modules.registry import RegistryManager
|
||||
|
||||
ADMIN_USER_ID = common.ADMIN_USER_ID
|
||||
|
||||
def registry(model):
|
||||
return openerp.modules.registry.RegistryManager.get(common.get_db_name())[model]
|
||||
@contextmanager
|
||||
def environment():
|
||||
""" Return an environment with a new cursor for the current database; the
|
||||
cursor is committed and closed after the context block.
|
||||
"""
|
||||
reg = registry(common.get_db_name())
|
||||
with reg.cursor() as cr:
|
||||
yield api.Environment(cr, SUPERUSER_ID, {})
|
||||
cr.commit()
|
||||
|
||||
def cursor():
|
||||
return openerp.modules.registry.RegistryManager.get(common.get_db_name()).cursor()
|
||||
|
||||
def get_module(module_name):
|
||||
registry = openerp.modules.registry.RegistryManager.get(common.get_db_name())
|
||||
return registry.get(module_name)
|
||||
MODULE = 'test_uninstall'
|
||||
MODEL = 'test_uninstall.model'
|
||||
|
||||
def reload_registry():
|
||||
openerp.modules.registry.RegistryManager.new(
|
||||
common.get_db_name(), update_module=True)
|
||||
|
||||
def search_registry(model_name, domain):
|
||||
cr = cursor()
|
||||
model = registry(model_name)
|
||||
record_ids = model.search(cr, SUPERUSER_ID, domain, {})
|
||||
cr.close()
|
||||
return record_ids
|
||||
|
||||
def install_module(module_name):
|
||||
ir_module_module = registry('ir.module.module')
|
||||
cr = cursor()
|
||||
module_ids = ir_module_module.search(cr, SUPERUSER_ID,
|
||||
[('name', '=', module_name)], {})
|
||||
assert len(module_ids) == 1
|
||||
ir_module_module.button_install(cr, SUPERUSER_ID, module_ids, {})
|
||||
cr.commit()
|
||||
cr.close()
|
||||
reload_registry()
|
||||
|
||||
def uninstall_module(module_name):
|
||||
ir_module_module = registry('ir.module.module')
|
||||
cr = cursor()
|
||||
module_ids = ir_module_module.search(cr, SUPERUSER_ID,
|
||||
[('name', '=', module_name)], {})
|
||||
assert len(module_ids) == 1
|
||||
ir_module_module.button_uninstall(cr, SUPERUSER_ID, module_ids, {})
|
||||
cr.commit()
|
||||
cr.close()
|
||||
reload_registry()
|
||||
|
||||
class test_uninstall(unittest.TestCase):
|
||||
class TestUninstall(unittest.TestCase):
|
||||
"""
|
||||
Test the install/uninstall of a test module. The module is available in
|
||||
`openerp.tests` which should be present in the addons-path.
|
||||
@@ -59,26 +33,29 @@ class test_uninstall(unittest.TestCase):
|
||||
|
||||
def test_01_install(self):
|
||||
""" Check a few things showing the module is installed. """
|
||||
install_module('test_uninstall')
|
||||
assert get_module('test_uninstall.model')
|
||||
with environment() as env:
|
||||
module = env['ir.module.module'].search([('name', '=', MODULE)])
|
||||
assert len(module) == 1
|
||||
module.button_install()
|
||||
RegistryManager.new(common.get_db_name(), update_module=True)
|
||||
|
||||
assert search_registry('ir.model.data',
|
||||
[('module', '=', 'test_uninstall')])
|
||||
|
||||
assert search_registry('ir.model.fields',
|
||||
[('model', '=', 'test_uninstall.model')])
|
||||
with environment() as env:
|
||||
self.assertIn('test_uninstall.model', env.registry)
|
||||
self.assertTrue(env['ir.model.data'].search([('module', '=', MODULE)]))
|
||||
self.assertTrue(env['ir.model.fields'].search([('model', '=', MODEL)]))
|
||||
|
||||
def test_02_uninstall(self):
|
||||
""" Check a few things showing the module is uninstalled. """
|
||||
uninstall_module('test_uninstall')
|
||||
assert not get_module('test_uninstall.model')
|
||||
|
||||
assert not search_registry('ir.model.data',
|
||||
[('module', '=', 'test_uninstall')])
|
||||
|
||||
assert not search_registry('ir.model.fields',
|
||||
[('model', '=', 'test_uninstall.model')])
|
||||
with environment() as env:
|
||||
module = env['ir.module.module'].search([('name', '=', MODULE)])
|
||||
assert len(module) == 1
|
||||
module.button_uninstall()
|
||||
RegistryManager.new(common.get_db_name(), update_module=True)
|
||||
|
||||
with environment() as env:
|
||||
self.assertNotIn('test_uninstall.model', env.registry)
|
||||
self.assertFalse(env['ir.model.data'].search([('module', '=', MODULE)]))
|
||||
self.assertFalse(env['ir.model.fields'].search([('model', '=', MODEL)]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import openerp.tests
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
class TestHasGroup(openerp.tests.TransactionCase):
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestHasGroup(TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestHasGroup, self).setUp()
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# This test can be run stand-alone with something like:
|
||||
# > PYTHONPATH=. python2 openerp/tests/test_view_validation.py
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from lxml import etree
|
||||
from StringIO import StringIO
|
||||
import unittest
|
||||
|
||||
from openerp.tools.view_validation import (valid_page_in_book, valid_att_in_form, valid_type_in_colspan,
|
||||
valid_type_in_col, valid_att_in_field, valid_att_in_label,
|
||||
valid_field_in_graph, valid_field_in_tree
|
||||
)
|
||||
from odoo.tools.view_validation import (
|
||||
valid_page_in_book, valid_att_in_form, valid_type_in_colspan,
|
||||
valid_type_in_col, valid_att_in_field, valid_att_in_label,
|
||||
valid_field_in_graph, valid_field_in_tree,
|
||||
)
|
||||
|
||||
invalid_form = etree.parse(StringIO('''\
|
||||
<form>
|
||||
@@ -92,7 +94,7 @@ valid_tree = etree.parse(StringIO('''\
|
||||
''')).getroot()
|
||||
|
||||
|
||||
class test_view_validation(unittest.TestCase):
|
||||
class TestViewValidation(unittest.TestCase):
|
||||
""" Test the view validation code (but not the views themselves). """
|
||||
|
||||
def test_page_validation(self):
|
||||
@@ -125,7 +127,3 @@ class test_view_validation(unittest.TestCase):
|
||||
def test_col_datatype_validation(self):
|
||||
assert not valid_type_in_col(invalid_form)
|
||||
assert valid_type_in_col(valid_form)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import openerp.tests.common
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class test_xmlrpc(openerp.tests.common.HttpCase):
|
||||
class TestXMLRPC(common.HttpCase):
|
||||
at_install = False
|
||||
post_install = True
|
||||
|
||||
def test_01_xmlrpc_login(self):
|
||||
""" Try to login on the common service. """
|
||||
db_name = openerp.tests.common.get_db_name()
|
||||
db_name = common.get_db_name()
|
||||
uid = self.xmlrpc_common.login(db_name, 'admin', 'admin')
|
||||
self.assertEqual(uid, 1)
|
||||
|
||||
def test_xmlrpc_ir_model_search(self):
|
||||
""" Try a search on the object service. """
|
||||
o = self.xmlrpc_object
|
||||
db_name = openerp.tests.common.get_db_name()
|
||||
db_name = common.get_db_name()
|
||||
ids = o.execute(db_name, 1, 'admin', 'ir.model', 'search', [])
|
||||
self.assertIsInstance(ids, list)
|
||||
ids = o.execute(db_name, 1, 'admin', 'ir.model', 'search', [], {})
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
The main duty of this module is to compile a domain expression into a
|
||||
SQL query. A lot of things should be documented here, but as a first
|
||||
step in the right direction, some tests in test_osv_expression.yml
|
||||
step in the right direction, some tests in test_expression.py
|
||||
might give you some additional information.
|
||||
|
||||
For legacy reasons, a domain uses an inconsistent two-levels abstract
|
||||
|
||||
Reference in New Issue
Block a user