Add a 'copy' action to One2Many and Many2Many's set method

issue3341
review1271002
This commit is contained in:
Laurent Defert
2013-11-19 11:04:33 +01:00
parent 2b2001f1ca
commit d143acdd0a
6 changed files with 88 additions and 28 deletions
+1
View File
@@ -1,3 +1,4 @@
* Add a "copy" action to One2Many and Many2Many's set method
* Force UTC as timezone (migration script available on tryton-tools)
* Add relation_field for many2one
+4
View File
@@ -511,6 +511,10 @@ This field accepts as written value a list of tuples like this:
- ``('set'[, ids, ...])``: it will link only the target ids to this record.
- ``('copy', ids[, {<field name>: value, ...}])``: it will copy the target
ids to this record. Optional field names and values may be added to
override some of the fields of the copied records.
:class:`One2Many` has some extra required arguments:
.. attribute:: One2Many.model_name
+15
View File
@@ -108,6 +108,7 @@ class Many2Many(Field):
(``add``, ``<ids>``),
(``unlink_all``),
(``set``, ``<ids>``)
(``copy``, ``<ids>``, ``[{<field name>: value}, ...]``)
'''
pool = Pool()
if not values:
@@ -215,6 +216,20 @@ class Many2Many(Field):
})
if to_create:
Relation.create(to_create)
elif act[0] == 'copy':
target_ids = list(act[1])
to_create = []
default = None
if len(act) > 2:
default = act[2]
for new in Target.copy(target_ids, default=default):
for record_id in ids:
to_create.append({
self.origin: field_value(record_id),
self.target: new.id,
})
if to_create:
Relation.create(to_create)
else:
raise Exception('Bad arguments')
+11
View File
@@ -114,6 +114,7 @@ class One2Many(Field):
(``add``, ``<ids>``),
(``unlink_all``),
(``set``, ``<ids>``)
(``copy``, ``<ids>``, ``[{<field name>: value}, ...]``)
'''
if not values:
return
@@ -196,6 +197,16 @@ class One2Many(Field):
Target.write(Target.browse(target_ids), {
self.field: field_value(record_id),
})
elif act[0] == 'copy':
copy_ids = map(int, act[1])
if len(act) > 2:
default = act[2].copy()
else:
default = {}
for record_id in ids:
default[self.field] = field_value(record_id)
Target.copy(copy_ids, default=default)
else:
raise Exception('Bad arguments')
+5 -26
View File
@@ -245,7 +245,6 @@ class ModelStorage(Model):
def convert_data(field_defs, data):
data = data.copy()
data_o2m = {}
for field_name in field_defs:
ftype = field_defs[field_name]['type']
@@ -271,46 +270,26 @@ class ModelStorage(Model):
pass
elif ftype in ('one2many',):
if data[field_name]:
data_o2m[field_name] = data[field_name]
data[field_name] = None
data[field_name] = [('copy', data[field_name])]
elif ftype == 'many2many':
if data[field_name]:
data[field_name] = [('set', data[field_name])]
if 'id' in data:
del data['id']
return data, data_o2m
return data
new_ids = {}
fields_names = [n for n, f in cls._fields.iteritems()
if (not isinstance(f, fields.Function)
or isinstance(f, fields.Property))]
ids = map(int, records)
datas = cls.read(ids, fields_names=fields_names)
field_defs = cls.fields_get(fields_names=fields_names)
data_ids = []
to_create = []
o2m_to_create = []
for data in datas:
data_ids.append(data['id'])
data, data_o2m = convert_data(field_defs, data)
data = convert_data(field_defs, data)
to_create.append(data)
o2m_to_create.append(data_o2m)
new_records = cls.create(to_create)
for data_id, new_record, data_o2m in izip(data_ids, new_records,
o2m_to_create):
new_ids[data_id] = new_record.id
for field_name in data_o2m:
Relation = pool.get(
field_defs[field_name]['relation'])
relation_field = field_defs[field_name]['relation_field']
if relation_field:
field = Relation._fields[relation_field]
if field._type == 'reference':
value = str(new_record)
else:
value = new_record.id
Relation.copy(Relation.browse(data_o2m[field_name]),
default={relation_field: value})
new_ids = dict(izip(ids, map(int, new_records)))
fields_translate = {}
for field_name, field in field_defs.iteritems():
@@ -332,7 +311,7 @@ class ModelStorage(Model):
fields_names=fields_translate.keys() + ['id'])
for data in datas:
data_id = data['id']
data, _ = convert_data(fields_translate, data)
data = convert_data(fields_translate, data)
cls.write([cls(new_ids[data_id])], data)
return cls.browse(new_ids.values())
+52 -2
View File
@@ -2528,7 +2528,32 @@ class FieldsTestCase(unittest.TestCase):
one2many.write([one2many1], {
'targets': [
('delete', [target2.id]),
('copy', [target1.id], {'name': 'copy1'}),
],
})
targets = one2many_target.search([
('id', 'not in', [target1.id, target2.id]),
])
self.assertEqual(len(targets), 1)
self.assertEqual(targets[0].name, 'copy1')
one2many.write([one2many1], {
'targets': [
('copy', [target2.id]),
],
})
self.assertEqual(len(one2many1.targets), 4)
targets = one2many_target.search([
('id', 'not in', [target1.id, target2.id]),
])
self.assertEqual(len(targets), 2)
names = set([target.name for target in targets])
self.assertEqual(names, set(('copy1', 'target2')))
copy_ids = [target.id for target in targets]
one2many.write([one2many1], {
'targets': [
('delete', [target2.id] + copy_ids),
],
})
self.assertEqual(one2many1.targets, (target1,))
@@ -2710,7 +2735,32 @@ class FieldsTestCase(unittest.TestCase):
many2many.write([many2many1], {
'targets': [
('delete', [target2.id]),
('copy', [target1.id], {'name': 'copy1'}),
],
})
targets = many2many_target.search([
('id', 'not in', [target1.id, target2.id]),
])
self.assertEqual(len(targets), 1)
self.assertEqual(targets[0].name, 'copy1')
many2many.write([many2many1], {
'targets': [
('copy', [target2.id]),
],
})
self.assertEqual(len(many2many1.targets), 4)
targets = many2many_target.search([
('id', 'not in', [target1.id, target2.id]),
])
self.assertEqual(len(targets), 2)
names = set([target.name for target in targets])
self.assertEqual(names, set(('copy1', 'target2')))
copy_ids = [target.id for target in targets]
many2many.write([many2many1], {
'targets': [
('delete', [target2.id] + copy_ids),
],
})
self.assertEqual(many2many1.targets, (target1,))