summaryrefslogtreecommitdiff
path: root/bin/report/print_xml.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/report/print_xml.py')
-rw-r--r--bin/report/print_xml.py358
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
+