Browse Source

[ADD] allow mapping records by equal field values

pull/988/head
Holger Brunn 7 years ago
parent
commit
2c1b13b344
No known key found for this signature in database GPG Key ID: 1C9760FECA3AE18
  1. 1
      base_import_odoo/__openerp__.py
  2. 42
      base_import_odoo/demo/import_odoo_database_field.xml
  3. 6
      base_import_odoo/demo/import_odoo_database_model.xml
  4. 93
      base_import_odoo/models/import_odoo_database.py
  5. 17
      base_import_odoo/models/import_odoo_database_field.py
  6. 36
      base_import_odoo/tests/test_base_import_odoo.py
  7. 10
      base_import_odoo/views/import_odoo_database.xml
  8. 42
      base_import_odoo/views/import_odoo_database_field.xml

1
base_import_odoo/__openerp__.py

@ -18,6 +18,7 @@
"demo/import_odoo_database_model.xml",
],
"data": [
"views/import_odoo_database_field.xml",
"security/ir.model.access.csv",
"views/import_odoo_database.xml",
"views/menu.xml",

42
base_import_odoo/demo/import_odoo_database_field.xml

@ -1,23 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data noupdate="1">
<record id="mapping_user_id" model="import.odoo.database.field">
<record id="mapping_partner_id_root" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">fixed</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="local_id" ref="base.partner_root" />
<field name="remote_id" ref="base.partner_root" />
</record>
<record id="mapping_partner_id_company" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">fixed</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="local_id" ref="base.main_partner" />
<field name="remote_id" ref="base.main_partner" />
</record>
<record id="mapping_partner_id_public" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">fixed</field>
<field name="model_id" ref="base.model_res_partner" />
<field name="local_id" ref="base.public_partner" />
<field name="remote_id" ref="base.public_partner" />
</record>
<record id="mapping_user_root" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">fixed</field>
<field name="model_id" ref="base.model_res_users" />
<field name="local_id" ref="mapped_admin" />
<field name="remote_id" ref="base.user_root" />
</record>
<record id="mapping_user_public" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">fixed</field>
<field name="model_id" ref="base.model_res_users" />
<field name="local_id" ref="base.public_user" />
<field name="remote_id" ref="base.public_user" />
</record>
<record id="mapping_company_id" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">fixed</field>
<field name="model_id" ref="base.model_res_company" />
<field name="local_id" ref="base.main_company" />
<field name="remote_id" ref="base.main_company" />
</record>
<record id="mapping_login" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">unique</field>
<field name="model_id" ref="base.model_res_users" />
<field name="fields_id" ref="base.field_res_users_login" />
<field name="unique" eval="True" />
<field name="field_ids" eval="[(4, ref('base.field_res_users_login'))]" />
</record>
<record id="mapping_groups" model="import.odoo.database.field">
<field name="database_id" ref="demodb" />
<field name="mapping_type">by_field</field>
<field name="model_id" ref="base.model_res_groups" />
<field name="field_ids" eval="[(4, ref('base.field_res_groups_name'))]" />
</record>
</data>
</openerp>

6
base_import_odoo/demo/import_odoo_database_model.xml

@ -13,5 +13,11 @@
<field name="database_id" ref="demodb" />
<field name="domain">[(1, '=', 1)]</field>
</record>
<record id="model_groups" model="import.odoo.database.model">
<field name="sequence">3</field>
<field name="model_id" ref="base.model_res_groups" />
<field name="database_id" ref="demodb" />
<field name="domain">[(1, '=', 1)]</field>
</record>
</data>
</openerp>

93
base_import_odoo/models/import_odoo_database.py

@ -220,24 +220,8 @@ class ImportOdooDatabase(models.Model):
dummy_instance(*(context.field_context + (_id,)))
)
if not _id:
mapping = self.import_field_mappings.filtered(
lambda x: x.model_id.model == model._name and
(
not x.fields_id or
x.fields_id.name == context.field_context.field_name and
x.fields_id.model_id.model ==
context.field_context.record_model
) and
x.local_id and
(x.remote_id == record['id'] or not x.remote_id)
)[:1]
if mapping:
if mapping.local_id:
_id = mapping.local_id
context.idmap[(model._name, record['id'])] = _id
else:
_id = self._run_import_create_dummy(
context, model, record, forcecreate=True,
_id = self._run_import_get_record_mapping(
context, model, record, create_dummy=create_dummy,
)
if not _id:
xmlid = self.env['ir.model.data'].search([
@ -252,6 +236,48 @@ class ImportOdooDatabase(models.Model):
_id = self._run_import_create_dummy(context, model, record)
return _id
@api.multi
def _run_import_get_record_mapping(
self, context, model, record, create_dummy=True,
):
current_field = self.env['ir.model.fields'].search([
('name', '=', context.field_context.field_name),
('model_id.model', '=', context.field_context.record_model),
])
mappings = self.import_field_mappings.filtered(
lambda x:
x.mapping_type == 'fixed' and
x.model_id.model == model._name and
(
not x.field_ids or current_field in x.field_ids
) and x.local_id and
(x.remote_id == record['id'] or not x.remote_id) or
x.mapping_type == 'by_field' and
x.model_id.model == model._name
)
_id = None
for mapping in mappings:
if mapping.mapping_type == 'fixed':
assert mapping.local_id
_id = mapping.local_id
context.idmap[(model._name, record['id'])] = _id
break
elif mapping.mapping_type == 'by_field':
assert mapping.field_ids
if len(record) == 1:
continue
records = model.search([
(field.name, '=', record[field.name])
for field in mapping.field_ids
], limit=1)
if records:
_id = records.id
context.idmap[(model._name, record['id'])] = _id
break
else:
raise exceptions.UserError(_('Unknown mapping'))
return _id
@api.multi
def _run_import_create_dummy(
self, context, model, record, forcecreate=False,
@ -265,6 +291,12 @@ class ImportOdooDatabase(models.Model):
v for (model_name, remote_id), v
in context.dummies.iteritems()
if model_name == model._name
] +
[
mapping.local_id for mapping
in self.import_field_mappings
if mapping.model_id.model == model._name and
mapping.local_id
]
),
], limit=1)
@ -336,12 +368,15 @@ class ImportOdooDatabase(models.Model):
new_context = context.with_field_context(
model._name, field_name, data['id']
)
comodel = self.env[model._fields[field_name].comodel_name]
data[field_name] = [
self._run_import_get_record(
new_context,
self.env[model._fields[field_name].comodel_name],
{'id': _id},
create_dummy=model._fields[field_name].required,
new_context, comodel, {'id': _id},
create_dummy=model._fields[field_name].required or
any(
m.model_id._name == comodel._name
for m in self.import_line_ids
),
)
for _id in ids
]
@ -354,18 +389,16 @@ 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 not mapping.fields_id:
if mapping.model_id.model != model._name or\
mapping.mapping_type != 'unique':
continue
if mapping.unique:
value = data.get(mapping.fields_id.name, '')
for field in mapping.field_ids:
value = data.get(field.name, '')
counter = 1
while model.with_context(active_test=False).search([
(
mapping.fields_id.name, '=',
data.get(mapping.fields_id.name, value)
),
(field.name, '=', data.get(field.name, value)),
]):
data[mapping.fields_id.name] = '%s (%d)' % (value, counter)
data[field.name] = '%s (%d)' % (value, counter)
counter += 1
return data

