~toolpart/openobject-server/toolpart

« back to all changes in this revision

Viewing changes to bin/tools/convert.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#----------------------------------------------------------
 
2
# Convert 
 
3
#----------------------------------------------------------
 
4
import re
 
5
import StringIO,xml.dom.minidom
 
6
import osv,ir,pooler
 
7
 
 
8
import csv
 
9
 
 
10
from config import config
 
11
 
 
12
class ConvertError(Exception):
 
13
        def __init__(self, doc, orig_excpt):
 
14
                self.d = doc
 
15
                self.orig = orig_excpt
 
16
        
 
17
        def __str__(self):
 
18
                return 'Exception:\n\t%s\nUsing file:\n%s' % (self.orig, self.d)
 
19
 
 
20
def _eval_xml(self,node, pool, cr, uid, idref):
 
21
        if node.nodeType == node.TEXT_NODE:
 
22
                return node.data.encode("utf8")
 
23
        elif node.nodeType == node.ELEMENT_NODE:
 
24
                if node.nodeName in ('field','value'):
 
25
                        t = node.getAttribute('type') or 'char'
 
26
                        if len(node.getAttribute('search')):
 
27
                                f_search = node.getAttribute("search").encode('utf-8')
 
28
                                f_model = node.getAttribute("model").encode('ascii')
 
29
                                f_use = node.getAttribute("use").encode('ascii')
 
30
                                f_name = node.getAttribute("name").encode('utf-8')
 
31
                                if len(f_use)==0:
 
32
                                        f_use = "id"
 
33
                                q = eval(f_search, idref)
 
34
                                ids = pool.get(f_model).search(cr, uid, q)
 
35
                                if f_use<>'id':
 
36
                                        ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
 
37
                                _cols = pool.get(f_model)._columns
 
38
                                if (f_name in _cols) and _cols[f_name]._type=='many2many':
 
39
                                        return ids
 
40
                                f_val = False
 
41
                                if len(ids):
 
42
                                        f_val = ids[0]
 
43
                                        if isinstance(f_val, tuple):
 
44
                                                f_val = f_val[0]
 
45
                                return f_val
 
46
                        a_eval = node.getAttribute('eval')
 
47
                        if len(a_eval):
 
48
                                import time
 
49
                                idref['time'] = time
 
50
                                idref['ref'] = lambda x: self.id_get(cr, False, x)
 
51
                                return eval(a_eval, idref)
 
52
                        if t == 'xml':
 
53
                                txt = '<?xml version="1.0"?>\n'+"".join([i.toxml().encode("utf8") for i in node.childNodes]) % idref
 
54
                                return txt
 
55
                        if t in ('char', 'int', 'float'):
 
56
                                d = ""
 
57
                                for n in [i for i in node.childNodes]:
 
58
                                        d+=str(_eval_xml(self,n,pool,cr,uid,idref))
 
59
                                if t == 'int':
 
60
                                        d = d.strip()
 
61
                                        if d=='None':
 
62
                                                return None
 
63
                                        else:
 
64
                                                d=int(d.strip())
 
65
                                elif t=='float':
 
66
                                        d=float(d.strip())
 
67
                                return d
 
68
                        elif t in ('list','tuple'):
 
69
                                res=[]
 
70
                                for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=='value')]:
 
71
                                        res.append(_eval_xml(self,n,pool,cr,uid,idref))
 
72
                                if t=='tuple':
 
73
                                        return tuple(res)
 
74
                                return res
 
75
                elif node.nodeName=="getitem":
 
76
                        for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
 
77
                                res=_eval_xml(self,n,pool,cr,uid,idref)
 
78
                        if not res:
 
79
                                raise LookupError
 
80
                        elif node.getAttribute('type') in ("int", "list"):
 
81
                                return res[int(node.getAttribute('index'))]
 
82
                        else:
 
83
                                return res[node.getAttribute('index').encode("utf8")]
 
84
                elif node.nodeName=="function":
 
85
                        args = []
 
86
                        a_eval = node.getAttribute('eval')
 
87
                        if len(a_eval):
 
88
                                args = eval(a_eval, idref)
 
89
                        for n in [i for i in node.childNodes if (i.nodeType == i.ELEMENT_NODE)]:
 
90
                                args.append(_eval_xml(self,n, pool, cr, uid, idref))
 
