[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:
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user