17
base_import_odoo/models/import_odoo_database_field.py

@ -7,7 +7,9 @@ from openerp import fields, models
class ImportOdooDatabaseField(models.Model):
_name = 'import.odoo.database.field'
_description = 'A field mapping for records in the remote database'
_order = 'database_id, sequence'
sequence = fields.Integer()
database_id = fields.Many2one(
'import.odoo.database', string='Database', required=True,
ondelete='cascade',
@ -15,14 +17,11 @@ class ImportOdooDatabaseField(models.Model):
model_id = fields.Many2one(
'ir.model', string='Model', required=True, ondelete='cascade',
)
fields_id = fields.Many2one(
model = fields.Char(related=['model_id', 'model'])
field_ids = fields.Many2many(
'ir.model.fields', string='Field', help='If set, the mapping is only '
'effective when setting said field', ondelete='cascade',
)
unique = fields.Boolean(
'Unique', help='If set on a char field, a number is appended until '
'the value is unique. Set this for fields with uniqueness constraints',
)
# 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 '
@ -33,3 +32,11 @@ class ImportOdooDatabaseField(models.Model):
'Remote ID', help='If you leave this empty, every (set) field value '
'will be mapped to the local ID'
)
mapping_type = fields.Selection(
[
('fixed', 'Fixed'),
('by_field', 'Based on equal fields'),
('unique', 'Unique'),
],
string='Type', required=True, default='fixed',
)

36
base_import_odoo/tests/test_base_import_odoo.py

@ -31,6 +31,9 @@ class TestBaseImportOdoo(TransactionCase):
**(context or self.env.context)
).browse(domain_or_ids).read(fields=fields)
group_count = self.env['res.groups'].search([], count=True)
user_count = self.env['res.users'].search([], count=True)
run = 1
for dummy in range(2):
# we run this two times to enter the code path where xmlids exist
self.env.ref('base_import_odoo.demodb').write({
@ -46,11 +49,32 @@ class TestBaseImportOdoo(TransactionCase):
self.env.ref(self._get_xmlid('base.user_demo')),
self.env.ref('base.user_demo'),
)
# 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)
self.assertEqual(
dict(self.env.ref(self._get_xmlid('base.user_demo'))._cache),
dict(self.env.ref('base.user_demo')._cache),
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,
self.env.ref(self._get_xmlid('base.partner_demo'))
)
# no new groups because they should be mapped by name
self.assertEqual(
group_count, self.env['res.groups'].search([], count=True)
)
# all users save for root should be duplicated for every run
self.assertEqual(
self.env['res.users'].search([], count=True),
user_count + (user_count - 1) * run,
)
# TODO: test much more
run += 1
demodb = self.env.ref('base_import_odoo.demodb')
demodb.action_import()
self.assertTrue(demodb.cronjob_id)
@ -66,3 +90,11 @@ class TestBaseImportOdoo(TransactionCase):
remote_obj._name.replace('.', '_'),
remote_obj.id,
)
def _get_cache(self, xmlid, fields):
record = self.env.ref(xmlid)
return {
field_name: record._cache[field_name]
for field_name in record._fields
if field_name in fields
}