91
                        model = pool.get(node.getAttribute('model'))
 
92
                        method = node.getAttribute('name')
 
93
                        res = getattr(model, method)(cr, uid, *args)
 
94
                        return res
 
95
 
 
96
escape_re = re.compile(r'(?<!\\)/')
 
97
def escape(x):
 
98
        return x.replace('\\/', '/')
 
99
 
 
100
class xml_import(object):
 
101
        def _tag_delete(self, cr, rec, data_node=None):
 
102
                d_model = rec.getAttribute("model")
 
103
                d_search = rec.getAttribute("search")
 
104
                ids = self.pool.get(d_model).search(cr,self.uid,eval(d_search))
 
105
                if len(ids):
 
106
                        self.pool.get(d_model).unlink(cr, self.uid, ids)
 
107
                        #self.pool.get('ir.model.data')._unlink(cr, self.uid, d_model, ids, direct=True)
 
108
                return False
 
109
 
 
110
        def _tag_report(self, cr, rec, data_node=None):
 
111
                res = {}
 
112
                for dest,f in (('name','string'),('model','model'),('report_name','name')):
 
113
                        res[dest] = rec.getAttribute(f).encode('utf8')
 
114
                        assert res[dest], "Attribute %s of report is empty !" % (f,)
 
115
                for field,dest in (('rml','report_rml'),('xml','report_xml'),('xsl','report_xsl')):
 
116
                        if rec.hasAttribute(field):
 
117
                                res[dest] = rec.getAttribute(field).encode('utf8')
 
118
                if rec.hasAttribute('auto'):
 
119
                        res['auto'] = eval(rec.getAttribute('auto'))
 
120
                xml_id = rec.getAttribute('id').encode('utf8')
 
121
                id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, mode=self.mode)
 
122
                self.idref[xml_id] = id
 
123
                if not rec.hasAttribute('menu') or eval(rec.getAttribute('menu')):
 
124
                        keyword = str(rec.getAttribute('keyword') or 'client_print_multi')
 
125
                        keys = [('action',keyword),('res_model',res['model'])]
 
126
                        value = 'ir.actions.report.xml,'+str(id)
 
127
                        replace = rec.hasAttribute('replace') and rec.getAttribute("replace")
 
128
                        self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, res['name'], [res['model']], value, replace=replace, isobject=True)
 
129
                return False
 
130
 
 
131
        def _tag_function(self, cr, rec, data_node=None):
 
132
                _eval_xml(self,rec, self.pool, cr, self.uid, self.idref)
 
133
                return False
 
134
 
 
135
        def _tag_wizard(self, cr, rec, data_node=None):
 
136
                string = rec.getAttribute("string").encode('utf8')
 
137
                model = rec.getAttribute("model").encode('utf8')
 
138
                name = rec.getAttribute("name").encode('utf8')
 
139
                xml_id = rec.getAttribute('id').encode('utf8')
 
140
                multi = rec.hasAttribute('multi') and  eval(rec.getAttribute('multi'))
 
141
                res = {'name': string, 'wiz_name': name, 'multi':multi}
 
142
 
 
143
                id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, mode=self.mode)
 
144
                self.idref[xml_id] = id
 
145
                # ir_set
 
146
                if not rec.hasAttribute('menu') or eval(rec.getAttribute('menu')):
 
147
                        keyword = str(rec.getAttribute('keyword') or 'client_action_multi')
 
148
                        keys = [('action',keyword),('res_model',model)]
 
149
                        value = 'ir.actions.wizard,'+str(id)
 
150
                        replace = rec.hasAttribute('replace') and rec.getAttribute("replace")
 
151
                        self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, string, [model], value, replace=replace, isobject=True)
 
152
                return False
 
153
 
 
154
        def _tag_ir_set(self, cr, rec, data_node=None):
 
155
                if not self.mode=='init':
 
156
                        return False
 
157
                res = {}
 
158
                for field in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="field")]:
 
159
                        f_name = field.getAttribute("name").encode('utf-8')
 
160
                        f_val = _eval_xml(self,field,self.pool, cr, self.uid, self.idref)
 
161
                        res[f_name] = f_val
 
