Merge lp:~credativ/openobject-server/trunk-csv-import-domain into lp:openobject-server

Proposed by Craig Gowing (credativ)
Status: Needs review
Proposed branch: lp:~credativ/openobject-server/trunk-csv-import-domain
Merge into: lp:openobject-server
Diff against target: 73 lines (+30/-1)
2 files modified
openerp/addons/base/ir/ir_fields.py (+11/-1)
openerp/osv/orm.py (+19/-0)
To merge this branch: bzr merge lp:~credativ/openobject-server/trunk-csv-import-domain
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+216989@code.launchpad.net

Description of the change

When importing CSV files, allow a domain to be specified so that unique matches to records can be made when either name search is not accurate enough (too many matches) or the external XML ID does not exist or is unknown.

The field is similar to /id and /.id, it is defined as /.domain
The domain is safe_eval'ed and a standard search is run on the object using the domain, so correct security limitations will be in effect.

https://blueprints.launchpad.net/openobject-addons/+spec/csv-import-domain

To post a comment you must log in.

Unmerged revisions

5196. By Craig Gowing (credativ)

[IMP] Allow domain searches on CSV import

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openerp/addons/base/ir/ir_fields.py'
--- openerp/addons/base/ir/ir_fields.py 2014-02-06 11:04:23 +0000
+++ openerp/addons/base/ir/ir_fields.py 2014-04-24 07:39:42 +0000
@@ -14,8 +14,9 @@
14from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT,\14from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT,\
15 DEFAULT_SERVER_DATETIME_FORMAT15 DEFAULT_SERVER_DATETIME_FORMAT
16from openerp.tools import html_sanitize16from openerp.tools import html_sanitize
17from openerp.tools.safe_eval import safe_eval as eval
1718
18REFERENCING_FIELDS = set([None, 'id', '.id'])19REFERENCING_FIELDS = set([None, 'id', '.id', '.domain'])
19def only_ref_fields(record):20def only_ref_fields(record):
20 return dict((k, v) for k, v in record.iteritems()21 return dict((k, v) for k, v in record.iteritems()
21 if k in REFERENCING_FIELDS)22 if k in REFERENCING_FIELDS)
@@ -338,6 +339,15 @@
338 _(u"Found multiple matches for field '%%(field)s' (%d matches)")339 _(u"Found multiple matches for field '%%(field)s' (%d matches)")
339 % (len(ids))))340 % (len(ids))))
340 id, _name = ids[0]341 id, _name = ids[0]
342 elif subfield == '.domain':
343 field_type = _(u"domain")
344 try:
345 ids = RelatedModel.search(cr, uid, eval(value), context=context)
346 if ids:
347 id = ids[0]
348 except ValueError:
349 raise ValueError(
350 _(u"Invalid domain '%s'") % value, {'moreinfo': action})
341 else:351 else:
342 raise Exception(_(u"Unknown sub-field '%s'") % subfield)352 raise Exception(_(u"Unknown sub-field '%s'") % subfield)
343353
344354
=== modified file 'openerp/osv/orm.py'
--- openerp/osv/orm.py 2014-04-16 14:34:31 +0000
+++ openerp/osv/orm.py 2014-04-24 07:39:42 +0000
@@ -1420,12 +1420,14 @@
1420 * None is the name_get for the record (to use with name_create/name_search)1420 * None is the name_get for the record (to use with name_create/name_search)
1421 * "id" is the External ID for the record1421 * "id" is the External ID for the record
1422 * ".id" is the Database ID for the record1422 * ".id" is the Database ID for the record
1423 * ".domain" is a domain expression for the record
1423 """1424 """
1424 columns = dict((k, v.column) for k, v in self._all_columns.iteritems())1425 columns = dict((k, v.column) for k, v in self._all_columns.iteritems())
1425 # Fake columns to avoid special cases in extractor1426 # Fake columns to avoid special cases in extractor
1426 columns[None] = fields.char('rec_name')1427 columns[None] = fields.char('rec_name')
1427 columns['id'] = fields.char('External ID')1428 columns['id'] = fields.char('External ID')
1428 columns['.id'] = fields.integer('Database ID')1429 columns['.id'] = fields.integer('Database ID')
1430 columns['.domain'] = fields.char('Domain')
14291431
1430 # m2o fields can't be on multiple lines so exclude them from the1432 # m2o fields can't be on multiple lines so exclude them from the
1431 # is_relational field rows filter, but special-case it later on to1433 # is_relational field rows filter, but special-case it later on to
@@ -1537,6 +1539,23 @@
1537 field='.id',1539 field='.id',
1538 message=_(u"Unknown database identifier '%s'") % dbid))1540 message=_(u"Unknown database identifier '%s'") % dbid))
1539 dbid = False1541 dbid = False
1542 if '.domain' in record:
1543 try:
1544 dbids = self.search(cr, uid, eval(record['.domain']), context=context)
1545 if not dbids:
1546 log(dict(extras,
1547 type='error',
1548 record=stream.index,
1549 field='.domain',
1550 message=_(u"Domain did not match record '%s'") % record['.domain']))
1551 else:
1552 dbid = dbids[0]
1553 except ValueError:
1554 log(dict(extras,
1555 type='error',
1556 record=stream.index,
1557 field='.domain',
1558 message=_(u"Domain could not be parsed '%s'") % record['.domain']))
15401559
1541 converted = convert(record, lambda field, err:\1560 converted = convert(record, lambda field, err:\
1542 _log(dict(extras, record=stream.index, field=field_names[field]), field, err))1561 _log(dict(extras, record=stream.index, field=field_names[field]), field, err))