10
base_import_odoo/views/import_odoo_database.xml

@ -35,15 +35,7 @@
<field name="domain" />
</tree>
</field>
<field name="import_field_mappings" attrs="{'readonly': [('cronjob_running', '=', True)]}">
<tree>
<field name="model_id" />
<field name="fields_id" />
<field name="local_id" />
<field name="remote_id" />
<field name="unique" />
</tree>
</field>
<field name="import_field_mappings" attrs="{'readonly': [('cronjob_running', '=', True)]}"/>
</sheet>
</form>
</field>

42
base_import_odoo/views/import_odoo_database_field.xml

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_import_odoo_database_field_form" model="ir.ui.view">
<field name="model">import.odoo.database.field</field>
<field name="arch" type="xml">
<form>
<group>
<field name="model_id" />
<field name="model" invisible="True" />
<field name="mapping_type" />
</group>
<div attrs="{'invisible': [('mapping_type', '!=', 'fixed')]}" class="oe_edit_only">
When a record of this model is imported, it will be replaced with the record you select as local ID. If you select a field and/or a remote ID, this replacement is only effective when setting the specified field and/or when the remote value is the specified record.
</div>
<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', '!=', '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)]"/>
</group>
</form>
</field>
</record>
<record id="view_import_odoo_database_field_tree" model="ir.ui.view">
<field name="model">import.odoo.database.field</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle" />
<field name="model_id" />
<field name="mapping_type" />
<field name="field_ids" />
</tree>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save