Browse Source

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

pull/988/head
Holger Brunn 7 years ago
parent
commit
753d5e25c7
No known key found for this signature in database GPG Key ID: 1C9760FECA3AE18
  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. 41
      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).
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
=====

1
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",

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="field_ids" eval="[(4, ref('base.field_res_groups_name'))]" />
</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>
</openerp>

6
base_import_odoo/demo/import_odoo_database_model.xml

@ -19,5 +19,11 @@
<field name="database_id" ref="demodb" />
<field name="domain">[(1, '=', 1)]</field>
</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>
</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>

41
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

28
base_import_odoo/models/import_odoo_database_field.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# 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]

25
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')

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">
Select fields which must be equal to treat a pair of remote and local records of this model as being equal.
</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">
Select fields for which to generate unique values during import. You'll need this for res.users#login for example.
</div>
<group>
<field name="local_id" attrs="{'invisible': [('mapping_type', '!=', 'fixed')], 'required': [('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>
</form>
</field>

Loading…
Cancel
Save