162
                self.pool.get('ir.model.data').ir_set(cr, self.uid, res['key'], res['key2'], res['name'], res['models'], res['value'], replace=res.get('replace',True), isobject=res.get('isobject', False), meta=res.get('meta',None))
 
163
                return False
 
164
 
 
165
        def _tag_workflow(self, cr, rec, data_node=None):
 
166
                import netsvc
 
167
                model = str(rec.getAttribute('model'))
 
168
                wf_service = netsvc.LocalService("workflow")
 
169
                wf_service.trg_validate(self.uid, model,
 
170
                        self.id_get(cr, model, rec.getAttribute('ref')),
 
171
                        str(rec.getAttribute('action')), cr)
 
172
                return False
 
173
 
 
174
        def _tag_menuitem(self, cr, rec, data_node=None):
 
175
                rec_id = rec.getAttribute("id").encode('ascii')
 
176
                m_l = map(escape, escape_re.split(rec.getAttribute("name").encode('utf8')))
 
177
                pid = False
 
178
                for idx, menu_elem in enumerate(m_l):
 
179
                        if pid:
 
180
                                cr.execute('select id from ir_ui_menu where parent_id=%d and name=%s', (pid, menu_elem))
 
181
                        else:
 
182
                                cr.execute('select id from ir_ui_menu where parent_id is null and name=%s', (menu_elem,))
 
183
                        res = cr.fetchone()
 
184
                        if idx==len(m_l)-1:
 
185
                                # we are at the last menu element/level (it's a leaf)
 
186
                                values = {'parent_id': pid,'name':menu_elem}
 
187
 
 
188
                                if rec.hasAttribute('action'):
 
189
                                        a_action = rec.getAttribute('action').encode('utf8')
 
190
                                        a_type = rec.getAttribute('type').encode('utf8') or 'act_window'
 
191
                                        icons = {
 
192
                                                "act_window": 'STOCK_NEW',
 
193
                                                "report.xml": 'STOCK_PASTE',
 
194
                                                "wizard": 'STOCK_EXECUTE',
 
195
                                        }
 
196
                                        values['icon'] = icons.get(a_type,'STOCK_NEW')
 
197
                                        if a_type=='act_window':
 
198
                                                a_id = self.id_get(cr, 'ir.actions.%s'% a_type, a_action)
 
199
                                                cr.execute('select view_type,view_mode from ir_act_window where id=%d', (int(a_id),))
 
200
                                                action_type,action_mode = cr.fetchone()
 
201
                                                if action_type=='tree':
 
202
                                                        values['icon'] = 'STOCK_INDENT'
 
203
                                                elif action_mode and action_mode.startswith('tree'):
 
204
                                                        values['icon'] = 'STOCK_JUSTIFY_FILL'
 
205
                                if rec.hasAttribute('sequence'):
 
206
                                        values['sequence'] = int(rec.getAttribute('sequence'))
 
207
                                if rec.hasAttribute('icon'):
 
208
                                        values['icon'] = str(rec.getAttribute('icon'))
 
209
                                if rec.hasAttribute('groups'):
 
210
                                        g_names = rec.getAttribute('groups').split(',')
 
211
                                        g_ids = []
 
212
                                        for group in g_names:
 
213
                                                g_ids.extend(self.pool.get('res.groups').search(cr, self.uid, [('name', '=', group)]))
 
214
                                        values['groups_id'] = [(6, 0, g_ids)]
 
215
                                xml_id = rec.getAttribute('id').encode('utf8')
 
216
                                pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, xml_id, idx==len(m_l)-1, mode=self.mode, res_id=res and res[0] or False)
 
217
                        elif res:
 
218
                                # the menuitem already exists
 
219
                                pid = res[0]
 
220
                                xml_id = idx==len(m_l)-1 and rec.getAttribute('id').encode('utf8')
 
221
                                try:
 
222
                                        npid = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, 'ir.ui.menu', self.module, xml_id, idx==len(m_l)-1)
 
223
                                except:
 
224
                                        print 'Menu Error', self.module, xml_id, idx==len(m_l)-1
 
225
                        else:
 
226
                                # the menuitem does't exist but we are in branch (not a leaf)
 
227
                                pid = self.pool.get('ir.ui.menu').create(cr, self.uid, {'parent_id' : pid, 'name' : menu_elem})
 
228
                if rec_id and pid:
 
229
                        self.idref[rec_id] = pid
 
