diff options
| author | Mohammed Shekha <msh-odoo@users.noreply.github.com> | 2018-08-16 14:40:35 +0530 |
|---|---|---|
| committer | xmo-odoo <xmo@odoo.com> | 2018-08-16 11:10:35 +0200 |
| commit | 8fbadb9575c25e20f08637c837b386fde213203c (patch) | |
| tree | 568cdc943c24a2bcee46812580de4b636d3a1899 | |
| parent | b3824aa6cbecc97fc0cd54773417045e69adc87a (diff) | |
[ADD] base_import: debug option to create M2O/M2M records
Adds a checkbox to import columns (in debug mode) allowing a user to
create records M2O and M2M records not found (via name_search).
Task ID: 1850633
* uses a context key to avoid altering basically all the import callstack
* attempted to lift the creation in the `_str_to_*` functions and create
m2m via commands, but that doesn't really work out
| -rw-r--r-- | addons/base_import/models/base_import.py | 3 | ||||
| -rw-r--r-- | addons/base_import/static/src/js/import_action.js | 37 | ||||
| -rw-r--r-- | addons/base_import/static/src/scss/base_import.scss | 1 | ||||
| -rw-r--r-- | addons/base_import/static/src/xml/base_import.xml | 9 | ||||
| -rw-r--r-- | odoo/addons/base/models/ir_fields.py | 16 | ||||
| -rw-r--r-- | odoo/addons/test_impex/models.py | 2 | ||||
| -rw-r--r-- | odoo/addons/test_impex/tests/test_load.py | 14 | ||||
| -rw-r--r-- | odoo/fields.py | 4 |
8 files changed, 78 insertions, 8 deletions
diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py index f1384bfb5a2..1d04c98b9ce 100644 --- a/addons/base_import/models/base_import.py +++ b/addons/base_import/models/base_import.py @@ -888,7 +888,8 @@ class Import(models.TransientModel): _logger.info('importing %d rows...', len(data)) - model = self.env[self.res_model].with_context(import_file=True) + name_create_enabled_fields = options.pop('name_create_enabled_fields', {}) + model = self.env[self.res_model].with_context(import_file=True, name_create_enabled_fields=name_create_enabled_fields) import_result = model.load(import_fields, data) _logger.info('done') diff --git a/addons/base_import/static/src/js/import_action.js b/addons/base_import/static/src/js/import_action.js index e2eff44c174..8349603fc9f 100644 --- a/addons/base_import/static/src/js/import_action.js +++ b/addons/base_import/static/src/js/import_action.js @@ -280,7 +280,8 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { var options = { headers: this.$('input.oe_import_has_header').prop('checked'), advanced: this.$('input.oe_import_advanced_mode').prop('checked'), - keep_matches: this.do_not_change_match + keep_matches: this.do_not_change_match, + name_create_enabled_fields: {}, }; _(this.opts).each(function (opt) { options[opt.name] = @@ -301,6 +302,12 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { }).get(); } this.do_not_change_match = false; + this.$('input.o_import_create_option').each(function () { + var field = this.getAttribute('field'); + if (field) { + options.name_create_enabled_fields[field] = this.checked; + } + }); return options; }, @@ -402,6 +409,24 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { }; $fields.each(function (k,v) { var filtered_data = self.generate_fields_completion(result, k); + + var $thing = $(); + var bind = function (d) {}; + if (session.debug) { + $thing = $(QWeb.render('ImportView.create_record_option')).insertAfter(v).hide(); + bind = function (data) { + switch (data.type) { + case 'many2one': case 'many2many': + $thing.find('input').attr('field', data.id); + $thing.show(); + break; + default: + $thing.find('input').attr('field', '').prop('checked', false); + $thing.hide(); + } + } + } + $(v).select2({ allowClear: true, minimumInputLength: 0, @@ -413,11 +438,15 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { return; } - callback(item_finder(default_value)); + var data = item_finder(default_value); + bind(data); + callback(data); }, placeholder: _t('Don\'t import'), width: 'resolve', dropdownCssClass: 'oe_import_selector' + }).on('change', function (e) { + bind(item_finder(e.currentTarget.value)); }); }); }, @@ -448,7 +477,8 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { collection.push({ id: id, text: label, - required: field.required + required: field.required, + type: field.type }); } @@ -521,6 +551,7 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { var columns = this.$('.oe_import_grid-header .oe_import_grid-cell .o_import_header_name').map(function () { return $(this).text().trim().toLowerCase() || false; }).get(); + var tracking_disable = 'tracking_disable' in kwargs ? kwargs.tracking_disable : !this.$('#oe_import_tracking').prop('checked') var defer_parent_store = 'defer_parent_store' in kwargs ? kwargs.defer_parent_store : !!this.$('#oe_import_deferparentstore').prop('checked') delete kwargs.tracking_disable; diff --git a/addons/base_import/static/src/scss/base_import.scss b/addons/base_import/static/src/scss/base_import.scss index f3686e7b448..d32cffdfb32 100644 --- a/addons/base_import/static/src/scss/base_import.scss +++ b/addons/base_import/static/src/scss/base_import.scss @@ -106,6 +106,7 @@ } td { padding: 4px; + vertical-align: top; } } } diff --git a/addons/base_import/static/src/xml/base_import.xml b/addons/base_import/static/src/xml/base_import.xml index fb29ac0c9ea..3b8d8136da9 100644 --- a/addons/base_import/static/src/xml/base_import.xml +++ b/addons/base_import/static/src/xml/base_import.xml @@ -100,6 +100,15 @@ <button type="button" class="btn btn-secondary o_import_cancel">Cancel</button> </t> + <t t-name="ImportView.create_record_option"> + <div class="mt4"> + <label title="Creates new records if they can't be found (instead of failing to import). Note that the value in the column will be used as the new record's 'name', and assumes this is sufficient to create the record."> + <input type="checkbox"/> + Create if doesn't exist + </label> + </div> + </t> + <t t-name="ImportView.preview"> <thead> <tr t-if="headers" class="oe_import_grid-header"> diff --git a/odoo/addons/base/models/ir_fields.py b/odoo/addons/base/models/ir_fields.py index 9a862f02eee..233c611478b 100644 --- a/odoo/addons/base/models/ir_fields.py +++ b/odoo/addons/base/models/ir_fields.py @@ -303,6 +303,7 @@ class IrFieldsConverter(models.AbstractModel): id = None warnings = [] + error_msg = '' action = {'type': 'ir.actions.act_window', 'target': 'new', 'view_mode': 'tree,form', 'view_type': 'form', 'views': [(False, 'tree'), (False, 'form')], @@ -346,6 +347,13 @@ class IrFieldsConverter(models.AbstractModel): _(u"Found multiple matches for field '%%(field)s' (%d matches)") % (len(ids)))) id, _name = ids[0] + else: + name_create_enabled_fields = self.env.context.get('name_create_enabled_fields') or {} + if name_create_enabled_fields.get(field.name): + try: + id, _name = RelatedModel.name_create(name=value) + except Exception as e: + error_msg = repr(e) else: raise self._format_import_error( Exception, @@ -354,10 +362,14 @@ class IrFieldsConverter(models.AbstractModel): ) if id is None: + if error_msg: + message = _("No matching record found for %(field_type)s '%(value)s' in field '%%(field)s' and the following error was encountered when we attempted to create one: %(error_message)s") + else: + message = _("No matching record found for %(field_type)s '%(value)s' in field '%%(field)s'") raise self._format_import_error( ValueError, - _(u"No matching record found for %(field_type)s '%(value)s' in field '%%(field)s'"), - {'field_type': field_type, 'value': value}, + message, + {'field_type': field_type, 'value': value, 'error_message': error_msg}, {'moreinfo': action}) return id, field_type, warnings diff --git a/odoo/addons/test_impex/models.py b/odoo/addons/test_impex/models.py index ddecc63b265..5a098936ccc 100644 --- a/odoo/addons/test_impex/models.py +++ b/odoo/addons/test_impex/models.py @@ -40,6 +40,7 @@ MODELS = [ for name, field in MODELS: class NewModel(models.Model): _name = 'export.%s' % name + _rec_name = 'value' const = fields.Integer(default=4) value = field @@ -55,7 +56,6 @@ for name, field in MODELS: else: return [] - class One2ManyChild(models.Model): _name = 'export.one2many.child' # FIXME: orm.py:1161, fix to name_get on m2o field diff --git a/odoo/addons/test_impex/tests/test_load.py b/odoo/addons/test_impex/tests/test_load.py index 817a56a1c9f..ff303eea407 100644 --- a/odoo/addons/test_impex/tests/test_load.py +++ b/odoo/addons/test_impex/tests/test_load.py @@ -675,6 +675,20 @@ class test_m2o(ImporterCase): u"name, external id or database id")]) self.assertIs(result['ids'], False) + def test_name_create_enabled_m2o(self): + result = self.import_(['value'], [[101]]) + self.assertEqual(result['messages'], [message( + u"No matching record found for name '101' " + u"in field 'Value'", moreinfo=moreaction( + res_model='export.integer'))]) + self.assertIs(result['ids'], False) + context = { + 'name_create_enabled_fields': {'value': True}, + } + result = self.import_(['value'], [[101]], context=context) + self.assertFalse(result['messages']) + self.assertEqual(len(result['ids']), 1) + class test_m2m(ImporterCase): model_name = 'export.many2many' diff --git a/odoo/fields.py b/odoo/fields.py index ec3a16b0a71..213c5696063 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -2659,7 +2659,9 @@ class Many2many(_RelationalMulti): elif act[0] in (5, 6): if recs and recs[-1] == record: flush() - links.difference_update(pair for pair in links if pair[0] == record.id) + # must reify the RHS as Python can update the subject on + # the fly leading to "RuntimeError: Set changed size during iteration" + links.difference_update([pair for pair in links if pair[0] == record.id]) if act[0] == 6: links.update((record.id, id2) for id2 in act[2]) |
