[IMP]Improve code for import data and preview of three records.
authorKunal Chavda (OpenERP) <kch@tinyerp.com>
Wed, 3 Aug 2011 12:32:42 +0000 (18:02 +0530)
committerKunal Chavda (OpenERP) <kch@tinyerp.com>
Wed, 3 Aug 2011 12:32:42 +0000 (18:02 +0530)
bzr revid: kch@tinyerp.com-20110803123242-bpyq87hw0bfm0iiv

addons/base/__openerp__.py
addons/base/controllers/main.py
addons/base/static/src/css/data_import.css [new file with mode: 0644]
addons/base/static/src/img/gradientlinebg.gif [new file with mode: 0644]
addons/base/static/src/js/import.js
addons/base/static/src/xml/base.xml

index 7153587..28b9280 100644 (file)
@@ -40,5 +40,6 @@
         "static/lib/jquery.ui.notify/css/ui.notify.css",
         "static/src/css/base.css",
         "static/src/css/data_export.css",
+        "static/src/css/data_import.css",
     ],
 }
index a2e6cc0..777fd56 100644 (file)
@@ -1204,8 +1204,86 @@ class Export(View):
 class Import(View):
     _cp_path = "/base/import"
 
+    def fields_get(self, req, model):
+        Model = req.session.model(model)
+        fields = Model.fields_get(False, req.session.eval_context(req.context))
+        return fields
+
+    @openerpweb.httprequest
+    def detect_data(self, req, session_id, model, id, csvfile, csvsep, csvdel, csvcode, csvskip):
+        import StringIO
+        _fields = {}
+        _fields_invert = {}
+        error = None
+
+        fields = dict(req.session.model(model).fields_get(False, req.session.eval_context(req.context)))
+        fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
+
+        def model_populate(fields, prefix_node='', prefix=None, prefix_value='', level=2):
+            def str_comp(x,y):
+                if x<y: return 1
+                elif x>y: return -1
+                else: return 0
+
+            fields_order = fields.keys()
+            fields_order.sort(lambda x,y: str_comp(fields[x].get('string', ''), fields[y].get('string', '')))
+            for field in fields_order:
+                if (fields[field].get('type','') not in ('reference',))\
+                            and (not fields[field].get('readonly')\
+                            or not dict(fields[field].get('states', {}).get(
+                            'draft', [('readonly', True)])).get('readonly',True)):
+
+                    st_name = prefix_value+fields[field]['string'] or field
+                    _fields[prefix_node+field] = st_name
+                    _fields_invert[st_name] = prefix_node+field
+
+                    if fields[field].get('type','')=='one2many' and level>0:
+                        fields2 = self.fields_get(req,  fields[field]['relation'])
+                        model_populate(fields2, prefix_node+field+'/', None, st_name+'/', level-1)
+
+                    if fields[field].get('relation',False) and level>0:
+                        model_populate({'/id': {'type': 'char', 'string': 'ID'}, '.id': {'type': 'char', 'string': 'Database ID'}},
+                                       prefix_node+field, None, st_name+'/', level-1)
+        fields.update({'id':{'string':'ID'},'.id':{'string':'Database ID'}})
+        model_populate(fields)
+
+        try:
+            data = csv.reader(csvfile.file, quotechar=str(csvdel), delimiter=str(csvsep))
+        except:
+            raise 'Error opening .CSV file', 'Input Error.'
+
+        records = []
+        fields = []
+        word=''
+        limit = 3
+
+        try:
+            for i, row in enumerate(data):
+                records.append(row)
+                if i == limit:
+                    break
+            for line in records:
+                for word in line:
+                    word = str(word.decode(csvcode))
+                    if word in _fields:
+                        fields.append((word, _fields[word]))
+                    elif word in _fields_invert.keys():
+                        fields.append((_fields_invert[word], word))
+                    else:
+                        error = {'message':("You cannot import the field '%s', because we cannot auto-detect it" % (word,))}
+                break
+        except:
+            error = {'message':('Error processing the first line of the file. Field "%s" is unknown') % (word,)}
+
+        if error:
+            csvfile.file.seek(0)
+            error=dict(error, preview=csvfile.file.read(200))
+            return simplejson.dumps({'error':error})
+
+        return simplejson.dumps({'records':records})
+
     @openerpweb.httprequest
-    def import_data(self, req, session_id, callback, model, id, csvfile, csvsep, csvdel, csvcode, csvskip, fields=[]):
+    def import_data(self, req, session_id, model, id, csvfile, csvsep, csvdel, csvcode, csvskip, fields=[]):
         import StringIO
 
         context = req.session.eval_context(req.context)
@@ -1217,7 +1295,8 @@ class Import(View):
         data = []
 
         if not (csvdel and len(csvdel) == 1):
-            return "The CSV delimiter must be a single character"
+            error={'message': "The CSV delimiter must be a single character"}
+            return simplejson.dumps({'error':error})
 
         try:
             for j, line in enumerate(csv.reader(input, quotechar=str(csvdel), delimiter=str(csvsep))):
@@ -1228,8 +1307,9 @@ class Import(View):
                     fields = line
                 else:
                     data.append(line)
-        except:
-            return "CSV Error"
+        except csv.Error, e:
+            error={'message': str(e),'title': 'File Format Error'}
+            return simplejson.dumps({'error':error})
 
         datas = []
         ctx = context
@@ -1245,19 +1325,24 @@ class Import(View):
 
         # If the file contains nothing,
         if not datas:
-            return "The file is empty."
+            error = {'message': 'The file is empty !', 'title': 'Importation !'}
+            return simplejson.dumps({'error':error})
 
         #Inverting the header into column names
         try:
             res = modle_obj.import_data(fields, datas, 'init', '', False, ctx)
-        except:
-            return "Error in Importing Data."
+        except Exception, e:
+            error = {'message':str(e), 'title':'XML-RPC error'}
+            return simplejson.dumps({'error':error})
 
         if res[0]>=0:
-            return "Successfully Imported %d objects." % (res[0],)
+            success={'message':'Imported %d objects' % (res[0],)}
+            return simplejson.dumps({'success':success})
 
         d = ''
         for key,val in res[1].items():
-            d+= ('%s: %s' % (key,val))
+            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), 'title':'ImportationError'}
 
-        return "Error trying to import this record :%s. ErrorMessage:%s %s" % (d,res[2],res[3])
+        return simplejson.dumps({'error':error})
diff --git a/addons/base/static/src/css/data_import.css b/addons/base/static/src/css/data_import.css
new file mode 100644 (file)
index 0000000..a0d63a2
--- /dev/null
@@ -0,0 +1,23 @@
+
+.grid {
+    border: none;
+    border-collapse: collapse;
+}
+
+.grid-header .grid-cell {
+    background: url(../img/gradientlinebg.gif);
+    border-bottom: 1px solid #E3E3E3;
+    font-weight: bold;
+    text-align: left;
+}
+
+.grid-row .grid-cell {
+    border-bottom: 1px solid #E3E3E3;
+}
+
+.openerp .separator.horizontal {
+    font-weight: bold;
+    border-bottom-width: 1px;
+    margin: 6px 4px 6px 1px;
+    height: 20px;
+}
\ No newline at end of file
diff --git a/addons/base/static/src/img/gradientlinebg.gif b/addons/base/static/src/img/gradientlinebg.gif
new file mode 100644 (file)
index 0000000..f40bd9c
Binary files /dev/null and b/addons/base/static/src/img/gradientlinebg.gif differ
index e13e4f0..a41fade 100644 (file)
@@ -24,12 +24,86 @@ openerp.base.Import = openerp.base.Dialog.extend({
                             self.stop();
                           },
                         "Import File" : function() {
-                                $("#import_data").submit();
-                                //self.do_import();
+                                //$("#import_data").submit();
+                                self.do_import();
                           }
                        },
                     close: function(event, ui){ self.stop();}
                    });