230
 
 
231
                if rec.hasAttribute('action') and pid:
 
232
                        a_action = rec.getAttribute('action').encode('utf8')
 
233
                        a_type = rec.getAttribute('type').encode('utf8') or 'act_window'
 
234
                        a_id = self.id_get(cr, 'ir.actions.%s' % a_type, a_action)
 
235
                        action = "ir.actions.%s,%d" % (a_type, a_id)
 
236
                        self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', 'tree_but_open', 'Menuitem', [('ir.ui.menu', int(pid))], action, True, True)
 
237
                return ('ir.ui.menu', pid)
 
238
 
 
239
        def _tag_record(self, cr, rec, data_node=None):
 
240
                rec_model = rec.getAttribute("model").encode('ascii')
 
241
                model = self.pool.get(rec_model)
 
242
                assert model, "The model %s does not exist !" % (rec_model,)
 
243
                rec_id = rec.getAttribute("id").encode('ascii')
 
244
 
 
245
#               if not rec_id and not data_node.getAttribute('noupdate'):
 
246
#                       print "Warning", rec_model
 
247
 
 
248
                if data_node.getAttribute('noupdate') and not self.mode == 'init':
 
249
                        # check if the xml record has an id string
 
250
                        if rec_id:
 
251
                                id = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, rec_model, self.module, rec_id)
 
252
                                # check if the resource already existed at the last update
 
253
                                if id:
 
254
                                        # if it existed, we don't update the data, but we need to 
 
255
                                        # know the id of the existing record anyway
 
256
                                        self.idref[rec_id] = id
 
257
                                        return None
 
258
                                else:
 
259
                                        # if the resource didn't exist
 
260
                                        if rec.getAttribute("forcecreate"):
 
261
                                                # we want to create it, so we let the normal "update" behavior happen
 
262
                                                pass
 
263
                                        else:
 
264
                                                # otherwise do nothing
 
265
                                                return None
 
266
                        else:
 
267
                                # otherwise it is skipped
 
268
                                return None
 
269
                                
 
270
                res = {}
 
271
                for field in [i for i in rec.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="field")]:
 
272
#TODO: most of this code is duplicated above (in _eval_xml)...
 
273
                        f_name = field.getAttribute("name").encode('utf-8')
 
274
                        f_ref = field.getAttribute("ref").encode('ascii')
 
275
                        f_search = field.getAttribute("search").encode('utf-8')
 
276
                        f_model = field.getAttribute("model").encode('ascii')
 
277
                        if not f_model and model._columns.get(f_name,False):
 
278
                                f_model = model._columns[f_name]._obj
 
279
                        f_use = field.getAttribute("use").encode('ascii') or 'id'
 
280
                        f_val = False
 
281
 
 
282
                        if len(f_search):
 
283
                                q = eval(f_search, self.idref)
 
284
                                field = []
 
285
                                assert f_model, 'Define an attribute model="..." in your .XML file !'
 
286
                                f_obj = self.pool.get(f_model)
 
287
                                # browse the objects searched
 
288
                                s = f_obj.browse(cr, self.uid, f_obj.search(cr, self.uid, q))
 
289
                                # column definitions of the "local" object
 
290
                                _cols = self.pool.get(rec_model)._columns
 
291
                                # if the current field is many2many
 
292
                                if (f_name in _cols) and _cols[f_name]._type=='many2many':
 
293
                                        f_val = [(6, 0, map(lambda x: x[f_use], s))]
 
294
                                elif len(s):
 
295
                                        # otherwise (we are probably in a many2one field),
 
296
                                        # take the first element of the search
 
297
                                        f_val = s[0][f_use]
 
298
                        elif len(f_ref):
 
299
                                if f_ref=="null":
 
300
                                        f_val = False
 
301
                                else:
 
302
                                        f_val = self.id_get(cr, f_model, f_ref)
 
303
                        else:
 
304
                                f_val = _eval_xml(self,field, self.pool, cr, self.uid, self.idref)
 
305
                                if model._columns.has_key(f_name):
 
306
                                        if isinstance(model._columns[f_name], osv.fields.integer):
 
307
                                                f_val = int(f_val)
 
308
                        res[f_name] = f_val
 
