From fc36345ca0730cf8cbd197d9177bc884764188f2 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 23 Jul 2012 17:03:06 +0200
Subject: [PATCH 01/36] [ADD] test cases for export of simple fields
bzr revid: xmo@openerp.com-20120723150306-6zgtr9ho0d3ud78u
---
openerp/modules/__init__.py | 6 +-
openerp/osv/orm.py | 6 +-
openerp/tests/__init__.py | 11 +-
openerp/tests/common.py | 5 +-
openerp/tests/test_export.py | 265 +++++++++++++++++++++++++++++++++++
5 files changed, 276 insertions(+), 17 deletions(-)
create mode 100644 openerp/tests/test_export.py
diff --git a/openerp/modules/__init__.py b/openerp/modules/__init__.py
index f28c397bb23..56265e353a2 100644
--- a/openerp/modules/__init__.py
+++ b/openerp/modules/__init__.py
@@ -24,11 +24,7 @@
"""
-import openerp.modules.db
-import openerp.modules.graph
-import openerp.modules.loading
-import openerp.modules.migration
-import openerp.modules.module
+from . import db, graph, loading, migration, module, registry
# TODO temporarily expose those things
from openerp.modules.module import \
diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index 78487e7641c..02a13a41dcb 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -4179,11 +4179,7 @@ class BaseModel(object):
# Try-except added to filter the creation of those records whose filds are readonly.
# Example : any dashboard which has all the fields readonly.(due to Views(database views))
- try:
- cr.execute("SELECT nextval('"+self._sequence+"')")
- except:
- raise except_orm(_('UserError'),
- _('You cannot perform this operation. New Record Creation is not allowed for this object as this object is for reporting purpose.'))
+ cr.execute("SELECT nextval('"+self._sequence+"')")
id_new = cr.fetchone()[0]
for table in tocreate:
diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py
index 913c5c759c9..7b30adece79 100644
--- a/openerp/tests/__init__.py
+++ b/openerp/tests/__init__.py
@@ -8,18 +8,17 @@ Tests can be explicitely added to the `fast_suite` or `checks` lists or not.
See the :ref:`test-framework` section in the :ref:`features` list.
"""
-import test_expression
-import test_ir_sequence
-import test_orm
-import test_uninstall
+from . import test_expression, test_ir_sequence, test_orm,\
+ test_uninstall, test_export
fast_suite = [
test_ir_sequence,
- ]
+]
checks = [
test_expression,
test_orm,
- ]
+ test_export,
+]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/common.py b/openerp/tests/common.py
index ef5b0586136..b1af4338312 100644
--- a/openerp/tests/common.py
+++ b/openerp/tests/common.py
@@ -39,13 +39,16 @@ class TransactionCase(unittest2.TestCase):
"""
def setUp(self):
- self.cr = openerp.modules.registry.RegistryManager.get(DB).db.cursor()
+ self.cr = self.cursor()
self.uid = openerp.SUPERUSER_ID
def tearDown(self):
self.cr.rollback()
self.cr.close()
+ def cursor(self):
+ return openerp.modules.registry.RegistryManager.get(DB).db.cursor()
+
def registry(self, model):
return openerp.modules.registry.RegistryManager.get(DB)[model]
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
new file mode 100644
index 00000000000..b1b51a608dc
--- /dev/null
+++ b/openerp/tests/test_export.py
@@ -0,0 +1,265 @@
+# -*- coding: utf-8 -*-
+import psycopg2
+
+import openerp.modules.registry
+import openerp
+from openerp.osv import orm, fields
+
+from . import common
+
+models = [
+ ('boolean', fields.boolean()),
+ ('integer', fields.integer()),
+ ('float', fields.float()),
+ ('decimal', fields.float(digits=(16, 3))),
+ ('string.bounded', fields.char('unknown', size=16)),
+ ('string', fields.char('unknown', size=None)),
+ ('date', fields.date()),
+ ('datetime', fields.datetime()),
+ ('text', fields.text()),
+ ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
+ # TODO: m2o, o2m, m2m
+ # TODO: function?
+ # TODO: related?
+ # TODO: reference?
+]
+for name, field in models:
+ attrs = {
+ '_name': 'export.%s' % name,
+ '_module': 'base',
+ '_columns': {
+ 'value': field
+ }
+ }
+ NewModel = type(
+ 'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
+ (orm.Model,),
+ attrs)
+
+def setUpModule():
+ openerp.tools.config['update'] = dict(base=1)
+ openerp.modules.registry.RegistryManager.new(
+ common.DB, update_module=True)
+
+class CreatorCase(common.TransactionCase):
+ model_name = False
+
+ def __init__(self, *args, **kwargs):
+ super(CreatorCase, self).__init__(*args, **kwargs)
+ self.model = None
+
+ def setUp(self):
+ super(CreatorCase, self).setUp()
+ self.model = self.registry(self.model_name)
+ def make(self, value):
+ id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': value})
+ return self.model.browse(self.cr, openerp.SUPERUSER_ID, [id])[0]
+ def export(self, value, context=None):
+ record = self.make(value)
+ return self.model._BaseModel__export_row(
+ self.cr, openerp.SUPERUSER_ID, record, [["value"]], context=context)
+
+class test_boolean_field(CreatorCase):
+ model_name = 'export.boolean'
+
+ def test_true(self):
+ self.assertEqual(
+ self.export(True),
+ [[u'True']])
+ def test_false(self):
+ """ ``False`` value to boolean fields is unique in being exported as a
+ (unicode) string, not a boolean
+ """
+ self.assertEqual(
+ self.export(False),
+ [[u'False']])
+
+class test_integer_field(CreatorCase):
+ model_name = 'export.integer'
+
+ def test_empty(self):
+ self.assertEqual(self.model.search(self.cr, openerp.SUPERUSER_ID, []), [],
+ "Test model should have no records")
+ def test_0(self):
+ self.assertEqual(
+ self.export(0),
+ [[False]])
+
+ def test_basic_value(self):
+ self.assertEqual(
+ self.export(42),
+ [[u'42']])
+
+ def test_negative(self):
+ self.assertEqual(
+ self.export(-32),
+ [[u'-32']])
+
+ def test_huge(self):
+ self.assertEqual(
+ self.export(2**31-1),
+ [[unicode(2**31-1)]])
+
+class test_float_field(CreatorCase):
+ model_name = 'export.float'
+
+ def test_0(self):
+ self.assertEqual(
+ self.export(0.0),
+ [[False]])
+
+ def test_epsilon(self):
+ self.assertEqual(
+ self.export(0.000000000027),
+ [[u'2.7e-11']])
+
+ def test_negative(self):
+ self.assertEqual(
+ self.export(-2.42),
+ [[u'-2.42']])
+
+ def test_positive(self):
+ self.assertEqual(
+ self.export(47.36),
+ [[u'47.36']])
+
+ def test_big(self):
+ self.assertEqual(
+ self.export(87654321.4678),
+ [[u'87654321.4678']])
+
+class test_decimal_field(CreatorCase):
+ model_name = 'export.decimal'
+
+ def test_0(self):
+ self.assertEqual(
+ self.export(0.0),
+ [[False]])
+
+ def test_epsilon(self):
+ """ epsilon gets sliced to 0 due to precision
+ """
+ self.assertEqual(
+ self.export(0.000000000027),
+ [[False]])
+
+ def test_negative(self):
+ self.assertEqual(
+ self.export(-2.42),
+ [[u'-2.42']])
+
+ def test_positive(self):
+ self.assertEqual(
+ self.export(47.36),
+ [[u'47.36']])
+
+ def test_big(self):
+ self.assertEqual(
+ self.export(87654321.4678), [[u'87654321.468']])
+
+class test_string_field(CreatorCase):
+ model_name = 'export.string.bounded'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(""),
+ [[False]])
+ def test_within_bounds(self):
+ self.assertEqual(
+ self.export("foobar"),
+ [[u"foobar"]])
+ def test_out_of_bounds(self):
+ self.assertEqual(
+ self.export("C for Sinking, "
+ "Java for Drinking, "
+ "Smalltalk for Thinking. "
+ "...and Power to the Penguin!"),
+ [[u"C for Sinking, J"]])
+
+class test_unbound_string_field(CreatorCase):
+ model_name = 'export.string'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(""),
+ [[False]])
+ def test_small(self):
+ self.assertEqual(
+ self.export("foobar"),
+ [[u"foobar"]])
+ def test_big(self):
+ self.assertEqual(
+ self.export("We flew down weekly to meet with IBM, but they "
+ "thought the way to measure software was the amount "
+ "of code we wrote, when really the better the "
+ "software, the fewer lines of code."),
+ [[u"We flew down weekly to meet with IBM, but they thought the "
+ u"way to measure software was the amount of code we wrote, "
+ u"when really the better the software, the fewer lines of "
+ u"code."]])
+
+class test_text(CreatorCase):
+ model_name = 'export.text'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(""),
+ [[False]])
+ def test_small(self):
+ self.assertEqual(
+ self.export("foobar"),
+ [[u"foobar"]])
+ def test_big(self):
+ self.assertEqual(
+ self.export("So, `bind' is `let' and monadic programming is"
+ " equivalent to programming in the A-normal form. That"
+ " is indeed all there is to monads"),
+ [[u"So, `bind' is `let' and monadic programming is equivalent to"
+ u" programming in the A-normal form. That is indeed all there"
+ u" is to monads"]])
+
+class test_date(CreatorCase):
+ model_name = 'export.date'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+ def test_basic(self):
+ self.assertEqual(
+ self.export('2011-11-07'),
+ [[u'2011-11-07']])
+
+class test_datetime(CreatorCase):
+ model_name = 'export.datetime'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+ def test_basic(self):
+ self.assertEqual(
+ self.export('2011-11-07 21:05:48'),
+ [[u'2011-11-07 21:05:48']])
+ def test_tz(self):
+ """ Export ignores the timezone and always exports to UTC
+ """
+ self.assertEqual(
+ self.export('2011-11-07 21:05:48', {'tz': 'Pacific/Norfolk'}),
+ [[u'2011-11-07 21:05:48']])
+
+class test_selection(CreatorCase):
+ model_name = 'export.selection'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+
+ def test_value(self):
+ """ selections export the *label* for their value
+ """
+ self.assertEqual(
+ self.export(2),
+ [[u"Bar"]])
+
From feb9efed4dd58dc3bbb20b58ee49b269d726f4e3 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 23 Jul 2012 17:38:26 +0200
Subject: [PATCH 02/36] [IMP] prepare export test cases for relational fields
bzr revid: xmo@openerp.com-20120723153826-hu7cwhj8uv6w0xu7
---
openerp/tests/test_export.py | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index b1b51a608dc..401a90fd635 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -54,10 +54,12 @@ class CreatorCase(common.TransactionCase):
def make(self, value):
id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': value})
return self.model.browse(self.cr, openerp.SUPERUSER_ID, [id])[0]
- def export(self, value, context=None):
+ def export(self, value, fields=('value',), context=None):
record = self.make(value)
return self.model._BaseModel__export_row(
- self.cr, openerp.SUPERUSER_ID, record, [["value"]], context=context)
+ self.cr, openerp.SUPERUSER_ID, record,
+ [f.split('/') for f in fields],
+ context=context)
class test_boolean_field(CreatorCase):
model_name = 'export.boolean'
@@ -245,7 +247,7 @@ class test_datetime(CreatorCase):
""" Export ignores the timezone and always exports to UTC
"""
self.assertEqual(
- self.export('2011-11-07 21:05:48', {'tz': 'Pacific/Norfolk'}),
+ self.export('2011-11-07 21:05:48', context={'tz': 'Pacific/Norfolk'}),
[[u'2011-11-07 21:05:48']])
class test_selection(CreatorCase):
From 5850df630c87ab2474fec8827af64c99d184e122 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 23 Jul 2012 18:00:41 +0200
Subject: [PATCH 03/36] [ADD] m2o field export tests
bzr revid: xmo@openerp.com-20120723160041-o6w24ia2kwnqu19z
---
openerp/tests/test_export.py | 41 +++++++++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index 401a90fd635..61c71510f42 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -18,6 +18,8 @@ models = [
('datetime', fields.datetime()),
('text', fields.text()),
('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
+ # just relate to an integer
+ ('many2one', fields.many2one('export.integer')),
# TODO: m2o, o2m, m2m
# TODO: function?
# TODO: related?
@@ -29,7 +31,11 @@ for name, field in models:
'_module': 'base',
'_columns': {
'value': field
- }
+ },
+ 'name_get': (lambda self, cr, uid, ids, context=None:
+ [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)])
+
}
NewModel = type(
'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
@@ -265,3 +271,36 @@ class test_selection(CreatorCase):
self.export(2),
[[u"Bar"]])
+class test_m2o(CreatorCase):
+ model_name = 'export.many2one'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+ def test_basic(self):
+ """ Exported value is the name_get of the related object
+ """
+ integer_id = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ name = dict(self.registry('export.integer').name_get(
+ self.cr, openerp.SUPERUSER_ID,[integer_id]))[integer_id]
+ self.assertEqual(
+ self.export(integer_id),
+ [[name]])
+ def test_path(self):
+ """ Can recursively export fields of m2o via path
+ """
+ integer_id = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ self.assertEqual(
+ self.export(integer_id, fields=['value/.id', 'value/value']),
+ [[unicode(integer_id), u'42']])
+ def test_external_id(self):
+ integer_id = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ # __export__.$class.$id
+ external_id = u'__export__.export_many2one_%d' % integer_id
+ self.assertEqual(
+ self.export(integer_id, fields=['value/id']),
+ [[external_id]])
From 02109d24e244037483d86f33e0532a0b455deca6 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 24 Jul 2012 12:27:28 +0200
Subject: [PATCH 04/36] [ADD] tests for o2m field export
bzr revid: xmo@openerp.com-20120724102728-g7noucvda19k7k5q
---
openerp/tests/test_export.py | 119 ++++++++++++++++++++++++++++++++++-
1 file changed, 117 insertions(+), 2 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index 61c71510f42..c46ef53837e 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -20,7 +20,8 @@ models = [
('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
# just relate to an integer
('many2one', fields.many2one('export.integer')),
- # TODO: m2o, o2m, m2m
+ ('one2many', fields.one2many('export.one2many.child', 'parent_id')),
+ # TODO: m2m
# TODO: function?
# TODO: related?
# TODO: reference?
@@ -30,18 +31,35 @@ for name, field in models:
'_name': 'export.%s' % name,
'_module': 'base',
'_columns': {
+ 'const': fields.integer(),
'value': field
},
+ '_defaults': {'const': 4},
'name_get': (lambda self, cr, uid, ids, context=None:
[(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)])
-
}
NewModel = type(
'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
(orm.Model,),
attrs)
+class One2ManyChild(orm.Model):
+ _name = 'export.one2many.child'
+ _module = 'base'
+ # FIXME: orm.py:1161, fix to name_get on m2o field
+ _rec_name = 'value'
+
+ _columns = {
+ 'parent_id': fields.many2one('export.one2many'),
+ 'str': fields.char('unknown', size=None),
+ 'value': fields.integer()
+ }
+ def name_get(self, cr, uid, ids, context=None):
+ return [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)]
+
+
def setUpModule():
openerp.tools.config['update'] = dict(base=1)
openerp.modules.registry.RegistryManager.new(
@@ -251,6 +269,8 @@ class test_datetime(CreatorCase):
[[u'2011-11-07 21:05:48']])
def test_tz(self):
""" Export ignores the timezone and always exports to UTC
+
+ .. note:: on the other hand, export uses user lang for name_get
"""
self.assertEqual(
self.export('2011-11-07 21:05:48', context={'tz': 'Pacific/Norfolk'}),
@@ -304,3 +324,98 @@ class test_m2o(CreatorCase):
self.assertEqual(
self.export(integer_id, fields=['value/id']),
[[external_id]])
+
+class test_o2m(CreatorCase):
+ model_name = 'export.one2many'
+ commands = [
+ (0, False, {'value': 4, 'str': 'record1'}),
+ (0, False, {'value': 42, 'str': 'record2'}),
+ (0, False, {'value': 36, 'str': 'record3'}),
+ (0, False, {'value': 4, 'str': 'record4'}),
+ (0, False, {'value': 13, 'str': 'record5'}),
+ ]
+ names = [
+ u'export.one2many.child:%d' % d['value']
+ for c, _, d in commands
+ ]
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+
+ def test_single(self):
+ self.assertEqual(
+ self.export([(0, False, {'value': 42})]),
+ # name_get result
+ [[u'export.one2many.child:42']])
+
+ def test_single_subfield(self):
+ self.assertEqual(
+ self.export([(0, False, {'value': 42})],
+ fields=['value', 'value/value']),
+ [[u'export.one2many.child:42', u'42']])
+
+ def test_integrate_one_in_parent(self):
+ self.assertEqual(
+ self.export([(0, False, {'value': 42})],
+ fields=['const', 'value/value']),
+ [[u'4', u'42']])
+
+ def test_multiple_records(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value/value']),
+ [
+ [u'4', u'4'],
+ [u'', u'42'],
+ [u'', u'36'],
+ [u'', u'4'],
+ [u'', u'13'],
+ ])
+
+ def test_multiple_records_name(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value']),
+ [[
+ u'4', u','.join(self.names)
+ ]])
+
+ def test_multiple_records_with_name_before(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value', 'value/value']),
+ [[ # exports sub-fields of very first o2m
+ u'4', u','.join(self.names), u'4'
+ ]])
+
+ def test_multiple_records_with_name_before(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value/value', 'value']),
+ [ # completely ignores name_get request
+ [u'4', u'4', ''],
+ [u'', u'42', ''],
+ [u'', u'36', ''],
+ [u'', u'4', ''],
+ [u'', u'13', ''],
+ ])
+
+ def test_multiple_subfields_neighbour(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value/str','value/value']),
+ [
+ [u'4', u'record1', u'4'],
+ ['', u'record2', u'42'],
+ ['', u'record3', u'36'],
+ ['', u'record4', u'4'],
+ ['', u'record5', u'13'],
+ ])
+
+ def test_multiple_subfields_separated(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['value/str', 'const', 'value/value']),
+ [
+ [u'record1', u'4', u'4'],
+ [u'record2', '', u'42'],
+ [u'record3', '', u'36'],
+ [u'record4', '', u'4'],
+ [u'record5', '', u'13'],
+ ])
From f3c315cf10e2fb766586e2c8c9e03e7b228c800b Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 24 Jul 2012 12:57:56 +0200
Subject: [PATCH 05/36] [ADD] some m2m tests
bzr revid: xmo@openerp.com-20120724105756-swxo1l4tahqjopzd
---
openerp/tests/test_export.py | 80 +++++++++++++++++++++++++++++++++---
1 file changed, 75 insertions(+), 5 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index c46ef53837e..030466dc674 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -21,7 +21,7 @@ models = [
# just relate to an integer
('many2one', fields.many2one('export.integer')),
('one2many', fields.one2many('export.one2many.child', 'parent_id')),
- # TODO: m2m
+ ('many2many', fields.many2many('export.many2many.other'))
# TODO: function?
# TODO: related?
# TODO: reference?
@@ -59,6 +59,19 @@ class One2ManyChild(orm.Model):
return [(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)]
+class Many2ManyChild(orm.Model):
+ _name = 'export.many2many.other'
+ _module = 'base'
+ # FIXME: orm.py:1161, fix to name_get on m2o field
+ _rec_name = 'value'
+
+ _columns = {
+ 'str': fields.char('unknown', size=None),
+ 'value': fields.integer()
+ }
+ def name_get(self, cr, uid, ids, context=None):
+ return [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)]
def setUpModule():
openerp.tools.config['update'] = dict(base=1)
@@ -392,10 +405,10 @@ class test_o2m(CreatorCase):
self.export(self.commands, fields=['const', 'value/value', 'value']),
[ # completely ignores name_get request
[u'4', u'4', ''],
- [u'', u'42', ''],
- [u'', u'36', ''],
- [u'', u'4', ''],
- [u'', u'13', ''],
+ ['', u'42', ''],
+ ['', u'36', ''],
+ ['', u'4', ''],
+ ['', u'13', ''],
])
def test_multiple_subfields_neighbour(self):
@@ -419,3 +432,60 @@ class test_o2m(CreatorCase):
[u'record4', '', u'4'],
[u'record5', '', u'13'],
])
+
+class test_m2m(CreatorCase):
+ model_name = 'export.many2many'
+ commands = [
+ (0, False, {'value': 4, 'str': 'record000'}),
+ (0, False, {'value': 42, 'str': 'record001'}),
+ (0, False, {'value': 36, 'str': 'record010'}),
+ (0, False, {'value': 4, 'str': 'record011'}),
+ (0, False, {'value': 13, 'str': 'record100'}),
+ ]
+ names = [
+ u'export.many2many.other:%d' % d['value']
+ for c, _, d in commands
+ ]
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+
+ def test_single(self):
+ self.assertEqual(
+ self.export([(0, False, {'value': 42})]),
+ # name_get result
+ [[u'export.many2many.other:42']])
+
+ def test_single_subfield(self):
+ self.assertEqual(
+ self.export([(0, False, {'value': 42})],
+ fields=['value', 'value/value']),
+ [[u'export.many2many.other:42', u'42']])
+
+ def test_integrate_one_in_parent(self):
+ self.assertEqual(
+ self.export([(0, False, {'value': 42})],
+ fields=['const', 'value/value']),
+ [[u'4', u'42']])
+
+ def test_multiple_records(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value/value']),
+ [
+ [u'4', u'4'],
+ [u'', u'42'],
+ [u'', u'36'],
+ [u'', u'4'],
+ [u'', u'13'],
+ ])
+
+ def test_multiple_records_name(self):
+ self.assertEqual(
+ self.export(self.commands, fields=['const', 'value']),
+ [[
+ u'4', u','.join(self.names)
+ ]])
+
+ # essentially same as o2m, so boring
From 53c82f4086e2fd2a029106fbbcc95beaad53c250 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Thu, 26 Jul 2012 12:08:04 +0200
Subject: [PATCH 06/36] [TEST] export of multiple o2m fields in the same object
bzr revid: xmo@openerp.com-20120726100804-ggsjwco93k9d5bqw
---
openerp/tests/export_models.py | 102 ++++++++++++++++++++
openerp/tests/test_export.py | 167 +++++++++++++++++++--------------
2 files changed, 200 insertions(+), 69 deletions(-)
create mode 100644 openerp/tests/export_models.py
diff --git a/openerp/tests/export_models.py b/openerp/tests/export_models.py
new file mode 100644
index 00000000000..d54c73ac4ad
--- /dev/null
+++ b/openerp/tests/export_models.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+from openerp.osv import orm, fields
+
+models = [
+ ('boolean', fields.boolean()),
+ ('integer', fields.integer()),
+ ('float', fields.float()),
+ ('decimal', fields.float(digits=(16, 3))),
+ ('string.bounded', fields.char('unknown', size=16)),
+ ('string', fields.char('unknown', size=None)),
+ ('date', fields.date()),
+ ('datetime', fields.datetime()),
+ ('text', fields.text()),
+ ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
+ # just relate to an integer
+ ('many2one', fields.many2one('export.integer')),
+ ('one2many', fields.one2many('export.one2many.child', 'parent_id')),
+ ('many2many', fields.many2many('export.many2many.other'))
+ # TODO: function?
+ # TODO: related?
+ # TODO: reference?
+]
+for name, field in models:
+ attrs = {
+ '_name': 'export.%s' % name,
+ '_module': 'base',
+ '_columns': {
+ 'const': fields.integer(),
+ 'value': field
+ },
+ '_defaults': {'const': 4},
+ 'name_get': (lambda self, cr, uid, ids, context=None:
+ [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)])
+ }
+ NewModel = type(
+ 'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
+ (orm.Model,),
+ attrs)
+
+class One2ManyChild(orm.Model):
+ _name = 'export.one2many.child'
+ _module = 'base'
+ # FIXME: orm.py:1161, fix to name_get on m2o field
+ _rec_name = 'value'
+
+ _columns = {
+ 'parent_id': fields.many2one('export.one2many'),
+ 'str': fields.char('unknown', size=None),
+ 'value': fields.integer()
+ }
+ def name_get(self, cr, uid, ids, context=None):
+ return [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)]
+
+class One2ManyMultiple(orm.Model):
+ _name = 'export.one2many.multiple'
+ _module = 'base'
+
+ _columns = {
+ 'const': fields.integer(),
+ 'child1': fields.one2many('export.one2many.child.1', 'parent_id'),
+ 'child2': fields.one2many('export.one2many.child.2', 'parent_id'),
+ }
+ _defaults = { 'const': 36 }
+
+class One2ManyChildMultiple(orm.Model):
+ _name = 'export.one2many.multiple.child'
+ _module = 'base'
+ # FIXME: orm.py:1161, fix to name_get on m2o field
+ _rec_name = 'value'
+
+ _columns = {
+ 'parent_id': fields.many2one('export.one2many.multiple'),
+ 'str': fields.char('unknown', size=None),
+ 'value': fields.integer()
+ }
+ def name_get(self, cr, uid, ids, context=None):
+ return [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)]
+class One2ManyChild1(orm.Model):
+ _name = 'export.one2many.child.1'
+ _module = 'base'
+ _inherit = 'export.one2many.multiple.child'
+class One2ManyChild2(orm.Model):
+ _name = 'export.one2many.child.2'
+ _module = 'base'
+ _inherit = 'export.one2many.multiple.child'
+
+class Many2ManyChild(orm.Model):
+ _name = 'export.many2many.other'
+ _module = 'base'
+ # FIXME: orm.py:1161, fix to name_get on m2o field
+ _rec_name = 'value'
+
+ _columns = {
+ 'str': fields.char('unknown', size=None),
+ 'value': fields.integer()
+ }
+ def name_get(self, cr, uid, ids, context=None):
+ return [(record.id, "%s:%s" % (self._name, record.value))
+ for record in self.browse(cr, uid, ids, context=context)]
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index 030466dc674..ea21cd36a8a 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -1,77 +1,10 @@
# -*- coding: utf-8 -*-
-import psycopg2
-
+import itertools
import openerp.modules.registry
import openerp
-from openerp.osv import orm, fields
-from . import common
+from . import common, export_models
-models = [
- ('boolean', fields.boolean()),
- ('integer', fields.integer()),
- ('float', fields.float()),
- ('decimal', fields.float(digits=(16, 3))),
- ('string.bounded', fields.char('unknown', size=16)),
- ('string', fields.char('unknown', size=None)),
- ('date', fields.date()),
- ('datetime', fields.datetime()),
- ('text', fields.text()),
- ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
- # just relate to an integer
- ('many2one', fields.many2one('export.integer')),
- ('one2many', fields.one2many('export.one2many.child', 'parent_id')),
- ('many2many', fields.many2many('export.many2many.other'))
- # TODO: function?
- # TODO: related?
- # TODO: reference?
-]
-for name, field in models:
- attrs = {
- '_name': 'export.%s' % name,
- '_module': 'base',
- '_columns': {
- 'const': fields.integer(),
- 'value': field
- },
- '_defaults': {'const': 4},
- 'name_get': (lambda self, cr, uid, ids, context=None:
- [(record.id, "%s:%s" % (self._name, record.value))
- for record in self.browse(cr, uid, ids, context=context)])
- }
- NewModel = type(
- 'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
- (orm.Model,),
- attrs)
-
-class One2ManyChild(orm.Model):
- _name = 'export.one2many.child'
- _module = 'base'
- # FIXME: orm.py:1161, fix to name_get on m2o field
- _rec_name = 'value'
-
- _columns = {
- 'parent_id': fields.many2one('export.one2many'),
- 'str': fields.char('unknown', size=None),
- 'value': fields.integer()
- }
- def name_get(self, cr, uid, ids, context=None):
- return [(record.id, "%s:%s" % (self._name, record.value))
- for record in self.browse(cr, uid, ids, context=context)]
-
-class Many2ManyChild(orm.Model):
- _name = 'export.many2many.other'
- _module = 'base'
- # FIXME: orm.py:1161, fix to name_get on m2o field
- _rec_name = 'value'
-
- _columns = {
- 'str': fields.char('unknown', size=None),
- 'value': fields.integer()
- }
- def name_get(self, cr, uid, ids, context=None):
- return [(record.id, "%s:%s" % (self._name, record.value))
- for record in self.browse(cr, uid, ids, context=context)]
def setUpModule():
openerp.tools.config['update'] = dict(base=1)
@@ -433,6 +366,102 @@ class test_o2m(CreatorCase):
[u'record5', '', u'13'],
])
+# todo: test with multiple o2m fields and exporting all
+class test_o2m_multiple(CreatorCase):
+ model_name = 'export.one2many.multiple'
+
+ def make(self, value=None, **values):
+ if value is not None: values['value'] = value
+ id = self.model.create(self.cr, openerp.SUPERUSER_ID, values)
+ return self.model.browse(self.cr, openerp.SUPERUSER_ID, [id])[0]
+ def export(self, value=None, fields=('child1', 'child2',), context=None, **values):
+ record = self.make(value, **values)
+ return self.model._BaseModel__export_row(
+ self.cr, openerp.SUPERUSER_ID, record,
+ [f.split('/') for f in fields],
+ context=context)
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(child1=False, child2=False),
+ [[False, False]])
+
+ def test_single_per_side(self):
+ self.assertEqual(
+ self.export(child1=False, child2=[(0, False, {'value': 42})]),
+ [[False, u'export.one2many.child.2:42']])
+
+ self.assertEqual(
+ self.export(child1=[(0, False, {'value': 43})], child2=False),
+ [[u'export.one2many.child.1:43', False]])
+
+ self.assertEqual(
+ self.export(child1=[(0, False, {'value': 43})],
+ child2=[(0, False, {'value': 42})]),
+ [[u'export.one2many.child.1:43', u'export.one2many.child.2:42']])
+
+ def test_single_integrate_subfield(self):
+ fields = ['const', 'child1/value', 'child2/value']
+ self.assertEqual(
+ self.export(child1=False, child2=[(0, False, {'value': 42})],
+ fields=fields),
+ [[u'36', False, u'42']])
+
+ self.assertEqual(
+ self.export(child1=[(0, False, {'value': 43})], child2=False,
+ fields=fields),
+ [[u'36', u'43', False]])
+
+ self.assertEqual(
+ self.export(child1=[(0, False, {'value': 43})],
+ child2=[(0, False, {'value': 42})],
+ fields=fields),
+ [[u'36', u'43', u'42']])
+
+ def test_multiple(self):
+ """ With two "concurrent" o2ms, exports the first line combined, then
+ exports the rows for the first o2m, then the rows for the second o2m.
+ """
+ fields = ['const', 'child1/value', 'child2/value']
+ child1 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
+ for index, v in zip(itertools.count(), [4, 42, 36, 4, 13])]
+ child2 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
+ for index, v in zip(itertools.count(10), [8, 12, 8, 55, 33, 13])]
+
+ self.assertEqual(
+ self.export(child1=child1, child2=False, fields=fields),
+ [
+ [u'36', u'4', False],
+ ['', u'42', ''],
+ ['', u'36', ''],
+ ['', u'4', ''],
+ ['', u'13', ''],
+ ])
+ self.assertEqual(
+ self.export(child1=False, child2=child2, fields=fields),
+ [
+ [u'36', False, u'8'],
+ ['', '', u'12'],
+ ['', '', u'8'],
+ ['', '', u'55'],
+ ['', '', u'33'],
+ ['', '', u'13'],
+ ])
+ self.assertEqual(
+ self.export(child1=child1, child2=child2, fields=fields),
+ [
+ [u'36', u'4', u'8'],
+ ['', u'42', ''],
+ ['', u'36', ''],
+ ['', u'4', ''],
+ ['', u'13', ''],
+ ['', '', u'12'],
+ ['', '', u'8'],
+ ['', '', u'55'],
+ ['', '', u'33'],
+ ['', '', u'13'],
+ ])
+
class test_m2m(CreatorCase):
model_name = 'export.many2many'
commands = [
From 73f3f24fb4564e9edb7bf4ddede1ccf46aaa94e7 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 12:32:14 +0200
Subject: [PATCH 07/36] [ADD] tests for selection[function] and function fields
export
bzr revid: xmo@openerp.com-20120730103214-t4s9g0z3sl1x05b3
---
openerp/tests/export_models.py | 19 +++++++++++++++----
openerp/tests/test_export.py | 34 +++++++++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/openerp/tests/export_models.py b/openerp/tests/export_models.py
index d54c73ac4ad..2f85ab473e8 100644
--- a/openerp/tests/export_models.py
+++ b/openerp/tests/export_models.py
@@ -1,6 +1,16 @@
# -*- coding: utf-8 -*-
from openerp.osv import orm, fields
+def selection_fn(obj, cr, uid, context=None):
+ return list(enumerate(["Corge", "Grault", "Wheee", "Moog"]))
+
+def function_fn(model, cr, uid, ids, field_name, arg, context):
+ return dict((id, 3) for id in ids)
+def function_fn_write(model, cr, uid, id, field_name, field_value, fnct_inv_arg, context):
+ """ just so CreatorCase.export can be used
+ """
+ pass
+
models = [
('boolean', fields.boolean()),
('integer', fields.integer()),
@@ -12,13 +22,14 @@ models = [
('datetime', fields.datetime()),
('text', fields.text()),
('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
+ ('selection.function', fields.selection(selection_fn)),
# just relate to an integer
('many2one', fields.many2one('export.integer')),
('one2many', fields.one2many('export.one2many.child', 'parent_id')),
- ('many2many', fields.many2many('export.many2many.other'))
- # TODO: function?
- # TODO: related?
- # TODO: reference?
+ ('many2many', fields.many2many('export.many2many.other')),
+ ('function', fields.function(function_fn, fnct_inv=function_fn_write, type="integer")),
+ # related: specialization of fields.function, should work the same way
+ # TODO: reference
]
for name, field in models:
attrs = {
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index ea21cd36a8a..ee4405db75d 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -7,7 +7,7 @@ from . import common, export_models
def setUpModule():
- openerp.tools.config['update'] = dict(base=1)
+ openerp.tools.config['update'] = {'base': 1}
openerp.modules.registry.RegistryManager.new(
common.DB, update_module=True)
@@ -237,6 +237,28 @@ class test_selection(CreatorCase):
self.export(2),
[[u"Bar"]])
+class test_selection_function(CreatorCase):
+ model_name = 'export.selection.function'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.export(False),
+ [[False]])
+
+ def test_value(self):
+ """ selection functions export the *value* itself
+ """
+ self.assertEqual(
+ self.export(1),
+ [[u'1']])
+ self.assertEqual(
+ self.export(3),
+ [[u'3']])
+ # fucking hell
+ self.assertEqual(
+ self.export(0),
+ [[False]])
+
class test_m2o(CreatorCase):
model_name = 'export.many2one'
@@ -518,3 +540,13 @@ class test_m2m(CreatorCase):
]])
# essentially same as o2m, so boring
+
+class test_function(CreatorCase):
+ model_name = 'export.function'
+
+ def test_value(self):
+ """ Exports value normally returned by accessing the function field
+ """
+ self.assertEqual(
+ self.export(42),
+ [[u'3']])
From 64910eaebad74019b4d7e0c58621a8487f2c007e Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 13:11:05 +0200
Subject: [PATCH 08/36] [ADD] boolean field import tests
bzr revid: xmo@openerp.com-20120730111105-k6q8xop0ru71l0dj
---
openerp/tests/__init__.py | 3 +-
openerp/tests/test_import.py | 95 ++++++++++++++++++++++++++++++++++++
2 files changed, 97 insertions(+), 1 deletion(-)
create mode 100644 openerp/tests/test_import.py
diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py
index 7b30adece79..4b8fa798aea 100644
--- a/openerp/tests/__init__.py
+++ b/openerp/tests/__init__.py
@@ -9,7 +9,7 @@ See the :ref:`test-framework` section in the :ref:`features` list.
"""
from . import test_expression, test_ir_sequence, test_orm,\
- test_uninstall, test_export
+ test_uninstall, test_export, test_import
fast_suite = [
test_ir_sequence,
@@ -19,6 +19,7 @@ checks = [
test_expression,
test_orm,
test_export,
+ test_import,
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
new file mode 100644
index 00000000000..4c5af087b2c
--- /dev/null
+++ b/openerp/tests/test_import.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+import openerp.modules.registry
+import openerp
+
+from . import common, export_models
+
+def ok(n):
+ """ Successful import of ``n`` records
+
+ :param int n: number of records which should have been imported
+ """
+ return n, 0, 0, 0
+
+def values(seq):
+ return [item['value'] for item in seq]
+
+def setupModule():
+ openerp.tools.config['update'] = {'base': 1}
+ openerp.modules.registry.RegistryManager.new(
+ common.DB, update_module=True)
+
+class ImporterCase(common.TransactionCase):
+ model_name = False
+
+ def __init__(self, *args, **kwargs):
+ super(ImporterCase, self).__init__(*args, **kwargs)
+ self.model = None
+
+ def setUp(self):
+ super(ImporterCase, self).setUp()
+ self.model = self.registry(self.model_name)
+
+ def import_(self, fields, rows, context=None):
+ return self.model.import_data(
+ self.cr, openerp.SUPERUSER_ID, fields, rows, context=context)
+ def read(self, fields=('value',), domain=(), context=None):
+ return self.model.read(
+ self.cr, openerp.SUPERUSER_ID,
+ self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
+ fields=fields, context=context)
+
+class test_boolean_field(ImporterCase):
+ model_name = 'export.boolean'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.import_(['value'], []),
+ ok(0))
+
+ def test_exported(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['False'],
+ ['True'],
+ ]),
+ ok(2))
+ records = self.read()
+ self.assertItemsEqual([
+ False,
+ True,
+ ], values(records))
+
+ def test_falses(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ [u'0'],
+ [u'off'],
+ [u'false'],
+ [u'FALSE'],
+ [u'OFF'],
+ ]),
+ ok(5))
+ self.assertItemsEqual([
+ False,
+ False,
+ False,
+ False,
+ False,
+ ],
+ values(self.read()))
+
+ def test_trues(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['no'],
+ ['None'],
+ ['nil'],
+ ['()'],
+ ['f'],
+ ['#f'],
+ ]),
+ ok(6))
+ self.assertItemsEqual(
+ [True] * 6,
+ values(self.read()))
From 59193b0c0fdcffb05e1a25a01f083bbf5b8d924d Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 13:36:33 +0200
Subject: [PATCH 09/36] [ADD] empty record/field case to booleans
bzr revid: xmo@openerp.com-20120730113633-tauioxm941k0iaqn
---
openerp/tests/test_import.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 4c5af087b2c..e29cc8a3ad9 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -55,7 +55,7 @@ class test_boolean_field(ImporterCase):
]),
ok(2))
records = self.read()
- self.assertItemsEqual([
+ self.assertEqual([
False,
True,
], values(records))
@@ -68,9 +68,11 @@ class test_boolean_field(ImporterCase):
[u'false'],
[u'FALSE'],
[u'OFF'],
+ [u''],
]),
- ok(5))
- self.assertItemsEqual([
+ ok(6))
+ self.assertEqual([
+ False,
False,
False,
False,
@@ -90,6 +92,7 @@ class test_boolean_field(ImporterCase):
['#f'],
]),
ok(6))
- self.assertItemsEqual(
+ self.assertEqual(
[True] * 6,
values(self.read()))
+
From 6af9bb41598dfdc03721fe228fb4c5f972335361 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 14:22:43 +0200
Subject: [PATCH 10/36] [TEST] integers import
bzr revid: xmo@openerp.com-20120730122243-wjpalm6ovwuk6k5c
---
openerp/tests/test_import.py | 88 +++++++++++++++++++++++++++++++++++-
1 file changed, 86 insertions(+), 2 deletions(-)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index e29cc8a3ad9..c38517a6f07 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -11,6 +11,18 @@ def ok(n):
"""
return n, 0, 0, 0
+def error(row, message, record=None, **kwargs):
+ """ Failed import of the record ``record`` at line ``row``, with the error
+ message ``message``
+
+ :param str message:
+ :param dict record:
+ """
+ return (
+ -1, dict(record or {}, **kwargs),
+ "Line %d : %s\n" % (row, message),
+ '')
+
def values(seq):
return [item['value'] for item in seq]
@@ -90,9 +102,81 @@ class test_boolean_field(ImporterCase):
['()'],
['f'],
['#f'],
+ # Problem: OpenOffice (and probably excel) output localized booleans
+ ['VRAI'],
]),
- ok(6))
+ ok(7))
self.assertEqual(
- [True] * 6,
+ [True] * 7,
values(self.read()))
+class test_integer_field(ImporterCase):
+ model_name = 'export.integer'
+
+ def test_none(self):
+ self.assertEqual(
+ self.import_(['value'], []),
+ ok(0))
+
+ def test_empty(self):
+ self.assertEqual(
+ self.import_(['value'], [['']]),
+ ok(1))
+ self.assertEqual(
+ [False],
+ values(self.read()))
+
+ def test_zero(self):
+ self.assertEqual(
+ self.import_(['value'], [['0']]),
+ ok(1))
+ self.assertEqual(
+ self.import_(['value'], [['-0']]),
+ ok(1))
+ self.assertEqual([False, False], values(self.read()))
+
+ def test_positives(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['1'],
+ ['42'],
+ [str(2**31-1)],
+ ['12345678']
+ ]),
+ ok(4))
+ self.assertEqual([
+ 1, 42, 2**31-1, 12345678
+ ], values(self.read()))
+
+ def test_negatives(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['-1'],
+ ['-42'],
+ [str(-(2**31 - 1))],
+ [str(-(2**31))],
+ ['-12345678']
+ ]),
+ ok(5))
+ self.assertEqual([
+ -1, -42, -(2**31 - 1), -(2**31), -12345678
+ ], values(self.read()))
+
+ def test_out_of_range(self):
+ self.assertEqual(
+ self.import_(['value'], [[str(2**31)]]),
+ error(1, "integer out of range", value=2**31))
+ # auto-rollbacks if error is in process_liness, but not during
+ # ir.model.data write. Can differentiate because former ends lines
+ # error lines with "!"
+ self.cr.rollback()
+ self.assertEqual(
+ self.import_(['value'], [[str(-2**32)]]),
+ error(1, "integer out of range", value=-2**32))
+
+
+ def test_nonsense(self):
+ # dafuq? why does that one raise an error?
+ self.assertRaises(
+ ValueError,
+ self.import_, ['value'], [['zorglub']])
From 1cf264cfd4ae468653f5aade0786f522a459bf58 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 16:28:51 +0200
Subject: [PATCH 11/36] [TEST] char and text fields
bzr revid: xmo@openerp.com-20120730142851-6854x99l4sxmoc0s
---
openerp/tests/test_import.py | 125 +++++++++++++++++++++++++++++++++++
1 file changed, 125 insertions(+)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index c38517a6f07..7fef60876e0 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -180,3 +180,128 @@ class test_integer_field(ImporterCase):
self.assertRaises(
ValueError,
self.import_, ['value'], [['zorglub']])
+
+class test_float_field(ImporterCase):
+ model_name = 'export.float'
+ def test_none(self):
+ self.assertEqual(
+ self.import_(['value'], []),
+ ok(0))
+
+ def test_empty(self):
+ self.assertEqual(
+ self.import_(['value'], [['']]),
+ ok(1))
+ self.assertEqual(
+ [False],
+ values(self.read()))
+
+ def test_zero(self):
+ self.assertEqual(
+ self.import_(['value'], [['0']]),
+ ok(1))
+ self.assertEqual(
+ self.import_(['value'], [['-0']]),
+ ok(1))
+ self.assertEqual([False, False], values(self.read()))
+
+ def test_positives(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['1'],
+ ['42'],
+ [str(2**31-1)],
+ ['12345678'],
+ [str(2**33)],
+ ['0.000001'],
+ ]),
+ ok(6))
+ self.assertEqual([
+ 1, 42, 2**31-1, 12345678, 2.0**33, .000001
+ ], values(self.read()))
+
+ def test_negatives(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['-1'],
+ ['-42'],
+ [str(-2**31 + 1)],
+ [str(-2**31)],
+ ['-12345678'],
+ [str(-2**33)],
+ ['-0.000001'],
+ ]),
+ ok(7))
+ self.assertEqual([
+ -1, -42, -(2**31 - 1), -(2**31), -12345678, -2.0**33, -.000001
+ ], values(self.read()))
+
+ def test_nonsense(self):
+ self.assertRaises(
+ ValueError,
+ self.import_, ['value'], [['foobar']])
+
+class test_string_field(ImporterCase):
+ model_name = 'export.string.bounded'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.import_(['value'], [['']]),
+ ok(1))
+ self.assertEqual([False], values(self.read()))
+
+ def test_imported(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ [u'foobar'],
+ [u'foobarbaz'],
+ [u'Með suð í eyrum við spilum endalaust'],
+ [u"People 'get' types. They use them all the time. Telling "
+ u"someone he can't pound a nail with a banana doesn't much "
+ u"surprise him."]
+ ]),
+ ok(4))
+ self.assertEqual([
+ u"foobar",
+ u"foobarbaz",
+ u"Með suð í eyrum ",
+ u"People 'get' typ",
+ ], values(self.read()))
+
+class test_unbound_string_field(ImporterCase):
+ model_name = 'export.string'
+
+ def test_imported(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ [u'í dag viðrar vel til loftárása'],
+ # ackbar.jpg
+ [u"If they ask you about fun, you tell them – fun is a filthy"
+ u" parasite"]
+ ]),
+ ok(2))
+ self.assertEqual([
+ u"í dag viðrar vel til loftárása",
+ u"If they ask you about fun, you tell them – fun is a filthy parasite"
+ ], values(self.read()))
+
+class test_text(ImporterCase):
+ model_name = 'export.text'
+
+ def test_empty(self):
+ self.assertEqual(
+ self.import_(['value'], [['']]),
+ ok(1))
+ self.assertEqual([False], values(self.read()))
+
+ def test_imported(self):
+ s = (u"Breiðskífa er notað um útgefna hljómplötu sem inniheldur "
+ u"stúdíóupptökur frá einum flytjanda. Breiðskífur eru oftast "
+ u"milli 25-80 mínútur og er lengd þeirra oft miðuð við 33⅓ "
+ u"snúninga 12 tommu vínylplötur (sem geta verið allt að 30 mín "
+ u"hvor hlið).\n\nBreiðskífur eru stundum tvöfaldar og eru þær þá"
+ u" gefnar út á tveimur geisladiskum eða tveimur vínylplötum.")
+ self.assertEqual(
+ self.import_(['value'], [[s]]),
+ ok(1))
+ self.assertEqual([s], values(self.read()))
From 5b5148b925e5750036257c33426faa41c5f61486 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 17:28:44 +0200
Subject: [PATCH 12/36] [TEST] selection fields import
bzr revid: xmo@openerp.com-20120730152844-xob3ezlw0qpb1kxc
---
openerp/tests/test_export.py | 2 ++
openerp/tests/test_import.py | 49 +++++++++++++++++++++++++++++++++---
2 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index ee4405db75d..01d0fbc7726 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -237,6 +237,8 @@ class test_selection(CreatorCase):
self.export(2),
[[u"Bar"]])
+ # TODO: localized export!
+
class test_selection_function(CreatorCase):
model_name = 'export.selection.function'
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 7fef60876e0..9c817236cf2 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -20,7 +20,7 @@ def error(row, message, record=None, **kwargs):
"""
return (
-1, dict(record or {}, **kwargs),
- "Line %d : %s\n" % (row, message),
+ "Line %d : %s" % (row, message),
'')
def values(seq):
@@ -165,14 +165,14 @@ class test_integer_field(ImporterCase):
def test_out_of_range(self):
self.assertEqual(
self.import_(['value'], [[str(2**31)]]),
- error(1, "integer out of range", value=2**31))
+ error(1, "integer out of range\n", value=2**31))
# auto-rollbacks if error is in process_liness, but not during
# ir.model.data write. Can differentiate because former ends lines
# error lines with "!"
self.cr.rollback()
self.assertEqual(
self.import_(['value'], [[str(-2**32)]]),
- error(1, "integer out of range", value=-2**32))
+ error(1, "integer out of range\n", value=-2**32))
def test_nonsense(self):
@@ -305,3 +305,46 @@ class test_text(ImporterCase):
self.import_(['value'], [[s]]),
ok(1))
self.assertEqual([s], values(self.read()))
+
+class test_selection(ImporterCase):
+ model_name = 'export.selection'
+
+ def test_imported(self):
+ self.assertEqual(
+ self.import_(['value'], [
+ ['Qux'],
+ ['Bar'],
+ ['Foo'],
+ [2],
+ ]),
+ ok(4))
+ self.assertEqual([3, 2, 1, 2], values(self.read()))
+
+ def test_invalid(self):
+ self.assertEqual(
+ self.import_(['value'], [['Baz']]),
+ error(1, "Key/value 'Baz' not found in selection field 'value'",
+ # what the fuck?
+ value=False))
+
+class test_selection_function(ImporterCase):
+ model_name = 'export.selection.function'
+
+ def test_imported(self):
+ """ By what bloody magic does that thing work?
+
+ => import uses fields_get, so translates import label (may or may not
+ be good news) *and* serializes the selection function to reverse
+ it: import does not actually know that the selection field uses a
+ function
+ """
+ # TODO: localized import
+ self.assertEqual(
+ self.import_(['value'], [
+ [3],
+ ["Grault"],
+ ]),
+ ok(2))
+ self.assertEqual(
+ ['3', '1'],
+ values(self.read()))
From 496177a9b1a8fbd517bf8faf453b8ac04a1e996c Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 17:30:17 +0200
Subject: [PATCH 13/36] [TEST] incorrect value for selection field import
bzr revid: xmo@openerp.com-20120730153017-iywveudrq5h0ykef
---
openerp/tests/test_import.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 9c817236cf2..c87f65c4c6e 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -326,6 +326,11 @@ class test_selection(ImporterCase):
error(1, "Key/value 'Baz' not found in selection field 'value'",
# what the fuck?
value=False))
+ self.cr.rollback()
+ self.assertEqual(
+ self.import_(['value'], [[42]]),
+ error(1, "Key/value '42' not found in selection field 'value'",
+ value=False))
class test_selection_function(ImporterCase):
model_name = 'export.selection.function'
From f8822ae313e380f72f5aff23b7f61d2f73939764 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 18:23:18 +0200
Subject: [PATCH 14/36] [TEST] m2o import
bzr revid: xmo@openerp.com-20120730162318-qwxncgvizrifgxyh
---
openerp/tests/export_models.py | 8 ++-
openerp/tests/test_import.py | 106 +++++++++++++++++++++++++++++++++
2 files changed, 113 insertions(+), 1 deletion(-)
diff --git a/openerp/tests/export_models.py b/openerp/tests/export_models.py
index 2f85ab473e8..277814808b4 100644
--- a/openerp/tests/export_models.py
+++ b/openerp/tests/export_models.py
@@ -42,7 +42,13 @@ for name, field in models:
'_defaults': {'const': 4},
'name_get': (lambda self, cr, uid, ids, context=None:
[(record.id, "%s:%s" % (self._name, record.value))
- for record in self.browse(cr, uid, ids, context=context)])
+ for record in self.browse(cr, uid, ids, context=context)]),
+ 'name_search': (lambda self, cr, uid, name, operator, context=None:
+ self.name_get(cr, uid,
+ self.search(cr, uid, [['value', operator, int(name.split(':')[1])]])
+ , context=context)
+ if isinstance(name, basestring) and name.split(':')[0] == self._name
+ else [])
}
NewModel = type(
'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index c87f65c4c6e..90e14375540 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -50,6 +50,12 @@ class ImporterCase(common.TransactionCase):
self.cr, openerp.SUPERUSER_ID,
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
fields=fields, context=context)
+ def browse(self, domain=(), context=None):
+ return self.model.browse(
+ self.cr, openerp.SUPERUSER_ID,
+ self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
+ context=context)
+
class test_boolean_field(ImporterCase):
model_name = 'export.boolean'
@@ -353,3 +359,103 @@ class test_selection_function(ImporterCase):
self.assertEqual(
['3', '1'],
values(self.read()))
+
+class test_o2m(ImporterCase):
+ model_name = 'export.many2one'
+
+ def test_by_name(self):
+ # create integer objects
+ integer_id1 = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ integer_id2 = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 36})
+ # get its name
+ name1 = dict(self.registry('export.integer').name_get(
+ self.cr, openerp.SUPERUSER_ID,[integer_id1]))[integer_id1]
+ name2 = dict(self.registry('export.integer').name_get(
+ self.cr, openerp.SUPERUSER_ID,[integer_id2]))[integer_id2]
+
+ self.assertEqual(
+ self.import_(['value'], [
+ # import by name_get
+ [name1],
+ [name1],
+ [name2],
+ ]),
+ ok(3))
+ # correct ids assigned to corresponding records
+ self.assertEqual([
+ (integer_id1, name1),
+ (integer_id1, name1),
+ (integer_id2, name2),],
+ values(self.read()))
+
+ # TODO: test import by xid
+
+ def test_by_id(self):
+ integer_id = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ self.assertEqual(
+ self.import_(['value/.id'], [[integer_id]]),
+ ok(1))
+ b = self.browse()
+ self.assertEqual(42, b[0].value.value)
+
+ def test_by_names(self):
+ integer_id1 = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ integer_id2 = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ name1 = dict(self.registry('export.integer').name_get(
+ self.cr, openerp.SUPERUSER_ID,[integer_id1]))[integer_id1]
+ name2 = dict(self.registry('export.integer').name_get(
+ self.cr, openerp.SUPERUSER_ID,[integer_id2]))[integer_id2]
+ # names should be the same
+ self.assertEqual(name1, name2)
+
+ self.assertEqual(
+ self.import_(['value'], [[name2]]),
+ ok(1))
+ # FIXME: is it really normal import does not care for name_search collisions?
+ self.assertEqual([
+ (integer_id1, name1)
+ ], values(self.read()))
+
+ def test_fail_by_implicit_id(self):
+ """ Can't implicitly import records by id
+ """
+ # create integer objects
+ integer_id1 = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ integer_id2 = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 36})
+
+ self.assertRaises(
+ ValueError, # Because name_search all the things. Fallback schmallback
+ self.import_, ['value'], [
+ # import by id, without specifying it
+ [integer_id1],
+ [integer_id2],
+ [integer_id1],
+ ])
+
+ def test_sub_field(self):
+ """ Does not implicitly create the record, does not warn that you can't
+ import m2o subfields (at all)...
+ """
+ self.assertRaises(
+ ValueError, # No record found for 42, name_searches the bloody thing
+ self.import_, ['value/value'], [['42']])
+
+ def test_fail_noids(self):
+ self.assertRaises(
+ ValueError,
+ self.import_, ['value'], [['nameisnoexist:3']])
+ self.cr.rollback()
+ self.assertRaises(
+ ValueError,
+ self.import_, ['value/id'], [['noxidhere']]),
+ self.cr.rollback()
+ self.assertRaises(
+ Exception, # FIXME: Why can't you be a ValueError like everybody else?
+ self.import_, ['value/.id'], [[66]])
From a3542213bc80ab9247e70a4f1353da6e36dd8266 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 30 Jul 2012 18:53:30 +0200
Subject: [PATCH 15/36] [TEST] ids handling on main record
bzr revid: xmo@openerp.com-20120730165330-lm4l1yzfjduajb1p
---
openerp/tests/test_import.py | 37 ++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 90e14375540..2305928a12e 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -56,6 +56,38 @@ class ImporterCase(common.TransactionCase):
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
context=context)
+class test_ids_stuff(ImporterCase):
+ model_name = 'export.integer'
+
+ def test_create_with_id(self):
+ self.assertRaises(
+ Exception, # dammit
+ self.import_, ['.id', 'value'], [['42', '36']])
+ def test_create_with_xid(self):
+ self.assertEqual(
+ self.import_(['id', 'value'], [['somexmlid', '42']]),
+ ok(1))
+ # TODO: get xid back, check that it is correct?
+
+ def test_update_with_id(self):
+ id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': 36})
+ self.assertEqual(
+ 36,
+ self.model.browse(self.cr, openerp.SUPERUSER_ID, id).value)
+
+ self.assertEqual(
+ self.import_(['.id', 'value'], [[str(id), '42']]),
+ ok(1))
+ self.assertEqual(
+ [42], # updated value to imported
+ values(self.read()))
+
+ def test_update_with_xid(self):
+ self.import_(['id', 'value'], [['somexmlid', '36']])
+ self.assertEqual([36], values(self.read()))
+
+ self.import_(['id', 'value'], [['somexmlid', '1234567']])
+ self.assertEqual([1234567], values(self.read()))
class test_boolean_field(ImporterCase):
model_name = 'export.boolean'
@@ -459,3 +491,8 @@ class test_o2m(ImporterCase):
self.assertRaises(
Exception, # FIXME: Why can't you be a ValueError like everybody else?
self.import_, ['value/.id'], [[66]])
+# TODO: M2M
+# TODO: O2M
+
+# function, related, reference: written to db as-is...
+# => function uses @type for value coercion/conversion
From 6bad3e84fb1093b3e9c1a3c99bea3cc19fd95e2e Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 31 Jul 2012 12:39:08 +0200
Subject: [PATCH 16/36] [TEST] m2o import link by xid
bzr revid: xmo@openerp.com-20120731103908-p1apmrx3ifnodz0f
---
openerp/tests/test_import.py | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 2305928a12e..0b0d8fe4d0d 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -392,7 +392,7 @@ class test_selection_function(ImporterCase):
['3', '1'],
values(self.read()))
-class test_o2m(ImporterCase):
+class test_m2o(ImporterCase):
model_name = 'export.many2one'
def test_by_name(self):
@@ -422,7 +422,21 @@ class test_o2m(ImporterCase):
(integer_id2, name2),],
values(self.read()))
- # TODO: test import by xid
+ def test_by_xid(self):
+ integer_id = self.registry('export.integer').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 42})
+ self.registry('ir.model.data').create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': 'export-integer-value',
+ 'model': 'export.integer',
+ 'res_id': integer_id,
+ 'module': 'test-export'
+ })
+
+ self.assertEqual(
+ self.import_(['value/id'], [['test-export.export-integer-value']]),
+ ok(1))
+ b = self.browse()
+ self.assertEqual(42, b[0].value.value)
def test_by_id(self):
integer_id = self.registry('export.integer').create(
@@ -491,7 +505,9 @@ class test_o2m(ImporterCase):
self.assertRaises(
Exception, # FIXME: Why can't you be a ValueError like everybody else?
self.import_, ['value/.id'], [[66]])
+
# TODO: M2M
+
# TODO: O2M
# function, related, reference: written to db as-is...
From ac647909bf97d6caf2ddc74b4daad6cea7752645 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 31 Jul 2012 15:54:49 +0200
Subject: [PATCH 17/36] [TEST] m2m import
bzr revid: xmo@openerp.com-20120731135449-i07ex1zswepen3wt
---
openerp/tests/export_models.py | 6 ++
openerp/tests/test_export.py | 2 +-
openerp/tests/test_import.py | 135 ++++++++++++++++++++++++++++++---
3 files changed, 132 insertions(+), 11 deletions(-)
diff --git a/openerp/tests/export_models.py b/openerp/tests/export_models.py
index 277814808b4..3bb5cf0c6d2 100644
--- a/openerp/tests/export_models.py
+++ b/openerp/tests/export_models.py
@@ -117,3 +117,9 @@ class Many2ManyChild(orm.Model):
def name_get(self, cr, uid, ids, context=None):
return [(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)]
+ def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
+ return (self.name_get(cr, user,
+ self.search(cr, user, [['value', operator, int(name.split(':')[1])]])
+ , context=context)
+ if isinstance(name, basestring) and name.split(':')[0] == self._name
+ else [])
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index 01d0fbc7726..d693de01993 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -537,7 +537,7 @@ class test_m2m(CreatorCase):
def test_multiple_records_name(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
- [[
+ [[ # FIXME: hardcoded comma, import uses config.csv_internal_sep
u'4', u','.join(self.names)
]])
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 0b0d8fe4d0d..b275db520c8 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -56,6 +56,30 @@ class ImporterCase(common.TransactionCase):
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
context=context)
+ def xid(self, record):
+ ModelData = self.registry('ir.model.data')
+
+ ids = ModelData.search(
+ self.cr, openerp.SUPERUSER_ID,
+ [('model', '=', record._table_name), ('res_id', '=', record.id)])
+ if ids:
+ d = ModelData.read(
+ self.cr, openerp.SUPERUSER_ID, ids, ['name', 'module'])[0]
+ if d['module']:
+ return '%s.%s' % (d['module'], d['name'])
+ return d['name']
+
+ name = dict(record.name_get())[record.id]
+ # fix dotted name_get results, otherwise xid lookups blow up
+ name = name.replace('.', '-')
+ ModelData.create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': name,
+ 'model': record._table_name,
+ 'res_id': record.id,
+ 'module': '__test__'
+ })
+ return '__test__.' + name
+
class test_ids_stuff(ImporterCase):
model_name = 'export.integer'
@@ -67,7 +91,9 @@ class test_ids_stuff(ImporterCase):
self.assertEqual(
self.import_(['id', 'value'], [['somexmlid', '42']]),
ok(1))
- # TODO: get xid back, check that it is correct?
+ self.assertEqual(
+ 'somexmlid',
+ self.xid(self.browse()[0]))
def test_update_with_id(self):
id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': 36})
@@ -423,17 +449,14 @@ class test_m2o(ImporterCase):
values(self.read()))
def test_by_xid(self):
- integer_id = self.registry('export.integer').create(
+ ExportInteger = self.registry('export.integer')
+ integer_id = ExportInteger.create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
- self.registry('ir.model.data').create(self.cr, openerp.SUPERUSER_ID, {
- 'name': 'export-integer-value',
- 'model': 'export.integer',
- 'res_id': integer_id,
- 'module': 'test-export'
- })
+ xid = self.xid(ExportInteger.browse(
+ self.cr, openerp.SUPERUSER_ID, [integer_id])[0])
self.assertEqual(
- self.import_(['value/id'], [['test-export.export-integer-value']]),
+ self.import_(['value/id'], [[xid]]),
ok(1))
b = self.browse()
self.assertEqual(42, b[0].value.value)
@@ -506,7 +529,99 @@ class test_m2o(ImporterCase):
Exception, # FIXME: Why can't you be a ValueError like everybody else?
self.import_, ['value/.id'], [[66]])
-# TODO: M2M
+class test_m2m(ImporterCase):
+ model_name = 'export.many2many'
+
+ # apparently, one and only thing which works is a
+ # csv_internal_sep-separated list of ids, xids, or names (depending if
+ # m2m/.id, m2m/id or m2m[/anythingelse]
+ def test_ids(self):
+ id1 = self.registry('export.many2many.other').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
+ id2 = self.registry('export.many2many.other').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
+ id3 = self.registry('export.many2many.other').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
+ id4 = self.registry('export.many2many.other').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
+ id5 = self.registry('export.many2many.other').create(
+ self.cr, openerp.SUPERUSER_ID, {'value': 99, 'str': 'record4'})
+
+ self.assertEqual(
+ self.import_(['value/.id'], [
+ ['%d,%d' % (id1, id2)],
+ ['%d,%d,%d' % (id1, id3, id4)],
+ ['%d,%d,%d' % (id1, id2, id3)],
+ ['%d' % id5]
+ ]),
+ ok(4))
+ ids = lambda records: [record.id for record in records]
+
+ b = self.browse()
+ self.assertEqual(ids(b[0].value), [id1, id2])
+ self.assertEqual(values(b[0].value), [3, 44])
+
+ self.assertEqual(ids(b[2].value), [id1, id2, id3])
+ self.assertEqual(values(b[2].value), [3, 44, 84])
+
+ def test_noids(self):
+ try:
+ self.import_(['value/.id'], [['42']])
+ self.fail("Should have raised an exception")
+ except Exception, e:
+ self.assertIs(type(e), Exception,
+ "test should be fixed on exception subclass")
+
+ def test_xids(self):
+ M2O_o = self.registry('export.many2many.other')
+ id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
+ id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
+ id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
+ id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
+ records = M2O_o.browse(self.cr, openerp.SUPERUSER_ID, [id1, id2, id3, id4])
+
+ self.assertEqual(
+ self.import_(['value/id'], [
+ ['%s,%s' % (self.xid(records[0]), self.xid(records[1]))],
+ ['%s' % self.xid(records[3])],
+ ['%s,%s' % (self.xid(records[2]), self.xid(records[1]))],
+ ]),
+ ok(3))
+
+ b = self.browse()
+ self.assertEqual(values(b[0].value), [3, 44])
+ self.assertEqual(values(b[2].value), [44, 84])
+ def test_noxids(self):
+ self.assertRaises(
+ ValueError,
+ self.import_, ['value/id'], [['noxidforthat']])
+
+ def test_names(self):
+ M2O_o = self.registry('export.many2many.other')
+ id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
+ id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
+ id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
+ id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
+ records = M2O_o.browse(self.cr, openerp.SUPERUSER_ID, [id1, id2, id3, id4])
+
+ name = lambda record: dict(record.name_get())[record.id]
+
+ self.assertEqual(
+ self.import_(['value'], [
+ ['%s,%s' % (name(records[1]), name(records[2]))],
+ ['%s,%s,%s' % (name(records[0]), name(records[1]), name(records[2]))],
+ ['%s,%s' % (name(records[0]), name(records[3]))],
+ ]),
+ ok(3))
+
+ b = self.browse()
+ self.assertEqual(values(b[1].value), [3, 44, 84])
+ self.assertEqual(values(b[2].value), [3, 9])
+
+ def test_nonames(self):
+ self.assertRaises(
+ ValueError,
+ self.import_, ['value'], [['wherethem2mhavenonames']])
# TODO: O2M
From 29e6a77fef10ebe06017bb55b492f8b004a0f80e Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 31 Jul 2012 16:46:06 +0200
Subject: [PATCH 18/36] [TEST] localized import/export of selection fields
bzr revid: xmo@openerp.com-20120731144606-ceax7lk3rfi7zumk
---
openerp/tests/test_export.py | 29 +++++++++++++-
openerp/tests/test_import.py | 74 +++++++++++++++++++++++++++++++++++-
2 files changed, 100 insertions(+), 3 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index d693de01993..d60e5a09dcb 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -224,6 +224,11 @@ class test_datetime(CreatorCase):
class test_selection(CreatorCase):
model_name = 'export.selection'
+ translations_fr = [
+ ("Qux", "toto"),
+ ("Bar", "titi"),
+ ("Foo", "tete"),
+ ]
def test_empty(self):
self.assertEqual(
@@ -237,7 +242,28 @@ class test_selection(CreatorCase):
self.export(2),
[[u"Bar"]])
- # TODO: localized export!
+ def test_localized_export(self):
+ self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': u'Français',
+ 'code': 'fr_FR',
+ 'translatable': True,
+ 'date_format': '%d.%m.%Y',
+ 'decimal_point': ',',
+ 'thousand_sep': ' ',
+ })
+ Translations = self.registry('ir.translation')
+ for source, value in self.translations_fr:
+ Translations.create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': 'export.selection,value',
+ 'lang': 'fr_FR',
+ 'type': 'selection',
+ 'src': source,
+ 'value': value
+ })
+ # FIXME: can't import an exported selection field label if lang != en_US
+ self.assertEqual(
+ self.export(2, context={'lang': 'fr_FR'}),
+ [[u'Bar']])
class test_selection_function(CreatorCase):
model_name = 'export.selection.function'
@@ -390,7 +416,6 @@ class test_o2m(CreatorCase):
[u'record5', '', u'13'],
])
-# todo: test with multiple o2m fields and exporting all
class test_o2m_multiple(CreatorCase):
model_name = 'export.one2many.multiple'
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index b275db520c8..7422ffd1a7a 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -372,6 +372,11 @@ class test_text(ImporterCase):
class test_selection(ImporterCase):
model_name = 'export.selection'
+ translations_fr = [
+ ("Qux", "toto"),
+ ("Bar", "titi"),
+ ("Foo", "tete"),
+ ]
def test_imported(self):
self.assertEqual(
@@ -384,6 +389,38 @@ class test_selection(ImporterCase):
ok(4))
self.assertEqual([3, 2, 1, 2], values(self.read()))
+ def test_imported_translated(self):
+ self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': u'Français',
+ 'code': 'fr_FR',
+ 'translatable': True,
+ 'date_format': '%d.%m.%Y',
+ 'decimal_point': ',',
+ 'thousand_sep': ' ',
+ })
+ Translations = self.registry('ir.translation')
+ for source, value in self.translations_fr:
+ Translations.create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': 'export.selection,value',
+ 'lang': 'fr_FR',
+ 'type': 'selection',
+ 'src': source,
+ 'value': value
+ })
+
+ self.assertEqual(
+ self.import_(['value'], [
+ ['toto'],
+ ['tete'],
+ ['titi'],
+ ], context={'lang': 'fr_FR'}),
+ ok(3))
+ self.assertEqual([3, 1, 2], values(self.read()))
+ self.assertEqual(
+ self.import_(['value'], [['Foo']], context={'lang': 'fr_FR'}),
+ error(1, "Key/value 'Foo' not found in selection field 'value'",
+ value=False))
+
def test_invalid(self):
self.assertEqual(
self.import_(['value'], [['Baz']]),
@@ -398,6 +435,12 @@ class test_selection(ImporterCase):
class test_selection_function(ImporterCase):
model_name = 'export.selection.function'
+ translations_fr = [
+ ("Corge", "toto"),
+ ("Grault", "titi"),
+ ("Whee", "tete"),
+ ("Moog", "tutu"),
+ ]
def test_imported(self):
""" By what bloody magic does that thing work?
@@ -407,7 +450,6 @@ class test_selection_function(ImporterCase):
it: import does not actually know that the selection field uses a
function
"""
- # TODO: localized import
self.assertEqual(
self.import_(['value'], [
[3],
@@ -418,6 +460,36 @@ class test_selection_function(ImporterCase):
['3', '1'],
values(self.read()))
+ def test_translated(self):
+ self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': u'Français',
+ 'code': 'fr_FR',
+ 'translatable': True,
+ 'date_format': '%d.%m.%Y',
+ 'decimal_point': ',',
+ 'thousand_sep': ' ',
+ })
+ Translations = self.registry('ir.translation')
+ for source, value in self.translations_fr:
+ Translations.create(self.cr, openerp.SUPERUSER_ID, {
+ 'name': 'export.selection,value',
+ 'lang': 'fr_FR',
+ 'type': 'selection',
+ 'src': source,
+ 'value': value
+ })
+ # FIXME: Fucking hell
+ self.assertEqual(
+ self.import_(['value'], [
+ ['toto'],
+ ['tete'],
+ ], context={'lang': 'fr_FR'}),
+ error(1, "Key/value 'toto' not found in selection field 'value'",
+ value=False))
+ self.assertEqual(
+ self.import_(['value'], [['Wheee']], context={'lang': 'fr_FR'}),
+ ok(1))
+
class test_m2o(ImporterCase):
model_name = 'export.many2one'
From e1c94f32212ed3d74b3aa84cc805fe614562e17a Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 31 Jul 2012 17:27:47 +0200
Subject: [PATCH 19/36] [TEST] importing m2m fields to an existing object with
m2m values
bzr revid: xmo@openerp.com-20120731152747-beg72fx2150upvay
---
openerp/tests/test_import.py | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 7422ffd1a7a..c2534caa929 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -695,7 +695,28 @@ class test_m2m(ImporterCase):
ValueError,
self.import_, ['value'], [['wherethem2mhavenonames']])
-# TODO: O2M
+ def test_import_to_existing(self):
+ M2O_o = self.registry('export.many2many.other')
+ id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
+ id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
+ id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
+ id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
+
+ xid = 'myxid'
+ self.assertEqual(
+ self.import_(['id', 'value/.id'], [[xid, '%d,%d' % (id1, id2)]]),
+ ok(1))
+ self.assertEqual(
+ self.import_(['id', 'value/.id'], [[xid, '%d,%d' % (id3, id4)]]),
+ ok(1))
+
+ b = self.browse()
+ self.assertEqual(len(b), 1)
+ # TODO: replacement of existing m2m values is correct?
+ self.assertEqual(values(b[0].value), [84, 9])
+
+class test_o2m(ImporterCase):
+ model_name = 'export.one2many'
# function, related, reference: written to db as-is...
# => function uses @type for value coercion/conversion
From c4a60df691a0822258489105b71018ff6b3d73c6 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Tue, 31 Jul 2012 18:36:31 +0200
Subject: [PATCH 20/36] [TEST] o2m db-id export and import
bzr revid: xmo@openerp.com-20120731163631-n97nxph9gm2f6kdp
---
openerp/tests/test_export.py | 17 +++++-
openerp/tests/test_import.py | 113 ++++++++++++++++++++++++++++++++++-
2 files changed, 127 insertions(+), 3 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index d60e5a09dcb..ed47b580365 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -376,6 +376,21 @@ class test_o2m(CreatorCase):
u'4', u','.join(self.names)
]])
+ def test_multiple_records_id(self):
+ export = self.export(self.commands, fields=['const', 'value/.id'])
+ O2M_c = self.registry('export.one2many.child')
+ ids = O2M_c.browse(self.cr, openerp.SUPERUSER_ID,
+ O2M_c.search(self.cr, openerp.SUPERUSER_ID, []))
+ self.assertEqual(
+ export,
+ [
+ ['4', str(ids[0].id)],
+ ['', str(ids[1].id)],
+ ['', str(ids[2].id)],
+ ['', str(ids[3].id)],
+ ['', str(ids[4].id)],
+ ])
+
def test_multiple_records_with_name_before(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value', 'value/value']),
@@ -383,7 +398,7 @@ class test_o2m(CreatorCase):
u'4', u','.join(self.names), u'4'
]])
- def test_multiple_records_with_name_before(self):
+ def test_multiple_records_with_name_after(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/value', 'value']),
[ # completely ignores name_get request
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index c2534caa929..c23d74d080a 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -23,8 +23,8 @@ def error(row, message, record=None, **kwargs):
"Line %d : %s" % (row, message),
'')
-def values(seq):
- return [item['value'] for item in seq]
+def values(seq, field='value'):
+ return [item[field] for item in seq]
def setupModule():
openerp.tools.config['update'] = {'base': 1}
@@ -718,5 +718,114 @@ class test_m2m(ImporterCase):
class test_o2m(ImporterCase):
model_name = 'export.one2many'
+ def test_single(self):
+ self.assertEqual(
+ self.import_(['const', 'value/value'], [
+ ['5', '63']
+ ]),
+ ok(1))
+
+ (b,) = self.browse()
+ self.assertEqual(b.const, 5)
+ self.assertEqual(values(b.value), [63])
+
+ def test_multicore(self):
+ self.assertEqual(
+ self.import_(['const', 'value/value'], [
+ ['5', '63'],
+ ['6', '64'],
+ ]),
+ ok(2))
+
+ b1, b2 = self.browse()
+ self.assertEqual(b1.const, 5)
+ self.assertEqual(values(b1.value), [63])
+ self.assertEqual(b2.const, 6)
+ self.assertEqual(values(b2.value), [64])
+
+ def test_multisub(self):
+ self.assertEqual(
+ self.import_(['const', 'value/value'], [
+ ['5', '63'],
+ ['', '64'],
+ ['', '65'],
+ ['', '66'],
+ ]),
+ ok(4))
+
+ (b,) = self.browse()
+ self.assertEqual(values(b.value), [63, 64, 65, 66])
+
+ def test_multi_subfields(self):
+ self.assertEqual(
+ self.import_(['value/str', 'const', 'value/value'], [
+ ['this', '5', '63'],
+ ['is', '', '64'],
+ ['the', '', '65'],
+ ['rhythm', '', '66'],
+ ]),
+ ok(4))
+
+ (b,) = self.browse()
+ self.assertEqual(values(b.value), [63, 64, 65, 66])
+ self.assertEqual(
+ values(b.value, 'str'),
+ 'this is the rhythm'.split())
+
+ def test_link(self):
+ id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
+ 'str': 'Bf', 'value': 109
+ })
+ id2 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
+ 'str': 'Me', 'value': 262
+ })
+
+ self.assertEqual(
+ self.import_(['const', 'value/.id'], [
+ ['42', str(id1)],
+ ['', str(id2)],
+ ]),
+ ok(2))
+
+ # No record values alongside id => o2m resolution skipped altogether,
+ # creates 2 records
+ b, b1 = self.browse()
+ self.assertEqual(b.const, 42)
+ self.assertEqual(values(b.value), [])
+ self.assertEqual(b1.const, 4)
+ self.assertEqual(values(b1.value), [])
+
+ def test_link_2(self):
+ O2M_c = self.registry('export.one2many.child')
+ id1 = O2M_c.create(self.cr, openerp.SUPERUSER_ID, {
+ 'str': 'Bf', 'value': 109
+ })
+ id2 = O2M_c.create(self.cr, openerp.SUPERUSER_ID, {
+ 'str': 'Me', 'value': 262
+ })
+
+ self.assertEqual(
+ self.import_(['const', 'value/.id', 'value/value'], [
+ ['42', str(id1), '1'],
+ ['', str(id2), '2'],
+ ]),
+ ok(2))
+
+ (b,) = self.browse()
+ # if an id (db or xid) is provided, expectations that objects are
+ # *already* linked and emits UPDATE (1, id, {}).
+ # Noid => CREATE (0, ?, {})
+ # TODO: xid ignored aside from getting corresponding db id?
+ self.assertEqual(b.const, 42)
+ self.assertEqual(values(b.value), [])
+
+ # FIXME: updates somebody else's records?
+ self.assertEqual(
+ O2M_c.read(self.cr, openerp.SUPERUSER_ID, id1),
+ {'id': id1, 'str': 'Bf', 'value': 1, 'parent_id': False})
+ self.assertEqual(
+ O2M_c.read(self.cr, openerp.SUPERUSER_ID, id2),
+ {'id': id2, 'str': 'Me', 'value': 2, 'parent_id': False})
+
# function, related, reference: written to db as-is...
# => function uses @type for value coercion/conversion
From 3f1ab77e2858659388426b5148b8c91c71c6bc3a Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Wed, 1 Aug 2012 09:08:03 +0200
Subject: [PATCH 21/36] [TEST] o2m importing of multiple fields
bzr revid: xmo@openerp.com-20120801070803-4sgvemuiifrhe61s
---
openerp/tests/test_import.py | 66 +++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index c23d74d080a..08c52dd902c 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -772,6 +772,8 @@ class test_o2m(ImporterCase):
values(b.value, 'str'),
'this is the rhythm'.split())
+ # TODO: failing inline LINK_TO
+
def test_link(self):
id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
@@ -788,7 +790,8 @@ class test_o2m(ImporterCase):
ok(2))
# No record values alongside id => o2m resolution skipped altogether,
- # creates 2 records
+ # creates 2 records => remove/don't import columns sideshow columns,
+ # get completely different semantics
b, b1 = self.browse()
self.assertEqual(b.const, 42)
self.assertEqual(values(b.value), [])
@@ -827,5 +830,66 @@ class test_o2m(ImporterCase):
O2M_c.read(self.cr, openerp.SUPERUSER_ID, id2),
{'id': id2, 'str': 'Me', 'value': 2, 'parent_id': False})
+ # TODO: name_get?
+
+class test_o2m_multiple(ImporterCase):
+ model_name = 'export.one2many.multiple'
+
+ def test_multi_mixed(self):
+ self.assertEqual(
+ self.import_(['const', 'child1/value', 'child2/value'], [
+ ['5', '11', '21'],
+ ['', '12', '22'],
+ ['', '13', '23'],
+ ['', '14', ''],
+ ]),
+ ok(4))
+ # Oh yeah, that's the stuff
+ (b, b1, b2) = self.browse()
+ self.assertEqual(values(b.child1), [11])
+ self.assertEqual(values(b.child2), [21])
+
+ self.assertEqual(values(b1.child1), [12])
+ self.assertEqual(values(b1.child2), [22])
+
+ self.assertEqual(values(b2.child1), [13, 14])
+ self.assertEqual(values(b2.child2), [23])
+
+ def test_multi(self):
+ self.assertEqual(
+ self.import_(['const', 'child1/value', 'child2/value'], [
+ ['5', '11', '21'],
+ ['', '12', ''],
+ ['', '13', ''],
+ ['', '14', ''],
+ ['', '', '22'],
+ ['', '', '23'],
+ ]),
+ ok(6))
+ # What the actual fuck?
+ (b, b1) = self.browse()
+ self.assertEqual(values(b.child1), [11, 12, 13, 14])
+ self.assertEqual(values(b.child2), [21])
+ self.assertEqual(values(b1.child2), [22, 23])
+
+ def test_multi_fullsplit(self):
+ self.assertEqual(
+ self.import_(['const', 'child1/value', 'child2/value'], [
+ ['5', '11', ''],
+ ['', '12', ''],
+ ['', '13', ''],
+ ['', '14', ''],
+ ['', '', '21'],
+ ['', '', '22'],
+ ['', '', '23'],
+ ]),
+ ok(7))
+ # oh wow
+ (b, b1) = self.browse()
+ self.assertEqual(b.const, 5)
+ self.assertEqual(values(b.child1), [11, 12, 13, 14])
+ self.assertEqual(b1.const, 36)
+ self.assertEqual(values(b1.child2), [21, 22, 23])
+
# function, related, reference: written to db as-is...
# => function uses @type for value coercion/conversion
From e3dc73880280fca68d43eb4352c8d56c3e47debc Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Wed, 1 Aug 2012 10:21:08 +0200
Subject: [PATCH 22/36] [TEST] failure of o2m relinking via inline id (as
exported)
bzr revid: xmo@openerp.com-20120801082108-vkind3ocwsqgd0bv
---
openerp/tests/test_import.py | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 08c52dd902c..87e7ae9c350 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -772,7 +772,24 @@ class test_o2m(ImporterCase):
values(b.value, 'str'),
'this is the rhythm'.split())
- # TODO: failing inline LINK_TO
+ def test_link_inline(self):
+ id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
+ 'str': 'Bf', 'value': 109
+ })
+ id2 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
+ 'str': 'Me', 'value': 262
+ })
+
+ try:
+ self.import_(['const', 'value/.id'], [
+ ['42', '%d,%d' % (id1, id2)]
+ ])
+ except ValueError, e:
+ # should be Exception(Database ID doesn't exist: export.one2many.child : $id1,$id2)
+ self.assertIs(type(e), ValueError)
+ self.assertEqual(
+ e.args[0],
+ "invalid literal for int() with base 10: '%d,%d'" % (id1, id2))
def test_link(self):
id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
@@ -830,8 +847,6 @@ class test_o2m(ImporterCase):
O2M_c.read(self.cr, openerp.SUPERUSER_ID, id2),
{'id': id2, 'str': 'Me', 'value': 2, 'parent_id': False})
- # TODO: name_get?
-
class test_o2m_multiple(ImporterCase):
model_name = 'export.one2many.multiple'
From 471ef96edf890014df766a0ee956fe190f4e5480 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Wed, 1 Aug 2012 11:44:34 +0200
Subject: [PATCH 23/36] [FIX] some notes and comments in import/export tests
bzr revid: xmo@openerp.com-20120801094434-t23wa2343utnevh6
---
openerp/tests/test_export.py | 5 ++---
openerp/tests/test_import.py | 21 +++++++++++----------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index ed47b580365..e545fe24c61 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -218,6 +218,7 @@ class test_datetime(CreatorCase):
.. note:: on the other hand, export uses user lang for name_get
"""
+ # NOTE: ignores user timezone, always exports to UTC
self.assertEqual(
self.export('2011-11-07 21:05:48', context={'tz': 'Pacific/Norfolk'}),
[[u'2011-11-07 21:05:48']])
@@ -260,7 +261,6 @@ class test_selection(CreatorCase):
'src': source,
'value': value
})
- # FIXME: can't import an exported selection field label if lang != en_US
self.assertEqual(
self.export(2, context={'lang': 'fr_FR'}),
[[u'Bar']])
@@ -274,8 +274,7 @@ class test_selection_function(CreatorCase):
[[False]])
def test_value(self):
- """ selection functions export the *value* itself
- """
+ # FIXME: selection functions export the *value* itself
self.assertEqual(
self.export(1),
[[u'1']])
diff --git a/openerp/tests/test_import.py b/openerp/tests/test_import.py
index 87e7ae9c350..de2553427e0 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/test_import.py
@@ -240,7 +240,7 @@ class test_integer_field(ImporterCase):
def test_nonsense(self):
- # dafuq? why does that one raise an error?
+ # FIXME: shit error reporting, exceptions half the time, messages the other half
self.assertRaises(
ValueError,
self.import_, ['value'], [['zorglub']])
@@ -384,7 +384,7 @@ class test_selection(ImporterCase):
['Qux'],
['Bar'],
['Foo'],
- [2],
+ ['2'],
]),
ok(4))
self.assertEqual([3, 2, 1, 2], values(self.read()))
@@ -408,6 +408,8 @@ class test_selection(ImporterCase):
'value': value
})
+ # FIXME: can't import an exported selection field label if lang != en_US
+ # (see test_export.test_selection.test_localized_export)
self.assertEqual(
self.import_(['value'], [
['toto'],
@@ -443,16 +445,14 @@ class test_selection_function(ImporterCase):
]
def test_imported(self):
- """ By what bloody magic does that thing work?
-
- => import uses fields_get, so translates import label (may or may not
- be good news) *and* serializes the selection function to reverse
- it: import does not actually know that the selection field uses a
- function
+ """ import uses fields_get, so translates import label (may or may not
+ be good news) *and* serializes the selection function to reverse it:
+ import does not actually know that the selection field uses a function
"""
+ # NOTE: conflict between a value and a label => ?
self.assertEqual(
self.import_(['value'], [
- [3],
+ ['3'],
["Grault"],
]),
ok(2))
@@ -461,6 +461,8 @@ class test_selection_function(ImporterCase):
values(self.read()))
def test_translated(self):
+ """ Expects output of selection function returns translated labels
+ """
self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
'name': u'Français',
'code': 'fr_FR',
@@ -478,7 +480,6 @@ class test_selection_function(ImporterCase):
'src': source,
'value': value
})
- # FIXME: Fucking hell
self.assertEqual(
self.import_(['value'], [
['toto'],
From 6d6e66cfc1758444c635e3e4abd55ca16e3e9dbe Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 6 Aug 2012 15:02:20 +0200
Subject: [PATCH 24/36] [IMP] fixme comment
bzr revid: xmo@openerp.com-20120806130220-6s525hr0jolzenv9
---
openerp/tests/test_export.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/openerp/tests/test_export.py b/openerp/tests/test_export.py
index e545fe24c61..b8e33b418a6 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/test_export.py
@@ -577,6 +577,7 @@ class test_m2m(CreatorCase):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
[[ # FIXME: hardcoded comma, import uses config.csv_internal_sep
+ # resolution: remove configurable csv_internal_sep
u'4', u','.join(self.names)
]])
From 346397530da50bcbb0bc8d3248212b7756a5ba13 Mon Sep 17 00:00:00 2001
From: Xavier Morel
Date: Mon, 6 Aug 2012 15:27:31 +0200
Subject: [PATCH 25/36] [FIX] weird dict.update calls
bzr revid: xmo@openerp.com-20120806132731-ck4usrs99qlh1pq9
---
openerp/osv/orm.py | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index 02a13a41dcb..31d68b64911 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -2434,9 +2434,9 @@ class BaseModel(object):
context=context)
result_template = dict.fromkeys(aggregated_fields, False)
- result_template.update({groupby + '_count':0})
+ result_template[groupby + '_count'] = 0
if groupby_list and len(groupby_list) > 1:
- result_template.update(__context={'group_by': groupby_list[1:]})
+ result_template['__context'] = {'group_by': groupby_list[1:]}
# Merge the left_side (current results as dicts) with the right_side (all
# possible values as m2o pairs). Both lists are supposed to be using the
@@ -2455,10 +2455,8 @@ class BaseModel(object):
grouped_value = right_side[0]
if not grouped_value in known_values:
line = dict(result_template)
- line.update({
- groupby: right_side,
- '__domain': [(groupby,'=',grouped_value)] + domain,
- })
+ line[groupby] = right_side
+ line['__domain'] = [(groupby,'=',grouped_value)] + domain
result.append(line)
known_values[grouped_value] = line
while read_group_result or all_groups:
From 00d2d2fe05b7adc4e04d665f281eb696871cfa53 Mon Sep 17 00:00:00 2001
From: Vo Minh Thu
Date: Tue, 7 Aug 2012 16:37:44 +0200
Subject: [PATCH 26/36] [IMP] impex tests: moved test cases and models in their
own test module.
bzr revid: vmt@openerp.com-20120807143744-zsbwktjmy5d79jki
---
openerp/tests/__init__.py | 4 +---
openerp/tests/addons/test_impex/__init__.py | 1 +
openerp/tests/addons/test_impex/__openerp__.py | 15 +++++++++++++++
.../test_impex/models.py} | 7 -------
openerp/tests/addons/test_impex/tests/__init__.py | 13 +++++++++++++
.../{ => addons/test_impex/tests}/test_export.py | 4 +---
.../{ => addons/test_impex/tests}/test_import.py | 4 +---
7 files changed, 32 insertions(+), 16 deletions(-)
create mode 100644 openerp/tests/addons/test_impex/__init__.py
create mode 100644 openerp/tests/addons/test_impex/__openerp__.py
rename openerp/tests/{export_models.py => addons/test_impex/models.py} (96%)
create mode 100644 openerp/tests/addons/test_impex/tests/__init__.py
rename openerp/tests/{ => addons/test_impex/tests}/test_export.py (99%)
rename openerp/tests/{ => addons/test_impex/tests}/test_import.py (99%)
diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py
index 4b8fa798aea..927a375df64 100644
--- a/openerp/tests/__init__.py
+++ b/openerp/tests/__init__.py
@@ -9,7 +9,7 @@ See the :ref:`test-framework` section in the :ref:`features` list.
"""
from . import test_expression, test_ir_sequence, test_orm,\
- test_uninstall, test_export, test_import
+ test_uninstall
fast_suite = [
test_ir_sequence,
@@ -18,8 +18,6 @@ fast_suite = [
checks = [
test_expression,
test_orm,
- test_export,
- test_import,
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/addons/test_impex/__init__.py b/openerp/tests/addons/test_impex/__init__.py
new file mode 100644
index 00000000000..bff786c0885
--- /dev/null
+++ b/openerp/tests/addons/test_impex/__init__.py
@@ -0,0 +1 @@
+import models
diff --git a/openerp/tests/addons/test_impex/__openerp__.py b/openerp/tests/addons/test_impex/__openerp__.py
new file mode 100644
index 00000000000..f3b5511dc30
--- /dev/null
+++ b/openerp/tests/addons/test_impex/__openerp__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': 'test-import-export',
+ 'version': '0.1',
+ 'category': 'Tests',
+ 'description': """A module to test import/export.""",
+ 'author': 'OpenERP SA',
+ 'maintainer': 'OpenERP SA',
+ 'website': 'http://www.openerp.com',
+ 'depends': ['base'],
+ 'data': [],
+ 'installable': True,
+ 'auto_install': False,
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/export_models.py b/openerp/tests/addons/test_impex/models.py
similarity index 96%
rename from openerp/tests/export_models.py
rename to openerp/tests/addons/test_impex/models.py
index 3bb5cf0c6d2..455ea6b22f4 100644
--- a/openerp/tests/export_models.py
+++ b/openerp/tests/addons/test_impex/models.py
@@ -34,7 +34,6 @@ models = [
for name, field in models:
attrs = {
'_name': 'export.%s' % name,
- '_module': 'base',
'_columns': {
'const': fields.integer(),
'value': field
@@ -57,7 +56,6 @@ for name, field in models:
class One2ManyChild(orm.Model):
_name = 'export.one2many.child'
- _module = 'base'
# FIXME: orm.py:1161, fix to name_get on m2o field
_rec_name = 'value'
@@ -72,7 +70,6 @@ class One2ManyChild(orm.Model):
class One2ManyMultiple(orm.Model):
_name = 'export.one2many.multiple'
- _module = 'base'
_columns = {
'const': fields.integer(),
@@ -83,7 +80,6 @@ class One2ManyMultiple(orm.Model):
class One2ManyChildMultiple(orm.Model):
_name = 'export.one2many.multiple.child'
- _module = 'base'
# FIXME: orm.py:1161, fix to name_get on m2o field
_rec_name = 'value'
@@ -97,16 +93,13 @@ class One2ManyChildMultiple(orm.Model):
for record in self.browse(cr, uid, ids, context=context)]
class One2ManyChild1(orm.Model):
_name = 'export.one2many.child.1'
- _module = 'base'
_inherit = 'export.one2many.multiple.child'
class One2ManyChild2(orm.Model):
_name = 'export.one2many.child.2'
- _module = 'base'
_inherit = 'export.one2many.multiple.child'
class Many2ManyChild(orm.Model):
_name = 'export.many2many.other'
- _module = 'base'
# FIXME: orm.py:1161, fix to name_get on m2o field
_rec_name = 'value'
diff --git a/openerp/tests/addons/test_impex/tests/__init__.py b/openerp/tests/addons/test_impex/tests/__init__.py
new file mode 100644
index 00000000000..d6af53cba1b
--- /dev/null
+++ b/openerp/tests/addons/test_impex/tests/__init__.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+
+from . import test_export, test_import
+
+fast_suite = [
+]
+
+checks = [
+ test_export,
+ test_import,
+]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/test_export.py b/openerp/tests/addons/test_impex/tests/test_export.py
similarity index 99%
rename from openerp/tests/test_export.py
rename to openerp/tests/addons/test_impex/tests/test_export.py
index b8e33b418a6..812a84b3a21 100644
--- a/openerp/tests/test_export.py
+++ b/openerp/tests/addons/test_impex/tests/test_export.py
@@ -3,13 +3,11 @@ import itertools
import openerp.modules.registry
import openerp
-from . import common, export_models
+from openerp.tests import common
def setUpModule():
openerp.tools.config['update'] = {'base': 1}
- openerp.modules.registry.RegistryManager.new(
- common.DB, update_module=True)
class CreatorCase(common.TransactionCase):
model_name = False
diff --git a/openerp/tests/test_import.py b/openerp/tests/addons/test_impex/tests/test_import.py
similarity index 99%
rename from openerp/tests/test_import.py
rename to openerp/tests/addons/test_impex/tests/test_import.py
index de2553427e0..9999a9c6e5d 100644
--- a/openerp/tests/test_import.py
+++ b/openerp/tests/addons/test_impex/tests/test_import.py
@@ -2,7 +2,7 @@
import openerp.modules.registry
import openerp
-from . import common, export_models
+from openerp.tests import common
def ok(n):
""" Successful import of ``n`` records
@@ -28,8 +28,6 @@ def values(seq, field='value'):
def setupModule():
openerp.tools.config['update'] = {'base': 1}
- openerp.modules.registry.RegistryManager.new(
- common.DB, update_module=True)
class ImporterCase(common.TransactionCase):
model_name = False
From b77da916e5386b5e291f3da6b54b4253ff9dac3e Mon Sep 17 00:00:00 2001
From: Vo Minh Thu
Date: Tue, 7 Aug 2012 16:45:19 +0200
Subject: [PATCH 27/36] [FIX] impex tests: removed unnecessary code.
bzr revid: vmt@openerp.com-20120807144519-r7tz3fh6ieslra1c
---
openerp/tests/addons/test_impex/tests/test_export.py | 3 ---
openerp/tests/addons/test_impex/tests/test_import.py | 3 ---
2 files changed, 6 deletions(-)
diff --git a/openerp/tests/addons/test_impex/tests/test_export.py b/openerp/tests/addons/test_impex/tests/test_export.py
index 812a84b3a21..7e67ba581a1 100644
--- a/openerp/tests/addons/test_impex/tests/test_export.py
+++ b/openerp/tests/addons/test_impex/tests/test_export.py
@@ -6,9 +6,6 @@ import openerp
from openerp.tests import common
-def setUpModule():
- openerp.tools.config['update'] = {'base': 1}
-
class CreatorCase(common.TransactionCase):
model_name = False
diff --git a/openerp/tests/addons/test_impex/tests/test_import.py b/openerp/tests/addons/test_impex/tests/test_import.py
index 9999a9c6e5d..ab12f0375b5 100644
--- a/openerp/tests/addons/test_impex/tests/test_import.py
+++ b/openerp/tests/addons/test_impex/tests/test_import.py
@@ -26,9 +26,6 @@ def error(row, message, record=None, **kwargs):
def values(seq, field='value'):
return [item[field] for item in seq]
-def setupModule():
- openerp.tools.config['update'] = {'base': 1}
-
class ImporterCase(common.TransactionCase):
model_name = False
From 80d8c2c866df4940c9fce48c32e4399b1b1303ff Mon Sep 17 00:00:00 2001
From: Stephane Wirtel
Date: Thu, 9 Aug 2012 11:57:33 +0200
Subject: [PATCH 28/36] [FIX] import_google: bad inheritance of the
crm_meeting_form view
bzr revid: stw@openerp.com-20120809095733-b4pjaww2muo5ncze
---
addons/import_google/sync_google_calendar_view.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addons/import_google/sync_google_calendar_view.xml b/addons/import_google/sync_google_calendar_view.xml
index 626d803d4df..c7f68de15a7 100644
--- a/addons/import_google/sync_google_calendar_view.xml
+++ b/addons/import_google/sync_google_calendar_view.xml
@@ -7,8 +7,8 @@
form
-
-
+
+ [('user_id', 'in', [uid, False])]
From 6aad16cf6b81aee5cf4563ef76a988d150dc9da1 Mon Sep 17 00:00:00 2001
From: Stephane Wirtel
Date: Thu, 9 Aug 2012 12:24:31 +0200
Subject: [PATCH 29/36] [FIX] account: show the product on the
account.invoice.line
bzr revid: stw@openerp.com-20120809102431-mxzx6c2iagwjp28f
---
addons/account/account_invoice_view.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 501a50b96c2..03d127249fb 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -347,7 +347,7 @@
-
+
Date: Thu, 9 Aug 2012 12:50:09 +0200
Subject: [PATCH 30/36] [FIX] project*: Replace the labels with 'Partner' by
Contact
bzr revid: stw@openerp.com-20120809105009-0f7mw99dnavgs01s
---
addons/project/project.py | 2 +-
addons/project/project_demo.xml | 2 +-
addons/project/project_view.xml | 4 ++--
addons/project/report/project_report.py | 2 +-
addons/project/report/project_report_view.xml | 2 +-
addons/project_issue/project_issue.py | 2 +-
addons/project_issue/project_issue_view.xml | 2 +-
addons/project_issue/report/project_issue_report.py | 2 +-
addons/project_issue/report/project_issue_report_view.xml | 2 +-
addons/project_timesheet/project_timesheet_view.xml | 2 +-
10 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/addons/project/project.py b/addons/project/project.py
index 707df5607c6..6f3b23f4746 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -788,7 +788,7 @@ class task(base_stage, osv.osv):
}),
'user_id': fields.many2one('res.users', 'Assigned to'),
'delegated_user_id': fields.related('child_ids', 'user_id', type='many2one', relation='res.users', string='Delegated To'),
- 'partner_id': fields.many2one('res.partner', 'Partner'),
+ 'partner_id': fields.many2one('res.partner', 'Contact'),
'work_ids': fields.one2many('project.task.work', 'task_id', 'Work done'),
'manager_id': fields.related('project_id', 'analytic_account_id', 'user_id', type='many2one', relation='res.users', string='Project Manager'),
'company_id': fields.many2one('res.company', 'Company'),
diff --git a/addons/project/project_demo.xml b/addons/project/project_demo.xml
index cf3353a3750..fb4b37edb2b 100644
--- a/addons/project/project_demo.xml
+++ b/addons/project/project_demo.xml
@@ -71,7 +71,7 @@
- Partner's suggestion
+ Contact's suggestion
Feature request
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 199dd5f712d..604b04fdb6c 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -171,10 +171,10 @@
-
+
-
+
diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py
index 36e025ab509..6c1f5443835 100644
--- a/addons/project/report/project_report.py
+++ b/addons/project/report/project_report.py
@@ -53,7 +53,7 @@ class report_project_task_user(osv.osv):
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True, groups="base.group_multi_company"),
- 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
+ 'partner_id': fields.many2one('res.partner', 'Contact', readonly=True),
}
_order = 'name desc, project_id'
diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml
index ab880536ced..9383a588e3a 100644
--- a/addons/project/report/project_report_view.xml
+++ b/addons/project/report/project_report_view.xml
@@ -80,7 +80,7 @@
-
+
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index 935935e28ca..7b2afbeacf2 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -219,7 +219,7 @@ class project_issue(base_stage, osv.osv):
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
- 'partner_id': fields.many2one('res.partner', 'Partner', select=1),
+ 'partner_id': fields.many2one('res.partner', 'Contact', select=1),
'company_id': fields.many2one('res.company', 'Company'),
'description': fields.text('Description'),
'state': fields.related('stage_id', 'state', type="selection", store=True,
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index de52ec8d033..c01409b9466 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -210,7 +210,7 @@
-
+
diff --git a/addons/project_issue/report/project_issue_report.py b/addons/project_issue/report/project_issue_report.py
index b43cbc51c50..bb95d5195c4 100644
--- a/addons/project_issue/report/project_issue_report.py
+++ b/addons/project_issue/report/project_issue_report.py
@@ -63,7 +63,7 @@ class project_issue_report(osv.osv):
'project_id':fields.many2one('project.project', 'Project',readonly=True),
'version_id': fields.many2one('project.issue.version', 'Version'),
'user_id' : fields.many2one('res.users', 'Assigned to',readonly=True),
- 'partner_id': fields.many2one('res.partner','Partner',domain="[('object_id.model', '=', 'project.issue')]"),
+ 'partner_id': fields.many2one('res.partner','Contact',domain="[('object_id.model', '=', 'project.issue')]"),
'channel_id': fields.many2one('crm.case.channel', 'Channel',readonly=True),
'task_id': fields.many2one('project.task', 'Task',domain="[('object_id.model', '=', 'project.issue')]" ),
'email': fields.integer('# Emails', size=128, readonly=True),
diff --git a/addons/project_issue/report/project_issue_report_view.xml b/addons/project_issue/report/project_issue_report_view.xml
index c1ae69517c2..076e542b827 100644
--- a/addons/project_issue/report/project_issue_report_view.xml
+++ b/addons/project_issue/report/project_issue_report_view.xml
@@ -62,7 +62,7 @@
-
+
diff --git a/addons/project_timesheet/project_timesheet_view.xml b/addons/project_timesheet/project_timesheet_view.xml
index 46e3ac43551..1c6ba1a05f4 100644
--- a/addons/project_timesheet/project_timesheet_view.xml
+++ b/addons/project_timesheet/project_timesheet_view.xml
@@ -36,7 +36,7 @@
-
+
From 5ac8f97de03d3109946989772aaf223c44191382 Mon Sep 17 00:00:00 2001
From: Launchpad Translations on behalf of openerp <>
Date: Fri, 10 Aug 2012 04:58:41 +0000
Subject: [PATCH 31/36] Launchpad automatic translations update.
bzr revid: launchpad_translations_on_behalf_of_openerp-20120810045841-5b2hoy7t0d4sotjr
---
openerp/addons/base/i18n/nl.po | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/openerp/addons/base/i18n/nl.po b/openerp/addons/base/i18n/nl.po
index 818bd5c4602..45560f7e363 100644
--- a/openerp/addons/base/i18n/nl.po
+++ b/openerp/addons/base/i18n/nl.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:44+0000\n"
-"PO-Revision-Date: 2012-02-19 13:01+0000\n"
+"PO-Revision-Date: 2012-08-09 06:15+0000\n"
"Last-Translator: Erwin \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-07-19 04:38+0000\n"
-"X-Generator: Launchpad (build 15637)\n"
+"X-Launchpad-Export-Date: 2012-08-10 04:58+0000\n"
+"X-Generator: Launchpad (build 15761)\n"
#. module: base
#: model:res.country,name:base.sh
@@ -1443,7 +1443,7 @@ msgstr ""
"U kunt de navolgende extra data toevoegen aan een verkooporder:\n"
"* Aanvraagdatum\n"
"* Bevestigde datum\n"
-"* Effectieve datum\n"
+"* Boek datum\n"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_sequence
@@ -8110,7 +8110,7 @@ msgstr "Kenmerk"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic
msgid "Analytic Accounting"
-msgstr "Kostenplaats boekhouding"
+msgstr "Kostenplaatsen"
#. module: base
#: view:ir.actions.report.xml:0
From 7bd54c9c0b0d6c2333e270b2056fbbc87c608e6d Mon Sep 17 00:00:00 2001
From: niv-openerp
Date: Fri, 10 Aug 2012 11:45:22 +0200
Subject: [PATCH 32/36] [IMP] correction of some comments
bzr revid: nicolas.vanhoren@openerp.com-20120810094522-4dpdw06ql3ex0ig3
---
addons/web_kanban/static/src/js/kanban.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js
index b4cffcba2d5..36394894167 100644
--- a/addons/web_kanban/static/src/js/kanban.js
+++ b/addons/web_kanban/static/src/js/kanban.js
@@ -503,9 +503,9 @@ instance.web_kanban.KanbanGroup = instance.web.OldWidget.extend({
}
},
/**
- * Handles a non-erroneous response from name_create
+ * Handles a newly created record
*
- * @param {(Id, String)} record name_get format for the newly created record
+ * @param {id} id of the newly created record
*/
quick_created: function (record) {
var id = record, self = this;
From d1d6203f4f9c546396f777401f0cdfea8a1af28c Mon Sep 17 00:00:00 2001
From: Vo Minh Thu
Date: Fri, 10 Aug 2012 14:09:36 +0200
Subject: [PATCH 33/36] [FIX]: orm: reverted a change in a previous commit
(where a try/except was removed).
bzr revid: vmt@openerp.com-20120810120936-13lewpbjn7euveg0
---
openerp/osv/orm.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index 2f850e23607..563c514726c 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -4191,7 +4191,11 @@ class BaseModel(object):
# Try-except added to filter the creation of those records whose filds are readonly.
# Example : any dashboard which has all the fields readonly.(due to Views(database views))
- cr.execute("SELECT nextval('"+self._sequence+"')")
+ try:
+ cr.execute("SELECT nextval('"+self._sequence+"')")
+ except:
+ raise except_orm(_('UserError'),
+ _('You cannot perform this operation. New Record Creation is not allowed for this object as this object is for reporting purpose.'))
id_new = cr.fetchone()[0]
for table in tocreate:
From cf57a87d41048f9031e99ecddc1c97f5f469f438 Mon Sep 17 00:00:00 2001
From: Fabien Pinckaers
Date: Fri, 10 Aug 2012 15:45:17 +0200
Subject: [PATCH 34/36] [IMP] point of sale backend, useability improvements
bzr revid: fp@tinyerp.com-20120810134517-tenqseu6otf0rdin
---
addons/point_of_sale/point_of_sale.py | 34 +++-
addons/point_of_sale/point_of_sale_data.xml | 7 +-
addons/point_of_sale/point_of_sale_view.xml | 175 ++++++++++++++++++++
3 files changed, 208 insertions(+), 8 deletions(-)
diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py
index 6d95b561fce..aa152ad94d3 100644
--- a/addons/point_of_sale/point_of_sale.py
+++ b/addons/point_of_sale/point_of_sale.py
@@ -55,7 +55,7 @@ class pos_config(osv.osv):
'shop_id' : fields.many2one('sale.shop', 'Shop',
required=True),
'journal_id' : fields.many2one('account.journal', 'Sale Journal',
- required=True, domain=[('type', '=', 'sale')],
+ domain=[('type', '=', 'sale')],
help="Accounting journal used to post sales entries."),
'iface_self_checkout' : fields.boolean('Self Checkout Mode',
help="Check this if this point of sale should open by default in a self checkout mode. If unchecked, OpenERP uses the normal cashier mode by default."),
@@ -301,11 +301,31 @@ class pos_session(osv.osv):
def create(self, cr, uid, values, context=None):
config_id = values.get('config_id', False) or False
-
- pos_config = None
if config_id:
- pos_config = self.pool.get('pos.config').browse(cr, uid, config_id, context=context)
+ # journal_id is not required on the pos_config because it does not
+ # exists at the installation. If nothing is configured at the
+ # installation we do the minimal configuration. Impossible to do in
+ # the .xml files as the CoA is not yet installed.
+ jobj = self.pool.get('pos.config')
+ pos_config = jobj.browse(cr, uid, config_id, context=context)
+ if not pos_config.journal_id:
+ jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id']
+ if jid:
+ jobj.write(cr, uid, [pos_config.id], {'journal_id': jid}, context=context)
+ else:
+ raise osv.except_osv( _('error!'),
+ _("Unable to open the session. You have to assign a sale journal to your point of sale."))
+ # define some cash journal if no payment method exists
+ if not pos_config.journal_ids:
+ cashids = self.pool.get('account.journal').search(cr, uid, [('journal_user','=',True)], context=context)
+ if not cashids:
+ cashids = self.pool.get('account.journal').search(cr, uid, [('type','=','cash')], context=context)
+ self.pool.get('account.journal').write(cr, uid, cashids, {'journal_user': True})
+ jobj.write(cr, uid, [pos_config.id], {'journal_ids': [(6,0, cashids)]})
+
+
+ pos_config = jobj.browse(cr, uid, config_id, context=context)
bank_statement_ids = []
for journal in pos_config.journal_ids:
bank_values = {
@@ -317,7 +337,8 @@ class pos_session(osv.osv):
values.update({
'name' : pos_config.sequence_id._next(),
- 'statement_ids' : [(6, 0, bank_statement_ids)]
+ 'statement_ids' : [(6, 0, bank_statement_ids)],
+ 'config_id': config_id
})
return super(pos_session, self).create(cr, uid, values, context=context)
@@ -329,7 +350,7 @@ class pos_session(osv.osv):
return True
def wkf_action_open(self, cr, uid, ids, context=None):
- # si pas de date start_at, je balance une date, sinon on utilise celle de l'utilisateur
+ # second browse because we need to refetch the data from the DB for cash_register_id
for record in self.browse(cr, uid, ids, context=context):
values = {}
if not record.start_at:
@@ -338,6 +359,7 @@ class pos_session(osv.osv):
record.write(values, context=context)
for st in record.statement_ids:
st.button_open(context=context)
+
return self.open_frontend_cb(cr, uid, ids, context=context)
def wkf_action_opening_control(self, cr, uid, ids, context=None):
diff --git a/addons/point_of_sale/point_of_sale_data.xml b/addons/point_of_sale/point_of_sale_data.xml
index 108dd98c750..92c04944792 100644
--- a/addons/point_of_sale/point_of_sale_data.xml
+++ b/addons/point_of_sale/point_of_sale_data.xml
@@ -12,12 +12,15 @@
automatic
100
-
-
Main
+
+
+
diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml
index 28407d0bcae..15a1aa7e6bb 100644
--- a/addons/point_of_sale/point_of_sale_view.xml
+++ b/addons/point_of_sale/point_of_sale_view.xml
@@ -11,6 +11,181 @@
Others
+
+ 1.00
+ Unreferenced Products
+
+ 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
+
+
pos.order
From f3d824424f9eb6d169b7b9598d95ad020c370003 Mon Sep 17 00:00:00 2001
From: niv-openerp
Date: Fri, 10 Aug 2012 15:48:15 +0200
Subject: [PATCH 35/36] [FIX] problem with tipsy & quick create in m2o
bzr revid: nicolas.vanhoren@openerp.com-20120810134815-qt91cbf1rndvxn0a
---
addons/web/static/src/js/view_form.js | 37 +++++++++++++++++----------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 4d06cb2d767..508b1046305 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -2784,8 +2784,8 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
}
}
});
- var tip_def = $.Deferred();
- var untip_def = $.Deferred();
+ self.tip_def = $.Deferred();
+ self.untip_def = $.Deferred();
var tip_delay = 200;
var tip_duration = 15000;
var anyoneLoosesFocus = function() {
@@ -2807,24 +2807,25 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
}
self.floating = false;
}
- if (used && self.get("value") === false) {
- tip_def.reject();
- untip_def.reject();
- tip_def = $.Deferred();
- tip_def.then(function() {
+ if (used && self.get("value") === false && ! self.no_tipsy) {
+ self.tip_def.reject();
+ self.untip_def.reject();
+ self.tip_def = $.Deferred();
+ self.tip_def.then(function() {
self.$input.tipsy("show");
});
setTimeout(function() {
- tip_def.resolve();
- untip_def.reject();
- untip_def = $.Deferred();
- untip_def.then(function() {
+ self.tip_def.resolve();
+ self.untip_def.reject();
+ self.untip_def = $.Deferred();
+ self.untip_def.then(function() {
self.$input.tipsy("hide");
});
- setTimeout(function() {untip_def.resolve();}, tip_duration);
+ setTimeout(function() {self.untip_def.resolve();}, tip_duration);
}, tip_delay);
} else {
- tip_def.reject();
+ self.no_tipsy = false;
+ self.tip_def.reject();
}
};
this.$input.focusout(anyoneLoosesFocus);
@@ -2953,7 +2954,15 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
},
focus: function () {
this.$input.focus();
- }
+ },
+ _quick_create: function() {
+ this.no_tipsy = true;
+ return instance.web.form.CompletionFieldMixin._quick_create.apply(this, arguments);
+ },
+ _search_create_popup: function() {
+ this.no_tipsy = true;
+ return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments);
+ },
});
/*
From 01dc1b218b2165973914938ee37bcf1b855addf5 Mon Sep 17 00:00:00 2001
From: Fabien Pinckaers
Date: Fri, 10 Aug 2012 15:55:48 +0200
Subject: [PATCH 36/36] [IMP] help menutips for PoS
bzr revid: fp@tinyerp.com-20120810135548-w2cgv11ynu6l8n5l
---
addons/point_of_sale/point_of_sale_view.xml | 26 ++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml
index 15a1aa7e6bb..bd11f5c070c 100644
--- a/addons/point_of_sale/point_of_sale_view.xml
+++ b/addons/point_of_sale/point_of_sale_view.xml
@@ -289,6 +289,15 @@ GXRFWHRTb2Z0d2FyZQBNaWNyb3NvZnQgT2ZmaWNlf+01cQAAAABJRU5ErkJggg==
tree,form
[]
+
+
+ Click to create a new order.
+
+ Use this menu to browse your preceeding orders. To record new
+ orders, you should better use the menu Your Session for
+ the touchscreen interface.
+
+
Sales
@@ -341,6 +350,7 @@ GXRFWHRTb2Z0d2FyZQBNaWNyb3NvZnQgT2ZmaWNlf+01cQAAAABJRU5ErkJggg==
form
tree,form,kanban
+
@@ -866,6 +876,18 @@ GXRFWHRTb2Z0d2FyZQBNaWNyb3NvZnQgT2ZmaWNlf+01cQAAAABJRU5ErkJggg==
form
tree,form
+
+
+ Click to define a new category.
+
+ Categories are used to browse your products through the
+ touchscreen interface.
+
+ If you put a photo on the category, the layout of the
+ touchscreen interface will automatically. We suggest not to put
+ a photo on categories for small (1024x768) screens.
+
+
@@ -885,7 +907,9 @@ GXRFWHRTb2Z0d2FyZQBNaWNyb3NvZnQgT2ZmaWNlf+01cQAAAABJRU5ErkJggg==
Click to add a payment method.
Payment methods are defined by accounting journals having the
- field Payment Method checked.
+ field PoS Payment Method checked. In order to be useable
+ from the touchscreen interface, you must set the payment method
+ on the Point of Sale configuration.