From 25c38ca653ff24773f68e2dbd90310a13c247786 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 23 Sep 2011 14:22:02 +0200 Subject: [PATCH] [IMP] move more import logic to javascript bzr revid: xmo@openerp.com-20110923122202-hnp6o1ybwgugive4 --- addons/web/controllers/main.py | 92 +++++++++++++------------ addons/web/static/src/js/data_import.js | 35 ++++++++-- addons/web/static/src/xml/base.xml | 1 - 3 files changed, 79 insertions(+), 49 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 4786d2193d5..f6fda7f7e32 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1419,7 +1419,7 @@ class Import(View): return fields @openerpweb.httprequest - def detect_data(self, req, model, csvfile, csvsep, csvdel, csvcode, jsonp): + def detect_data(self, req, csvfile, csvsep, csvdel, csvcode, jsonp): try: data = list(csv.reader( csvfile, quotechar=str(csvdel), delimiter=str(csvsep))) @@ -1447,65 +1447,69 @@ class Import(View): })) @openerpweb.httprequest - def import_data(self, req, model, csvfile, csvsep, csvdel, csvcode, jsonp): - # TODO: reintroduce CSVSKIP param - context = req.session.eval_context(req.context) + def import_data(self, req, model, csvfile, csvsep, csvdel, csvcode, jsonp, + meta): modle_obj = req.session.model(model) - res = None - data = [] + skip, indices, fields = operator.itemgetter('skip', 'indices', 'fields')( + simplejson.loads(meta)) + error = None if not (csvdel and len(csvdel) == 1): - error={'message': "The CSV delimiter must be a single character"} - return '' % ( - jsonp, simplejson.dumps({'error':error})) + error = u"The CSV delimiter must be a single character" + if not indices and fields: + error = u"You must select at least one field to import" + + if error: + return '' % ( + jsonp, simplejson.dumps({'error': {'message': error}})) + + # skip ignored records + data_record = itertools.islice( + csv.reader(csvfile, quotechar=str(csvdel), delimiter=str(csvsep)), + skip, None) + + # if only one index, itemgetter will return an atom rather than a tuple + if len(indices) == 1: mapper = lambda row: [row[indices[0]]] + else: mapper = operator.itemgetter(*indices) + + data = None + error = None try: - data_record = csv.reader(csvfile, quotechar=str(csvdel), delimiter=str(csvsep)) - for rec in itertools.islice(data_record,0,None): - data.append(rec) - - headers = itertools.islice(data,1) - fields = headers.next() - + # decode each data row + data = [ + [record.decode(csvcode) for record in row] + for row in itertools.imap(mapper, data_record) + # don't insert completely empty rows (can happen due to fields + # filtering in case of e.g. o2m content rows) + if any(row) + ] + except UnicodeDecodeError: + error = u"Failed to decode CSV file using encoding %s" % csvcode except csv.Error, e: - error={'message': str(e),'title': 'File Format Error'} - return '' % ( - jsonp, simplejson.dumps({'error':error})) - - datas = [] - ctx = context - - if not isinstance(fields, list): - fields = [fields] - - for line in data[1:]: - try: - datas.append(map(lambda x:x.decode(csvcode).encode('utf-8'), line)) - except: - datas.append(map(lambda x:x.decode('latin').encode('utf-8'), line)) + error = u"Could not process CSV file: %s" % e # If the file contains nothing, - if not datas: - error = {'message': 'The file is empty !'} + if not data: + error = u"File to import is empty" + if error: return '' % ( - jsonp, simplejson.dumps({'error':error})) + jsonp, simplejson.dumps({'error': {'message': error}})) - #Inverting the header into column names try: - res = modle_obj.import_data(fields, datas, 'init', '', False, ctx) + (code, record, message, _nope) = modle_obj.import_data( + fields, data, 'init', '', False, + req.session.eval_context(req.context)) except xmlrpclib.Fault, e: - error = {"message":e.faultCode} + error = {"message": u"%s, %s" % (e.faultCode, e.faultString)} return '' % ( jsonp, simplejson.dumps({'error':error})) - if res[0]>=0: + if code != -1: return '' % ( jsonp, simplejson.dumps({'success':True})) - d = '' - for key,val in res[1].items(): - d+= ('%s: %s' % (str(key),str(val))) - msg = 'Error trying to import this record:%s. ErrorMessage:%s %s' % (d,res[2],res[3]) - error = {'message':str(msg)} + msg = u"Error during import: %s\n\nTrying to import record %r" % ( + message, record) return '' % ( - jsonp, simplejson.dumps({'error':error})) + jsonp, simplejson.dumps({'error': {'message':msg}})) diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js index c62901e4795..70cb9ef9755 100644 --- a/addons/web/static/src/js/data_import.js +++ b/addons/web/static/src/js/data_import.js @@ -14,14 +14,18 @@ var QWeb = openerp.web.qweb; * @param {Function} callback function to call with the returned data */ function jsonp(form, attributes, callback) { + attributes = attributes || {}; var options = {jsonp: _.uniqueId('import_callback_')}; window[options.jsonp] = function () { delete window[options.jsonp]; callback.apply(null, arguments); }; - $(form).ajaxSubmit(_.extend({ - data: options - }, attributes)); + if ('data' in attributes) { + _.extend(attributes.data, options); + } else { + _.extend(attributes, {data: options}); + } + $(form).ajaxSubmit(attributes); } openerp.web.DataImport = openerp.web.Dialog.extend({ @@ -113,8 +117,31 @@ openerp.web.DataImport = openerp.web.Dialog.extend({ }, do_import: function() { if(!this.$element.find('#csvfile').val()) { return; } + var lines_to_skip = parseInt(this.$element.find('#csv_skip').val(), 10); + var with_headers = this.$element.find('#file_has_headers').prop('checked'); + if (!lines_to_skip && with_headers) { + lines_to_skip = 1; + } + var indices = [], fields = []; + this.$element.find(".sel_fields").each(function(index, element) { + var val = element.value; + if (!val) { + return; + } + indices.push(index); + fields.push(val); + }); + jsonp(this.$element.find('#import_data'), { - url: '/web/import/import_data' + url: '/web/import/import_data', + data: { + model: this.model, + meta: JSON.stringify({ + skip: lines_to_skip, + indices: indices, + fields: fields + }) + } }, this.on_import_results); }, on_autodetect_data: function() { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index c735a6fa815..78fc4c4eb21 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1389,7 +1389,6 @@
-

1. Import a .CSV file

Select a .CSV file to import. If you need a sample of file to import, you should use the export tool with the "Import Compatible" option.