Add a 'copy' action to One2Many and Many2Many's set method
issue3341 review1271002
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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,))
|
||||
|
||||
Reference in New Issue
Block a user