Browse Source

[ADD] make it possible to import res_model,res_id references

10.0
Holger Brunn 7 years ago
committed by OCA-git-bot
parent
commit
04b0c74c81
  1. 4
      base_import_odoo/README.rst
  2. 1
      base_import_odoo/__openerp__.py
  3. 7
      base_import_odoo/demo/import_odoo_database_field.xml
  4. 6
      base_import_odoo/demo/import_odoo_database_model.xml
  5. 11
      base_import_odoo/demo/ir_attachment.xml
  6. 25
      base_import_odoo/models/import_odoo_database.py
  7. 28
      base_import_odoo/models/import_odoo_database_field.py
  8. 25
      base_import_odoo/tests/test_base_import_odoo.py
  9. 7
      base_import_odoo/views/import_odoo_database_field.xml

4
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). 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 Usage
===== =====

1
base_import_odoo/__openerp__.py

@ -13,6 +13,7 @@
], ],
"demo": [ "demo": [
"demo/res_users.xml", "demo/res_users.xml",
"demo/ir_attachment.xml",
"demo/import_odoo_database.xml", "demo/import_odoo_database.xml",
"demo/import_odoo_database_field.xml", "demo/import_odoo_database_field.xml",
"demo/import_odoo_database_model.xml", "demo/import_odoo_database_model.xml",

7
base_import_odoo/demo/import_odoo_database_field.xml

@ -55,5 +55,12 @@
<field name="model_id" ref="base.model_res_groups" /> <field name="model_id" ref="base.model_res_groups" />
<field name="field_ids" eval="[(4, ref('base.field_res_groups_name'))]" /> <field name="field_ids" eval="[(4, ref('base.field_res_groups_name'))]" />
</record> </record>
<record id="mapping_attachment" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">by_reference</field>
<field name="model_id" ref="base.model_ir_attachment" />
<field name="model_field_id" ref="base.field_ir_attachment_res_model" />
<field name="id_field_id" ref="base.field_ir_attachment_res_id" />
</record>
</data> </data>
</openerp> </openerp>

6
base_import_odoo/demo/import_odoo_database_model.xml

@ -19,5 +19,11 @@
<field name="database_id" ref="demodb" /> <field name="database_id" ref="demodb" />
<field name="domain">[(1, '=', 1)]</field> <field name="domain">[(1, '=', 1)]</field>
</record> </record>
<record id="model_attachment" model="import.odoo.database.model">
<field name="sequence">4</field>
<field name="model_id" ref="base.model_ir_attachment" />
<field name="database_id" ref="demodb" />
<field name="domain">[('res_model', 'in', ['res.users'])]</field>
</record>
</data> </data>
</openerp> </openerp>

11
base_import_odoo/demo/ir_attachment.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="attachment_demo" model="ir.attachment">
<field name="name">Demo attachment</field>
<field name="res_model">res.users</field>
<field name="res_id" ref="base.user_demo" />
<field name="datas">aGVsbG8gd29ybGQK</field>
</record>
</data>
</openerp>

25
base_import_odoo/models/import_odoo_database.py

@ -393,9 +393,9 @@ class ImportOdooDatabase(models.Model):
else: else:
data[field_name] = [(6, 0, data[field_name])] data[field_name] = [(6, 0, data[field_name])]
for mapping in self.import_field_mappings: 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 continue
if mapping.mapping_type == 'unique':
for field in mapping.field_ids: for field in mapping.field_ids:
value = data.get(field.name, '') value = data.get(field.name, '')
counter = 1 counter = 1
@ -404,6 +404,27 @@ class ImportOdooDatabase(models.Model):
]): ]):
data[field.name] = '%s (%d)' % (value, counter) data[field.name] = '%s (%d)' % (value, counter)
counter += 1 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 return data
@api.multi @api.multi

