diff options
Diffstat (limited to 'bin/report/print_xml.py')
| -rw-r--r-- | bin/report/print_xml.py | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/bin/report/print_xml.py b/bin/report/print_xml.py new file mode 100644 index 00000000000..671ec9806d1 --- /dev/null +++ b/bin/report/print_xml.py @@ -0,0 +1,358 @@ +############################################################################## +# +# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. +# +# $Id: print_xml.py 1005 2005-07-25 08:41:42Z nicoe $ +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +import os,types +from xml.dom import minidom + +import netsvc +import tools +import print_fnc + +from osv.orm import browse_null, browse_record +import pooler + +class InheritDict(dict): + # Might be usefull when we're doing name lookup for call or eval. + + def __init__(self, parent=None): + self.parent = parent + + def __getitem__(self, name): + if name in self: + return super(InheritDict, self).__getitem__(name) + else: + if not self.parent: + raise KeyError + else: + return self.parent[name] + +def tounicode(val): + if isinstance(val, str): + unicode_val = unicode(val, 'utf-8') + elif isinstance(val, unicode): + unicode_val = val + else: + unicode_val = unicode(val) + return unicode_val + +class document(object): + def __init__(self, cr, uid, datas, func=False): + # create a new document + self.cr = cr + self.pool = pooler.get_pool(cr.dbname) + self.doc = minidom.Document() + self.func = func or {} + self.datas = datas + self.uid = uid + self.bin_datas = {} + + def node_attrs_get(self, node): + attrs = {} + nattr = node.attributes + for i in range(nattr.length): + attr = nattr.item(i) + attrs[attr.localName] = attr.nodeValue +# attrs[attr.name] = attr.nodeValue + return attrs + + def get_value(self, browser, field_path): + fields = field_path.split('.') + + if not len(fields): + print "WARNING: field name is empty!" + return '' + + value = browser + for f in fields: + if isinstance(value, list): + if len(value)==0: + print "WARNING: empty list found!" + return '' +# elif len(value)>1: +# print "WARNING:", len(value), "possibilities for", value[0]._table_name , "picking first..." + value = value[0] + if isinstance(value, browse_null): + return '' + else: + value = value[f] + + if isinstance(value, browse_null) or (type(value)==bool and not value): + return '' + else: + return value + + def get_value2(self, browser, field_path): + value = self.get_value(browser, field_path) + if isinstance(value, browse_record): + return value.id + elif isinstance(value, browse_null): + return False + else: + return value + + def eval(self, record, expr): +#TODO: support remote variables (eg address.title) in expr +# how to do that: parse the string, find dots, replace those dotted variables by temporary +# "simple ones", fetch the value of those variables and add them (temporarily) to the _data +# dictionary passed to eval + +#FIXME: it wont work if the data hasn't been fetched yet... this could +# happen if the eval node is the first one using this browse_record +# the next line is a workaround for the problem: it causes the resource to be loaded +#Pinky: Why not this ? eval(expr, browser) ? +# name = browser.name +# data_dict = browser._data[self.get_value(browser, 'id')] + return eval(expr) + + def parse_node(self, node, parent, browser, datas=None): + # node is the node of the xml template to be parsed + # parent = the parent node in the xml data tree we are creating + + if node.nodeType == node.ELEMENT_NODE: +# print '-'*60 +# print "parse_node", node +# print "parent: ", parent +# print "ids:", ids +# print "model:", model +# print "datas:", datas + + # convert the attributes of the node to a dictionary + + attrs = self.node_attrs_get(node) + if 'type' in attrs: + if attrs['type']=='field': + value = self.get_value(browser, attrs['name']) +#TODO: test this + if value == '' and 'default' in attrs: + value = attrs['default'] + el = self.doc.createElement(node.localName) + parent.appendChild(el) + el_txt = self.doc.createTextNode(tounicode(value)) + el.appendChild(el_txt) + +#TODO: test this + for key, value in attrs.iteritems(): + if key not in ('type', 'name', 'default'): + el.setAttribute(key, value) + + elif attrs['type']=='attachment': + if isinstance(browser, list): + model = browser[0]._table_name + else: + model = browser._table_name + + value = self.get_value(browser, attrs['name']) + + service = netsvc.LocalService("object_proxy") + ids = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'search', [('res_model','=',model),('res_id','=',int(value))]) + datas = service.execute(self.cr.dbname, self.uid, 'ir.attachment', 'read', ids) + + if len(datas): + # if there are several, pick first + datas = datas[0] + fname = str(datas['datas_fname']) + ext = fname.split('.')[-1].lower() + if ext in ('jpg','jpeg', 'png'): + import base64, StringIO + dt = base64.decodestring(datas['datas']) + fp = StringIO.StringIO(dt) + i = str(len(self.bin_datas)) + self.bin_datas[i] = fp + + el = self.doc.createElement(node.localName) + parent.appendChild(el) + # node content is the length of the image + el_txt = self.doc.createTextNode(i) + el.appendChild(el_txt) + + elif attrs['type']=='data': +#TODO: test this + el = self.doc.createElement(node.localName) + parent.appendChild(el) + txt = self.datas.get('form', {}).get(attrs['name'], '') + el_txt = self.doc.createTextNode(tounicode(txt)) + el.appendChild(el_txt) + + elif attrs['type']=='function': + el = self.doc.createElement(node.localName) + parent.appendChild(el) + if attrs['name'] in self.func: + txt = self.func[attrs['name']](node) + else: + txt = print_fnc.print_fnc(attrs['name'], node) + el_txt = self.doc.createTextNode(txt) + el.appendChild(el_txt) + + elif attrs['type']=='eval': +#TODO: faire ca plus proprement + if isinstance(browser, list): + print "ERROR: EVAL!" + el = self.doc.createElement(node.localName) + parent.appendChild(el) + value = self.eval(browser, attrs['expr']) + el_txt = self.doc.createTextNode(str(value)) + el.appendChild(el_txt) + + elif attrs['type']=='fields': + fields = attrs['name'].split(',') + vals = {} + for b in browser: + value = tuple([self.get_value2(b, f) for f in fields]) + if not value in vals: + vals[value]=[] + vals[value].append(b) + keys = vals.keys() + keys.sort() + + if 'order' in attrs and attrs['order']=='desc': + keys.reverse() + + v_list = [vals[k] for k in keys] + for v in v_list: + el = self.doc.createElement(node.localName) + parent.appendChild(el) + el_cld = node.firstChild + while el_cld: + self.parse_node(el_cld, el, v) + el_cld = el_cld.nextSibling + + elif attrs['type']=='call': + if len(attrs['args']): +#TODO: test this + # fetches the values of the variables which names where passed in the args attribute + args = [self.eval(browser, arg) for arg in attrs['args'].split(',')] + else: + args = [] + + # get the object + if attrs.has_key('model'): + obj = self.pool.get(attrs['model']) + else: + if isinstance(browser, list): + obj = browser[0]._table + else: + obj = browser._table + + # get the ids + if attrs.has_key('ids'): + ids = self.eval(browser, attrs['ids']) + else: + if isinstance(browser, list): + ids = [b.id for b in browser] + else: + ids = [browser.id] + + # call the method itself + newdatas = getattr(obj, attrs['name'])(self.cr, self.uid, ids, *args) + + def parse_result_tree(node, parent, datas): + if node.nodeType == node.ELEMENT_NODE: + el = self.doc.createElement(node.localName) + parent.appendChild(el) + atr = self.node_attrs_get(node) + if 'value' in atr: + #print "type=>",type(datas[atr['value']]) + #print "value=>",datas[atr['value']] + if not isinstance(datas[atr['value']], (str, unicode)): + txt = self.doc.createTextNode(str(datas[atr['value']])) + else: + txt = self.doc.createTextNode(datas[atr['value']].decode('utf-8')) + el.appendChild(txt) + else: + el_cld = node.firstChild + while el_cld: + parse_result_tree(el_cld, el, datas) + el_cld = el_cld.nextSibling + elif node.nodeType==node.TEXT_NODE: + el = self.doc.createTextNode(node.nodeValue) + parent.appendChild(el) + else: + pass + + if not isinstance(newdatas, list): + newdatas = [newdatas] + for newdata in newdatas: + parse_result_tree(node, parent, newdata) + + elif attrs['type']=='zoom': + value = self.get_value(browser, attrs['name']) + + if value: + if not isinstance(value, list): + v_list = [value] + else: + v_list = value + for v in v_list: + el = self.doc.createElement(node.localName) + parent.appendChild(el) + el_cld = node.firstChild + while el_cld: + self.parse_node(el_cld, el, v) + el_cld = el_cld.nextSibling + else: + # if there is no "type" attribute in the node, copy it to the xml data and parse its childs + el = self.doc.createElement(node.localName) + parent.appendChild(el) + el_cld = node.firstChild + while el_cld: + self.parse_node(el_cld, el, browser) + el_cld = el_cld.nextSibling + + elif node.nodeType==node.TEXT_NODE: + # if it's a text node, copy it to the xml data + el = self.doc.createTextNode(node.nodeValue) + parent.appendChild(el) + else: + pass + + def xml_get(self): + return self.doc.toxml('utf-8') + + def parse_tree(self, ids, model, context={}): + browser = self.pool.get(model).browse(self.cr, self.uid, ids, context) + self.parse_node(self.dom.documentElement, self.doc, browser) + + def parse_string(self, xml, ids, model, context={}): + # parses the xml template to memory + self.dom = minidom.parseString(xml) + + # create the xml data from the xml template + self.parse_tree(ids, model, context) + + def parse(self, filename, ids, model, context={}): + # parses the xml template to memory + self.dom = minidom.parse(os.path.join(tools.config['root_path'],filename)) + + # create the xml data from the xml template + self.parse_tree(ids, model, context) + + def close(self): + self.doc = None + self.dom = None + |
