[IMP] base_import: support multiple xlsx sheets

Excel can store data in multiple tables, each is called a sheet. Odoo
was only importing the first sheet making the process to import a file
containing multiple sheets cumbersome.

It is now possible to select the sheet in the import options. By default
the first sheet is selected.

closes odoo/odoo#40728

Task: 2043768
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
This commit is contained in:
Julien Castiaux
2019-11-26 09:26:01 +00:00
parent 1bfcbe4b3c
commit 3460b3ca15
3 changed files with 42 additions and 6 deletions
+8 -4
View File
@@ -264,10 +264,12 @@ class Import(models.TransientModel):
def _read_xls(self, options):
""" Read file content, using xlrd lib """
book = xlrd.open_workbook(file_contents=self.file or b'')
return self._read_xls_book(book)
sheets = options['sheets'] = book.sheet_names()
sheet = options['sheet'] = options.get('sheet') or sheets[0]
return self._read_xls_book(book, sheet)
def _read_xls_book(self, book):
sheet = book.sheet_by_index(0)
def _read_xls_book(self, book, sheet_name):
sheet = book.sheet_by_name(sheet_name)
# emulate Sheet.get_rows for pre-0.9.4
for rowx, row in enumerate(map(sheet.row, range(sheet.nrows)), 1):
values = []
@@ -309,10 +311,12 @@ class Import(models.TransientModel):
def _read_ods(self, options):
""" Read file content using ODSReader custom lib """
doc = odf_ods_reader.ODSReader(file=io.BytesIO(self.file or b''))
sheets = options['sheets'] = list(doc.SHEETS.keys())
sheet = options['sheet'] = options.get('sheet') or sheets[0]
return (
row
for row in doc.getFirstSheet()
for row in doc.getSheet(sheet)
if any(x for x in row if x.strip())
)
@@ -82,6 +82,9 @@ var DataImport = AbstractAction.extend({
{name: 'separator', label: _lt("Separator:"), value: ''},
{name: 'quoting', label: _lt("Text Delimiter:"), value: '"'}
],
spreadsheet_opts: [
{name: 'sheet', label: _lt("Selected Sheet:"), value: ''},
],
parse_opts_formats: [
{name: 'date_format', label: _lt("Date Format:"), value: ''},
{name: 'datetime_format', label: _lt("Datetime Format:"), value: ''},
@@ -146,6 +149,7 @@ var DataImport = AbstractAction.extend({
this.session = session;
this._title = _t('Import a File'); // Displayed in the breadcrumbs
this.do_not_change_match = false;
this.sheets = [];
},
/**
* @override
@@ -168,6 +172,7 @@ var DataImport = AbstractAction.extend({
this.setup_separator_picker();
this.setup_float_format_picker();
this.setup_date_format_picker();
this.setup_sheets_picker();
return Promise.all([
this._super(),
@@ -285,6 +290,18 @@ var DataImport = AbstractAction.extend({
}
})
},
setup_sheets_picker: function () {
var data = this.sheets.map(_make_option);
this.$('input.oe_import_sheet').select2({
width: '50%',
data: data,
query: dataFilteredQuery,
initSelection: function ($e, c) {
c(_from_data(data, $e.val()) || _make_option($e.val()))
},
minimumResultsForSearch: 10,
});
},
import_options: function () {
var self = this;
@@ -297,7 +314,7 @@ var DataImport = AbstractAction.extend({
skip: Number(this.$('#oe_import_row_start').val()) - 1 || 0,
limit: Number(this.$('#oe_import_batch_limit').val()) || null,
};
_(this.opts).each(function (opt) {
_.each(_.union(this.opts, this.spreadsheet_opts), function (opt) {
options[opt.name] =
self.$('input.oe_import_' + opt.name).val();
});
@@ -334,6 +351,7 @@ var DataImport = AbstractAction.extend({
if (!this.$('input.oe_import_file').val()) { return this['settings_changed'](); }
this.$('.oe_import_date_format').select2('val', '');
this.$('.oe_import_datetime_format').val('');
this.$('.oe_import_sheet').val('');
this.$form.removeClass('oe_import_preview oe_import_error');
var import_toggle = false;
@@ -400,8 +418,16 @@ var DataImport = AbstractAction.extend({
this.onresults(null, null, null, {'messages': messages});
}
if (!_.isEqual(this.sheets, result.options.sheets)) {
this.sheets = result.options.sheets || [];
this.setup_sheets_picker();
}
this.$('div.oe_import_has_multiple_sheets').toggle(
this.sheets.length > 1
);
// merge option values back in case they were updated/guessed
_.each(['encoding', 'separator', 'float_thousand_separator', 'float_decimal_separator'], function (id) {
_.each(['encoding', 'separator', 'float_thousand_separator', 'float_decimal_separator', 'sheet'], function (id) {
self.$('.oe_import_' + id).select2('val', result.options[id])
});
this.$('.oe_import_date_format').select2('val', time.strftime_to_moment_format(result.options.date_format));
@@ -54,6 +54,12 @@
Track history during import
</label>
</div>
<div class="oe_import_has_multiple_sheets js_import_options">
<label for="oe_import_sheet">Selected Sheet:</label>
<input class="oe_import_sheet" id="oe_import_sheet"/>
</div>
<div>
<input type="checkbox" class="oe_import_has_header"
id="oe_import_has_header" checked="checked"/>