28
base_import_odoo/models/import_odoo_database_field.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl> # © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # 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): class ImportOdooDatabaseField(models.Model):
@ -22,6 +22,18 @@ class ImportOdooDatabaseField(models.Model):
'ir.model.fields', string='Field', help='If set, the mapping is only ' 'ir.model.fields', string='Field', help='If set, the mapping is only '
'effective when setting said field', ondelete='cascade', '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 # TODO: create a reference function field to set this conveniently
local_id = fields.Integer( local_id = fields.Integer(
'Local ID', help='If you leave this empty, a new record will be ' 'Local ID', help='If you leave this empty, a new record will be '
@ -36,7 +48,21 @@ class ImportOdooDatabaseField(models.Model):
[ [
('fixed', 'Fixed'), ('fixed', 'Fixed'),
('by_field', 'Based on equal fields'), ('by_field', 'Based on equal fields'),
('by_reference', 'By reference'),
('unique', 'Unique'), ('unique', 'Unique'),
], ],
string='Type', required=True, default='fixed', 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]

25
base_import_odoo/tests/test_base_import_odoo.py

@ -20,7 +20,7 @@ class TestBaseImportOdoo(TransactionCase):
# remote ids are the same # remote ids are the same
def _mock_execute(model, method, *args): def _mock_execute(model, method, *args):
if method == 'read': 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': if method == 'search':
return self.env[model].search(args[0]).ids 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 # here the actual test begins - check that we created new
# objects, check xmlids, check values, check if dummies are # objects, check xmlids, check values, check if dummies are
# cleaned up/replaced # 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 # check that the imported scalars are equal
fields = ['name', 'email', 'signature', 'active'] 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.assertEqual(
self._get_cache(self._get_xmlid('base.user_demo'), fields), self._get_cache(self._get_xmlid('base.user_demo'), fields),
self._get_cache('base.user_demo', fields), self._get_cache('base.user_demo', fields),
) )
# check that links are correctly mapped # check that links are correctly mapped
self.assertEqual( 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')) self.env.ref(self._get_xmlid('base.partner_demo'))
) )
# no new groups because they should be mapped by name # no new groups because they should be mapped by name
@ -65,6 +61,15 @@ class TestBaseImportOdoo(TransactionCase):
self.env['res.users'].search([], count=True), self.env['res.users'].search([], count=True),
user_count + (user_count - 1) * run, 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 # TODO: test much more
run += 1 run += 1
demodb = self.env.ref('base_import_odoo.demodb') demodb = self.env.ref('base_import_odoo.demodb')

7
base_import_odoo/views/import_odoo_database_field.xml

@ -16,13 +16,18 @@
<div attrs="{'invisible': [('mapping_type', '!=', 'by_field')]}" class="oe_edit_only"> <div attrs="{'invisible': [('mapping_type', '!=', 'by_field')]}" class="oe_edit_only">
Select fields which must be equal to treat a pair of remote and local records of this model as being equal. Select fields which must be equal to treat a pair of remote and local records of this model as being equal.
</div> </div>
<div attrs="{'invisible': [('mapping_type', '!=', 'by_reference')]}" class="oe_edit_only">
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.
</div>
<div attrs="{'invisible': [('mapping_type', '!=', 'unique')]}" class="oe_edit_only"> <div attrs="{'invisible': [('mapping_type', '!=', 'unique')]}" class="oe_edit_only">
Select fields for which to generate unique values during import. You'll need this for res.users#login for example. Select fields for which to generate unique values during import. You'll need this for res.users#login for example.
</div> </div>
<group> <group>
<field name="local_id" attrs="{'invisible': [('mapping_type', '!=', 'fixed')], 'required': [('mapping_type', '=', 'fixed')]}" /> <field name="local_id" attrs="{'invisible': [('mapping_type', '!=', 'fixed')], 'required': [('mapping_type', '=', 'fixed')]}" />
<field name="remote_id" attrs="{'invisible': [('mapping_type', '!=', 'fixed')]}" /> <field name="remote_id" attrs="{'invisible': [('mapping_type', '!=', 'fixed')]}" />
<field name="field_ids" attrs="{'required': [('mapping_type', 'in', ['by_field', 'unique'])]}" widget="many2many_tags" domain="[mapping_type == 'fixed' and ('relation', '=', model) or ('model_id', '=', model_id)]"/>
<field name="field_ids" attrs="{'invisible': [('mapping_type', 'not in', ['fixed', 'by_field', 'unique'])], 'required': [('mapping_type', 'in', ['by_field', 'unique'])]}" widget="many2many_tags" domain="[mapping_type == 'fixed' and ('relation', '=', model) or ('model_id', '=', model_id)]"/>
<field name="model_field_id" attrs="{'invisible': [('mapping_type', '!=', 'by_reference')], 'required': [('mapping_type', '=', 'by_reference')]}" domain="[('ttype', '=', 'char'), ('model_id.model', '=', model)]" />
<field name="id_field_id" attrs="{'invisible': [('mapping_type', '!=', 'by_reference')], 'required': [('mapping_type', '=', 'by_reference')]}" domain="[('ttype', '=', 'integer'), ('model_id.model', '=', model)]" />
</group> </group>
</form> </form>
</field> </field>

Loading…
Cancel
Save