1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 from xml.dom import minidom
23 from osv import fields,osv
29 class xElement(minidom.Element):
30 """dom.Element with compact print
31 The Element in minidom has a problem: if printed, adds whitespace
32 around the text nodes. The standard will not ignore that whitespace.
33 This class simply prints the contained nodes in their compact form, w/o
36 def writexml(self, writer, indent="", addindent="", newl=""):
38 minidom.Element.writexml(self, writer, indent='', addindent='', newl='')
41 def doc_createXElement(xdoc, tagName):
43 e.ownerDocument = xdoc
47 from tools import yaml_tag # This import is not unused! Do not remove!
48 # Please do not override yaml_tag here: modify it in server bin/tools/yaml_tag.py
50 class base_module_record(osv.osv):
51 _name = "ir.module.record"
55 def __init__(self, *args, **kwargs):
57 self.recording_data = []
59 super(base_module_record, self).__init__(*args, **kwargs)
62 def _create_id(self, cr, uid, model, data):
66 name = filter(lambda x: x in string.letters, (data.get('name','') or '').lower())
69 # name=data.get('name','') or ''.lower()
70 val = model.replace('.','_')+'_'+ name + str(i)
72 if val not in self.ids.values():
76 def _get_id(self, cr, uid, model, id):
77 if type(id)==type(()):
79 if (model,id) in self.ids:
80 res_id = self.ids[(model,id)]
82 dt = self.pool.get('ir.model.data')
83 dtids = dt.search(cr, uid, [('model','=',model), ('res_id','=',id)])
86 obj = dt.browse(cr, uid, dtids[0])
87 self.depends[obj.module] = True
88 return obj.module+'.'+obj.name, obj.noupdate
90 def _create_record(self, cr, uid, doc, model, data, record_id, noupdate=False):
91 data_pool = self.pool.get('ir.model.data')
92 model_pool = self.pool.get(model)
94 record = doc.createElement('record')
95 record.setAttribute("id", record_id)
96 record.setAttribute("model", model)
97 record_list = [record]
99 lids = data_pool.search(cr, uid, [('model','=',model)])
100 res = data_pool.read(cr, uid, lids[:1], ['module'])
102 self.depends[res[0]['module']]=True
103 fields = model_pool.fields_get(cr, uid)
104 for key,val in data.items():
105 if not (val or (fields[key]['type']=='boolean')):
107 if fields[key]['type'] in ('integer','float'):
108 field = doc.createElement('field')
109 field.setAttribute("name", key)
110 field.setAttribute("eval", val and str(val) or 'False' )
111 record.appendChild(field)
112 elif fields[key]['type'] in ('boolean',):
113 field = doc.createElement('field')
114 field.setAttribute("name", key)
115 field.setAttribute("eval", val and '1' or '0' )
116 record.appendChild(field)
117 elif fields[key]['type'] in ('many2one',):
118 field = doc.createElement('field')
119 field.setAttribute("name", key)
120 if type(val) in (type(''),type(u'')):
123 id,update = self._get_id(cr, uid, fields[key]['relation'], val)
124 noupdate = noupdate or update
126 relation_pool = self.pool.get(fields[key]['relation'])
128 field.setAttribute("model", fields[key]['relation'])
129 fld_nm = relation_pool._rec_name
130 name = relation_pool.read(cr, uid, val,[fld_nm])[fld_nm] or False
131 field.setAttribute("search", str([(str(fld_nm) ,'=', name)]))
133 field.setAttribute("ref", id)
134 record.appendChild(field)
135 elif fields[key]['type'] in ('one2many',):
136 for valitem in (val or []):
137 if valitem[0] in (0,1):
138 if key in model_pool._columns:
139 model_pool._columns[key]._fields_id
141 model_pool._inherit_fields[key][2]._fields_id
143 newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
146 newid,update = self._get_id(cr, uid, fields[key]['relation'], valitem[1])
148 newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
150 self.ids[(fields[key]['relation'], valitem[1])] = newid
152 childrecord, update = self._create_record(cr, uid, doc, fields[key]['relation'],valitem[2], newid)
153 noupdate = noupdate or update
154 record_list += childrecord
157 elif fields[key]['type'] in ('many2many',):
159 for valitem in (val or []):
161 for id2 in valitem[2]:
162 id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
163 self.ids[(fields[key]['relation'],id2)] = id
164 noupdate = noupdate or update
166 field = doc.createElement('field')
167 field.setAttribute("name", key)
168 field.setAttribute("eval", "[(6,0,["+','.join(map(lambda x: "ref('%s')" % (x,), res))+'])]')
169 record.appendChild(field)
171 field = doc_createXElement(doc, 'field')
172 field.setAttribute("name", key)
173 field.appendChild(doc.createTextNode(val))
174 record.appendChild(field)
176 return record_list, noupdate
178 def _create_yaml_record(self, cr, uid, model, data, record_id):
179 record={'model': model, 'id': str(record_id)}
181 model_pool = self.pool.get(model)
182 data_pool = self.pool.get('ir.model.data')
183 lids = data_pool.search(cr, uid, [('model','=',model)])
185 res = data_pool.read(cr, uid, lids[:1], ['module'])
188 self.depends[res[0]['module']]=True
189 fields = model_pool.fields_get(cr, uid)
192 defaults[model] = model_pool.default_get(cr, uid, data)
195 for key,val in data.items():
196 if ((key in defaults[model]) and (val == defaults[model][key])) and not(fields[key].get('required',False)):
198 if fields[key]['type'] in ('integer','float'):
202 elif not (val or (fields[key]['type']=='function')):
204 elif fields[key]['type'] in ('boolean',):
208 elif fields[key]['type'] in ('many2one',):
209 if type(val) in (type(''), type(u'')):
212 id, update = self._get_id(cr, uid, fields[key]['relation'], val)
214 elif fields[key]['type'] in ('one2many',):
216 for valitem in (val or []):
217 if valitem[0] in (0,1):
218 if key in model_pool._columns:
219 fname = model_pool._columns[key]._fields_id
221 fname = model_pool._inherit_fields[key][2]._fields_id
222 del valitem[2][fname] #delete parent_field from child's fields list
224 childrecord = self._create_yaml_record(cr, uid, fields[key]['relation'],valitem[2], None)
225 items[0].append(childrecord['attrs'])
227 elif fields[key]['type'] in ('many2many',):
228 if (key in defaults[model]) and (val[0][2] == defaults[model][key]):
231 for valitem in (val or []):
233 for id2 in valitem[2]:
234 id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
235 self.ids[(fields[key]['relation'],id2)] = id
244 attrs[key]=tools.ustr(val)
245 attrs[key]=attrs[key].replace('"','\'')
246 record['attrs'] = attrs
249 def get_copy_data(self, cr, uid, model, id, result):
251 obj=self.pool.get(model)
252 data=obj.read(cr, uid,[id])
253 if type(data)==type([]):
259 mod_fields = obj.fields_get(cr, uid)
260 for f in filter(lambda a: isinstance(obj._columns[a], fields.function)\
261 and (not obj._columns[a].store),obj._columns):
264 for key,val in data.items():
265 if result.has_key(key):
267 if mod_fields[key]['type'] == 'many2one':
268 if type(data[key])==type(True) or type(data[key])==type(1):
269 result[key]=data[key]
273 result[key]=data[key][0]
275 elif mod_fields[key]['type'] in ('one2many',):
276 # continue # due to this start stop recording will not record one2many field
277 rel = mod_fields[key]['relation']
280 for rel_id in data[key]:
282 res.append(self.get_copy_data(cr, uid,rel,rel_id,{}))
286 result[key]=data[key]
288 elif mod_fields[key]['type'] == 'many2many':
289 result[key]=[(6,0,data[key])]
292 result[key]=data[key]
293 for k,v in obj._inherits.items():
297 def _create_function(self, cr, uid, doc, model, name, record_id):
298 record = doc.createElement('function')
299 record.setAttribute("name", name)
300 record.setAttribute("model", model)
301 record_list = [record]
303 value = doc.createElement('value')
304 value.setAttribute('eval', '[ref(\'%s\')]' % (record_id, ))
305 value.setAttribute('model', model)
307 record.appendChild(value)
308 return record_list, False
310 def _generate_object_xml(self, cr, uid, rec, recv, doc, result=None):
315 id,update = self._get_id(cr, uid, rec[2], id)
316 noupdate = noupdate or update
319 record,update = self._create_record(cr, uid, doc, rec[2], rec[5], id)
320 noupdate = noupdate or update
321 record_list += record
323 elif rec[4] in ('menu_create',):
325 id,update = self._get_id(cr, uid, rec[3], id)
326 noupdate = noupdate or update
329 record,update = self._create_function(cr, uid, doc, rec[3], rec[4], id)
330 noupdate = noupdate or update
331 record_list += record
333 elif rec[3]=='create':
334 id = self._create_id(cr, uid, rec[2],rec[4])
335 record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[4], id)
336 self.ids[(rec[2], result)] = id
337 record_list += record
340 data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
341 copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
343 rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
344 self.recording_data=rec_data
345 id = self._create_id(cr, uid, rec[2],rec[5])
346 record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[5], id)
347 self.ids[(rec[2], result)] = id
348 record_list += record
350 return record_list,noupdate
352 def _generate_object_yaml(self, cr, uid, rec, result=None):
353 if self.mode=="create":
354 yml_id = self._create_id(cr, uid, rec[2],rec[4])
355 self.ids[(rec[2], result)] = yml_id
356 record = self._create_yaml_record(cr, uid, rec[2], rec[4], yml_id)
358 if self.mode=="workflow":
359 id,update = self._get_id(cr, uid, rec[2], rec[4])
361 data['model'] = rec[2]
362 data['action'] = rec[3]
365 if self.mode=="write":
366 id,update = self._get_id(cr, uid, rec[2],rec[4][0])
367 record = self._create_yaml_record(cr, uid, rec[2], rec[5], id)
369 data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
370 copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
372 rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
373 self.recording_data=rec_data
374 id = self._create_id(cr, uid, rec[2],rec[5])
375 record = self._create_yaml_record(cr, uid, str(rec[2]), rec[5], id)
376 self.ids[(rec[2], result)] = id
379 def _generate_function_yaml(self, cr, uid, args):
380 db, uid, model, action, ids, context = args
381 temp_context = context.copy()
382 active_id = temp_context['active_id']
383 active_model = temp_context['active_model']
384 active_id, update = self._get_id(cr, uid, active_model, active_id)
387 rec_id, noupdate = self._get_id(cr, uid, model, ids[0])
388 temp_context['active_id'] = "ref('%s')"%unicode(active_id)
389 temp_context['active_ids'][0] = "ref('%s')"%str(active_id)
391 function['model'] = model
392 function['action'] = action
393 attrs = "self.%s(cr, uid, [ref('%s')], {" %(action, rec_id, )
394 for k, v in temp_context.iteritems():
395 if isinstance(v, str):
396 f= "'"+k+"': "+"'%s'"%v + ", "
398 v=str(v).replace('"', '')
399 f= "'"+k+"': "+"%s"%v + ", "
401 attrs=str(attrs)+'})'
402 function['attrs'] = attrs
405 def _generate_assert_xml(self, rec, doc):
408 def generate_xml(self, cr, uid):
409 # Create the minidom document
410 if len(self.recording_data):
412 doc = minidom.Document()
413 terp = doc.createElement("openerp")
414 doc.appendChild(terp)
415 for rec in self.recording_data:
416 if rec[0]=='workflow':
417 rec_id,noupdate = self._get_id(cr, uid, rec[1][2], rec[1][4])
420 data = doc.createElement("data")
421 terp.appendChild(data)
422 wkf = doc.createElement('workflow')
423 data.appendChild(wkf)
424 wkf.setAttribute("model", rec[1][2])
425 wkf.setAttribute("action", rec[1][3])
427 data.setAttribute("noupdate", "1")
428 wkf.setAttribute("ref", rec_id)
430 res_list,noupdate = self._generate_object_xml(cr, uid, rec[1], rec[2], doc, rec[3])
431 data = doc.createElement("data")
433 data.setAttribute("noupdate", "1")
435 terp.appendChild(data)
437 data.appendChild(res)
438 elif rec[0]=='assert':
440 return doc.toprettyxml(indent="\t").encode('utf-8')
442 def generate_yaml(self, cr, uid):
444 if len(self.recording_data):
447 for rec in self.recording_data:
448 if rec[1][3] == 'create':
450 elif rec[1][3] == 'write':
452 elif rec[1][3] == 'copy':
454 elif rec[0] == 'workflow':
456 elif rec[0] == 'osv_memory_action':
457 self.mode='osv_memory_action'
460 if self.mode == "workflow":
461 record = self._generate_object_yaml(cr, uid, rec[1],rec[0])
462 yaml_file += "!comment Performing a workflow action %s on module %s"%(record['action'], record['model']) + '''\n'''
463 object = yaml.load(unicode('''\n !workflow %s \n'''%record,'iso-8859-1'))
464 yaml_file += str(object) + '''\n\n'''
465 elif self.mode == 'osv_memory_action':
466 osv_action = self._generate_function_yaml(cr, uid, rec[1])
467 yaml_file += "!comment Performing an osv_memory action %s on module %s"%(osv_action['action'], osv_action['model']) + '''\n'''
468 osv_action = yaml.load(unicode('''\n !python %s \n'''%osv_action,'iso-8859-1'))
469 yaml_file += str(osv_action) + '''\n'''
470 attrs = yaml.dump(osv_action.attrs, default_flow_style=False)
471 attrs = attrs.replace("''", '"')
472 attrs = attrs.replace("'", '')
473 yaml_file += attrs + '''\n\n'''
475 record = self._generate_object_yaml(cr, uid, rec[1], rec[3])
476 if self.mode == "create" or self.mode == "copy":
477 yaml_file += "!comment Creating a %s record"%(record['model']) + '''\n'''
479 yaml_file += "!comment Modifying a %s record"%(record['model']) + '''\n'''
480 object = yaml.load(unicode('''\n !record %s \n'''%record,'iso-8859-1'))
481 yaml_file += str(object) + '''\n'''
482 attrs = yaml.dump(object.attrs, default_flow_style=False)
483 yaml_file += attrs + '''\n\n'''
486 for line in yaml_file.split('\n'):
487 line=line.replace("''","'")
488 if (line.find('!record') == 0) or (line.find('!workflow') == 0) or (line.find('!python') == 0):
489 line = "- \n" + " " + line
490 elif line.find('!comment') == 0:
491 line=line.replace('!comment','- \n ')
492 elif line.find('- -') != -1:
493 line=line.replace('- -',' -')
497 yaml_result += line + '''\n'''
502 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: