[IMP]Implement Import data Functionality.
authorKunal Chavda (OpenERP) <kch@tinyerp.com>
Wed, 27 Jul 2011 06:43:25 +0000 (12:13 +0530)
committerKunal Chavda (OpenERP) <kch@tinyerp.com>
Wed, 27 Jul 2011 06:43:25 +0000 (12:13 +0530)
bzr revid: kch@tinyerp.com-20110727064325-zh8j9w7bvcdckv7v

addons/base/__openerp__.py
addons/base/controllers/main.py
addons/base/static/src/js/base.js
addons/base/static/src/js/import.js [new file with mode: 0644]
addons/base/static/src/js/views.js
addons/base/static/src/xml/base.xml

index a983a42..b4ff705 100644 (file)
@@ -28,6 +28,7 @@
         "static/src/js/list-editable.js",
         "static/src/js/search.js",
         "static/src/js/view_tree.js",
+        "static/src/js/import.js",
     ],
     'css' : [
         "static/lib/jquery.superfish/css/superfish.css",
index 628a086..16b4613 100644 (file)
@@ -10,7 +10,7 @@ import openerpweb.ast
 import openerpweb.nonliterals
 
 import cherrypy
-
+import csv
 # Should move to openerpweb.Xml2Json
 class Xml2Json:
     # xml2json-direct
@@ -119,8 +119,8 @@ class WebClient(openerpweb.Controller):
             %s
             <script type="text/javascript">
             $(function() {
-                QWeb = new QWeb2.Engine(); 
-                openerp.init().base.webclient("oe"); 
+                QWeb = new QWeb2.Engine();
+                openerp.init().base.webclient("oe");
             });
             </script>
             <link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
@@ -222,7 +222,7 @@ class Session(openerpweb.Controller):
         context, domain = eval_context_and_domain(req.session,
                                                   openerpweb.nonliterals.CompoundContext(*(contexts or [])),
                                                   openerpweb.nonliterals.CompoundDomain(*(domains or [])))
-        
+
         group_by_sequence = []
         for candidate in (group_by_seq or []):
             ctx = req.session.eval_context(candidate, context)
@@ -233,7 +233,7 @@ class Session(openerpweb.Controller):
                 group_by_sequence.append(group_by)
             else:
                 group_by_sequence.extend(group_by)
-        
+
         return {
             'context': context,
             'domain': domain,
@@ -246,7 +246,7 @@ class Session(openerpweb.Controller):
         This method store an action object in the session object and returns an integer
         identifying that action. The method get_session_action() can be used to get
         back the action.
-        
+
         :param the_action: The action to save in the session.
         :type the_action: anything
         :return: A key identifying the saved action.
@@ -269,7 +269,7 @@ class Session(openerpweb.Controller):
         """
         Gets back a previously saved action. This method can return None if the action
         was saved since too much time (this case should be handled in a smart way).
-        
+
         :param key: The key given by save_session_action()
         :type key: integer
         :return: The saved action or None.
@@ -404,7 +404,7 @@ class Menu(openerpweb.Controller):
         menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context)
         menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, '']}
         menu_items.append(menu_root)
-        
+
         # make a tree using parent_id
         menu_items_map = dict((menu_item["id"], menu_item) for menu_item in menu_items)
         for menu_item in menu_items:
@@ -511,7 +511,7 @@ class DataSet(openerpweb.Controller):
         record_map = dict((record['id'], record) for record in records)
 
         return [record_map[id] for id in ids if record_map.get(id)]
-    
+
     @openerpweb.jsonrequest
     def load(self, req, model, id, fields):
         m = req.session.model(model)
@@ -674,7 +674,7 @@ class View(openerpweb.Controller):
         except ValueError:
             # not a literal
             return openerpweb.nonliterals.Domain(session, domain)
-        
+
     def parse_context(self, context, session):
         """ Parses an arbitrary string containing a context, transforms it
         to either a literal context or a :class:`openerpweb.nonliterals.Context`
@@ -764,7 +764,7 @@ class SearchView(View):
             if field.get('context'):
                 field["context"] = self.parse_domain(field["context"], req.session)
         return {'fields': fields}
-    
+
     @openerpweb.jsonrequest
     def get_filters(self, req, model):
         Model = req.session.model("ir.filters")
@@ -773,7 +773,7 @@ class SearchView(View):
             filter["context"] = req.session.eval_context(self.parse_context(filter["context"], req.session))
             filter["domain"] = req.session.eval_domain(self.parse_domain(filter["domain"], req.session))
         return filters
-    
+
     @openerpweb.jsonrequest
     def save_filter(self, req, model, name, context_to_save, domain):
         Model = req.session.model("ir.filters")
@@ -903,4 +903,64 @@ class Action(openerpweb.Controller):
         return clean_action(req.session.model('ir.actions.server').run(
             [action_id], req.session.eval_context(req.context)), req.session)
 
-#
+class Import(View):
+    _cp_path = "/base/import"
+
+    @openerpweb.httprequest
+    def import_data(self, req, session_id, callback, model, id, csvfile, csvsep, csvdel, csvcode, csvskip, fields=[]):
+        import StringIO
+        context = req.session.eval_context(req.context)
+        modle_obj = req.session.model(model)
+
+        res = None
+        content = csvfile.file.read()
+        print "\n content++++++++++++++++++++++++++++",content
+        input=StringIO.StringIO(content)
+        limit = 0
+        data = []
+
+        if not (csvdel and len(csvdel) == 1):
+            return "The CSV delimiter must be a single character"
+
+        try:
+            for j, line in enumerate(csv.reader(input, quotechar=str(csvdel), delimiter=str(csvsep))):
+                # If the line contains no data, we should skip it.
+                if not line:
+                    continue
+                if j == limit:
+                    fields = line
+                else:
+                    data.append(line)
+        except:
+            return "CSV Error"
+
+        datas = []
+        ctx = context
+
+        if not isinstance(fields, list):
+            fields = [fields]
+
+        for line in data:
+            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))
+
+        # If the file contains nothing,
+        if not datas:
+            return "The file is empty."
+
+        #Inverting the header into column names
+        try:
+            res = modle_obj.import_data(fields, datas, 'init', '', False, ctx)
+        except:
+            return "Error in Importing Data."
+
+        if res[0]>=0:
+            return "Successfully Imported %d objects." % (res[0],)
+
+        d = ''
+        for key,val in res[1].items():
+            d+= ('%s: %s' % (key,val))
+
+        return "Error trying to import this record :%s. ErrorMessage:%s %s" % (d,res[2],res[3])
index 28022f8..d5f2320 100644 (file)
@@ -87,6 +87,9 @@ openerp.base = function(instance) {
     if (openerp.base.view_tree) {
         openerp.base.view_tree(instance);
     }
+    if (openerp.base.import){
+        openerp.base.import(instance);
+    }
 };
 
 // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/base/static/src/js/import.js b/addons/base/static/src/js/import.js
new file mode 100644 (file)
index 0000000..5b6affe
--- /dev/null
@@ -0,0 +1,35 @@
+openerp.base.import = function(openerp) {
+openerp.base.Import = openerp.base.Dialog.extend({
+    init: function(parent, dataset, views){
+        this._super(parent);
+        this.dataset = dataset;
+        this.views = views;
+        this.views_id = {};
+        for (var key in this.views) {
+            this.views_id[key] = this.views[key].view_id
+        }
+    },
+    start: function() {
+        var self = this
+        self._super(false);
+        self.template = 'ImportDataView';
+        self.dialog_title = "Import Data"
+        self.open({
+                    modal: true,
+                    width: '70%',
+                    height: 'auto',
+                    position: 'top',
+                    buttons : {
+                        "Close" : function() {
+                            self.stop();
+                          },
+                        "Import File" : function() {
+                                $("#import_data").submit();
+                                //self.do_import();
+                          }
+                       },
+                    close: function(event, ui){ self.close();}
+                   });
+    },
+});
+}
\ No newline at end of file
index b98b0bc..1d44fb3 100644 (file)
@@ -212,11 +212,24 @@ openerp.base.ViewManager =  openerp.base.Controller.extend({
                 }
             }
         }
+        if(this.flags && this.flags.sidebar) {
+            if(this.$element.find('#importview')){
+                this.$element.find('#importview').remove()
+            }
+            if(this.active_view == 'list' || this.active_view == 'form') {
+                this.views[this.active_view].controller.$element.after(QWeb.render('ImportView'))
+                this.$element.find('#importview').click(function(ev) {
+                    var import_view = new openerp.base.Import(self, self.dataset, self.views);
+                    import_view.start(false);
+                    ev.preventDefault();
+                });
+            }
+        }
         return view_promise;
     },
     /**
      * Event launched when a controller has been inited.
-     * 
+     *
      * @param {String} view_type type of view
      * @param {String} view the inited controller
      */
@@ -522,7 +535,7 @@ openerp.base.View = openerp.base.Controller.extend({
      * Directly set a view to use instead of calling fields_view_get. This method must
      * be called before start(). When an embedded view is set, underlying implementations
      * of openerp.base.View must use the provided view instead of any other one.
-     * 
+     *
      * @param embedded_view A view.
      */
     set_embedded_view: function(embedded_view) {
index 10d1539..f7c2cf5 100644 (file)
     <div class="oe_login_right_pane">
         <p>We think that daily job activities can be more intuitive, efficient, automated, .. and even fun.</p>
         <h3>OpenERP's vision to be:</h3>
-        
+
         <table cellpadding="0" cellspacing="0" width="100%" style="border:none;">
             <tbody>
             <tr>
             </tr>
             </tbody>
         </table>
-        
+
     </div>
 </t>
 <t t-name="Header">
     t-att-data-index="row_index">
     <t t-foreach="columns" t-as="column">
         <td t-if="column.meta">
-            
+
         </td>
     </t>
     <th t-if="options.selectable" class="oe-record-selector" width="1">
             <option value="all">All the following conditions must match</option>
             <option value="none">None of the following conditions must match</option>
         </select>
-        <a class="searchview_extended_delete_group" 
+        <a class="searchview_extended_delete_group"
                 href="javascript:void(0)"><span></span></a>
         <div class="searchview_extended_propositions_list">
         </div>
             .unwrap();
     </t>
 </t>
+<t t-name="ImportView">
+    <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">
+    <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%">
+        <tr>
+            <td>
+                <table width="100%">
+                    <tr>
+                        <td width="100%" valign="middle" colspan="4">
+                            <h2>1. Import a .CSV file</h2>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            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.
+                        </td>
+                    </tr>
+                </table>
+            </td>
+        </tr>
+        <tr>
+            <td>
+                <table align="center">
+                    <tr>
+                        <td><label>CSV File:</label></td>
+                        <td>
+                            <input type="file" id="csvfile" size="50" name="csvfile"/>
+                        </td>
+                    </tr>
+                </table>
+            </td>
+        </tr>
+        <tr>
+            <td height="10px">
+            </td>
+        </tr>
+        <tr>
+            <td width="100%">
+                <div id="record">
+                    <table width="100%">
+                        <tr>
+                            <td width="100%" valign="middle">
+                                <h2>2. Check your file format</h2>
+                            </td>
+                        </tr>
+                    </table>
+                    <table id="records_data" width="100%" style="margin: 5px 0;">
+                    </table>
+                    <fieldset>
+                        <legend style="cursor:pointer;">CSV Options</legend>
+                        <table style="display:block">
+                            <tr>
+                               <td class="label"><label for="csv_separator">Separator:</label></td>
+                                <td><input type="text" name="csvsep" id="csv_separator" value=","/></td>
+                                <td class="label"><label for="csv_delimiter">Delimiter:</label></td>
+                                <td><input type="text" name="csvdel" id="csv_delimiter" value='"'/></td>
+                            </tr>
+                            <tr>
+                                <td><label for="csv_encoding">Encoding:</label></td>
+                                <td>
+                                    <select name="csvcode" id="csv_encoding">
+                                        <option value="utf-8">UTF-8</option>
+                                        <option value="latin1">Latin 1</option>
+                                    </select>
+                                </td>
+                                <td><label>Lines to skip:</label></td>
+                                <td><input type="text" name="csvskip" id="csv_skip" value="1"/></td>
+                            </tr>
+                        </table>
+                    </fieldset>
+                </div>
+            </td>
+        </tr>
+    </table>
+</form>
+</t>
 </templates>