diff --git a/base_import_odoo/__openerp__.py b/base_import_odoo/__openerp__.py index 31191330d..fdd6f8f7f 100644 --- a/base_import_odoo/__openerp__.py +++ b/base_import_odoo/__openerp__.py @@ -12,6 +12,7 @@ 'base', ], "demo": [ + "demo/res_partner.xml", "demo/res_users.xml", "demo/ir_attachment.xml", "demo/import_odoo_database.xml", diff --git a/base_import_odoo/demo/res_partner.xml b/base_import_odoo/demo/res_partner.xml new file mode 100644 index 000000000..50c1b2a99 --- /dev/null +++ b/base_import_odoo/demo/res_partner.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/base_import_odoo/models/import_odoo_database.py b/base_import_odoo/models/import_odoo_database.py index 684bf0fbc..3965dd49f 100644 --- a/base_import_odoo/models/import_odoo_database.py +++ b/base_import_odoo/models/import_odoo_database.py @@ -11,6 +11,7 @@ import traceback from urlparse import urlparse from openerp import _, api, exceptions, fields, models, tools from collections import namedtuple +_logger = logging.getLogger('base_import_odoo') import_context_tuple = namedtuple( @@ -116,6 +117,7 @@ class ImportOdooDatabase(models.Model): 'counts': remote_counts, 'ids': remote_ids, 'error': None, + 'dummies': None, 'done': {}, } }) @@ -151,9 +153,17 @@ class ImportOdooDatabase(models.Model): raise done[model._name] += len(ids) self.write({'status_data': dict(self.status_data, done=done)}) + if commit and not tools.config['test_enable']: # pylint: disable=invalid-commit self.env.cr.commit() + missing = {} + for dummy_model, remote_id in dummies.keys(): + if remote_id: + missing.setdefault(dummy_model, []).append(remote_id) + self.write({ + 'status_data': dict(self.status_data, dummies=dict(missing)), + }) @api.multi def _run_import_model(self, context): @@ -163,7 +173,9 @@ class ImportOdooDatabase(models.Model): for data in context.remote.execute( model._name, 'read', context.ids, fields.keys() ): - self._run_import_get_record(context, model, data) + self._run_import_get_record( + context, model, data, create_dummy=False, + ) if (model._name, data['id']) in context.idmap: # there's a mapping for this record, nothing to do continue @@ -179,13 +191,14 @@ class ImportOdooDatabase(models.Model): """Create a record, add an xmlid""" _id = record.pop('id') xmlid = '%d-%s-%d' % ( - self.id, model._name.replace('.', '_'), _id, + self.id, model._name.replace('.', '_'), _id or 0, ) if self.env.ref('base_import_odoo.%s' % xmlid, False): new = self.env.ref('base_import_odoo.%s' % xmlid) new.with_context( **self._create_record_context(model, record) ).write(record) + _logger.debug('Updated record %s', xmlid) else: new = model.with_context( **self._create_record_context(model, record) @@ -199,6 +212,7 @@ class ImportOdooDatabase(models.Model): 'import_database_id': self.id, 'import_database_record_id': _id, }) + _logger.debug('Created record %s', xmlid) context.idmap[mapping_key(model._name, _id)] = new.id return new @@ -218,16 +232,28 @@ class ImportOdooDatabase(models.Model): """Find the local id of some remote record. Create a dummy if not available""" _id = context.idmap.get((model._name, record['id'])) + logged = False if not _id: _id = context.dummies.get((model._name, record['id'])) if _id: context.dummy_instances.append( dummy_instance(*(context.field_context + (_id,))) ) + else: + logged = True + _logger.debug( + 'Got %s(%d[%d]) from idmap', model._model, _id, + record['id'] or 0, + ) if not _id: _id = self._run_import_get_record_mapping( context, model, record, create_dummy=create_dummy, ) + elif not logged: + logged = True + _logger.debug( + 'Got %s(%d[%d]) from dummies', model._model, _id, record['id'], + ) if not _id: xmlid = self.env['ir.model.data'].search([ ('import_database_id', '=', self.id), @@ -237,8 +263,22 @@ class ImportOdooDatabase(models.Model): if xmlid: _id = xmlid.res_id context.idmap[(model._name, record['id'])] = _id + elif not logged: + logged = True + _logger.debug( + 'Got %s(%d[%d]) from mappings', + model._model, _id, record['id'], + ) if not _id and create_dummy: - _id = self._run_import_create_dummy(context, model, record) + _id = self._run_import_create_dummy( + context, model, record, + forcecreate=record['id'] not in + self.status_data['ids'].get(model._name, []) + ) + elif _id and not logged: + _logger.debug( + 'Got %s(%d[%d]) from xmlid', model._model, _id, record['id'], + ) return _id @api.multi @@ -270,9 +310,19 @@ class ImportOdooDatabase(models.Model): elif mapping.mapping_type == 'by_field': assert mapping.field_ids if len(record) == 1: - continue + # just the id of a record we haven't seen yet. + # read the whole record from remote to check if + # this can be mapped to an existing record + record = context.remote.execute( + model._name, 'read', record['id'], + mapping.field_ids.mapped('name'), + ) or None + if not record: + continue + if isinstance(record, list): + record = record[0] records = model.search([ - (field.name, '=', record[field.name]) + (field.name, '=', record.get(field.name)) for field in mapping.field_ids ], limit=1) if records: @@ -310,6 +360,13 @@ class ImportOdooDatabase(models.Model): context.dummy_instances.append( dummy_instance(*(context.field_context + (dummy.id,))) ) + _logger.debug( + 'Using %d as dummy for %s(%d[%d]).%s[%d]', + dummy.id, context.field_context.record_model, + context.idmap.get(context.field_context.record_id, 0), + context.field_context.record_id, + context.field_context.field_name, record['id'], + ) return dummy.id required = [ name @@ -331,6 +388,8 @@ class ImportOdooDatabase(models.Model): elif model._fields[name].type in ['date', 'datetime']: value = '2000-01-01' elif field.type in ['many2one']: + if name in model._inherits.values(): + continue new_context = context.with_field_context( model._name, name, record['id'] ) @@ -345,12 +404,20 @@ class ImportOdooDatabase(models.Model): value = field.selection(model)[0][0] values[name] = value dummy = self._create_record(context, model, values) + del context.idmap[mapping_key(model._name, record['id'])] context.dummies[mapping_key(model._name, record['id'])] = dummy.id context.to_delete.setdefault(model._name, []) context.to_delete[model._name].append(dummy.id) context.dummy_instances.append( dummy_instance(*(context.field_context + (dummy.id,))) ) + _logger.debug( + 'Created %d as dummy for %s(%d[%d]).%s[%d]', + dummy.id, context.field_context.record_model, + context.idmap.get(context.field_context.record_id, 0), + context.field_context.record_id or 0, + context.field_context.field_name, record['id'], + ) return dummy.id @api.multi @@ -378,7 +445,7 @@ class ImportOdooDatabase(models.Model): new_context, comodel, {'id': _id}, create_dummy=model._fields[field_name].required or any( - m.model_id._name == comodel._name + m.model_id.model == comodel._name for m in self.import_line_ids ), ) @@ -440,22 +507,28 @@ class ImportOdooDatabase(models.Model): def _run_import_model_cleanup_dummies( self, context, model, remote_id, local_id ): + if not (model._name, remote_id) in context.dummies: + return for instance in context.dummy_instances: - if ( - instance.model_name != model._name or - instance.remote_id != remote_id - ): + key = mapping_key(instance.model_name, instance.remote_id) + if key not in context.idmap: continue - if not context.idmap.get(instance.remote_id): + dummy_id = context.dummies[(model._name, remote_id)] + record_model = self.env[instance.model_name] + comodel = record_model._fields[instance.field_name].comodel_name + if comodel != model._name or instance.dummy_id != dummy_id: continue - model = self.env[instance.model_name] - record = model.browse(context.idmap[instance.remote_id]) - field_name = instance.field_id.name + record = record_model.browse(context.idmap[key]) + field_name = instance.field_name + _logger.debug( + 'Replacing dummy %d on %s(%d).%s with %d', + dummy_id, record_model._name, record.id, field_name, local_id, + ) if record._fields[field_name].type == 'many2one': record.write({field_name: local_id}) elif record._fields[field_name].type == 'many2many': record.write({field_name: [ - (3, context.idmap[remote_id]), + (3, dummy_id), (4, local_id), ]}) else: @@ -464,10 +537,11 @@ class ImportOdooDatabase(models.Model): record._fields[field_name].type ) context.dummy_instances.remove(instance) - dummy_id = context.dummies[(record._model, remote_id)] if dummy_id in context.to_delete: model.browse(dummy_id).unlink() - del context.dummies[(record._model, remote_id)] + _logger.debug('Deleting dummy %d', dummy_id) + if (model._name, remote_id) in context.dummies: + del context.dummies[(model._name, remote_id)] def _get_connection(self): self.ensure_one() diff --git a/base_import_odoo/views/import_odoo_database.xml b/base_import_odoo/views/import_odoo_database.xml index c919798c9..ab8333a8d 100644 --- a/base_import_odoo/views/import_odoo_database.xml +++ b/base_import_odoo/views/import_odoo_database.xml @@ -76,6 +76,16 @@

+            
+ The following remote ids don't have a mapping but have to be imported anyways due to not null constraints. +
+ +
+
+ +
+ To fix this, create mappings for the remote ids listed, or if this is not feasible, map the whole model. You might also have a too specific domain on your import model definition. +