+        this.$element.find('#csvfile').change(this.on_autodetect_data);
+        this.$element.find('fieldset legend').click(function () {
+                $(this).next().toggle();
+        });
+    },
+    do_import: function() {
+            var self = this;
+            if(!this.$element.find('#csvfile').val()) { return; }
+            this.$element.find('#import_data').attr({
+                'action': '/base/import/import_data'
+            }).ajaxSubmit({
+                success: this.import_results
+            });
+    },
+    on_autodetect_data: function() {
+            var self = this;
+            if(this.$element.find("#res td")){
+                this.$element.find("#res td").remove();
+                this.$element.find("#imported_success").css('display','none');
+            }
+            if(!this.$element.find('#csvfile').val()) { return; }
+            this.$element.find('#import_data').attr({
+                'action': '/base/import/detect_data'
+            }).ajaxSubmit({
+                success: this.import_results
+            });
+    },
+    import_results:function(res){
+        var self = this;
+        var results = $.parseJSON(res);
+
+        if (results['records']){
+            var result = results['records'];
+            if ($('#error').find('table')){
+                $("#error table").remove();
+            }
+            if ($('#records_data').find('tr')){
+                $("#records_data tr").remove();
+            }
+            for (i in result) {
+                if (i == 0){
+                    $('#records_data').append('<tr class="grid-header"></tr>');
+                    for (m in result[i]){
+                        $('.grid-header').append('<th class="grid-cell">'+result[i][m]+'</th>');
+                    }
+                }else{
+                    $('#records_data tr:last').after('<tr id='+i+' class="grid-row"></tr>');
+                    for (n in result[i]){
+                        $("tr[id="+i+"]").append('<td class="grid-cell">'+result[i][n]+'</td>');
+                    }
+                }
+            }
+        }else if(results['error']){
+            var result = results['error'];
+            if ($('#records_data').find('tr')){
+                $("#records_data tr").remove();
+            }
+            if ($('#error').find('table')){
+                $("#error table").remove();
+            }
+            $("#error").append('<table id="error_tbl"><tr style="white-space: pre-line;">The import failed due to:'+result['message']+'</tr></table>');
+            if (result['preview']){
+                $("#error_tbl tr:last").after('<tr>Here is a preview of the file we could not import:</tr>');
+                $("#error_tbl tr:last").after('<tr><pre>'+result['preview']+'</pre></tr>');
+            }
+        }else if(results['success']){
+            var result = results['success'];
+            $("#imported_success").css('display','block');
+            $("#res").append('<td>'+result['message']+'</td>')
+        }
+    },
+    stop: function() {
+        $(this.$dialog).remove();
+        this._super();
     },
 });
 }
\ No newline at end of file
index 9f76bf1..563c5ba 100644 (file)
     <a id="importview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Import</a>
 </t>
 <t t-name="ImportDataView">
-<form name="import_data" id="import_data" action="/base/import/import_data" method="post" enctype="multipart/form-data">
+<form name="import_data" id="import_data" action="" method="post" enctype="multipart/form-data">
     <input type="hidden" name="session_id" t-att-value="session.session_id"/>
-    <input type="hidden" name="callback" t-attf-value="#{element_id}_iframe"/>
     <input type="hidden" name="model" t-att-value="dataset.model"/>
     <input type="hidden" name="id" t-att-value="dataset.id"/>
      <table cellspacing="5" border="0" width="100%">
                 <table width="100%">
                     <tr>
                         <td width="100%" valign="middle" colspan="4">
-                            <h2>1. Import a .CSV file</h2>
+                            <h2 class="separator horizontal">1. Import a .CSV file</h2>
                         </td>
                     </tr>
                     <tr>
                     <table width="100%">
                         <tr>
                             <td width="100%" valign="middle">
-                                <h2>2. Check your file format</h2>
+                                <h2 class="separator horizontal">2. Check your file format</h2>
                             </td>
                         </tr>
                     </table>
-                    <table id="records_data" width="100%" style="margin: 5px 0;">
+                    <div id="error">
+                    </div>
+                    <table id="records_data" class="grid" width="100%" style="margin: 5px 0;">
                     </table>
                     <fieldset>
                         <legend style="cursor:pointer;">CSV Options</legend>
-                        <table style="display:block">
+                        <table style="display:none">
                             <tr>
                                <td class="label"><label for="csv_separator">Separator:</label></td>
                                 <td><input type="text" name="csvsep" id="csv_separator" value=","/></td>
                 </div>
             </td>
         </tr>
+        <tr>
+            <td width="100%">
+                <div id="imported_success" style="display:none;">
+                    <table width="100%">
+                        <tr>
+                            <td width="100%" valign="middle" colspan="4">
+                                <h2 class="separator horizontal">3. File imported</h2>
+                            </td>
+                        </tr>
+                        <tr id="res">
+                        </tr>
+                    </table>
+                </div>
+            </td>
+        </tr>
     </table>
 </form>
 </t>