309
                id = self.pool.get('ir.model.data')._update(cr, self.uid, rec_model, self.module, res, rec_id or False, not data_node.getAttribute('noupdate'), noupdate=data_node.getAttribute('noupdate'), mode=self.mode )
 
310
                if rec_id:
 
311
                        self.idref[rec_id] = id
 
312
                return rec_model, id
 
313
 
 
314
        def id_get(self, cr, model, id_str):
 
315
                if id_str in self.idref:
 
316
                        return self.idref[id_str]
 
317
                mod = self.module
 
318
                if '.' in id_str:
 
319
                        mod,id_str = id_str.split('.')
 
320
                result = self.pool.get('ir.model.data')._get_id(cr, self.uid, mod, id_str)
 
321
                return self.pool.get('ir.model.data').read(cr, self.uid, [result], ['res_id'])[0]['res_id']
 
322
 
 
323
        def parse(self, xmlstr):
 
324
                d = xml.dom.minidom.parseString(xmlstr)
 
325
                de = d.documentElement
 
326
                for n in [i for i in de.childNodes if (i.nodeType == i.ELEMENT_NODE and i.nodeName=="data")]:
 
327
                        for rec in n.childNodes:
 
328
                                if rec.nodeType == rec.ELEMENT_NODE:
 
329
                                        if rec.nodeName in self._tags:
 
330
                                                try:
 
331
                                                        self._tags[rec.nodeName](self.cr, rec, n)
 
332
                                                except:
 
333
                                                        print rec.toxml()
 
334
                                                        raise
 
335
                self.cr.commit()
 
336
                return True
 
337
 
 
338
        def __init__(self, cr, module, idref, mode):
 
339
                self.mode = mode
 
340
                self.module = module
 
341
                self.cr = cr
 
342
                self.idref = idref
 
343
                self.pool = pooler.get_pool(cr.dbname)
 
344
#               self.pool = osv.osv.FakePool(module)
 
345
                self.uid = 1
 
346
                self._tags = {
 
347
                        'menuitem': self._tag_menuitem,
 
348
                        'record': self._tag_record,
 
349
                        'report': self._tag_report,
 
350
                        'wizard': self._tag_wizard,
 
351
                        'delete': self._tag_delete,
 
352
                        'ir_set': self._tag_ir_set,
 
353
                        'function': self._tag_function,
 
354
                        'workflow': self._tag_workflow,
 
355
                }
 
356
 
 
357
#
 
358
# Import a CSV file:
 
359
#     quote: "
 
360
#     delimiter: ,
 
361
#     encoding: UTF8
 
362
#
 
363
def convert_csv_import(cr, module, fname, csvcontent, idref={}, mode='init'):
 
364
        if mode != 'init':
 
365
                return
 
366
        model = ('.'.join(fname.split('.')[:-1]).split('-'))[0]
 
367
        #model = fname.split('.')[0].replace('_', '.')
 
368
        pool = pooler.get_pool(cr.dbname)
 
369
#       pool = osv.osv.FakePool(module)
 
370
 
 
371
        input=StringIO.StringIO(csvcontent)
 
372
        data = list(csv.reader(input, quotechar='"', delimiter=','))
 
373
 
 
374
        datas = []
 
375
        for line in data:
 
376
                datas.append( map(lambda x:x.decode('utf8').encode('utf8'), line))
 
377
 
 
378
        uid = 1
 
379
        pool.get(model).import_data(cr, uid, data[0], datas[1:])
 
380
        cr.commit()
 
381
 
 
382
#
 
383
# xml import/export
 
384
#
 
385
def convert_xml_import(cr, module, xmlstr, idref={}, mode='init'):
 
386
        obj = xml_import(cr, module, idref, mode)
 
387
        obj.parse(xmlstr)
 
388
        del obj
 
389
        return True
 
390
 
 
391
def convert_xml_export(res):
 
392
        uid=1
 
393
        pool=pooler.get_pool(cr.dbname)
 
394
        cr=pooler.db.cursor()
 
395
        idref = {}
 
396
        d = xml.dom.minidom.getDOMImplementation().createDocument(None, "terp", None)
 
397
        de = d.documentElement
 
398
        data=d.createElement("data")
 
399
        de.appendChild(data)
 
400
        de.appendChild(d.createTextNode('Some textual content.'))
 
401
        cr.commit()
 
402
        cr.close()
 
403