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') or
108 fields[key]['type'] == 'selection' and isinstance(val, int)):
109 field = doc.createElement('field')
110 field.setAttribute("name", key)
111 field.setAttribute("eval", val and str(val) or 'False' )
112 record.appendChild(field)
113 elif fields[key]['type'] in ('boolean',):
114 field = doc.createElement('field')
115 field.setAttribute("name", key)
116 field.setAttribute("eval", val and '1' or '0' )
117 record.appendChild(field)
118 elif fields[key]['type'] in ('many2one',):
119 field = doc.createElement('field')
120 field.setAttribute("name", key)
121 if type(val) in (type(''),type(u'')):
124 id,update = self._get_id(cr, uid, fields[key]['relation'], val)
125 noupdate = noupdate or update
127 relation_pool = self.pool.get(fields[key]['relation'])
129 field.setAttribute("model", fields[key]['relation'])
130 fld_nm = relation_pool._rec_name
131 name = relation_pool.read(cr, uid, val,[fld_nm])[fld_nm] or False
132 field.setAttribute("search", str([(str(fld_nm) ,'=', name)]))
134 field.setAttribute("ref", id)
135 record.appendChild(field)
136 elif fields[key]['type'] in ('one2many',):
137 for valitem in (val or []):
138 if valitem[0] in (0,1):
139 if key in model_pool._columns:
140 model_pool._columns[key]._fields_id
142 model_pool._inherit_fields[key][2]._fields_id
144 newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
147 newid,update = self._get_id(cr, uid, fields[key]['relation'], valitem[1])
149 newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
151 self.ids[(fields[key]['relation'], valitem[1])] = newid
153 childrecord, update = self._create_record(cr, uid, doc, fields[key]['relation'],valitem[2], newid)
154 noupdate = noupdate or update
155 record_list += childrecord
158 elif fields[key]['type'] in ('many2many',):
160 for valitem in (val or []):
162 for id2 in valitem[2]:
163 id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
164 self.ids[(fields[key]['relation'],id2)] = id
165 noupdate = noupdate or update
167 field = doc.createElement('field')
168 field.setAttribute("name", key)
169 field.setAttribute("eval", "[(6,0,["+','.join(map(lambda x: "ref('%s')" % (x,), res))+'])]')
170 record.appendChild(field)
172 field = doc_createXElement(doc, 'field')
173 field.setAttribute("name", key)
174 field.appendChild(doc.createTextNode(val))
175 record.appendChild(field)
177 return record_list, noupdate
179 def _create_yaml_record(self, cr, uid, model, data, record_id):
180 record={'model': model, 'id': str(record_id)}
182 model_pool = self.pool.get(model)
183 data_pool = self.pool.get('ir.model.data')
184 lids = data_pool.search(cr, uid, [('model','=',model)])
186 res = data_pool.read(cr, uid, lids[:1], ['module'])
189 self.depends[res[0]['module']]=True
190 fields = model_pool.fields_get(cr, uid)
193 defaults[model] = model_pool.default_get(cr, uid, data)
196 for key,val in data.items():
197 if ((key in defaults[model]) and (val == defaults[model][key])) and not(fields[key].get('required',False)):
199 if fields[key]['type'] in ('integer','float'):
203 elif not (val or (fields[key]['type']=='function')):
205 elif fields[key]['type'] in ('boolean',):
209 elif fields[key]['type'] in ('many2one',):
210 if type(val) in (type(''), type(u'')):
213 id, update = self._get_id(cr, uid, fields[key]['relation'], val)
215 elif fields[key]['type'] in ('one2many',):
217 for valitem in (val or []):
218 if valitem[0] in (0,1):
219 if key in model_pool._columns:
220 fname = model_pool._columns[key]._fields_id
222 fname = model_pool._inherit_fields[key][2]._fields_id
223 del valitem[2][fname] #delete parent_field from child's fields list
225 childrecord = self._create_yaml_record(cr, uid, fields[key]['relation'],valitem[2], None)
226 items[0].append(childrecord['attrs'])
228 elif fields[key]['type'] in ('many2many',):
229 if (key in defaults[model]) and (val[0][2] == defaults[model][key]):
232 for valitem in (val or []):
234 for id2 in valitem[2]:
235 id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
236 self.ids[(fields[key]['relation'],id2)] = id
245 attrs[key]=tools.ustr(val)
246 attrs[key]=attrs[key].replace('"','\'')
247 record['attrs'] = attrs
250 def get_copy_data(self, cr, uid, model, id, result):
252 obj=self.pool.get(model)
253 data=obj.read(cr, uid,[id])
254 if type(data)==type([]):
260 mod_fields = obj.fields_get(cr, uid)
261 for f in filter(lambda a: isinstance(obj._columns[a], fields.function)\
262 and (not obj._columns[a].store),obj._columns):
265 for key,val in data.items():
266 if result.has_key(key):
268 if mod_fields[key]['type'] == 'many2one':
269 if type(data[key])==type(True) or type(data[key])==type(1):
270 result[key]=data[key]
274 result[key]=data[key][0]
276 elif mod_fields[key]['type'] in ('one2many',):
277 # continue # due to this start stop recording will not record one2many field
278 rel = mod_fields[key]['relation']
281 for rel_id in data[key]:
283 res.append(self.get_copy_data(cr, uid,rel,rel_id,{}))
287 result[key]=data[key]
289 elif mod_fields[key]['type'] == 'many2many':
290 result[key]=[(6,0,data[key])]
293 result[key]=data[key]
294 for k,v in obj._inherits.items():
298 def _create_function(self, cr, uid, doc, model, name, record_id):
299 record = doc.createElement('function')
300 record.setAttribute("name", name)
301 record.setAttribute("model", model)
302 record_list = [record]
304 value = doc.createElement('value')
305 value.setAttribute('eval', '[ref(\'%s\')]' % (record_id, ))
306 value.setAttribute('model', model)
308 record.appendChild(value)
309 return record_list, False
311 def _generate_object_xml(self, cr, uid, rec, recv, doc, result=None):
316 id,update = self._get_id(cr, uid, rec[2], id)
317 noupdate = noupdate or update
320 record,update = self._create_record(cr, uid, doc, rec[2], rec[5], id)
321 noupdate = noupdate or update
322 record_list += record
324 elif rec[4] in ('menu_create',):
326 id,update = self._get_id(cr, uid, rec[3], id)
327 noupdate = noupdate or update
330 record,update = self._create_function(cr, uid, doc, rec[3], rec[4], id)
331 noupdate = noupdate or update
332 record_list += record
334 elif rec[3]=='create':
335 id = self._create_id(cr, uid, rec[2],rec[4])
336 record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[4], id)
337 self.ids[(rec[2], result)] = id
338 record_list += record
341 data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
342 copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
344 rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
345 self.recording_data=rec_data
346 id = self._create_id(cr, uid, rec[2],rec[5])
347 record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[5], id)
348 self.ids[(rec[2], result)] = id
349 record_list += record
351 return record_list,noupdate
353 def _generate_object_yaml(self, cr, uid, rec, result=None):
354 if self.mode=="create":
355 yml_id = self._create_id(cr, uid, rec[2],rec[4])
356 self.ids[(rec[2], result)] = yml_id
357 record = self._create_yaml_record(cr, uid, rec[2], rec[4], yml_id)
359 if self.mode=="workflow":
360 id,update = self._get_id(cr, uid, rec[2], rec[4])
362 data['model'] = rec[2]
363 data['action'] = rec[3]
366 if self.mode=="write":
367 id,update = self._get_id(cr, uid, rec[2],rec[4][0])
368 record = self._create_yaml_record(cr, uid, rec[2], rec[5], id)
370 data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
371 copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
373 rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
374 self.recording_data=rec_data
375 id = self._create_id(cr, uid, rec[2],rec[5])
376 record = self._create_yaml_record(cr, uid, str(rec[2]), rec[5], id)
377 self.ids[(rec[2], result)] = id
380 def _generate_function_yaml(self, cr, uid, args):
381 db, uid, model, action, ids, context = args
382 temp_context = context.copy()
383 active_id = temp_context['active_id']
384 active_model = temp_context['active_model']
385 active_id, update = self._get_id(cr, uid, active_model, active_id)
388 rec_id, noupdate = self._get_id(cr, uid, model, ids[0])
389 temp_context['active_id'] = "ref('%s')"%unicode(active_id)
390 temp_context['active_ids'][0] = "ref('%s')"%str(active_id)
392 function['model'] = model
393 function['action'] = action
394 attrs = "self.%s(cr, uid, [ref('%s')], {" %(action, rec_id, )
395 for k, v in temp_context.iteritems():
396 if isinstance(v, str):
397 f= "'"+k+"': "+"'%s'"%v + ", "
399 v=str(v).replace('"', '')
400 f= "'"+k+"': "+"%s"%v + ", "
402 attrs=str(attrs)+'})'
403 function['attrs'] = attrs
406 def _generate_assert_xml(self, rec, doc):
409 def generate_xml(self, cr, uid):
410 # Create the minidom document
411 if len(self.recording_data):
413 doc = minidom.Document()
414 terp = doc.createElement("openerp")
415 doc.appendChild(terp)
416 for rec in self.recording_data:
417 if rec[0]=='workflow':
418 rec_id,noupdate = self._get_id(cr, uid, rec[1][2], rec[1][4])
421 data = doc.createElement("data")
422 terp.appendChild(data)
423 wkf = doc.createElement('workflow')
424 data.appendChild(wkf)
425 wkf.setAttribute("model", rec[1][2])
426 wkf.setAttribute("action", rec[1][3])
428 data.setAttribute("noupdate", "1")
429 wkf.setAttribute("ref", rec_id)
431 res_list,noupdate = self._generate_object_xml(cr, uid, rec[1], rec[2], doc, rec[3])
432 data = doc.createElement("data")
434 data.setAttribute("noupdate", "1")
436 terp.appendChild(data)
438 data.appendChild(res)
439 elif rec[0]=='assert':
441 return doc.toprettyxml(indent="\t").encode('utf-8')
443 def generate_yaml(self, cr, uid):
445 if len(self.recording_data):
448 for rec in self.recording_data:
449 if rec[1][3] == 'create':
451 elif rec[1][3] == 'write':
453 elif rec[1][3] == 'copy':
455 elif rec[0] == 'workflow':
457 elif rec[0] == 'osv_memory_action':
458 self.mode='osv_memory_action'
461 if self.mode == "workflow":
462 record = self._generate_object_yaml(cr, uid, rec[1],rec[0])
463 yaml_file += "!comment Performing a workflow action %s on module %s"%(record['action'], record['model']) + '''\n'''
464 object = yaml.load(unicode('''\n !workflow %s \n'''%record,'iso-8859-1'))
465 yaml_file += str(object) + '''\n\n'''
466 elif self.mode == 'osv_memory_action':
467 osv_action = self._generate_function_yaml(cr, uid, rec[1])
468 yaml_file += "!comment Performing an osv_memory action %s on module %s"%(osv_action['action'], osv_action['model']) + '''\n'''
469 osv_action = yaml.load(unicode('''\n !python %s \n'''%osv_action,'iso-8859-1'))
470 yaml_file += str(osv_action) + '''\n'''
471 attrs = yaml.dump(osv_action.attrs, default_flow_style=False)
472 attrs = attrs.replace("''", '"')
473 attrs = attrs.replace("'", '')
474 yaml_file += attrs + '''\n\n'''
476 record = self._generate_object_yaml(cr, uid, rec[1], rec[3])
477 if self.mode == "create" or self.mode == "copy":
478 yaml_file += "!comment Creating a %s record"%(record['model']) + '''\n'''
480 yaml_file += "!comment Modifying a %s record"%(record['model']) + '''\n'''
481 object = yaml.load(unicode('''\n !record %s \n'''%record,'iso-8859-1'))
482 yaml_file += str(object) + '''\n'''
483 attrs = yaml.dump(object.attrs, default_flow_style=False)
484 yaml_file += attrs + '''\n\n'''
487 for line in yaml_file.split('\n'):
488 line=line.replace("''","'")
489 if (line.find('!record') == 0) or (line.find('!workflow') == 0) or (line.find('!python') == 0):
490 line = "- \n" + " " + line
491 elif line.find('!comment') == 0:
492 line=line.replace('!comment','- \n ')
493 elif line.find('- -') != -1:
494 line=line.replace('- -',' -')
498 yaml_result += line + '''\n'''
503 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: