~openerp-groupes/openobject-server/6.0-fix-setup-windows

« back to all changes in this revision

Viewing changes to bin/report/interface.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
#
 
3
# Copyright (c) 2004-2006 TINY SPRL. (http://tiny.be) All Rights Reserved.
 
4
#
 
5
# $Id: interface.py 1304 2005-09-08 14:35:42Z nicoe $
 
6
#
 
7
# WARNING: This program as such is intended to be used by professional
 
8
# programmers who take the whole responsability of assessing all potential
 
9
# consequences resulting from its eventual inadequacies and bugs
 
10
# End users who are looking for a ready-to-use solution with commercial
 
11
# garantees and support are strongly adviced to contract a Free Software
 
12
# Service Company
 
13
#
 
14
# This program is Free Software; you can redistribute it and/or
 
15
# modify it under the terms of the GNU General Public License
 
16
# as published by the Free Software Foundation; either version 2
 
17
# of the License, or (at your option) any later version.
 
18
#
 
19
# This program is distributed in the hope that it will be useful,
 
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
# GNU General Public License for more details.
 
23
#
 
24
# You should have received a copy of the GNU General Public License
 
25
# along with this program; if not, write to the Free Software
 
26
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
27
#
 
28
##############################################################################
 
29
 
 
30
import os,re
 
31
 
 
32
#Ged> Why do we use libxml2 here instead of xml.dom like in other places of the code?
 
33
import libxml2
 
34
import libxslt
 
35
 
 
36
import netsvc
 
37
import pooler
 
38
 
 
39
import tools
 
40
import print_xml
 
41
import render
 
42
 
 
43
#
 
44
# encode a value to a string in utf8 and converts XML entities
 
45
#
 
46
def toxml(val):
 
47
        if isinstance(val, str):
 
48
                str_utf8 = val
 
49
        elif isinstance(val, unicode):
 
50
                str_utf8 = val.encode('utf-8')
 
51
        else:
 
52
                str_utf8 = str(val)
 
53
        return str_utf8.replace('&', '&amp;').replace('<','&lt;').replace('>','&gt;')
 
54
 
 
55
class report_int(netsvc.Service):
 
56
        def __init__(self, name, audience='*'):
 
57
                super(report_int, self).__init__(name, audience)
 
58
                if name[0:7]<>'report.':
 
59
                        raise 'ConceptionError, bad report name'
 
60
                self.name = name
 
61
                self.id = 0
 
62
                self.name2 = '.'.join(name.split('.')[1:])
 
63
                self.joinGroup('report')
 
64
                self.exportMethod(self.create)
 
65
 
 
66
        def create(self, cr, uid, ids, datas, context={}):
 
67
                return False
 
68
 
 
69
"""
 
70
        Class to automatically build a document using the transformation process:
 
71
                XML -> DATAS -> RML -> PDF
 
72
                                    -> HTML
 
73
        using a XSL:RML transformation
 
74
"""
 
75
class report_rml(report_int):
 
76
        def __init__(self, name, table, tmpl, xsl):
 
77
                super(report_rml, self).__init__(name)
 
78
                self.table = table
 
79
                self.tmpl = tmpl
 
80
                self.xsl = xsl
 
81
                self.bin_datas = {}
 
82
                self.generators = {'pdf': self.create_pdf, 'html': self.create_html, 'raw': self.create_raw}
 
83
 
 
84
        def create(self, cr, uid, ids, datas, context):
 
85
                xml = self.create_xml(cr, uid, ids, datas, context)
 
86
#               file('/tmp/terp.xml','wb+').write(xml)
 
87
                if datas.get('report_type', 'pdf') == 'raw':
 
88
                        return xml
 
89
                rml = self.create_rml(cr, xml, uid, context)
 
90
#               file('/tmp/terp.rml','wb+').write(rml)
 
91
                report_type = datas.get('report_type', 'pdf')
 
92
                create_doc = self.generators[report_type]
 
93
                pdf = create_doc(rml)
 
94
                return (pdf, report_type)
 
95
        
 
96
        def create_xml(self, cr, uid, ids, datas, context={}):
 
97
                doc = print_xml.document(cr, uid, datas, {})
 
98
                self.bin_datas = doc.bin_datas
 
99
                doc.parse(self.tmpl, ids, self.table, context)
 
100
                xml = doc.xml_get()
 
101
                doc.close()
 
102
                return self.post_process_xml_data(cr, uid, xml, context)
 
103
 
 
104
        def post_process_xml_data(self, cr, uid, xml, context={}):
 
105
                # find the position of the 3rd tag 
 
106
                # (skip the <?xml ...?> and the "root" tag)
 
107
                iter = re.finditer('<[^>]*>', xml)
 
108
                i = iter.next()
 
109
                i = iter.next()
 
110
                pos_xml = i.end()
 
111
 
 
112
                doc = print_xml.document(cr, uid, {}, {})
 
113
                tmpl_path = os.path.join(tools.config['root_path'], 'addons/custom/corporate_defaults.xml')
 
114
                doc.parse(tmpl_path, [uid], 'res.users', context)
 
115
                corporate_header = doc.xml_get()
 
116
                doc.close()
 
117
 
 
118
                # find the position of the tag after the <?xml ...?> tag
 
119
                iter = re.finditer('<[^>]*>', corporate_header)
 
120
                i = iter.next()
 
121
                pos_header = i.end()
 
122
 
 
123
                return xml[:pos_xml] + corporate_header[pos_header:] + xml[pos_xml:]
 
124
 
 
125
        #
 
126
        # TODO: The translation doesn't work for "<tag t="1">textext<tag> tex</tag>text</tag>"
 
127
        #
 
128
        def create_rml(self, cr, xml, uid, context={}):
 
129
                service = netsvc.LocalService("object_proxy")
 
130
 
 
131
                # In some case we might not use xsl ...
 
132
                if not self.xsl:
 
133
                        return xml
 
134
 
 
135
                # load XSL (parse it to the XML level)
 
136
                styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],self.xsl))
 
137
                
 
138
                #TODO: get all the translation in one query. That means we have to: 
 
139
                # * build a list of items to translate, 
 
140
                # * issue the query to translate them,
 
141
                # * (re)build/update the stylesheet with the translated items
 
142
 
 
143
                # translate the XSL stylesheet
 
144
                def look_down(child, lang):
 
145
                        while child is not None:
 
146
                                if (child.type == "element") and child.hasProp('t'):
 
147
                                        #FIXME: use cursor
 
148
                                        res = service.execute(cr.dbname, uid, 'ir.translation', '_get_source', self.name2, 'xsl', lang, child.content)
 
149
                                        if res:
 
150
                                                child.setContent(res)
 
151
                                look_down(child.children, lang)
 
152
                                child = child.next
 
153
 
 
154
                if context.get('lang', False):
 
155
                        look_down(styledoc.children, context['lang'])
 
156
 
 
157
                style = libxslt.parseStylesheetDoc(styledoc)                    # parse XSL
 
158
 
 
159
                doc = libxml2.parseMemory(xml,len(xml))                                 # load XML (data)
 
160
                result = style.applyStylesheet(doc, None)                               # create RML (apply XSL to XML data)
 
161
                xml = style.saveResultToString(result)                                  # save result to string
 
162
                
 
163
                style.freeStylesheet()
 
164
                doc.freeDoc()
 
165
                result.freeDoc()
 
166
                return xml
 
167
        
 
168
        def create_pdf(self, xml):
 
169
                obj = render.rml(xml, self.bin_datas, os.path.dirname(self.tmpl))
 
170
                obj.render()
 
171
                return obj.get()
 
172
 
 
173
        def create_html(self, xml):
 
174
                obj = render.rml2html(xml, self.bin_datas)
 
175
                obj.render()
 
176
                return obj.get()
 
177
 
 
178
        def create_raw(self, xml):
 
179
                return xml
 
180
 
 
181
from report_sxw import report_sxw
 
182
 
 
183
def register_all(db):
 
184
        opj = os.path.join
 
185
        #FIXME: multi-db, quoique... ca init le code donc ok. Enfin, du moins si les modules sont les memes.
 
186
        cr = db.cursor()
 
187
        cr.execute("SELECT * FROM ir_act_report_xml WHERE auto ORDER BY id")
 
188
        result = cr.dictfetchall()
 
189
        cr.close()
 
190
        for r in result:
 
191
                if r['report_rml']:
 
192
                        report_sxw('report.'+r['report_name'], r['model'], opj('addons',r['report_rml']))
 
193
                if r['report_xsl']:
 
194
                        report_rml('report.'+r['report_name'], r['model'], opj('addons',r['report_xml']), r['report_xsl'] and opj('addons',r['report_xsl']))
 
195