From 04b0c74c81c92dc4738b052733e27eb3883de03c Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Thu, 12 Oct 2017 10:07:53 +0200 Subject: [PATCH] [ADD] make it possible to import res_model,res_id references --- base_import_odoo/README.rst | 4 +- base_import_odoo/__openerp__.py | 1 + .../demo/import_odoo_database_field.xml | 7 ++++ .../demo/import_odoo_database_model.xml | 6 +++ base_import_odoo/demo/ir_attachment.xml | 11 +++++ .../models/import_odoo_database.py | 41 ++++++++++++++----- .../models/import_odoo_database_field.py | 28 ++++++++++++- .../tests/test_base_import_odoo.py | 25 ++++++----- .../views/import_odoo_database_field.xml | 7 +++- 9 files changed, 107 insertions(+), 23 deletions(-) create mode 100644 base_import_odoo/demo/ir_attachment.xml diff --git a/base_import_odoo/README.rst b/base_import_odoo/README.rst index fc58abb1c..3ff3d68b6 100644 --- a/base_import_odoo/README.rst +++ b/base_import_odoo/README.rst @@ -31,7 +31,9 @@ The module doesn't import one2many fields, if you want to have those, add the mo If you don't fill in a remote ID, the addon will use the configured local ID for every record of the model (this way, you can for example map all users in the remote system to some import user in the current system). -For fields that have a uniqueness constraint (like `res.users#login`), set the flag `unique`, then the import will generate a unique value for this field. +For fields that have a uniqueness constraint (like `res.users#login`), create a field mapping if type `unique`, then the import will generate a unique value for this field. + +For models using references with two fields (like `ir.attachment`), create a field mapping of type `by reference` and select the two fields involved. The import will transform known ids (=ids of models you import) to the respective local id, and clean out the model/id fields for unknown models/ids. Usage ===== diff --git a/base_import_odoo/__openerp__.py b/base_import_odoo/__openerp__.py index 5c40fc3a8..31191330d 100644 --- a/base_import_odoo/__openerp__.py +++ b/base_import_odoo/__openerp__.py @@ -13,6 +13,7 @@ ], "demo": [ "demo/res_users.xml", + "demo/ir_attachment.xml", "demo/import_odoo_database.xml", "demo/import_odoo_database_field.xml", "demo/import_odoo_database_model.xml", diff --git a/base_import_odoo/demo/import_odoo_database_field.xml b/base_import_odoo/demo/import_odoo_database_field.xml index af9e3d137..b1a368a27 100644 --- a/base_import_odoo/demo/import_odoo_database_field.xml +++ b/base_import_odoo/demo/import_odoo_database_field.xml @@ -55,5 +55,12 @@ + + + by_reference + + + + diff --git a/base_import_odoo/demo/import_odoo_database_model.xml b/base_import_odoo/demo/import_odoo_database_model.xml index a10fb3bee..bbaa33021 100644 --- a/base_import_odoo/demo/import_odoo_database_model.xml +++ b/base_import_odoo/demo/import_odoo_database_model.xml @@ -19,5 +19,11 @@ [(1, '=', 1)] + + 4 + + + [('res_model', 'in', ['res.users'])] + diff --git a/base_import_odoo/demo/ir_attachment.xml b/base_import_odoo/demo/ir_attachment.xml new file mode 100644 index 000000000..5cfa63277 --- /dev/null +++ b/base_import_odoo/demo/ir_attachment.xml @@ -0,0 +1,11 @@ + + + + + Demo attachment + res.users + + aGVsbG8gd29ybGQK + + + diff --git a/base_import_odoo/models/import_odoo_database.py b/base_import_odoo/models/import_odoo_database.py index 2b99d2133..684bf0fbc 100644 --- a/base_import_odoo/models/import_odoo_database.py +++ b/base_import_odoo/models/import_odoo_database.py @@ -393,17 +393,38 @@ class ImportOdooDatabase(models.Model): else: data[field_name] = [(6, 0, data[field_name])] for mapping in self.import_field_mappings: - if mapping.model_id.model != model._name or\ - mapping.mapping_type != 'unique': + if mapping.model_id.model != model._name: continue - for field in mapping.field_ids: - value = data.get(field.name, '') - counter = 1 - while model.with_context(active_test=False).search([ - (field.name, '=', data.get(field.name, value)), - ]): - data[field.name] = '%s (%d)' % (value, counter) - counter += 1 + if mapping.mapping_type == 'unique': + for field in mapping.field_ids: + value = data.get(field.name, '') + counter = 1 + while model.with_context(active_test=False).search([ + (field.name, '=', data.get(field.name, value)), + ]): + data[field.name] = '%s (%d)' % (value, counter) + counter += 1 + elif mapping.mapping_type == 'by_reference': + res_model = data.get(mapping.model_field_id.name) + res_id = data.get(mapping.id_field_id.name) + update = { + mapping.model_field_id.name: None, + mapping.id_field_id.name: None, + } + if res_model in self.env.registry and res_id: + new_context = context.with_field_context( + model._name, res_id, data['id'] + ) + record_id = self._run_import_get_record( + new_context, self.env[res_model], {'id': res_id}, + create_dummy=False + ) + if record_id: + update.update({ + mapping.model_field_id.name: res_model, + mapping.id_field_id.name: record_id, + }) + data.update(update) return data @api.multi diff --git a/base_import_odoo/models/import_odoo_database_field.py b/base_import_odoo/models/import_odoo_database_field.py index 95d9b1959..bec3db204 100644 --- a/base_import_odoo/models/import_odoo_database_field.py +++ b/base_import_odoo/models/import_odoo_database_field.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # © 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import fields, models +from openerp import api, fields, models class ImportOdooDatabaseField(models.Model): @@ -22,6 +22,18 @@ class ImportOdooDatabaseField(models.Model): 'ir.model.fields', string='Field', help='If set, the mapping is only ' 'effective when setting said field', ondelete='cascade', ) + model_field_id = fields.Many2one( + 'ir.model.fields', string='Model field', compute=lambda self: + self._compute_reference_field('model_field_id', 'char'), + inverse=lambda self: + self._inverse_reference_field('model_field_id', 'char'), + ) + id_field_id = fields.Many2one( + 'ir.model.fields', string='ID field', compute=lambda self: + self._compute_reference_field('id_field_id', 'integer'), + inverse=lambda self: + self._inverse_reference_field('id_field_id', 'integer'), + ) # TODO: create a reference function field to set this conveniently local_id = fields.Integer( 'Local ID', help='If you leave this empty, a new record will be ' @@ -36,7 +48,21 @@ class ImportOdooDatabaseField(models.Model): [ ('fixed', 'Fixed'), ('by_field', 'Based on equal fields'), + ('by_reference', 'By reference'), ('unique', 'Unique'), ], string='Type', required=True, default='fixed', ) + + @api.multi + def _compute_reference_field(self, field_name, ttype): + for this in self: + this[field_name] = this.field_ids.filtered( + lambda x: x.ttype == ttype + ) + + @api.multi + def _inverse_reference_field(self, field_name, ttype): + self.field_ids = self.field_ids.filtered( + lambda x: x.ttype != ttype + ) + self[field_name] diff --git a/base_import_odoo/tests/test_base_import_odoo.py b/base_import_odoo/tests/test_base_import_odoo.py index 76739fe56..7951840c5 100644 --- a/base_import_odoo/tests/test_base_import_odoo.py +++ b/base_import_odoo/tests/test_base_import_odoo.py @@ -20,7 +20,7 @@ class TestBaseImportOdoo(TransactionCase): # remote ids are the same def _mock_execute(model, method, *args): if method == 'read': - return self.env[model].browse(args[0]).read(fields=args[1]) + return self.env[model].browse(args[0]).read(args[1]) if method == 'search': return self.env[model].search(args[0]).ids @@ -37,23 +37,19 @@ class TestBaseImportOdoo(TransactionCase): # here the actual test begins - check that we created new # objects, check xmlids, check values, check if dummies are # cleaned up/replaced - self.assertNotEqual( - self.env.ref(self._get_xmlid('base.user_demo')), - self.env.ref('base.user_demo'), - ) + imported_user = self.env.ref(self._get_xmlid('base.user_demo')) + user = self.env.ref('base.user_demo') + self.assertNotEqual(imported_user, user) # check that the imported scalars are equal fields = ['name', 'email', 'signature', 'active'] - ( - self.env.ref(self._get_xmlid('base.user_demo')) + - self.env.ref('base.user_demo') - ).read(fields) + (imported_user + user).read(fields) self.assertEqual( self._get_cache(self._get_xmlid('base.user_demo'), fields), self._get_cache('base.user_demo', fields), ) # check that links are correctly mapped self.assertEqual( - self.env.ref(self._get_xmlid('base.user_demo')).partner_id, + imported_user.partner_id, self.env.ref(self._get_xmlid('base.partner_demo')) ) # no new groups because they should be mapped by name @@ -65,6 +61,15 @@ class TestBaseImportOdoo(TransactionCase): self.env['res.users'].search([], count=True), user_count + (user_count - 1) * run, ) + # check that there's a new attachment + attachment = self.env.ref('base_import_odoo.attachment_demo') + imported_attachment = self.env['ir.attachment'].search([ + ('res_model', '=', 'res.users'), + ('res_id', '=', imported_user.id), + ]) + self.assertTrue(attachment) + self.assertEqual(attachment.datas, imported_attachment.datas) + self.assertNotEqual(attachment, imported_attachment) # TODO: test much more run += 1 demodb = self.env.ref('base_import_odoo.demodb') diff --git a/base_import_odoo/views/import_odoo_database_field.xml b/base_import_odoo/views/import_odoo_database_field.xml index 061b63e50..8d44bd57c 100644 --- a/base_import_odoo/views/import_odoo_database_field.xml +++ b/base_import_odoo/views/import_odoo_database_field.xml @@ -16,13 +16,18 @@
Select fields which must be equal to treat a pair of remote and local records of this model as being equal.
+
+ Select the field that stores the model name and the one that stores the linked ID. The IDs for previously imported records will be mapped to the local ID, for unknown models or IDs, the fields are set to NULL. +
Select fields for which to generate unique values during import. You'll need this for res.users#login for example.
- + + +