Status: | Needs review |
---|---|
Proposed branch: | lp:~mechiscogo/aeroo/mx |
Merge into: | lp:aeroo/trunk |
Diff against target: |
3132 lines (+3039/-0) 17 files modified
ExtraFunctions.py (+367/-0) __init__.py (+31/-0) __openerp__.py (+37/-0) barcode/EANBarCode.py (+148/-0) barcode/__init__.py (+30/-0) barcode/barcode.py (+59/-0) barcode/code128.py (+184/-0) barcode/code39.py (+153/-0) currency_to_text.py (+490/-0) data/report_aeroo_data.xml (+25/-0) domain_parser.py (+45/-0) report_aeroo.py (+636/-0) report_view.xml (+224/-0) report_xml.py (+365/-0) wizard/__init__.py (+30/-0) wizard/report_actions.py (+118/-0) wizard/report_actions_remove.py (+97/-0) |
To merge this branch: | bzr merge lp:~mechiscogo/aeroo/mx |
Related bugs: | |
Related blueprints: |
Mexican currency in currency_to_text
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alistek developers - http://www.alistek.com | Pending | ||
Review via email: mp+113566@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 2. By mechiscogo <mechiscogo@openerp>
-
Adds MXN (Mexican peso) and Spanish translations to currency_to_text. All the translations for Spanish have the Mexican format: <amount in words> <cents>/100 <currency>
- 1. By mechiscogo <mechiscogo@openerp>
-
Agrega moneda MXN y traducciones al español en currency_to_text. Todas las traducciones llevan formato para México <importe con letra> <centavos>/100 <moneda>
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'ExtraFunctions.py' | |||
2 | --- ExtraFunctions.py 1970-01-01 00:00:00 +0000 | |||
3 | +++ ExtraFunctions.py 2012-07-05 12:25:24 +0000 | |||
4 | @@ -0,0 +1,367 @@ | |||
5 | 1 | ############################################################################## | ||
6 | 2 | # | ||
7 | 3 | # Copyright (c) 2008-2009 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
8 | 4 | # General contacts <info@kndati.lv> | ||
9 | 5 | # | ||
10 | 6 | # WARNING: This program as such is intended to be used by professional | ||
11 | 7 | # programmers who take the whole responsability of assessing all potential | ||
12 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
13 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
14 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
15 | 11 | # Service Company | ||
16 | 12 | # | ||
17 | 13 | # This program is Free Software; you can redistribute it and/or | ||
18 | 14 | # modify it under the terms of the GNU General Public License | ||
19 | 15 | # as published by the Free Software Foundation; either version 2 | ||
20 | 16 | # of the License, or (at your option) any later version. | ||
21 | 17 | # | ||
22 | 18 | # This program is distributed in the hope that it will be useful, | ||
23 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | 21 | # GNU General Public License for more details. | ||
26 | 22 | # | ||
27 | 23 | # You should have received a copy of the GNU General Public License | ||
28 | 24 | # along with this program; if not, write to the Free Software | ||
29 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
30 | 26 | # | ||
31 | 27 | ############################################################################## | ||
32 | 28 | |||
33 | 29 | from barcode import barcode | ||
34 | 30 | from tools import translate | ||
35 | 31 | from domain_parser import domain2statement | ||
36 | 32 | from currency_to_text import currency_to_text | ||
37 | 33 | import base64 | ||
38 | 34 | import StringIO | ||
39 | 35 | from PIL import Image | ||
40 | 36 | import pooler | ||
41 | 37 | import time | ||
42 | 38 | import osv | ||
43 | 39 | from report import report_sxw | ||
44 | 40 | from tools.translate import _ | ||
45 | 41 | import netsvc | ||
46 | 42 | |||
47 | 43 | class ExtraFunctions(object): | ||
48 | 44 | """ This class contains some extra functions which | ||
49 | 45 | can be called from the report's template. | ||
50 | 46 | """ | ||
51 | 47 | def __init__(self, cr, uid, report_id, context): | ||
52 | 48 | self.cr = cr | ||
53 | 49 | self.uid = uid | ||
54 | 50 | self.pool = pooler.get_pool(self.cr.dbname) | ||
55 | 51 | self.report_id = report_id | ||
56 | 52 | self.context = context | ||
57 | 53 | self.functions = { | ||
58 | 54 | 'asarray':self._asarray, | ||
59 | 55 | 'asimage':self._asimage, | ||
60 | 56 | 'html_embed_image':self._embed_image, | ||
61 | 57 | 'get_attachments':self._get_attachments, | ||
62 | 58 | 'get_name':self._get_name, | ||
63 | 59 | 'get_label':self._get_label, | ||
64 | 60 | 'getLang':self._get_lang, | ||
65 | 61 | 'get_selection_item':self._get_selection_items('item'), | ||
66 | 62 | 'safe':self._get_safe, | ||
67 | 63 | 'countif':self._countif, | ||
68 | 64 | 'count':self._count, | ||
69 | 65 | 'sumif':self._sumif, | ||
70 | 66 | 'sum':self._sum, | ||
71 | 67 | 'max':self._max, | ||
72 | 68 | 'min':self._min, | ||
73 | 69 | 'average':self._average, | ||
74 | 70 | 'large':self._large, | ||
75 | 71 | 'small':self._small, | ||
76 | 72 | 'count_blank':self._count_blank, | ||
77 | 73 | '_':self._translate_text, | ||
78 | 74 | 'gettext':self._translate_text, | ||
79 | 75 | 'currency_to_text':self._currency2text(context['company'].currency_id.name), #self._currency2text(context['company'].currency_id.code), | ||
80 | 76 | 'barcode':barcode.make_barcode, | ||
81 | 77 | 'debugit':self.debugit, | ||
82 | 78 | 'dec_to_time':self._dec2time, | ||
83 | 79 | 'chunks':self._chunks, | ||
84 | 80 | 'browse':self._browse, | ||
85 | 81 | 'field_size':self._field_size, | ||
86 | 82 | 'bool_as_icon':self._bool_as_icon, | ||
87 | 83 | 'time':time, | ||
88 | 84 | 'report_xml': self._get_report_xml(), | ||
89 | 85 | 'get_log': self._perm_read(self.cr, self.uid), | ||
90 | 86 | 'get_selection_items': self._get_selection_items(), | ||
91 | 87 | } | ||
92 | 88 | |||
93 | 89 | def _perm_read(self, cr, uid): | ||
94 | 90 | def get_log(obj, field=None): | ||
95 | 91 | if field: | ||
96 | 92 | return obj.perm_read(self.uid, [obj.id])[0][field] | ||
97 | 93 | else: | ||
98 | 94 | return obj.perm_read(self.uid, [obj.id])[0] | ||
99 | 95 | return get_log | ||
100 | 96 | |||
101 | 97 | def _get_report_xml(self): | ||
102 | 98 | return self.pool.get('ir.actions.report.xml').browse(self.cr, self.uid, self.report_id) | ||
103 | 99 | |||
104 | 100 | def _get_lang(self, source='current'): | ||
105 | 101 | if source=='current': | ||
106 | 102 | return self.context['lang'] or self.context['user_lang'] | ||
107 | 103 | elif source=='company': | ||
108 | 104 | return self.context['user'].company_id.partner_id.lang | ||
109 | 105 | elif source=='user': | ||
110 | 106 | return self.context['user_lang'] | ||
111 | 107 | |||
112 | 108 | def _bool_as_icon(self, val, kind=0): | ||
113 | 109 | if isinstance(kind, (list, tuple)): | ||
114 | 110 | if val==True: | ||
115 | 111 | return kind [0] | ||
116 | 112 | elif val==False: | ||
117 | 113 | return kind[1] | ||
118 | 114 | else: | ||
119 | 115 | return kind[2] | ||
120 | 116 | bool_kind = {0:{True:self._translate_text('True'), False:self._translate_text('False'), None:""}, | ||
121 | 117 | 1:{True:self._translate_text('T'), False:self._translate_text('F'), None:""}, | ||
122 | 118 | 2:{True:self._translate_text('Yes'), False:self._translate_text('No'), None:""}, | ||
123 | 119 | 3:{True:self._translate_text('Y'), False:self._translate_text('N'), None:""}, | ||
124 | 120 | 4:{True:'+', False:'-', None:""}, | ||
125 | 121 | 5:{True:'[ + ]', False:'[ - ]', None:"[ ]"}, | ||
126 | 122 | 6:{True:'[ x ]', False:'[ ]', None:"[ ]"}, | ||
127 | 123 | } | ||
128 | 124 | return bool_kind.get(kind, {}).get(val, val) | ||
129 | 125 | |||
130 | 126 | def _dec2time(self, dec, h_format, min_format): | ||
131 | 127 | if dec==0.0: | ||
132 | 128 | return None | ||
133 | 129 | elif int(dec)==0: | ||
134 | 130 | return min_format.replace('%M', str(int(round((dec-int(dec))*60)))) | ||
135 | 131 | elif dec-int(dec)==0.0: | ||
136 | 132 | return h_format.replace('%H', str(int(dec))) | ||
137 | 133 | else: | ||
138 | 134 | return h_format.replace('%H', str(int(dec)))+min_format.replace('%M', str(int(round((dec-int(dec))*60)))) | ||
139 | 135 | |||
140 | 136 | def _currency2text(self, currency): | ||
141 | 137 | def c_to_text(sum, currency=currency, language=None): | ||
142 | 138 | return unicode(currency_to_text(sum, currency, language or self._get_lang()), "UTF-8") | ||
143 | 139 | return c_to_text | ||
144 | 140 | |||
145 | 141 | def _translate_text(self, source): | ||
146 | 142 | trans_obj = self.pool.get('ir.translation') | ||
147 | 143 | trans = trans_obj.search(self.cr,self.uid,[('res_id','=',self.report_id),('type','=','report'),('src','=',source),('lang','=',self.context['lang'] or self.context['user_lang'])]) | ||
148 | 144 | if not trans: | ||
149 | 145 | trans_obj.create(self.cr, self.uid, {'src':source,'type':'report','lang':self._get_lang(),'res_id':self.report_id,'name':('ir.actions.report.xml,%s' % source)[:128]}) | ||
150 | 146 | return translate(self.cr, False, 'report', self._get_lang(), source) or source | ||
151 | 147 | |||
152 | 148 | def _countif(self, attr, domain): | ||
153 | 149 | statement = domain2statement(domain) | ||
154 | 150 | expr = "for o in objects:\n\tif%s:\n\t\tcount+=1" % statement | ||
155 | 151 | localspace = {'objects':attr, 'count':0} | ||
156 | 152 | exec expr in localspace | ||
157 | 153 | return localspace['count'] | ||
158 | 154 | |||
159 | 155 | def _count_blank(self, attr, field): | ||
160 | 156 | expr = "for o in objects:\n\tif not o.%s:\n\t\tcount+=1" % field | ||
161 | 157 | localspace = {'objects':attr, 'count':0} | ||
162 | 158 | exec expr in localspace | ||
163 | 159 | return localspace['count'] | ||
164 | 160 | |||
165 | 161 | def _count(self, attr): | ||
166 | 162 | return len(attr) | ||
167 | 163 | |||
168 | 164 | def _sumif(self, attr, sum_field, domain): | ||
169 | 165 | statement = domain2statement(domain) | ||
170 | 166 | expr = "for o in objects:\n\tif%s:\n\t\tsumm+=float(o.%s)" % (statement, sum_field) | ||
171 | 167 | localspace = {'objects':attr, 'summ':0} | ||
172 | 168 | exec expr in localspace | ||
173 | 169 | return localspace['summ'] | ||
174 | 170 | |||
175 | 171 | def _sum(self, attr, sum_field): | ||
176 | 172 | expr = "for o in objects:\n\tsumm+=float(o.%s)" % sum_field | ||
177 | 173 | localspace = {'objects':attr, 'summ':0} | ||
178 | 174 | exec expr in localspace | ||
179 | 175 | return localspace['summ'] | ||
180 | 176 | |||
181 | 177 | def _max(self, attr, field): | ||
182 | 178 | expr = "for o in objects:\n\tvalue_list.append(o.%s)" % field | ||
183 | 179 | localspace = {'objects':attr, 'value_list':[]} | ||
184 | 180 | exec expr in localspace | ||
185 | 181 | return max(localspace['value_list']) | ||
186 | 182 | |||
187 | 183 | def _min(self, attr, field): | ||
188 | 184 | expr = "for o in objects:\n\tvalue_list.append(o.%s)" % field | ||
189 | 185 | localspace = {'objects':attr, 'value_list':[]} | ||
190 | 186 | exec expr in localspace | ||
191 | 187 | return min(localspace['value_list']) | ||
192 | 188 | |||
193 | 189 | def _average(self, attr, field): | ||
194 | 190 | expr = "for o in objects:\n\tvalue_list.append(o.%s)" % field | ||
195 | 191 | localspace = {'objects':attr, 'value_list':[]} | ||
196 | 192 | exec expr in localspace | ||
197 | 193 | return float(sum(localspace['value_list']))/float(len(localspace['value_list'])) | ||
198 | 194 | |||
199 | 195 | def _asarray(self, attr, field): | ||
200 | 196 | expr = "for o in objects:\n\tvalue_list.append(o.%s)" % field | ||
201 | 197 | localspace = {'objects':attr, 'value_list':[]} | ||
202 | 198 | exec expr in localspace | ||
203 | 199 | return localspace['value_list'] | ||
204 | 200 | |||
205 | 201 | def _get_name(self, obj): | ||
206 | 202 | if obj.__class__==osv.orm.browse_record: | ||
207 | 203 | return self.pool.get(obj._table_name).name_get(self.cr, self.uid, [obj.id], {'lang':self._get_lang()})[0][1] | ||
208 | 204 | return '' | ||
209 | 205 | |||
210 | 206 | #def _get_label(self, obj, field): | ||
211 | 207 | # try: | ||
212 | 208 | # if isinstance(obj, report_sxw.browse_record_list): | ||
213 | 209 | # obj = obj[0] | ||
214 | 210 | # if isinstance(obj, (str,unicode)): | ||
215 | 211 | # model = obj | ||
216 | 212 | # else: | ||
217 | 213 | # model = obj._table_name | ||
218 | 214 | # if isinstance(obj, (str,unicode)) or hasattr(obj, field): | ||
219 | 215 | # label = self.pool.get(model)._columns[field].string | ||
220 | 216 | # return translate(self.cr, False, 'field', self._get_lang(), label) or label | ||
221 | 217 | # except Exception, e: | ||
222 | 218 | # return '' | ||
223 | 219 | |||
224 | 220 | def _get_label(self, obj, field): | ||
225 | 221 | try: | ||
226 | 222 | if isinstance(obj, report_sxw.browse_record_list): | ||
227 | 223 | obj = obj[0] | ||
228 | 224 | if isinstance(obj, (str,unicode)): | ||
229 | 225 | model = obj | ||
230 | 226 | else: | ||
231 | 227 | model = obj._table_name | ||
232 | 228 | if isinstance(obj, (str,unicode)) or hasattr(obj, field): | ||
233 | 229 | labels = self.pool.get(model).fields_get(self.cr, self.uid, fields=[field], context=self.context) | ||
234 | 230 | return labels[field]['string'] | ||
235 | 231 | except Exception, e: | ||
236 | 232 | return '' | ||
237 | 233 | |||
238 | 234 | def _field_size(self, obj, field): | ||
239 | 235 | try: | ||
240 | 236 | if getattr(obj, field): | ||
241 | 237 | size = self.pool.get(obj._table_name)._columns[field].size | ||
242 | 238 | return size | ||
243 | 239 | except Exception: | ||
244 | 240 | return '' | ||
245 | 241 | |||
246 | 242 | def _get_selection_items(self, kind='items'): | ||
247 | 243 | def get_selection_item(obj, field, value=None): | ||
248 | 244 | try: | ||
249 | 245 | if isinstance(obj, report_sxw.browse_record_list): | ||
250 | 246 | obj = obj[0] | ||
251 | 247 | if isinstance(obj, (str,unicode)): | ||
252 | 248 | model = obj | ||
253 | 249 | field_val = value | ||
254 | 250 | else: | ||
255 | 251 | model = obj._table_name | ||
256 | 252 | field_val = getattr(obj, field) | ||
257 | 253 | if kind=='item': | ||
258 | 254 | if field_val: | ||
259 | 255 | return dict(self.pool.get(model).fields_get(self.cr, self.uid, fields=[field], context=self.context)[field]['selection'])[field_val] | ||
260 | 256 | elif kind=='items': | ||
261 | 257 | return self.pool.get(model).fields_get(self.cr, self.uid, fields=[field], context=self.context)[field]['selection'] | ||
262 | 258 | #selection = self.pool.get(model)._columns[field].selection | ||
263 | 259 | #if selection.__class__==list: | ||
264 | 260 | # val_dict = dict(selection) | ||
265 | 261 | #else: | ||
266 | 262 | # val_dict = dict(selection(self.pool.get(model), self.cr, self.uid, {'lang':self._get_lang()})) | ||
267 | 263 | #return val_dict[field_val] | ||
268 | 264 | return '' | ||
269 | 265 | except Exception: | ||
270 | 266 | return '' | ||
271 | 267 | return get_selection_item | ||
272 | 268 | |||
273 | 269 | def _get_attachments(self, o, index=None): | ||
274 | 270 | attach_obj = self.pool.get('ir.attachment') | ||
275 | 271 | srch_param = [('res_model','=',o._name),('res_id','=',o.id)] | ||
276 | 272 | if type(index)==str: | ||
277 | 273 | srch_param.append(('name','=',index)) | ||
278 | 274 | attachments = attach_obj.search(self.cr,self.uid,srch_param) | ||
279 | 275 | res = [x['datas'] for x in attach_obj.read(self.cr,self.uid,attachments,['datas']) if x['datas']] | ||
280 | 276 | if type(index)==int: | ||
281 | 277 | return res[index] | ||
282 | 278 | return len(res)==1 and res[0] or res | ||
283 | 279 | |||
284 | 280 | def _asimage(self, field_value, rotate=None): | ||
285 | 281 | if not field_value: | ||
286 | 282 | return StringIO.StringIO(), 'image/png' | ||
287 | 283 | field_value = base64.decodestring(field_value) | ||
288 | 284 | tf = StringIO.StringIO(field_value) | ||
289 | 285 | tf.seek(0) | ||
290 | 286 | im=Image.open(tf) | ||
291 | 287 | try: | ||
292 | 288 | if rotate!=None: | ||
293 | 289 | im=im.rotate(int(rotate)) | ||
294 | 290 | tf.seek(0) | ||
295 | 291 | im.save(tf, im.format.lower()) | ||
296 | 292 | except Exception, e: | ||
297 | 293 | pass | ||
298 | 294 | size_x = str(im.size[0]/96.0)+'in' | ||
299 | 295 | size_y = str(im.size[1]/96.0)+'in' | ||
300 | 296 | return tf, 'image/%s' % im.format.lower(), size_x, size_y | ||
301 | 297 | |||
302 | 298 | def _embed_image(self, extention, img, width=0, height=0) : | ||
303 | 299 | "Transform a DB image into an embeded HTML image" | ||
304 | 300 | try: | ||
305 | 301 | if width : | ||
306 | 302 | width = 'width="%spx"'%(width) | ||
307 | 303 | else : | ||
308 | 304 | width = ' ' | ||
309 | 305 | if height : | ||
310 | 306 | height = 'width="%spx"'%(height) | ||
311 | 307 | else : | ||
312 | 308 | height = ' ' | ||
313 | 309 | toreturn = '<img %s %s src="data:image/%s;base64,%s">' % (width, height, extention, str(img)) | ||
314 | 310 | return toreturn | ||
315 | 311 | except Exception, exp: | ||
316 | 312 | print exp | ||
317 | 313 | return 'No image' | ||
318 | 314 | |||
319 | 315 | def _large(self, attr, field, n): | ||
320 | 316 | array=self._asarray(attr, field) | ||
321 | 317 | try: | ||
322 | 318 | n-=1 | ||
323 | 319 | while(n): | ||
324 | 320 | array.remove(max(array)) | ||
325 | 321 | n-=1 | ||
326 | 322 | return max(array) | ||
327 | 323 | except ValueError, e: | ||
328 | 324 | return None | ||
329 | 325 | |||
330 | 326 | def _small(self, attr, field, n): | ||
331 | 327 | array=self._asarray(attr, field) | ||
332 | 328 | try: | ||
333 | 329 | n-=1 | ||
334 | 330 | while(n): | ||
335 | 331 | array.remove(min(array)) | ||
336 | 332 | n-=1 | ||
337 | 333 | return min(array) | ||
338 | 334 | except ValueError, e: | ||
339 | 335 | return None | ||
340 | 336 | |||
341 | 337 | def _chunks(self, l, n): | ||
342 | 338 | """ Yield successive n-sized chunks from l. | ||
343 | 339 | """ | ||
344 | 340 | for i in xrange(0, len(l), n): | ||
345 | 341 | yield l[i:i+n] | ||
346 | 342 | |||
347 | 343 | def _browse(self, *args): | ||
348 | 344 | if not args or (args and not args[0]): | ||
349 | 345 | return None | ||
350 | 346 | if len(args)==1: | ||
351 | 347 | model, id = args[0].split(',') | ||
352 | 348 | id = int(id) | ||
353 | 349 | elif len(args)==2: | ||
354 | 350 | model, id = args | ||
355 | 351 | else: | ||
356 | 352 | raise None | ||
357 | 353 | return self.pool.get(model).browse(self.cr, self.uid, id) | ||
358 | 354 | |||
359 | 355 | def _get_safe(self, expression, obj): | ||
360 | 356 | try: | ||
361 | 357 | return eval(expression, {'o':obj}) | ||
362 | 358 | except Exception, e: | ||
363 | 359 | return None | ||
364 | 360 | |||
365 | 361 | def debugit(self, object): | ||
366 | 362 | """ Run the server from command line and | ||
367 | 363 | call 'debugit' from the template to inspect variables. | ||
368 | 364 | """ | ||
369 | 365 | import pdb;pdb.set_trace() | ||
370 | 366 | return | ||
371 | 367 | |||
372 | 0 | 368 | ||
373 | === added file '__init__.py' | |||
374 | --- __init__.py 1970-01-01 00:00:00 +0000 | |||
375 | +++ __init__.py 2012-07-05 12:25:24 +0000 | |||
376 | @@ -0,0 +1,31 @@ | |||
377 | 1 | ############################################################################## | ||
378 | 2 | # | ||
379 | 3 | # Copyright (c) 2008-2009 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
380 | 4 | # General contacts <info@kndati.lv> | ||
381 | 5 | # | ||
382 | 6 | # WARNING: This program as such is intended to be used by professional | ||
383 | 7 | # programmers who take the whole responsability of assessing all potential | ||
384 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
385 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
386 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
387 | 11 | # Service Company | ||
388 | 12 | # | ||
389 | 13 | # This program is Free Software; you can redistribute it and/or | ||
390 | 14 | # modify it under the terms of the GNU General Public License | ||
391 | 15 | # as published by the Free Software Foundation; either version 2 | ||
392 | 16 | # of the License, or (at your option) any later version. | ||
393 | 17 | # | ||
394 | 18 | # This program is distributed in the hope that it will be useful, | ||
395 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
396 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
397 | 21 | # GNU General Public License for more details. | ||
398 | 22 | # | ||
399 | 23 | # You should have received a copy of the GNU General Public License | ||
400 | 24 | # along with this program; if not, write to the Free Software | ||
401 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
402 | 26 | # | ||
403 | 27 | ############################################################################## | ||
404 | 28 | |||
405 | 29 | import report_xml | ||
406 | 30 | import report_aeroo | ||
407 | 31 | import wizard | ||
408 | 0 | 32 | ||
409 | === added file '__openerp__.py' | |||
410 | --- __openerp__.py 1970-01-01 00:00:00 +0000 | |||
411 | +++ __openerp__.py 2012-07-05 12:25:24 +0000 | |||
412 | @@ -0,0 +1,37 @@ | |||
413 | 1 | # -*- encoding: utf-8 -*- | ||
414 | 2 | |||
415 | 3 | ######################################################################### | ||
416 | 4 | # # | ||
417 | 5 | # Copyright (C) 2009 Domsense s.r.l. # | ||
418 | 6 | # @authors: Simone Orsi # | ||
419 | 7 | # Copyright (C) 2009-2010 KN dati, Ltd # | ||
420 | 8 | # # | ||
421 | 9 | #This program is free software: you can redistribute it and/or modify # | ||
422 | 10 | #it under the terms of the GNU General Public License as published by # | ||
423 | 11 | #the Free Software Foundation, either version 3 of the License, or # | ||
424 | 12 | #(at your option) any later version. # | ||
425 | 13 | # # | ||
426 | 14 | #This program is distributed in the hope that it will be useful, # | ||
427 | 15 | #but WITHOUT ANY WARRANTY; without even the implied warranty of # | ||
428 | 16 | #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | ||
429 | 17 | #GNU General Public License for more details. # | ||
430 | 18 | # # | ||
431 | 19 | #You should have received a copy of the GNU General Public License # | ||
432 | 20 | #along with this program. If not, see <http://www.gnu.org/licenses/>. # | ||
433 | 21 | ######################################################################### | ||
434 | 22 | |||
435 | 23 | { | ||
436 | 24 | 'name': 'Aeroo Reports', | ||
437 | 25 | 'version': '1.0', | ||
438 | 26 | 'category': 'Generic Modules/Aeroo Reporting', | ||
439 | 27 | 'description': """ Make possible to easily create complicated reports with OOo. | ||
440 | 28 | Requires "relatorio", "openoffice.org", "openoffice-python" to be installed. | ||
441 | 29 | """, | ||
442 | 30 | 'author': 'KN dati Ltd, Simone Orsi - Domsense', | ||
443 | 31 | 'website': 'http://www.alistek.com', | ||
444 | 32 | 'depends': ['base'], | ||
445 | 33 | "init_xml" : [], | ||
446 | 34 | 'update_xml': ["report_view.xml", "data/report_aeroo_data.xml", "security/ir.model.access.csv"], | ||
447 | 35 | 'installable': True, | ||
448 | 36 | 'active': False, | ||
449 | 37 | } | ||
450 | 0 | 38 | ||
451 | === added directory 'barcode' | |||
452 | === added file 'barcode/EANBarCode.py' | |||
453 | --- barcode/EANBarCode.py 1970-01-01 00:00:00 +0000 | |||
454 | +++ barcode/EANBarCode.py 2012-07-05 12:25:24 +0000 | |||
455 | @@ -0,0 +1,148 @@ | |||
456 | 1 | # Copyright (c) 2009-2010 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
457 | 2 | # General contacts <info@kndati.lv> | ||
458 | 3 | |||
459 | 4 | from tools import config | ||
460 | 5 | |||
461 | 6 | """ | ||
462 | 7 | This class generate EAN bar code, it required PIL (python imaging library) | ||
463 | 8 | installed. | ||
464 | 9 | |||
465 | 10 | If the code has not checksum (12 digits), it added automatically. | ||
466 | 11 | |||
467 | 12 | Create bar code sample : | ||
468 | 13 | from EANBarCode import EanBarCode | ||
469 | 14 | bar = EanBarCode() | ||
470 | 15 | bar.getImage("9782212110708",50,"gif") | ||
471 | 16 | |||
472 | 17 | """ | ||
473 | 18 | |||
474 | 19 | class EanBarCode: | ||
475 | 20 | """ Compute the EAN bar code """ | ||
476 | 21 | def __init__(self): | ||
477 | 22 | A = {0 : "0001101", 1 : "0011001", 2 : "0010011", 3 : "0111101", 4 : "0100011", | ||
478 | 23 | 5 : "0110001", 6 : "0101111", 7 : "0111011", 8 : "0110111", 9 : "0001011"} | ||
479 | 24 | B = {0 : "0100111", 1 : "0110011", 2 : "0011011", 3 : "0100001", 4 : "0011101", | ||
480 | 25 | 5 : "0111001", 6 : "0000101", 7 : "0010001", 8 : "0001001", 9 : "0010111"} | ||
481 | 26 | C = {0 : "1110010", 1 : "1100110", 2 : "1101100", 3 : "1000010", 4 : "1011100", | ||
482 | 27 | 5 : "1001110", 6 : "1010000", 7 : "1000100", 8 : "1001000", 9 : "1110100"} | ||
483 | 28 | self.groupC = C | ||
484 | 29 | |||
485 | 30 | self.family = {0 : (A,A,A,A,A,A), 1 : (A,A,B,A,B,B), 2 : (A,A,B,B,A,B), 3 : (A,A,B,B,B,A), 4 : (A,B,A,A,B,B), | ||
486 | 31 | 5 : (A,B,B,A,A,B), 6 : (A,B,B,B,A,A), 7 : (A,B,A,B,A,B), 8 : (A,B,A,B,B,A), 9 : (A,B,B,A,B,A)} | ||
487 | 32 | |||
488 | 33 | |||
489 | 34 | def makeCode(self, code): | ||
490 | 35 | """ Create the binary code | ||
491 | 36 | return a string which contains "0" for white bar, "1" for black bar, "L" for long bar """ | ||
492 | 37 | |||
493 | 38 | # Convert code string in integer list | ||
494 | 39 | self.EAN13 = [] | ||
495 | 40 | for digit in code: | ||
496 | 41 | self.EAN13.append(int(digit)) | ||
497 | 42 | |||
498 | 43 | # If the code has already a checksum | ||
499 | 44 | if len(self.EAN13) == 13: | ||
500 | 45 | # Verify checksum | ||
501 | 46 | self.verifyChecksum(self.EAN13) | ||
502 | 47 | # If the code has not yet checksum | ||
503 | 48 | elif len(self.EAN13) == 12: | ||
504 | 49 | # Add checksum value | ||
505 | 50 | self.EAN13.append(self.computeChecksum(self.EAN13)) | ||
506 | 51 | |||
507 | 52 | # Get the left codage class | ||
508 | 53 | left = self.family[self.EAN13[0]] | ||
509 | 54 | |||
510 | 55 | # Add start separator | ||
511 | 56 | strCode = 'L0L' | ||
512 | 57 | |||
513 | 58 | # Compute the left part of bar code | ||
514 | 59 | for i in range(0,6): | ||
515 | 60 | strCode += left[i][self.EAN13[i+1]] | ||
516 | 61 | |||
517 | 62 | # Add middle separator | ||
518 | 63 | strCode += '0L0L0' | ||
519 | 64 | |||
520 | 65 | # Compute the right codage class | ||
521 | 66 | for i in range (7,13): | ||
522 | 67 | strCode += self.groupC[self.EAN13[i]] | ||
523 | 68 | |||
524 | 69 | # Add stop separator | ||
525 | 70 | strCode += 'L0L' | ||
526 | 71 | |||
527 | 72 | return strCode | ||
528 | 73 | |||
529 | 74 | |||
530 | 75 | def computeChecksum(self, arg): | ||
531 | 76 | """ Compute the checksum of bar code """ | ||
532 | 77 | # UPCA/EAN13 | ||
533 | 78 | weight=[1,3]*6 | ||
534 | 79 | magic=10 | ||
535 | 80 | sum = 0 | ||
536 | 81 | |||
537 | 82 | for i in range(12): # checksum based on first 12 digits. | ||
538 | 83 | sum = sum + int(arg[i]) * weight[i] | ||
539 | 84 | z = ( magic - (sum % magic) ) % magic | ||
540 | 85 | if z < 0 or z >= magic: | ||
541 | 86 | return None | ||
542 | 87 | return z | ||
543 | 88 | |||
544 | 89 | |||
545 | 90 | def verifyChecksum(self, bits): | ||
546 | 91 | """ Verify the checksum """ | ||
547 | 92 | computedChecksum = self.computeChecksum(bits[:12]) | ||
548 | 93 | codeBarChecksum = bits[12] | ||
549 | 94 | |||
550 | 95 | if codeBarChecksum != computedChecksum: | ||
551 | 96 | raise Exception ("Bad checksum is %s and should be %s"%(codeBarChecksum, computedChecksum)) | ||
552 | 97 | |||
553 | 98 | |||
554 | 99 | def getImage(self, value, height = 50, xw=1, rotate=None, extension = "PNG"): | ||
555 | 100 | """ Get an image with PIL library | ||
556 | 101 | value code barre value | ||
557 | 102 | height height in pixel of the bar code | ||
558 | 103 | extension image file extension""" | ||
559 | 104 | import Image, ImageFont, ImageDraw, os | ||
560 | 105 | from string import lower, upper | ||
561 | 106 | |||
562 | 107 | # Get the bar code list | ||
563 | 108 | bits = self.makeCode(value) | ||
564 | 109 | |||
565 | 110 | # Get thee bar code with the checksum added | ||
566 | 111 | code = "" | ||
567 | 112 | for digit in self.EAN13: | ||
568 | 113 | code += "%d"%digit | ||
569 | 114 | |||
570 | 115 | # Create a new image | ||
571 | 116 | position = 8 | ||
572 | 117 | im = Image.new("1",(len(bits)+position,height)) | ||
573 | 118 | |||
574 | 119 | # Load font | ||
575 | 120 | font = ImageFont.load(config['addons_path']+"/report_aeroo/barcode/courB08.pil") | ||
576 | 121 | |||
577 | 122 | # Create drawer | ||
578 | 123 | draw = ImageDraw.Draw(im) | ||
579 | 124 | |||
580 | 125 | # Erase image | ||
581 | 126 | draw.rectangle(((0,0),(im.size[0],im.size[1])),fill=256) | ||
582 | 127 | |||
583 | 128 | # Draw first part of number | ||
584 | 129 | draw.text((0, height-9), code[0], font=font, fill=0) | ||
585 | 130 | |||
586 | 131 | # Draw first part of number | ||
587 | 132 | draw.text((position+7, height-9), code[1:7], font=font, fill=0) | ||
588 | 133 | |||
589 | 134 | # Draw second part of number | ||
590 | 135 | draw.text((len(bits)/2+6+position, height-9), code[7:], font=font, fill=0) | ||
591 | 136 | |||
592 | 137 | # Draw the bar codes | ||
593 | 138 | for bit in range(len(bits)): | ||
594 | 139 | # Draw normal bar | ||
595 | 140 | if bits[bit] == '1': | ||
596 | 141 | draw.rectangle(((bit+position,0),(bit+position,height-10)),fill=0) | ||
597 | 142 | # Draw long bar | ||
598 | 143 | elif bits[bit] == 'L': | ||
599 | 144 | draw.rectangle(((bit+position,0),(bit+position,height-3)),fill=0) | ||
600 | 145 | |||
601 | 146 | # Save the result image | ||
602 | 147 | return im | ||
603 | 148 | |||
604 | 0 | 149 | ||
605 | === added file 'barcode/FreeMonoBold.ttf' | |||
606 | 1 | Binary files barcode/FreeMonoBold.ttf 1970-01-01 00:00:00 +0000 and barcode/FreeMonoBold.ttf 2012-07-05 12:25:24 +0000 differ | 150 | Binary files barcode/FreeMonoBold.ttf 1970-01-01 00:00:00 +0000 and barcode/FreeMonoBold.ttf 2012-07-05 12:25:24 +0000 differ |
607 | === added file 'barcode/__init__.py' | |||
608 | --- barcode/__init__.py 1970-01-01 00:00:00 +0000 | |||
609 | +++ barcode/__init__.py 2012-07-05 12:25:24 +0000 | |||
610 | @@ -0,0 +1,30 @@ | |||
611 | 1 | ############################################################################## | ||
612 | 2 | # | ||
613 | 3 | # Copyright (c) 2008-2009 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
614 | 4 | # General contacts <info@kndati.lv> | ||
615 | 5 | # | ||
616 | 6 | # WARNING: This program as such is intended to be used by professional | ||
617 | 7 | # programmers who take the whole responsability of assessing all potential | ||
618 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
619 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
620 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
621 | 11 | # Service Company | ||
622 | 12 | # | ||
623 | 13 | # This program is Free Software; you can redistribute it and/or | ||
624 | 14 | # modify it under the terms of the GNU General Public License | ||
625 | 15 | # as published by the Free Software Foundation; either version 2 | ||
626 | 16 | # of the License, or (at your option) any later version. | ||
627 | 17 | # | ||
628 | 18 | # This program is distributed in the hope that it will be useful, | ||
629 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
630 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
631 | 21 | # GNU General Public License for more details. | ||
632 | 22 | # | ||
633 | 23 | # You should have received a copy of the GNU General Public License | ||
634 | 24 | # along with this program; if not, write to the Free Software | ||
635 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
636 | 26 | # | ||
637 | 27 | ############################################################################## | ||
638 | 28 | |||
639 | 29 | import barcode | ||
640 | 30 | |||
641 | 0 | 31 | ||
642 | === added file 'barcode/barcode.py' | |||
643 | --- barcode/barcode.py 1970-01-01 00:00:00 +0000 | |||
644 | +++ barcode/barcode.py 2012-07-05 12:25:24 +0000 | |||
645 | @@ -0,0 +1,59 @@ | |||
646 | 1 | ############################################################################## | ||
647 | 2 | # | ||
648 | 3 | # Copyright (c) 2008-2009 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
649 | 4 | # General contacts <info@kndati.lv> | ||
650 | 5 | # | ||
651 | 6 | # WARNING: This program as such is intended to be used by professional | ||
652 | 7 | # programmers who take the whole responsability of assessing all potential | ||
653 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
654 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
655 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
656 | 11 | # Service Company | ||
657 | 12 | # | ||
658 | 13 | # This program is Free Software; you can redistribute it and/or | ||
659 | 14 | # modify it under the terms of the GNU General Public License | ||
660 | 15 | # as published by the Free Software Foundation; either version 2 | ||
661 | 16 | # of the License, or (at your option) any later version. | ||
662 | 17 | # | ||
663 | 18 | # This program is distributed in the hope that it will be useful, | ||
664 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
665 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
666 | 21 | # GNU General Public License for more details. | ||
667 | 22 | # | ||
668 | 23 | # You should have received a copy of the GNU General Public License | ||
669 | 24 | # along with this program; if not, write to the Free Software | ||
670 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
671 | 26 | # | ||
672 | 27 | ############################################################################## | ||
673 | 28 | |||
674 | 29 | from code128 import get_code | ||
675 | 30 | from code39 import create_c39 | ||
676 | 31 | from EANBarCode import EanBarCode | ||
677 | 32 | try: | ||
678 | 33 | from cStringIO import StringIO | ||
679 | 34 | except ImportError: | ||
680 | 35 | from StringIO import StringIO | ||
681 | 36 | |||
682 | 37 | def make_barcode(code, code_type='ean13', rotate=None, height=50, xw=1): | ||
683 | 38 | if code: | ||
684 | 39 | if code_type.lower()=='ean13': | ||
685 | 40 | bar=EanBarCode() | ||
686 | 41 | im = bar.getImage(code,height) | ||
687 | 42 | elif code_type.lower()=='code128': | ||
688 | 43 | im = get_code(code, xw, height) | ||
689 | 44 | elif code_type.lower()=='code39': | ||
690 | 45 | im = create_c39(height, xw, code) | ||
691 | 46 | else: | ||
692 | 47 | return StringIO(), 'image/png' | ||
693 | 48 | |||
694 | 49 | tf = StringIO() | ||
695 | 50 | try: | ||
696 | 51 | if rotate!=None: | ||
697 | 52 | im=im.rotate(int(rotate)) | ||
698 | 53 | except Exception, e: | ||
699 | 54 | pass | ||
700 | 55 | im.save(tf, 'png') | ||
701 | 56 | size_x = str(im.size[0]/96.0)+'in' | ||
702 | 57 | size_y = str(im.size[1]/96.0)+'in' | ||
703 | 58 | return tf, 'image/png', size_x, size_y | ||
704 | 59 | |||
705 | 0 | 60 | ||
706 | === added file 'barcode/code128.py' | |||
707 | --- barcode/code128.py 1970-01-01 00:00:00 +0000 | |||
708 | +++ barcode/code128.py 2012-07-05 12:25:24 +0000 | |||
709 | @@ -0,0 +1,184 @@ | |||
710 | 1 | # Copyright (c) 2009-2010 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
711 | 2 | # General contacts <info@kndati.lv> | ||
712 | 3 | # This list was cut'n'pasted verbatim from the "Code 128 Specification Page" | ||
713 | 4 | # at http://www.adams1.com/pub/russadam/128code.html | ||
714 | 5 | |||
715 | 6 | codelist="""0 SP SP 00 2 1 2 2 2 2 | ||
716 | 7 | 1 ! ! 01 2 2 2 1 2 2 | ||
717 | 8 | 2 " " 02 2 2 2 2 2 1 | ||
718 | 9 | 3 # # 03 1 2 1 2 2 3 | ||
719 | 10 | 4 $ $ 04 1 2 1 3 2 2 | ||
720 | 11 | 5 % % 05 1 3 1 2 2 2 | ||
721 | 12 | 6 & & 06 1 2 2 2 1 3 | ||
722 | 13 | 7 ' ' 07 1 2 2 3 1 2 | ||
723 | 14 | 8 ( ( 08 1 3 2 2 1 2 | ||
724 | 15 | 9 ) ) 09 2 2 1 2 1 3 | ||
725 | 16 | 10 * * 10 2 2 1 3 1 2 | ||
726 | 17 | 11 + + 11 2 3 1 2 1 2 | ||
727 | 18 | 12 , , 12 1 1 2 2 3 2 | ||
728 | 19 | 13 - - 13 1 2 2 1 3 2 | ||
729 | 20 | 14 . . 14 1 2 2 2 3 1 | ||
730 | 21 | 15 / / 15 1 1 3 2 2 2 | ||
731 | 22 | 16 0 0 16 1 2 3 1 2 2 | ||
732 | 23 | 17 1 1 17 1 2 3 2 2 1 | ||
733 | 24 | 18 2 2 18 2 2 3 2 1 1 | ||
734 | 25 | 19 3 3 19 2 2 1 1 3 2 | ||
735 | 26 | 20 4 4 20 2 2 1 2 3 1 | ||
736 | 27 | 21 5 5 21 2 1 3 2 1 2 | ||
737 | 28 | 22 6 6 22 2 2 3 1 1 2 | ||
738 | 29 | 23 7 7 23 3 1 2 1 3 1 | ||
739 | 30 | 24 8 8 24 3 1 1 2 2 2 | ||
740 | 31 | 25 9 9 25 3 2 1 1 2 2 | ||
741 | 32 | 26 : : 26 3 2 1 2 2 1 | ||
742 | 33 | 27 ; ; 27 3 1 2 2 1 2 | ||
743 | 34 | 28 < < 28 3 2 2 1 1 2 | ||
744 | 35 | 29 = = 29 3 2 2 2 1 1 | ||
745 | 36 | 30 > > 30 2 1 2 1 2 3 | ||
746 | 37 | 31 ? ? 31 2 1 2 3 2 1 | ||
747 | 38 | 32 @ @ 32 2 3 2 1 2 1 | ||
748 | 39 | 33 A A 33 1 1 1 3 2 3 | ||
749 | 40 | 34 B B 34 1 3 1 1 2 3 | ||
750 | 41 | 35 C C 35 1 3 1 3 2 1 | ||
751 | 42 | 36 D D 36 1 1 2 3 1 3 | ||
752 | 43 | 37 E E 37 1 3 2 1 1 3 | ||
753 | 44 | 38 F F 38 1 3 2 3 1 1 | ||
754 | 45 | 39 G G 39 2 1 1 3 1 3 | ||
755 | 46 | 40 H H 40 2 3 1 1 1 3 | ||
756 | 47 | 41 I I 41 2 3 1 3 1 1 | ||
757 | 48 | 42 J J 42 1 1 2 1 3 3 | ||
758 | 49 | 43 K K 43 1 1 2 3 3 1 | ||
759 | 50 | 44 L L 44 1 3 2 1 3 1 | ||
760 | 51 | 45 M M 45 1 1 3 1 2 3 | ||
761 | 52 | 46 N N 46 1 1 3 3 2 1 | ||
762 | 53 | 47 O O 47 1 3 3 1 2 1 | ||
763 | 54 | 48 P P 48 3 1 3 1 2 1 | ||
764 | 55 | 49 Q Q 49 2 1 1 3 3 1 | ||
765 | 56 | 50 R R 50 2 3 1 1 3 1 | ||
766 | 57 | 51 S S 51 2 1 3 1 1 3 | ||
767 | 58 | 52 T T 52 2 1 3 3 1 1 | ||
768 | 59 | 53 U U 53 2 1 3 1 3 1 | ||
769 | 60 | 54 V V 54 3 1 1 1 2 3 | ||
770 | 61 | 55 W W 55 3 1 1 3 2 1 | ||
771 | 62 | 56 X X 56 3 3 1 1 2 1 | ||
772 | 63 | 57 Y Y 57 3 1 2 1 1 3 | ||
773 | 64 | 58 Z Z 58 3 1 2 3 1 1 | ||
774 | 65 | 59 [ [ 59 3 3 2 1 1 1 | ||
775 | 66 | 60 \\ \\ 60 3 1 4 1 1 1 | ||
776 | 67 | 61 ] ] 61 2 2 1 4 1 1 | ||
777 | 68 | 62 ^ ^ 62 4 3 1 1 1 1 | ||
778 | 69 | 63 _ _ 63 1 1 1 2 2 4 | ||
779 | 70 | 64 NUL ' 64 1 1 1 4 2 2 | ||
780 | 71 | 65 SOH a 65 1 2 1 1 2 4 | ||
781 | 72 | 66 STX b 66 1 2 1 4 2 1 | ||
782 | 73 | 67 ETX c 67 1 4 1 1 2 2 | ||
783 | 74 | 68 EOT d 68 1 4 1 2 2 1 | ||
784 | 75 | 69 ENQ e 69 1 1 2 2 1 4 | ||
785 | 76 | 70 ACK f 70 1 1 2 4 1 2 | ||
786 | 77 | 71 BEL g 61 1 2 2 1 1 4 | ||
787 | 78 | 72 BS h 72 1 2 2 4 1 1 | ||
788 | 79 | 73 HT i 73 1 4 2 1 1 2 | ||
789 | 80 | 74 LF j 74 1 4 2 2 1 1 | ||
790 | 81 | 75 VT k 75 2 4 1 2 1 1 | ||
791 | 82 | 76 FF l 76 2 2 1 1 1 4 | ||
792 | 83 | 77 CR m 77 4 1 3 1 1 1 | ||
793 | 84 | 78 SO n 78 2 4 1 1 1 2 | ||
794 | 85 | 79 SI o 79 1 3 4 1 1 1 | ||
795 | 86 | 80 DLE p 80 1 1 1 2 4 2 | ||
796 | 87 | 81 DC1 q 81 1 2 1 1 4 2 | ||
797 | 88 | 82 DC2 r 82 1 2 1 2 4 1 | ||
798 | 89 | 83 DC3 s 83 1 1 4 2 1 2 | ||
799 | 90 | 84 DC4 t 84 1 2 4 1 1 2 | ||
800 | 91 | 85 NAK u 85 1 2 4 2 1 1 | ||
801 | 92 | 86 SYN v 86 4 1 1 2 1 2 | ||
802 | 93 | 87 ETB w 87 4 2 1 1 1 2 | ||
803 | 94 | 88 CAN x 88 4 2 1 2 1 1 | ||
804 | 95 | 89 EM y 89 2 1 2 1 4 1 | ||
805 | 96 | 90 SUB z 90 2 1 4 1 2 1 | ||
806 | 97 | 91 ESC { 91 4 1 2 1 2 1 | ||
807 | 98 | 92 FS | 92 1 1 1 1 4 3 | ||
808 | 99 | 93 GS } 93 1 1 1 3 4 1 | ||
809 | 100 | 94 RS ~ 94 1 3 1 1 4 1 | ||
810 | 101 | 95 (Hex 7F) US DEL 95 1 1 4 1 1 3 | ||
811 | 102 | 96 (Hex 80) FNC 3 FNC 3 96 1 1 4 3 1 1 | ||
812 | 103 | 97 (Hex 81) FNC 2 FNC 2 97 4 1 1 1 1 3 | ||
813 | 104 | 98 (Hex 82) SHIFT SHIFT 98 4 1 1 3 1 1 | ||
814 | 105 | 99 (Hex 83) CODE C CODE C 99 1 1 3 1 4 1 | ||
815 | 106 | 100 (Hex 84) CODE B FNC 4 CODE B 1 1 4 1 3 1 | ||
816 | 107 | 101 (Hex 85) FNC 4 CODE A CODE A 3 1 1 1 4 1 | ||
817 | 108 | 102 (Hex 86) FNC 1 FNC 1 FNC 1 4 1 1 1 3 1""" | ||
818 | 109 | |||
819 | 110 | |||
820 | 111 | |||
821 | 112 | |||
822 | 113 | other="""103 (Hex 87) START (Code A) 2 1 1 4 1 2 | ||
823 | 114 | 104 (Hex 88) START (Code B) 2 1 1 2 1 4 | ||
824 | 115 | 105 (Hex 89) START (Code C) 2 1 1 2 3 2 | ||
825 | 116 | 106 STOP 2 3 3 1 1 1 2""" | ||
826 | 117 | |||
827 | 118 | |||
828 | 119 | codes={} | ||
829 | 120 | values={} | ||
830 | 121 | for l in codelist.split('\n'): | ||
831 | 122 | l.strip() | ||
832 | 123 | num,a1,b1,c1,code=l.split('\t') | ||
833 | 124 | num=int(num.split(' ')[0]) | ||
834 | 125 | values[num]=[int(x) for x in code.split()] | ||
835 | 126 | codes[b1.strip()]=num | ||
836 | 127 | |||
837 | 128 | codes[' ']=codes['SP'] | ||
838 | 129 | |||
839 | 130 | for l in other.split('\n'): | ||
840 | 131 | l.strip() | ||
841 | 132 | num,name,code=l.split('\t') | ||
842 | 133 | num=int(num.split(' ')[0]) | ||
843 | 134 | values[num]=[int(x) for x in code.split()] | ||
844 | 135 | codes[name.strip()]=num | ||
845 | 136 | |||
846 | 137 | def encode_message(msg): | ||
847 | 138 | startnum=codes['START (Code B)'] | ||
848 | 139 | message=values[startnum][:] | ||
849 | 140 | chksum=startnum | ||
850 | 141 | mult=1 | ||
851 | 142 | for c in msg: | ||
852 | 143 | if not codes.has_key(c): | ||
853 | 144 | raise "No code for "+c | ||
854 | 145 | chksum=chksum+mult*codes[c] | ||
855 | 146 | mult=mult+1 | ||
856 | 147 | message=message+values[codes[c]] | ||
857 | 148 | |||
858 | 149 | chksum=chksum%103 | ||
859 | 150 | |||
860 | 151 | message=message+values[chksum] | ||
861 | 152 | message=message+values[codes['STOP']] | ||
862 | 153 | |||
863 | 154 | return message | ||
864 | 155 | |||
865 | 156 | |||
866 | 157 | import Image, os | ||
867 | 158 | def get_code(message,xw=1,h=100,rotate=None): | ||
868 | 159 | """ message is message to code. | ||
869 | 160 | xw is horizontal multiplier (in pixels width of narrowest bar) | ||
870 | 161 | h is height in pixels. | ||
871 | 162 | |||
872 | 163 | Returns a Python Imaging Library object.""" | ||
873 | 164 | |||
874 | 165 | widths=[xw*20]+encode_message(message)+[xw*20] | ||
875 | 166 | |||
876 | 167 | bits=[] | ||
877 | 168 | i=1 | ||
878 | 169 | for w in widths: | ||
879 | 170 | bits=bits+[i]*w*xw | ||
880 | 171 | i=1-i | ||
881 | 172 | |||
882 | 173 | #print len(bits) | ||
883 | 174 | #print bits | ||
884 | 175 | |||
885 | 176 | i=Image.new('1',(len(bits),h),1) | ||
886 | 177 | |||
887 | 178 | for b in range(len(bits)): | ||
888 | 179 | for y in range(h): | ||
889 | 180 | i.putpixel((b,y),255*bits[b]) | ||
890 | 181 | |||
891 | 182 | return i | ||
892 | 183 | |||
893 | 184 | |||
894 | 0 | 185 | ||
895 | === added file 'barcode/code39.py' | |||
896 | --- barcode/code39.py 1970-01-01 00:00:00 +0000 | |||
897 | +++ barcode/code39.py 2012-07-05 12:25:24 +0000 | |||
898 | @@ -0,0 +1,153 @@ | |||
899 | 1 | # Copyright (c) 2008 marscel.wordpress.com | ||
900 | 2 | # | ||
901 | 3 | # Copyright (c) 2010 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
902 | 4 | # General contacts <info@kndati.lv> | ||
903 | 5 | |||
904 | 6 | # Code39.py v1 | ||
905 | 7 | # Requires Python and Python Imaging Library (PIL), | ||
906 | 8 | # has been tested with Python v2.6 and PIL v1.1.6 | ||
907 | 9 | |||
908 | 10 | # Usage example: | ||
909 | 11 | # code39.py 100 2 "Hello World" barcode.png | ||
910 | 12 | # | ||
911 | 13 | # This creates a PNG image "barcode.png" containing a barcode of the height of 100px | ||
912 | 14 | # a min line width of 2px with "Hello World" encoded as "*HELLO WORLD*" in Code 39 | ||
913 | 15 | |||
914 | 16 | import Image, ImageDraw, ImageFont, sys | ||
915 | 17 | from tools import config | ||
916 | 18 | |||
917 | 19 | marginx = 10 | ||
918 | 20 | marginy = 10 | ||
919 | 21 | fontsize = 15 | ||
920 | 22 | |||
921 | 23 | charmap = { | ||
922 | 24 | '*':[0,3,0,1,2,1,2,1,0], | ||
923 | 25 | '-':[0,3,0,1,0,1,2,1,2], | ||
924 | 26 | '$':[0,3,0,3,0,3,0,1,0], | ||
925 | 27 | '%':[0,1,0,3,0,3,0,3,0], | ||
926 | 28 | ' ':[0,3,2,1,0,1,2,1,0], | ||
927 | 29 | '.':[2,3,0,1,0,1,2,1,0], | ||
928 | 30 | '/':[0,3,0,3,0,1,0,3,0], | ||
929 | 31 | '+':[0,3,0,1,0,3,0,3,0], | ||
930 | 32 | '0':[0,1,0,3,2,1,2,1,0], | ||
931 | 33 | '1':[2,1,0,3,0,1,0,1,2], | ||
932 | 34 | '2':[0,1,2,3,0,1,0,1,2], | ||
933 | 35 | '3':[2,1,2,3,0,1,0,1,0], | ||
934 | 36 | '4':[0,1,0,3,2,1,0,1,2], | ||
935 | 37 | '5':[2,1,0,3,2,1,0,1,0], | ||
936 | 38 | '6':[0,1,2,3,2,1,0,1,0], | ||
937 | 39 | '7':[0,1,0,3,0,1,2,1,2], | ||
938 | 40 | '8':[2,1,0,3,0,1,2,1,0], | ||
939 | 41 | '9':[0,1,2,3,0,1,2,1,0], | ||
940 | 42 | 'A':[2,1,0,1,0,3,0,1,2], | ||
941 | 43 | 'B':[0,1,2,1,0,3,0,1,2], | ||
942 | 44 | 'C':[2,1,2,1,0,3,0,1,0], | ||
943 | 45 | 'D':[0,1,0,1,2,3,0,1,2], | ||
944 | 46 | 'E':[2,1,0,1,2,3,0,1,0], | ||
945 | 47 | 'F':[0,1,2,1,2,3,0,1,0], | ||
946 | 48 | 'G':[0,1,0,1,0,3,2,1,2], | ||
947 | 49 | 'H':[2,1,0,1,0,3,2,1,0], | ||
948 | 50 | 'I':[0,1,2,1,0,3,2,1,0], | ||
949 | 51 | 'J':[0,1,0,1,2,3,2,1,0], | ||
950 | 52 | 'K':[2,1,0,1,0,1,0,3,2], | ||
951 | 53 | 'L':[0,1,2,1,0,1,0,3,2], | ||
952 | 54 | 'M':[2,1,2,1,0,1,0,3,0], | ||
953 | 55 | 'N':[0,1,0,1,2,1,0,3,2], | ||
954 | 56 | 'O':[2,1,0,1,2,1,0,3,0], | ||
955 | 57 | 'P':[0,1,2,1,2,1,0,3,0], | ||
956 | 58 | 'Q':[0,1,0,1,0,1,2,3,2], | ||
957 | 59 | 'R':[2,1,0,1,0,1,2,3,0], | ||
958 | 60 | 'S':[0,1,2,1,0,1,2,3,0], | ||
959 | 61 | 'T':[0,1,0,1,2,1,2,3,0], | ||
960 | 62 | 'U':[2,3,0,1,0,1,0,1,2], | ||
961 | 63 | 'V':[0,3,2,1,0,1,0,1,2], | ||
962 | 64 | 'W':[2,3,2,1,0,1,0,1,0], | ||
963 | 65 | 'X':[0,3,0,1,2,1,0,1,2], | ||
964 | 66 | 'Y':[2,3,0,1,2,1,0,1,0], | ||
965 | 67 | 'Z':[0,3,2,1,2,1,0,1,0] | ||
966 | 68 | } | ||
967 | 69 | |||
968 | 70 | def create_c39(height, smallest, text): | ||
969 | 71 | pixel_length = 0 | ||
970 | 72 | i = 0 | ||
971 | 73 | newtext = "" | ||
972 | 74 | machinetext = "*" + text + "*" | ||
973 | 75 | seglist = [] | ||
974 | 76 | while i < len(machinetext): | ||
975 | 77 | char = machinetext[i].capitalize() | ||
976 | 78 | i = i + 1 | ||
977 | 79 | try: | ||
978 | 80 | map = charmap[char] | ||
979 | 81 | if len(map) != 9: | ||
980 | 82 | continue | ||
981 | 83 | |||
982 | 84 | j = 0 | ||
983 | 85 | while j < 9: | ||
984 | 86 | seg = int(map[j]) | ||
985 | 87 | |||
986 | 88 | if seg == 0 or seg == 1: | ||
987 | 89 | pixel_length = pixel_length + smallest | ||
988 | 90 | seglist.append(seg) | ||
989 | 91 | elif seg == 2 or seg == 3: | ||
990 | 92 | pixel_length = pixel_length + smallest * 3 | ||
991 | 93 | seglist.append(seg) | ||
992 | 94 | |||
993 | 95 | j = j + 1 | ||
994 | 96 | |||
995 | 97 | newtext += char | ||
996 | 98 | except: | ||
997 | 99 | continue | ||
998 | 100 | |||
999 | 101 | pixel_length = pixel_length + 2*marginx + len(newtext) * smallest | ||
1000 | 102 | pixel_height = height + 2*marginy + fontsize | ||
1001 | 103 | |||
1002 | 104 | barcode_img = Image.new('RGB', [pixel_length, pixel_height], "white") | ||
1003 | 105 | |||
1004 | 106 | if len(seglist) == 0: | ||
1005 | 107 | return barcode_img | ||
1006 | 108 | |||
1007 | 109 | i = 0 | ||
1008 | 110 | draw = ImageDraw.Draw(barcode_img) | ||
1009 | 111 | current_x = marginx | ||
1010 | 112 | |||
1011 | 113 | while i < len(seglist): | ||
1012 | 114 | seg = seglist[i] | ||
1013 | 115 | color = (255, 255, 255) | ||
1014 | 116 | wdth = smallest | ||
1015 | 117 | |||
1016 | 118 | if seg == 0 or seg == 2: | ||
1017 | 119 | color = 0 | ||
1018 | 120 | if seg == 0: | ||
1019 | 121 | wdth = smallest | ||
1020 | 122 | else: | ||
1021 | 123 | wdth = smallest * 3 | ||
1022 | 124 | elif seg == 1 or seg == 3: | ||
1023 | 125 | color = (255, 255, 255) | ||
1024 | 126 | if seg == 1: | ||
1025 | 127 | wdth = smallest | ||
1026 | 128 | else: | ||
1027 | 129 | wdth = smallest * 3 | ||
1028 | 130 | |||
1029 | 131 | j = 1 | ||
1030 | 132 | |||
1031 | 133 | while j <= wdth: | ||
1032 | 134 | draw.line((current_x, marginy, current_x, marginy+height), fill=color) | ||
1033 | 135 | current_x = current_x + 1 | ||
1034 | 136 | j = j + 1 | ||
1035 | 137 | |||
1036 | 138 | if ((i+1) % 9) == 0: | ||
1037 | 139 | j = 1 | ||
1038 | 140 | while j <= smallest: | ||
1039 | 141 | draw.line((current_x, marginy, current_x, marginy+height), fill=(255,255,255)) | ||
1040 | 142 | current_x = current_x + 1 | ||
1041 | 143 | j = j + 1 | ||
1042 | 144 | i = i + 1 | ||
1043 | 145 | |||
1044 | 146 | font = ImageFont.truetype(config['addons_path']+"/report_aeroo/barcode/FreeMonoBold.ttf", fontsize) | ||
1045 | 147 | |||
1046 | 148 | draw.text((pixel_length/2 - len(newtext)*(fontsize/2)/2-len(newtext), height+fontsize), newtext, font=font, fill=0) | ||
1047 | 149 | |||
1048 | 150 | del draw | ||
1049 | 151 | |||
1050 | 152 | return barcode_img | ||
1051 | 153 | |||
1052 | 0 | 154 | ||
1053 | === added file 'barcode/courB08.pbm' | |||
1054 | 1 | Binary files barcode/courB08.pbm 1970-01-01 00:00:00 +0000 and barcode/courB08.pbm 2012-07-05 12:25:24 +0000 differ | 155 | Binary files barcode/courB08.pbm 1970-01-01 00:00:00 +0000 and barcode/courB08.pbm 2012-07-05 12:25:24 +0000 differ |
1055 | === added file 'barcode/courB08.pil' | |||
1056 | 2 | Binary files barcode/courB08.pil 1970-01-01 00:00:00 +0000 and barcode/courB08.pil 2012-07-05 12:25:24 +0000 differ | 156 | Binary files barcode/courB08.pil 1970-01-01 00:00:00 +0000 and barcode/courB08.pil 2012-07-05 12:25:24 +0000 differ |
1057 | === added file 'currency_to_text.py' | |||
1058 | --- currency_to_text.py 1970-01-01 00:00:00 +0000 | |||
1059 | +++ currency_to_text.py 2012-07-05 12:25:24 +0000 | |||
1060 | @@ -0,0 +1,490 @@ | |||
1061 | 1 | #!/usr/bin/python | ||
1062 | 2 | # -*- coding: utf8 -*- | ||
1063 | 3 | |||
1064 | 4 | ########################################################### | ||
1065 | 5 | # Developed by Kaspars Vilkens - KN dati Ltd. (c) 2009 | ||
1066 | 6 | # pep-8, unicode and doctests by Paul Stevens, paul@nfg.nl, 2010 | ||
1067 | 7 | # | ||
1068 | 8 | # Supported currencies: LVL, EUR, USD, UAH | ||
1069 | 9 | # Supported sum: 0 ... 999999999999.99 | ||
1070 | 10 | # Supported languages: lv_LV, en_US, ru_RU, uk_UA | ||
1071 | 11 | ########################################################### | ||
1072 | 12 | import string | ||
1073 | 13 | |||
1074 | 14 | supported_currency = ['LVL','EUR','USD', 'UAH'] | ||
1075 | 15 | supported_language = ['lv_LV','en_US','ru_RU', 'uk_UA'] | ||
1076 | 16 | |||
1077 | 17 | def currency_to_text(sum, currency, language): | ||
1078 | 18 | """ | ||
1079 | 19 | |||
1080 | 20 | first some simple tests | ||
1081 | 21 | |||
1082 | 22 | >>> currency_to_text(123, 'EUR', 'en_US') | ||
1083 | 23 | 'one hundred twenty three euros zero cents' | ||
1084 | 24 | |||
1085 | 25 | >>> currency_to_text(1.11, 'EUR', 'en_US') | ||
1086 | 26 | 'one euro eleven cents' | ||
1087 | 27 | |||
1088 | 28 | >>> currency_to_text(1.10, 'USD', 'en_US') | ||
1089 | 29 | 'one US dollar ten cents' | ||
1090 | 30 | |||
1091 | 31 | >>> currency_to_text(1.01, 'USD', 'en_US') | ||
1092 | 32 | 'one US dollar one cent' | ||
1093 | 33 | |||
1094 | 34 | >>> currency_to_text(1.01, 'LVL', 'lv_LV') == 'viens lats viens santīms' | ||
1095 | 35 | True | ||
1096 | 36 | |||
1097 | 37 | >>> currency_to_text(123.12, 'LVL', 'ru_RU') == 'стo двaдцать три лата двенадцать сантимов' | ||
1098 | 38 | True | ||
1099 | 39 | |||
1100 | 40 | >>> currency_to_text(123.12, 'USD', 'ru_RU') == 'стo двaдцать три доллара США двенадцать центов' | ||
1101 | 41 | True | ||
1102 | 42 | |||
1103 | 43 | |||
1104 | 44 | """ | ||
1105 | 45 | if sum < 0 or sum > 999999999999.99 : | ||
1106 | 46 | raise Exception('Sum out of bounds: must be from 0 to 999999999999.99') | ||
1107 | 47 | if currency not in supported_currency: | ||
1108 | 48 | raise Exception("""Unsupported or no currency: must be one of (%s)""" % \ | ||
1109 | 49 | string.join(supported_currency,',')) | ||
1110 | 50 | if language not in supported_language: | ||
1111 | 51 | raise Exception("""Unsupported or no language: must be one of (%s)""" % \ | ||
1112 | 52 | string.join(supported_language,',')) | ||
1113 | 53 | #--------------for currencies with 100 fractions | ||
1114 | 54 | sum = float(sum) | ||
1115 | 55 | sum = round(sum, 2) | ||
1116 | 56 | # find out digits before floating point - currency | ||
1117 | 57 | sum_cur = int(sum) | ||
1118 | 58 | # find out digits after floating point - fractions | ||
1119 | 59 | sum_frc = int(round((sum - sum_cur) * 100,0)) | ||
1120 | 60 | cur_in_words = dtowords(sum_cur, language) | ||
1121 | 61 | #print cur_in_words | ||
1122 | 62 | frc_in_words = dtowords(sum_frc, language) | ||
1123 | 63 | #print frc_in_words | ||
1124 | 64 | #------------------------------------ | ||
1125 | 65 | if language == 'lv_LV' : | ||
1126 | 66 | if sum_cur == 1 or (str(sum_cur)[-1] == '1' and str(sum_cur)[-2] != '1'): # is the currency sum one | ||
1127 | 67 | if currency == 'LVL': | ||
1128 | 68 | cur_in_words += u' lats' | ||
1129 | 69 | elif currency == 'EUR': | ||
1130 | 70 | cur_in_words += u' eiro' | ||
1131 | 71 | elif currency == 'USD': | ||
1132 | 72 | cur_in_words += u' dolārs' | ||
1133 | 73 | elif currency == 'UAH': | ||
1134 | 74 | cur_in_words += u' grivna' | ||
1135 | 75 | else: | ||
1136 | 76 | if currency == 'LVL': | ||
1137 | 77 | cur_in_words += u' lati' | ||
1138 | 78 | elif currency == 'EUR': | ||
1139 | 79 | cur_in_words += u' eiro' | ||
1140 | 80 | elif currency == 'USD': | ||
1141 | 81 | cur_in_words += u' dolāri' | ||
1142 | 82 | elif currency == 'UAH': | ||
1143 | 83 | cur_in_words += u' grivnas' | ||
1144 | 84 | |||
1145 | 85 | if sum_frc == 1 or (str(sum_frc)[-1] == '1' and str(sum_frc)[-2] != '1'): # is the fraction sum one | ||
1146 | 86 | if currency == 'LVL': | ||
1147 | 87 | frc_in_words += u' santīms' | ||
1148 | 88 | elif currency == 'EUR' or currency == 'USD' : | ||
1149 | 89 | frc_in_words += u' cents' | ||
1150 | 90 | elif currency == 'UAH': | ||
1151 | 91 | frc_in_words += u' kapeika' | ||
1152 | 92 | else: | ||
1153 | 93 | if currency == 'LVL': | ||
1154 | 94 | frc_in_words += u' santīmi' | ||
1155 | 95 | elif currency == 'EUR' or currency == 'USD': | ||
1156 | 96 | frc_in_words += u' centi' | ||
1157 | 97 | elif currency == 'UAH': | ||
1158 | 98 | frc_in_words += u' kapeikas' | ||
1159 | 99 | #------------------------------------ | ||
1160 | 100 | if language == 'en_US' : | ||
1161 | 101 | if sum_cur == 1 or (str(sum_cur)[-1] == '1' and str(sum_cur)[-2] != '1'): # is the currency sum one | ||
1162 | 102 | if currency == 'LVL': | ||
1163 | 103 | cur_in_words += u' Latvian lats' | ||
1164 | 104 | elif currency == 'EUR': | ||
1165 | 105 | cur_in_words += u' euro' | ||
1166 | 106 | elif currency == 'USD': | ||
1167 | 107 | cur_in_words += u' US dollar' | ||
1168 | 108 | else: | ||
1169 | 109 | if currency == 'LVL': | ||
1170 | 110 | cur_in_words += u' Latvian lats' | ||
1171 | 111 | elif currency == 'EUR': | ||
1172 | 112 | cur_in_words += u' euros' | ||
1173 | 113 | elif currency == 'USD': | ||
1174 | 114 | cur_in_words += u' dollars' | ||
1175 | 115 | if sum_frc == 1 or (str(sum_frc)[-1] == '1' and str(sum_frc)[-2] != '1'): # is the fraction sum one | ||
1176 | 116 | if currency == 'LVL': | ||
1177 | 117 | frc_in_words += u' santim' | ||
1178 | 118 | elif currency == 'EUR' or currency == 'USD': | ||
1179 | 119 | frc_in_words += u' cent' | ||
1180 | 120 | else: | ||
1181 | 121 | if currency == 'LVL': | ||
1182 | 122 | frc_in_words += u' santims' | ||
1183 | 123 | elif currency == 'EUR' or currency == 'USD' : | ||
1184 | 124 | frc_in_words += u' cents' | ||
1185 | 125 | #------------------------------------ | ||
1186 | 126 | if language == 'ru_RU' : | ||
1187 | 127 | if sum_cur == 1 or (str(sum_cur)[-1] == '1' and str(sum_cur)[-2] != '1'): # is the currency sum one | ||
1188 | 128 | if currency == 'LVL': | ||
1189 | 129 | cur_in_words += u' лат' | ||
1190 | 130 | elif currency == 'EUR': | ||
1191 | 131 | cur_in_words += u' евро' | ||
1192 | 132 | elif currency == 'USD': | ||
1193 | 133 | cur_in_words += u' доллар США' | ||
1194 | 134 | elif (sum_cur in [2, 3, 4]) or (str(sum_cur)[-1] in ['2', '3', '4'] and str(sum_cur)[-2] != '1'): | ||
1195 | 135 | if currency == 'LVL': | ||
1196 | 136 | cur_in_words += u' лата' | ||
1197 | 137 | elif currency == 'EUR' : | ||
1198 | 138 | cur_in_words += u' евро' | ||
1199 | 139 | elif currency == 'USD' : | ||
1200 | 140 | cur_in_words += u' доллара США' | ||
1201 | 141 | elif (sum_cur >= 5 and sum_cur <= 20) or str(sum_cur)[-1] not in [2, 3, 4]: | ||
1202 | 142 | if currency == 'LVL' : | ||
1203 | 143 | cur_in_words += u' латов' | ||
1204 | 144 | elif currency == 'EUR' : | ||
1205 | 145 | cur_in_words += u' евро' | ||
1206 | 146 | elif currency == 'USD' : | ||
1207 | 147 | cur_in_words += u' долларов США' | ||
1208 | 148 | |||
1209 | 149 | if sum_frc == 1 or (str(sum_frc)[-1] == '1' and str(sum_frc)[-2] != '1') : # is the fraction one | ||
1210 | 150 | if currency == 'LVL' : | ||
1211 | 151 | frc_in_words += u' сантим' | ||
1212 | 152 | elif currency == 'EUR' or currency == 'USD' : | ||
1213 | 153 | frc_in_words += u' цент' | ||
1214 | 154 | elif (sum_frc in [2, 3, 4]) or (str(sum_frc)[-1] in ['2', '3', '4'] and str(sum_frc)[-2] != '1') : | ||
1215 | 155 | if currency == 'LVL' : | ||
1216 | 156 | frc_in_words += u' сантима' | ||
1217 | 157 | elif currency == 'EUR' or currency == 'USD' : | ||
1218 | 158 | frc_in_words += u' цента' | ||
1219 | 159 | elif (sum_frc >= 5 and sum_frc <= 20) or str(sum_frc)[-1] not in [2, 3, 4] : | ||
1220 | 160 | if currency == 'LVL' : | ||
1221 | 161 | frc_in_words += u' сантимов' | ||
1222 | 162 | elif currency == 'EUR' or currency == 'USD' : | ||
1223 | 163 | frc_in_words += u' центов' | ||
1224 | 164 | #------------------------------------ | ||
1225 | 165 | if language == 'uk_UA' : | ||
1226 | 166 | if sum_cur == 1 or (str(sum_cur)[-1] == '1' and str(sum_cur)[-2] != '1') : # is the currency sum one | ||
1227 | 167 | if currency == 'LVL' : | ||
1228 | 168 | cur_in_words += u' лат' | ||
1229 | 169 | elif currency == 'EUR' : | ||
1230 | 170 | cur_in_words += u' евро' | ||
1231 | 171 | elif currency == 'USD' : | ||
1232 | 172 | cur_in_words += u' доллар США' | ||
1233 | 173 | elif currency == 'UAH' : | ||
1234 | 174 | cur_in_words += u' гривня' | ||
1235 | 175 | elif (sum_cur in [2, 3, 4]) or (str(sum_cur)[-1] in ['2', '3', '4'] and str(sum_cur)[-2] != '1') : | ||
1236 | 176 | if currency == 'LVL' : | ||
1237 | 177 | cur_in_words += u' лата' | ||
1238 | 178 | elif currency == 'EUR' : | ||
1239 | 179 | cur_in_words += u' евро' | ||
1240 | 180 | elif currency == 'USD' : | ||
1241 | 181 | cur_in_words += u' доллара США' | ||
1242 | 182 | elif currency == 'UAH' : | ||
1243 | 183 | cur_in_words += u' гривні' | ||
1244 | 184 | elif (sum_cur >= 5 and sum_cur <= 20) or str(sum_cur)[-1] not in [2, 3, 4] : | ||
1245 | 185 | if currency == 'LVL' : | ||
1246 | 186 | cur_in_words += u' латов' | ||
1247 | 187 | elif currency == 'EUR' : | ||
1248 | 188 | cur_in_words += u' евро' | ||
1249 | 189 | elif currency == 'USD' : | ||
1250 | 190 | cur_in_words += u' долларов США' | ||
1251 | 191 | elif currency == 'UAH' : | ||
1252 | 192 | cur_in_words += u' гривень' | ||
1253 | 193 | |||
1254 | 194 | if sum_frc == 1 or (str(sum_frc)[-1] == '1' and str(sum_frc)[-2] != '1') : # is the fraction one | ||
1255 | 195 | if currency == 'LVL' : | ||
1256 | 196 | frc_in_words += u' сантим' | ||
1257 | 197 | elif currency == 'EUR' or currency == 'USD' : | ||
1258 | 198 | frc_in_words += u' цент' | ||
1259 | 199 | elif currency == 'UAH' : | ||
1260 | 200 | frc_in_words += u' копійка' | ||
1261 | 201 | elif (sum_frc in [2, 3, 4]) or (str(sum_frc)[-1] in ['2', '3', '4'] and str(sum_frc)[-2] != '1') : | ||
1262 | 202 | if currency == 'LVL' : | ||
1263 | 203 | frc_in_words += u' сантима' | ||
1264 | 204 | elif currency == 'EUR' or currency == 'USD' : | ||
1265 | 205 | frc_in_words += u' цента' | ||
1266 | 206 | elif currency == 'UAH' : | ||
1267 | 207 | frc_in_words += u' копійки' | ||
1268 | 208 | elif (sum_frc >= 5 and sum_frc <= 20) or str(sum_frc)[-1] not in [2, 3, 4] : | ||
1269 | 209 | if currency == 'LVL' : | ||
1270 | 210 | frc_in_words += u' сантимов' | ||
1271 | 211 | elif currency == 'EUR' or currency == 'USD' : | ||
1272 | 212 | frc_in_words += u' центов' | ||
1273 | 213 | elif currency == 'UAH' : | ||
1274 | 214 | frc_in_words += u' копійок' | ||
1275 | 215 | frc_in_words = str(sum_frc) + u' коп.' | ||
1276 | 216 | |||
1277 | 217 | return (cur_in_words + ' ' + frc_in_words).strip().encode('utf-8') | ||
1278 | 218 | |||
1279 | 219 | |||
1280 | 220 | def dtowords(sum_integers, language): | ||
1281 | 221 | """ | ||
1282 | 222 | >>> dtowords(0, 'en_US') | ||
1283 | 223 | u'zero' | ||
1284 | 224 | |||
1285 | 225 | >>> dtowords(1, 'en_US') | ||
1286 | 226 | u'one' | ||
1287 | 227 | |||
1288 | 228 | >>> dtowords(11, 'en_US') | ||
1289 | 229 | u'eleven' | ||
1290 | 230 | |||
1291 | 231 | >>> dtowords(169, 'en_US') | ||
1292 | 232 | u'one hundred sixty nine' | ||
1293 | 233 | |||
1294 | 234 | >>> dtowords(12345, 'en_US') | ||
1295 | 235 | u'twelve thousand three hundred fourty five' | ||
1296 | 236 | |||
1297 | 237 | >>> dtowords(123456, 'en_US') | ||
1298 | 238 | u'one hundred twenty three thousand four hundred fifty six' | ||
1299 | 239 | |||
1300 | 240 | >>> dtowords(0, 'lv_LV') | ||
1301 | 241 | u'nulle' | ||
1302 | 242 | |||
1303 | 243 | >>> dtowords(1, 'lv_LV') | ||
1304 | 244 | u'viens' | ||
1305 | 245 | |||
1306 | 246 | >>> dtowords(11, 'lv_LV') | ||
1307 | 247 | u'vienpadsmit' | ||
1308 | 248 | |||
1309 | 249 | >>> dtowords(169, 'lv_LV').encode('utf-8') == 'simts sešdesmit deviņi' | ||
1310 | 250 | True | ||
1311 | 251 | |||
1312 | 252 | >>> dtowords(12345, 'lv_LV').encode('utf-8') == 'divpadsmit tūkstoši trīs simti četrdesmit pieci' | ||
1313 | 253 | True | ||
1314 | 254 | |||
1315 | 255 | >>> dtowords(123456, 'lv_LV').encode('utf-8') == 'simts divdesmit trīs tūkstoši četri simti piecdesmit seši' | ||
1316 | 256 | True | ||
1317 | 257 | |||
1318 | 258 | >>> dtowords(0, 'ru_RU').encode('utf-8') == 'ноль' | ||
1319 | 259 | True | ||
1320 | 260 | |||
1321 | 261 | >>> dtowords(1, 'ru_RU').encode('utf-8') == 'один' | ||
1322 | 262 | True | ||
1323 | 263 | |||
1324 | 264 | >>> dtowords(11, 'ru_RU').encode('utf-8') == 'одиннадцать' | ||
1325 | 265 | True | ||
1326 | 266 | |||
1327 | 267 | >>> dtowords(169, 'ru_RU').encode('utf-8') == 'стo шестьдесят девять' | ||
1328 | 268 | True | ||
1329 | 269 | |||
1330 | 270 | >>> dtowords(12345, 'ru_RU').encode('utf-8') == 'двенадцать тысяч триста сорок пять' | ||
1331 | 271 | True | ||
1332 | 272 | |||
1333 | 273 | >>> dtowords(123456, 'ru_RU').encode('utf-8') == 'стo двaдцать три тысячи четыреста пятьдесят шесть' | ||
1334 | 274 | True | ||
1335 | 275 | |||
1336 | 276 | |||
1337 | 277 | """ | ||
1338 | 278 | diginwords = u'' | ||
1339 | 279 | if sum_integers == 0: | ||
1340 | 280 | return wordify('0', 0, language) | ||
1341 | 281 | elif sum_integers > 0: | ||
1342 | 282 | lengthx = len(str(sum_integers)) | ||
1343 | 283 | nrchunks = (lengthx / 3) | ||
1344 | 284 | if nrchunks < (float(lengthx) / 3) : | ||
1345 | 285 | nrchunks+=1 | ||
1346 | 286 | inc = 1 | ||
1347 | 287 | while inc <= nrchunks: | ||
1348 | 288 | startpos = (lengthx - inc * 3) | ||
1349 | 289 | chunklength = 3 | ||
1350 | 290 | if startpos < 0: | ||
1351 | 291 | chunklength += startpos | ||
1352 | 292 | startpos = 0 | ||
1353 | 293 | chunk = str(sum_integers)[startpos : startpos + chunklength] | ||
1354 | 294 | #print str(startpos)+' '+str(chunklength)+' '+ chunk | ||
1355 | 295 | wordified = wordify(chunk, inc-1, language) | ||
1356 | 296 | inc += 1 | ||
1357 | 297 | spacer = '' | ||
1358 | 298 | if len(diginwords) > 0 : | ||
1359 | 299 | spacer = ' ' | ||
1360 | 300 | diginwords = wordified + spacer + diginwords | ||
1361 | 301 | return diginwords | ||
1362 | 302 | |||
1363 | 303 | def wordify(chunk, chunknr, language): | ||
1364 | 304 | #print 'chunk '+str(chunk) | ||
1365 | 305 | #print 'cunknr '+str(chunknr) | ||
1366 | 306 | words = u'' | ||
1367 | 307 | |||
1368 | 308 | if language == 'lv_LV': | ||
1369 | 309 | skaitli = [u'nulle', u'viens', u'divi', u'trīs', u'četri', u'pieci', | ||
1370 | 310 | u'seši', u'septiņi', u'astoņi', u'deviņi'] | ||
1371 | 311 | skaitlix = [u'nulle', u'vien', u'div', u'trīs', u'četr', u'piec', u'seš', | ||
1372 | 312 | u'septiņ', u'astoņ', u'deviņ'] | ||
1373 | 313 | skaitli_teens = [u'desmit', u'vienpadsmit', u'divpadsmit', u'trīspadsmit', | ||
1374 | 314 | u'četrpadsmit', u'piecpadsmit', u'sešpadsmit', | ||
1375 | 315 | u'septiņpadsmit', u'astoņpadsmit', u'deviņpadsmit'] | ||
1376 | 316 | daudzums = [u'simts', u' tūkstotis', u' miljons', u' miljards'] | ||
1377 | 317 | daudzumsx = [u' simti', u' tūkstoši', u' miljoni', u' miljardi'] | ||
1378 | 318 | |||
1379 | 319 | elif language == 'en_US': | ||
1380 | 320 | skaitli = [u'zero', u'one', u'two', u'three', u'four', u'five', u'six', | ||
1381 | 321 | u'seven', u'eight', u'nine'] | ||
1382 | 322 | skaitlix = [u'zero', u'one', u'twen', u'thir', u'four', u'fif', u'six', | ||
1383 | 323 | u'seven', u'eigh', u'nine'] | ||
1384 | 324 | skaitli_teens = [u'ten', u'eleven', u'twelve', u'thirteen', u'fourteen', | ||
1385 | 325 | u'fifteen', u'sixteen', u'seventeen', u'eighteen', u'nineteen'] | ||
1386 | 326 | daudzums = [u' hundred', u' thousand', u' million', u' billion'] | ||
1387 | 327 | daudzumsx = daudzums | ||
1388 | 328 | |||
1389 | 329 | elif language == 'ru_RU': | ||
1390 | 330 | skaitli = [u'ноль', u'один', u'два', u'три', u'четыре', u'пять', u'шесть', | ||
1391 | 331 | u'семь', u'восемь', u'девять'] | ||
1392 | 332 | skaitlix = [u'', u'один', u'двa', u'три', u'четыре', u'пять', u'шесть', | ||
1393 | 333 | u'семь', u'восемь', u'девять'] | ||
1394 | 334 | skaitli_teens = [u'десять', u'одиннадцать', u'двенадцать', u'тринадцать', | ||
1395 | 335 | u'четырнадцать', u'пятнадцать', u'шестнадцать', u'семнадцать', | ||
1396 | 336 | u'восемнадцать', u'девятнадцать'] | ||
1397 | 337 | daudzums = [u'стo', u' тысяча', u' миллион', u' миллиард'] | ||
1398 | 338 | daudzumsx = [u'сoт', u' тысяч', u' миллионов', u' миллиардов'] | ||
1399 | 339 | |||
1400 | 340 | elif language == 'uk_UA' : | ||
1401 | 341 | skaitli = [u'ноль', u'один', u'два', u'три', u'чотири', u'п\'ять', u'шість', | ||
1402 | 342 | u'сім', u'вісім', u'дев\'ять'] | ||
1403 | 343 | skaitlix = [u'', u'один', u'двa', u'три', u'чотири', u'п\'ять', u'шість', | ||
1404 | 344 | u'сім', u'вісім', u'дев\'ять'] | ||
1405 | 345 | skaitli_teens = [u'десять', u'одинадцять', u'дванадцять', u'тринадцять', | ||
1406 | 346 | u'чотирнадцять', u'п\'ятнадцять', u'шістнадцять', u'сімнадцять', | ||
1407 | 347 | u'вісімнадцять', u'дев\'ятнадцять'] | ||
1408 | 348 | daudzums = [u'стo', u' тисяча', u' мiллiон', u' мiллiард'] | ||
1409 | 349 | daudzumsx = [u'сoт', u' тисяч', u' мiллiонiв', u' мiллiардов'] | ||
1410 | 350 | digit1 = u'' | ||
1411 | 351 | digit2 = u'' | ||
1412 | 352 | digit3 = u'' | ||
1413 | 353 | chunklength = len(chunk) | ||
1414 | 354 | # placing digits in right places | ||
1415 | 355 | if chunklength == 1: | ||
1416 | 356 | digit3 = chunk[0 : 1] | ||
1417 | 357 | if chunklength == 2: | ||
1418 | 358 | digit2 = chunk[0 : 1] | ||
1419 | 359 | digit3 = chunk[1 : 2] | ||
1420 | 360 | if chunklength == 3: | ||
1421 | 361 | digit1 = chunk[0 : 1] | ||
1422 | 362 | digit2 = chunk[1 : 2] | ||
1423 | 363 | digit3 = chunk[-1] | ||
1424 | 364 | # processing zero | ||
1425 | 365 | if chunklength == 1 and digit3 == '0' : | ||
1426 | 366 | return skaitli[0] | ||
1427 | 367 | # processing hundreds | ||
1428 | 368 | if chunklength == 3 : | ||
1429 | 369 | if digit1 == '1' : | ||
1430 | 370 | if language == 'lv_LV' or language == 'ru_RU' or language == 'uk_UA': | ||
1431 | 371 | words += daudzums[0] | ||
1432 | 372 | elif language == 'en_US' : | ||
1433 | 373 | words += skaitli[int(digit1)] + daudzumsx[0] | ||
1434 | 374 | else : | ||
1435 | 375 | if language == 'lv_LV' : | ||
1436 | 376 | if int(digit1) > 1 : words += skaitli[int(digit1)] + daudzumsx[0] | ||
1437 | 377 | elif language == 'en_US' : | ||
1438 | 378 | if int(digit1) > 1 : words += skaitli[int(digit1)] + daudzumsx[0] | ||
1439 | 379 | elif language == 'ru_RU' : | ||
1440 | 380 | if int(digit1) == 2 : | ||
1441 | 381 | words += u'двести' | ||
1442 | 382 | elif int(digit1) == 3 : | ||
1443 | 383 | words += u'триста' | ||
1444 | 384 | elif int(digit1) == 4 : | ||
1445 | 385 | words += u'четыреста' | ||
1446 | 386 | elif int(digit1) >= 5 : | ||
1447 | 387 | words += skaitli[int(digit1)] + daudzumsx[0] | ||
1448 | 388 | elif language == 'uk_UA' : | ||
1449 | 389 | if int(digit1) == 2 : | ||
1450 | 390 | words += u'двісті' | ||
1451 | 391 | elif int(digit1) == 3 : | ||
1452 | 392 | words += u'триста' | ||
1453 | 393 | elif int(digit1) == 4 : | ||
1454 | 394 | words += u'чотириста' | ||
1455 | 395 | elif int(digit1) >= 5 : | ||
1456 | 396 | words += skaitli[int(digit1)] + daudzumsx[0] | ||
1457 | 397 | # processing tens | ||
1458 | 398 | if chunklength > 1: | ||
1459 | 399 | spacer = '' | ||
1460 | 400 | if len(words) > 0 : spacer = ' ' | ||
1461 | 401 | if digit2 == '1': | ||
1462 | 402 | if language == 'lv_LV' or language == 'en_US' or language == 'ru_RU' or language == 'uk_UA': | ||
1463 | 403 | words += spacer + skaitli_teens[int(digit3)] | ||
1464 | 404 | else: | ||
1465 | 405 | if language == 'lv_LV': | ||
1466 | 406 | if int(digit2) > 1 and int(digit2) > 0: | ||
1467 | 407 | words += spacer + skaitlix[int(digit2)] + u'desmit' | ||
1468 | 408 | elif language == 'en_US': | ||
1469 | 409 | if int(digit2) > 1 and int(digit2) > 0: | ||
1470 | 410 | words += spacer + skaitlix[int(digit2)] + u'ty' | ||
1471 | 411 | elif language == 'ru_RU': | ||
1472 | 412 | if int(digit2) > 1 and int(digit2) < 4: | ||
1473 | 413 | words += spacer + skaitlix[int(digit2)] + u'дцать' | ||
1474 | 414 | elif digit2 == '4': | ||
1475 | 415 | words += spacer + u'сорок' | ||
1476 | 416 | elif int(digit2) >= 5 and int(digit2) != 9: | ||
1477 | 417 | words += spacer + skaitlix[int(digit2)] + u'десят' | ||
1478 | 418 | elif digit2 == '9': | ||
1479 | 419 | words += spacer + u'девяносто' | ||
1480 | 420 | elif language == 'uk_UA' : | ||
1481 | 421 | if int(digit2) > 1 and int(digit2) < 4: | ||
1482 | 422 | words += spacer + skaitlix[int(digit2)] + u'дцять' | ||
1483 | 423 | elif digit2 == '4': | ||
1484 | 424 | words += spacer + u'сорок' | ||
1485 | 425 | elif int(digit2) >= 5 and int(digit2) != 9: | ||
1486 | 426 | words += spacer + skaitlix[int(digit2)] + u'десят' | ||
1487 | 427 | elif digit2 == '9': | ||
1488 | 428 | words += spacer + u'дев\'яносто' | ||
1489 | 429 | # processing ones | ||
1490 | 430 | if chunklength > 0 and digit2 != '1' : | ||
1491 | 431 | spacer = '' | ||
1492 | 432 | if len(words) > 0: spacer = u' ' | ||
1493 | 433 | if language == 'lv_LV' or language == 'en_US': | ||
1494 | 434 | if int(digit3) > 0: | ||
1495 | 435 | words += spacer + skaitli[int(digit3)] | ||
1496 | 436 | elif language == 'ru_RU': | ||
1497 | 437 | if chunknr == 1: | ||
1498 | 438 | if int(digit3) == 1: | ||
1499 | 439 | words += spacer + u'одна' | ||
1500 | 440 | elif int(digit3) == 2: | ||
1501 | 441 | words += spacer + u'две' | ||
1502 | 442 | elif int(digit3) >= 3 and int(digit3) != 0: | ||
1503 | 443 | words += spacer + skaitli[int(digit3)] | ||
1504 | 444 | else: | ||
1505 | 445 | if int(digit3) > 0: words += spacer + skaitli[int(digit3)] | ||
1506 | 446 | elif language == 'uk_UA' : | ||
1507 | 447 | if chunknr == 1 : | ||
1508 | 448 | if int(digit3) == 1 : words += spacer + u'одна' | ||
1509 | 449 | elif int(digit3) == 2 : words += spacer + u'дві' | ||
1510 | 450 | elif int(digit3) >= 3 and int(digit3) != 0: words += spacer + skaitli[int(digit3)] | ||
1511 | 451 | else: | ||
1512 | 452 | if int(digit3) > 0 : words += spacer + skaitli[int(digit3)] | ||
1513 | 453 | # end processing | ||
1514 | 454 | if len(words) > 0 : | ||
1515 | 455 | |||
1516 | 456 | if digit3 == '1' and chunknr > 0: | ||
1517 | 457 | return words + daudzums[chunknr] | ||
1518 | 458 | elif digit3 != '1' and chunknr > 0: | ||
1519 | 459 | if language == 'lv_LV' or language == 'en_US' : | ||
1520 | 460 | return words + daudzumsx[chunknr] | ||
1521 | 461 | elif language == 'ru_RU' : | ||
1522 | 462 | if (int(digit3) == 2 or int(digit3) == 3 or int(digit3) == 4) and digit2 != '1' : | ||
1523 | 463 | if chunknr == 1 : | ||
1524 | 464 | return words + u' тысячи' | ||
1525 | 465 | elif chunknr == 2 : | ||
1526 | 466 | return words + u' миллионa' | ||
1527 | 467 | elif chunknr == 3 : | ||
1528 | 468 | return words + u' миллиардa' | ||
1529 | 469 | else: | ||
1530 | 470 | return words + daudzumsx[chunknr] | ||
1531 | 471 | elif language == 'uk_UA' : | ||
1532 | 472 | if (int(digit3) == 2 or int(digit3) == 3 or int(digit3) == 4) and digit2 != '1' : | ||
1533 | 473 | if chunknr == 1 : | ||
1534 | 474 | return words + u' тисячі' | ||
1535 | 475 | elif chunknr == 2 : | ||
1536 | 476 | return words + u' мілліонa' | ||
1537 | 477 | elif chunknr == 3 : | ||
1538 | 478 | return words + u' мілліардa' | ||
1539 | 479 | else: | ||
1540 | 480 | return words + daudzumsx[chunknr] | ||
1541 | 481 | else: | ||
1542 | 482 | return words | ||
1543 | 483 | else: | ||
1544 | 484 | return '' | ||
1545 | 485 | |||
1546 | 486 | |||
1547 | 487 | if __name__ == '__main__': | ||
1548 | 488 | import doctest | ||
1549 | 489 | doctest.testmod() | ||
1550 | 490 | |||
1551 | 0 | 491 | ||
1552 | === added directory 'data' | |||
1553 | === added file 'data/report_aeroo_data.xml' | |||
1554 | --- data/report_aeroo_data.xml 1970-01-01 00:00:00 +0000 | |||
1555 | +++ data/report_aeroo_data.xml 2012-07-05 12:25:24 +0000 | |||
1556 | @@ -0,0 +1,25 @@ | |||
1557 | 1 | <?xml version="1.0"?> | ||
1558 | 2 | <openerp> | ||
1559 | 3 | <data noupdate="1"> | ||
1560 | 4 | |||
1561 | 5 | <record model="report.mimetypes" id="report_mimetypes_odt_odt" > | ||
1562 | 6 | <field name="name">ODF Text Document (.odt)</field> | ||
1563 | 7 | <field name="code">oo-odt</field> | ||
1564 | 8 | <field name="compatible_types">oo-odt</field> | ||
1565 | 9 | </record> | ||
1566 | 10 | |||
1567 | 11 | <record model="report.mimetypes" id="report_mimetypes_ods_ods" > | ||
1568 | 12 | <field name="name">ODF Spreadsheet (.ods)</field> | ||
1569 | 13 | <field name="code">oo-ods</field> | ||
1570 | 14 | <field name="compatible_types">oo-ods</field> | ||
1571 | 15 | </record> | ||
1572 | 16 | |||
1573 | 17 | <record model="report.mimetypes" id="report_mimetypes_raw" > | ||
1574 | 18 | <field name="name">Generic</field> | ||
1575 | 19 | <field name="code">genshi-raw</field> | ||
1576 | 20 | <field name="compatible_types">genshi-raw</field> | ||
1577 | 21 | </record> | ||
1578 | 22 | |||
1579 | 23 | </data> | ||
1580 | 24 | </openerp> | ||
1581 | 25 | |||
1582 | 0 | 26 | ||
1583 | === added file 'domain_parser.py' | |||
1584 | --- domain_parser.py 1970-01-01 00:00:00 +0000 | |||
1585 | +++ domain_parser.py 2012-07-05 12:25:24 +0000 | |||
1586 | @@ -0,0 +1,45 @@ | |||
1587 | 1 | ############################################################################## | ||
1588 | 2 | # | ||
1589 | 3 | # Copyright (c) 2009 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
1590 | 4 | # General contacts <info@kndati.lv> | ||
1591 | 5 | # | ||
1592 | 6 | # WARNING: This program as such is intended to be used by professional | ||
1593 | 7 | # programmers who take the whole responsability of assessing all potential | ||
1594 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
1595 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
1596 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
1597 | 11 | # Service Company | ||
1598 | 12 | # | ||
1599 | 13 | # This program is Free Software; you can redistribute it and/or | ||
1600 | 14 | # modify it under the terms of the GNU General Public License | ||
1601 | 15 | # as published by the Free Software Foundation; either version 2 | ||
1602 | 16 | # of the License, or (at your option) any later version. | ||
1603 | 17 | # | ||
1604 | 18 | # This program is distributed in the hope that it will be useful, | ||
1605 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1606 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1607 | 21 | # GNU General Public License for more details. | ||
1608 | 22 | # | ||
1609 | 23 | # You should have received a copy of the GNU General Public License | ||
1610 | 24 | # along with this program; if not, write to the Free Software | ||
1611 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
1612 | 26 | # | ||
1613 | 27 | ############################################################################## | ||
1614 | 28 | |||
1615 | 29 | def domain2statement(domain): | ||
1616 | 30 | statement='' | ||
1617 | 31 | operator=False | ||
1618 | 32 | for d in domain: | ||
1619 | 33 | if not operator: | ||
1620 | 34 | if type(d)==str: | ||
1621 | 35 | if d=='|': | ||
1622 | 36 | operator=' or' | ||
1623 | 37 | continue | ||
1624 | 38 | else: | ||
1625 | 39 | operator=False | ||
1626 | 40 | statement+=' o.'+str(d[0])+' '+(d[1]=='=' and '==' or d[1])+' '+(isinstance(d[2], str) and '\''+d[2]+'\'' or str(d[2])) | ||
1627 | 41 | if d!=domain[-1]: | ||
1628 | 42 | statement+=operator or ' and' | ||
1629 | 43 | operator=False | ||
1630 | 44 | return statement | ||
1631 | 45 | |||
1632 | 0 | 46 | ||
1633 | === added file 'report_aeroo.py' | |||
1634 | --- report_aeroo.py 1970-01-01 00:00:00 +0000 | |||
1635 | +++ report_aeroo.py 2012-07-05 12:25:24 +0000 | |||
1636 | @@ -0,0 +1,636 @@ | |||
1637 | 1 | # -*- encoding: utf-8 -*- | ||
1638 | 2 | |||
1639 | 3 | ############################################################################## | ||
1640 | 4 | # | ||
1641 | 5 | # Copyright (c) 2009-2010 KN dati, SIA. (http://kndati.lv) All Rights Reserved. | ||
1642 | 6 | # General contacts <info@kndati.lv> | ||
1643 | 7 | # Copyright (C) 2009 Domsense s.r.l. | ||
1644 | 8 | # | ||
1645 | 9 | # WARNING: This program as such is intended to be used by professional | ||
1646 | 10 | # programmers who take the whole responsability of assessing all potential | ||
1647 | 11 | # consequences resulting from its eventual inadequacies and bugs | ||
1648 | 12 | # End users who are looking for a ready-to-use solution with commercial | ||
1649 | 13 | # garantees and support are strongly adviced to contract a Free Software | ||
1650 | 14 | # Service Company | ||
1651 | 15 | # | ||
1652 | 16 | # This program is Free Software; you can redistribute it and/or | ||
1653 | 17 | # modify it under the terms of the GNU General Public License | ||
1654 | 18 | # as published by the Free Software Foundation; either version 2 | ||
1655 | 19 | # of the License, or (at your option) any later version. | ||
1656 | 20 | # | ||
1657 | 21 | # This program is distributed in the hope that it will be useful, | ||
1658 | 22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1659 | 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1660 | 24 | # GNU General Public License for more details. | ||
1661 | 25 | # | ||
1662 | 26 | # You should have received a copy of the GNU General Public License | ||
1663 | 27 | # along with this program; if not, write to the Free Software | ||
1664 | 28 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
1665 | 29 | # | ||
1666 | 30 | ############################################################################## | ||
1667 | 31 | |||
1668 | 32 | import os, sys, traceback | ||
1669 | 33 | import tempfile | ||
1670 | 34 | import report | ||
1671 | 35 | from report.report_sxw import * | ||
1672 | 36 | #import zipfile | ||
1673 | 37 | try: | ||
1674 | 38 | from cStringIO import StringIO | ||
1675 | 39 | except ImportError: | ||
1676 | 40 | from StringIO import StringIO | ||
1677 | 41 | from xml.dom import minidom | ||
1678 | 42 | import base64 | ||
1679 | 43 | from osv import osv | ||
1680 | 44 | from tools.translate import _ | ||
1681 | 45 | import time | ||
1682 | 46 | import re | ||
1683 | 47 | import copy | ||
1684 | 48 | |||
1685 | 49 | from addons import load_information_from_description_file | ||
1686 | 50 | import release | ||
1687 | 51 | |||
1688 | 52 | import aeroolib | ||
1689 | 53 | from aeroolib.plugins.opendocument import Template, OOSerializer | ||
1690 | 54 | from genshi.template import NewTextTemplate | ||
1691 | 55 | import pooler | ||
1692 | 56 | import netsvc | ||
1693 | 57 | logger = netsvc.Logger() | ||
1694 | 58 | |||
1695 | 59 | from ExtraFunctions import ExtraFunctions | ||
1696 | 60 | |||
1697 | 61 | class Counter(object): | ||
1698 | 62 | def __init__(self, name, start=0, interval=1): | ||
1699 | 63 | self.name = name | ||
1700 | 64 | self._number = start | ||
1701 | 65 | self._interval = interval | ||
1702 | 66 | |||
1703 | 67 | def next(self): | ||
1704 | 68 | curr_number = self._number | ||
1705 | 69 | self._number += self._interval | ||
1706 | 70 | return curr_number | ||
1707 | 71 | |||
1708 | 72 | def get_inc(self): | ||
1709 | 73 | return self._number | ||
1710 | 74 | |||
1711 | 75 | def prev(self): | ||
1712 | 76 | return self._number-self._interval | ||
1713 | 77 | |||
1714 | 78 | class Aeroo_report(report_sxw): | ||
1715 | 79 | |||
1716 | 80 | def logger(self, message, level=netsvc.LOG_DEBUG): | ||
1717 | 81 | netsvc.Logger().notifyChannel('report_aeroo', level, message) | ||
1718 | 82 | |||
1719 | 83 | def __init__(self, cr, name, table, rml=False, parser=False, header=True, store=False): | ||
1720 | 84 | super(Aeroo_report, self).__init__(name, table, rml, parser, header, store) | ||
1721 | 85 | self.logger("registering %s (%s)" % (name, table), netsvc.LOG_INFO) | ||
1722 | 86 | self.oo_subreports = [] | ||
1723 | 87 | self.epl_images = [] | ||
1724 | 88 | self.counters = {} | ||
1725 | 89 | |||
1726 | 90 | pool = pooler.get_pool(cr.dbname) | ||
1727 | 91 | ir_obj = pool.get('ir.actions.report.xml') | ||
1728 | 92 | report_xml_ids = ir_obj.search(cr, 1, [('report_name', '=', name[7:])]) | ||
1729 | 93 | if report_xml_ids: | ||
1730 | 94 | report_xml = ir_obj.browse(cr, 1, report_xml_ids[0]) | ||
1731 | 95 | |||
1732 | 96 | if report_xml.preload_mode == 'preload': | ||
1733 | 97 | file_data = report_xml.report_sxw_content | ||
1734 | 98 | if not file_data: | ||
1735 | 99 | self.logger("template is not defined in %s (%s) !" % (name, table), netsvc.LOG_WARNING) | ||
1736 | 100 | template_io = None | ||
1737 | 101 | else: | ||
1738 | 102 | template_io = StringIO() | ||
1739 | 103 | template_io.write(base64.decodestring(file_data)) | ||
1740 | 104 | style_io=self.get_styles_file(cr, 1, report_xml) | ||
1741 | 105 | if template_io: | ||
1742 | 106 | self.serializer = OOSerializer(template_io, oo_styles=style_io) | ||
1743 | 107 | |||
1744 | 108 | ##### Counter functions ##### | ||
1745 | 109 | def _def_inc(self, name, start=0, interval=1): | ||
1746 | 110 | self.counters[name] = Counter(name, start, interval) | ||
1747 | 111 | |||
1748 | 112 | def _get_inc(self, name): | ||
1749 | 113 | return self.counters[name].get_inc() | ||
1750 | 114 | |||
1751 | 115 | def _prev(self, name): | ||
1752 | 116 | return self.counters[name].prev() | ||
1753 | 117 | |||
1754 | 118 | def _next(self, name): | ||
1755 | 119 | return self.counters[name].next() | ||
1756 | 120 | ############################# | ||
1757 | 121 | |||
1758 | 122 | def _epl_asimage(self, data): | ||
1759 | 123 | from PIL import Image | ||
1760 | 124 | from math import ceil | ||
1761 | 125 | if not data: | ||
1762 | 126 | return '' | ||
1763 | 127 | img = Image.open(StringIO(base64.decodestring(data))) | ||
1764 | 128 | if img.format!='BMP': | ||
1765 | 129 | return '' | ||
1766 | 130 | data = base64.decodestring(data)[62:] | ||
1767 | 131 | line_len = int(ceil(img.size[0]/32.0)*4) | ||
1768 | 132 | temp_data = '' | ||
1769 | 133 | for n in range(img.size[1]): | ||
1770 | 134 | curr_pos = n*line_len | ||
1771 | 135 | temp_data = data[curr_pos:curr_pos+line_len][:int(img.size[0]/8)] + temp_data | ||
1772 | 136 | |||
1773 | 137 | new_data = '' | ||
1774 | 138 | for d in temp_data: | ||
1775 | 139 | new_data += chr(ord(d)^255) | ||
1776 | 140 | self.epl_images.append(new_data) | ||
1777 | 141 | return img.size | ||
1778 | 142 | |||
1779 | 143 | def _epl2_gw(self, start_x, start_y, data): | ||
1780 | 144 | if not data: | ||
1781 | 145 | return None | ||
1782 | 146 | size_x, size_y = self._epl_asimage(data) | ||
1783 | 147 | return 'GW'+str(start_x)+','+str(start_y)+','+str(int(size_x/8))+','+str(size_y)+',<binary_data>' | ||
1784 | 148 | |||
1785 | 149 | def _include_document(self, aeroo_ooo=False): | ||
1786 | 150 | def include_document(data, silent=False): | ||
1787 | 151 | if not aeroo_ooo: | ||
1788 | 152 | return _("Error! Include document not available!") | ||
1789 | 153 | import binascii, urllib2 | ||
1790 | 154 | dummy_fd, temp_file_name = tempfile.mkstemp(suffix='.odt', prefix='aeroo-report-') | ||
1791 | 155 | temp_file = open(temp_file_name, 'wb') | ||
1792 | 156 | if os.path.isfile(data): | ||
1793 | 157 | fd = file(data, 'rb') | ||
1794 | 158 | data = fd.read() | ||
1795 | 159 | else: | ||
1796 | 160 | error = False | ||
1797 | 161 | try: | ||
1798 | 162 | url_file = urllib2.urlopen(data) | ||
1799 | 163 | data = url_file.read() | ||
1800 | 164 | except urllib2.HTTPError: | ||
1801 | 165 | os.unlink(temp_file_name) | ||
1802 | 166 | error = _('HTTP Error 404! Not file found:')+' %s' % data | ||
1803 | 167 | except urllib2.URLError, e: | ||
1804 | 168 | os.unlink(temp_file_name) | ||
1805 | 169 | error = _('Error!')+' %s' % e | ||
1806 | 170 | except IOError, e: | ||
1807 | 171 | os.unlink(temp_file_name) | ||
1808 | 172 | error = _('Error!')+' %s' % e | ||
1809 | 173 | except Exception, e: | ||
1810 | 174 | try: | ||
1811 | 175 | data = base64.decodestring(data) | ||
1812 | 176 | except binascii.Error: | ||
1813 | 177 | os.unlink(temp_file_name) | ||
1814 | 178 | error = _('Error! Not file found:')+' %s' % data | ||
1815 | 179 | if error: | ||
1816 | 180 | if not silent: | ||
1817 | 181 | return error | ||
1818 | 182 | else: | ||
1819 | 183 | return None | ||
1820 | 184 | try: | ||
1821 | 185 | temp_file.write(data) | ||
1822 | 186 | finally: | ||
1823 | 187 | temp_file.close() | ||
1824 | 188 | self.oo_subreports.append(temp_file_name) | ||
1825 | 189 | return "<insert_doc('%s')>" % temp_file_name | ||
1826 | 190 | return include_document | ||
1827 | 191 | |||
1828 | 192 | def _subreport(self, cr, uid, output='odt', aeroo_ooo=False, context={}): | ||
1829 | 193 | pool = pooler.get_pool(cr.dbname) | ||
1830 | 194 | ir_obj = pool.get('ir.actions.report.xml') | ||
1831 | 195 | #### for odt documents #### | ||
1832 | 196 | def odt_subreport(name=None, obj=None): | ||
1833 | 197 | if not aeroo_ooo: | ||
1834 | 198 | return _("Error! Subreports not available!") | ||
1835 | 199 | report_xml_ids = ir_obj.search(cr, uid, [('report_name', '=', name)], context=context) | ||
1836 | 200 | if report_xml_ids: | ||
1837 | 201 | report_xml = ir_obj.browse(cr, uid, report_xml_ids[0], context=context) | ||
1838 | 202 | data = {'model': obj._table_name, 'id': obj.id, 'report_type': 'aeroo', 'in_format': 'oo-odt'} | ||
1839 | 203 | report, output = netsvc.Service._services['report.%s' % name].create_aeroo_report(cr, uid, \ | ||
1840 | 204 | [obj.id], data, report_xml, context=context, output='odt') # change for OpenERP 6.0 - Service class usage | ||
1841 | 205 | |||
1842 | 206 | dummy_fd, temp_file_name = tempfile.mkstemp(suffix='.odt', prefix='aeroo-report-') | ||
1843 | 207 | temp_file = open(temp_file_name, 'wb') | ||
1844 | 208 | try: | ||
1845 | 209 | temp_file.write(report) | ||
1846 | 210 | finally: | ||
1847 | 211 | temp_file.close() | ||
1848 | 212 | |||
1849 | 213 | self.oo_subreports.append(temp_file_name) | ||
1850 | 214 | |||
1851 | 215 | return "<insert_doc('%s')>" % temp_file_name | ||
1852 | 216 | return None | ||
1853 | 217 | #### for text documents #### | ||
1854 | 218 | def raw_subreport(name=None, obj=None): | ||
1855 | 219 | report_xml_ids = ir_obj.search(cr, uid, [('report_name', '=', name)], context=context) | ||
1856 | 220 | if report_xml_ids: | ||
1857 | 221 | report_xml = ir_obj.browse(cr, uid, report_xml_ids[0], context=context) | ||
1858 | 222 | data = {'model': obj._table_name, 'id': obj.id, 'report_type': 'aeroo', 'in_format': 'genshi-raw'} | ||
1859 | 223 | report, output = netsvc.Service._services['report.%s' % name].create_genshi_raw_report(cr, uid, \ | ||
1860 | 224 | [obj.id], data, report_xml, context=context, output=output) # change for OpenERP 6.0 - Service class usage | ||
1861 | 225 | return report | ||
1862 | 226 | return None | ||
1863 | 227 | |||
1864 | 228 | if output=='odt': | ||
1865 | 229 | return odt_subreport | ||
1866 | 230 | elif output=='raw': | ||
1867 | 231 | return raw_subreport | ||
1868 | 232 | |||
1869 | 233 | def set_xml_data_fields(self, objects, parser): | ||
1870 | 234 | xml_data_fields = parser.localcontext.get('xml_data_fields', False) | ||
1871 | 235 | if xml_data_fields: | ||
1872 | 236 | for field in xml_data_fields: | ||
1873 | 237 | for o in objects: | ||
1874 | 238 | if getattr(o, field): | ||
1875 | 239 | xml_data = base64.decodestring(getattr(o, field)) | ||
1876 | 240 | xmldoc = minidom.parseString(xml_data) | ||
1877 | 241 | setattr(o, field, xmldoc.firstChild) | ||
1878 | 242 | return objects | ||
1879 | 243 | |||
1880 | 244 | def get_other_template(self, cr, uid, data, parser): | ||
1881 | 245 | if hasattr(parser, 'get_template'): | ||
1882 | 246 | pool = pooler.get_pool(cr.dbname) | ||
1883 | 247 | record = pool.get(data['model']).browse(cr, uid, data['id'], {}) | ||
1884 | 248 | template = parser.get_template(cr, uid, record) | ||
1885 | 249 | return template | ||
1886 | 250 | else: | ||
1887 | 251 | return False | ||
1888 | 252 | |||
1889 | 253 | def get_styles_file(self, cr, uid, report_xml, context=None): | ||
1890 | 254 | pool = pooler.get_pool(cr.dbname) | ||
1891 | 255 | style_io=None | ||
1892 | 256 | if report_xml.styles_mode!='default': | ||
1893 | 257 | if report_xml.styles_mode=='global': | ||
1894 | 258 | company_id = pool.get('res.users')._get_company(cr, uid, context=context) | ||
1895 | 259 | style_content = pool.get('res.company').browse(cr, uid, company_id, context=context).stylesheet_id | ||
1896 | 260 | style_content = style_content and style_content.report_styles or False | ||
1897 | 261 | elif report_xml.styles_mode=='specified': | ||
1898 | 262 | style_content = report_xml.stylesheet_id | ||
1899 | 263 | style_content = style_content and style_content.report_styles or False | ||
1900 | 264 | if style_content: | ||
1901 | 265 | style_io = StringIO() | ||
1902 | 266 | style_io.write(base64.decodestring(style_content)) | ||
1903 | 267 | return style_io | ||
1904 | 268 | |||
1905 | 269 | def create_genshi_raw_report(self, cr, uid, ids, data, report_xml, context=None, output='raw'): | ||
1906 | 270 | def preprocess(data): | ||
1907 | 271 | self.epl_images.reverse() | ||
1908 | 272 | while self.epl_images: | ||
1909 | 273 | img = self.epl_images.pop() | ||
1910 | 274 | data = data.replace('<binary_data>', img, 1) | ||
1911 | 275 | return data.replace('\n', '\r\n') | ||
1912 | 276 | |||
1913 | 277 | if not context: | ||
1914 | 278 | context={} | ||
1915 | 279 | context = context.copy() | ||
1916 | 280 | objects = self.getObjects(cr, uid, ids, context) | ||
1917 | 281 | oo_parser = self.parser(cr, uid, self.name2, context=context) | ||
1918 | 282 | oo_parser.objects = objects | ||
1919 | 283 | self.set_xml_data_fields(objects, oo_parser) # Get/Set XML | ||
1920 | 284 | file_data = self.get_other_template(cr, uid, data, oo_parser) or report_xml.report_sxw_content # Get other Tamplate | ||
1921 | 285 | ################################################ | ||
1922 | 286 | if not file_data: | ||
1923 | 287 | return False, output | ||
1924 | 288 | |||
1925 | 289 | oo_parser.localcontext['objects'] = objects | ||
1926 | 290 | oo_parser.localcontext['data'] = data | ||
1927 | 291 | oo_parser.localcontext['user_lang'] = context['lang'] | ||
1928 | 292 | if len(objects)>0: | ||
1929 | 293 | oo_parser.localcontext['o'] = objects[0] | ||
1930 | 294 | xfunc = ExtraFunctions(cr, uid, report_xml.id, oo_parser.localcontext) | ||
1931 | 295 | oo_parser.localcontext.update(xfunc.functions) | ||
1932 | 296 | oo_parser.localcontext['include_subreport'] = self._subreport(cr, uid, output='raw', aeroo_ooo=False, context=context) | ||
1933 | 297 | oo_parser.localcontext['epl2_gw'] = self._epl2_gw | ||
1934 | 298 | |||
1935 | 299 | self.epl_images = [] | ||
1936 | 300 | basic = NewTextTemplate(source=file_data) | ||
1937 | 301 | #try: | ||
1938 | 302 | data = preprocess(basic.generate(**oo_parser.localcontext).render().decode('utf8').encode(report_xml.charset)) | ||
1939 | 303 | #except Exception, e: | ||
1940 | 304 | # self.logger(str(e), netsvc.LOG_ERROR) | ||
1941 | 305 | # return False, output | ||
1942 | 306 | |||
1943 | 307 | if report_xml.content_fname: | ||
1944 | 308 | output = report_xml.content_fname | ||
1945 | 309 | return data, output | ||
1946 | 310 | |||
1947 | 311 | def create_aeroo_report(self, cr, uid, ids, data, report_xml, context=None, output='odt'): | ||
1948 | 312 | """ Returns an aeroo report generated with aeroolib | ||
1949 | 313 | """ | ||
1950 | 314 | pool = pooler.get_pool(cr.dbname) | ||
1951 | 315 | if not context: | ||
1952 | 316 | context={} | ||
1953 | 317 | context = context.copy() | ||
1954 | 318 | if self.name=='report.printscreen.list': | ||
1955 | 319 | context['model'] = data['model'] | ||
1956 | 320 | context['ids'] = ids | ||
1957 | 321 | |||
1958 | 322 | objects = not context.get('no_objects', False) and self.getObjects(cr, uid, ids, context) or [] | ||
1959 | 323 | oo_parser = self.parser(cr, uid, self.name2, context=context) | ||
1960 | 324 | |||
1961 | 325 | oo_parser.objects = objects | ||
1962 | 326 | self.set_xml_data_fields(objects, oo_parser) # Get/Set XML | ||
1963 | 327 | |||
1964 | 328 | style_io=self.get_styles_file(cr, uid, report_xml, context) | ||
1965 | 329 | if report_xml.tml_source in ('file', 'database'): | ||
1966 | 330 | file_data = base64.decodestring(report_xml.report_sxw_content) | ||
1967 | 331 | else: | ||
1968 | 332 | file_data = self.get_other_template(cr, uid, data, oo_parser) | ||
1969 | 333 | if not file_data and not report_xml.report_sxw_content: | ||
1970 | 334 | return False, output | ||
1971 | 335 | #elif file_data: | ||
1972 | 336 | # template_io = StringIO() | ||
1973 | 337 | # template_io.write(file_data or report_xml.report_sxw_content) | ||
1974 | 338 | # basic = Template(source=template_io, styles=style_io) | ||
1975 | 339 | else: | ||
1976 | 340 | if report_xml.preload_mode == 'preload' and hasattr(self, 'serializer'): | ||
1977 | 341 | serializer = copy.copy(self.serializer) | ||
1978 | 342 | serializer.apply_style(style_io) | ||
1979 | 343 | template_io = serializer.template | ||
1980 | 344 | else: | ||
1981 | 345 | template_io = StringIO() | ||
1982 | 346 | template_io.write(file_data or base64.decodestring(report_xml.report_sxw_content) ) | ||
1983 | 347 | serializer = OOSerializer(template_io, oo_styles=style_io) | ||
1984 | 348 | basic = Template(source=template_io, serializer=serializer) | ||
1985 | 349 | |||
1986 | 350 | #if not file_data: | ||
1987 | 351 | # return False, output | ||
1988 | 352 | |||
1989 | 353 | #basic = Template(source=template_io, serializer=serializer) | ||
1990 | 354 | |||
1991 | 355 | oo_parser.localcontext['objects'] = objects | ||
1992 | 356 | oo_parser.localcontext['data'] = data | ||
1993 | 357 | oo_parser.localcontext['user_lang'] = context['lang'] | ||
1994 | 358 | if len(objects)==1: | ||
1995 | 359 | oo_parser.localcontext['o'] = objects[0] | ||
1996 | 360 | xfunc = ExtraFunctions(cr, uid, report_xml.id, oo_parser.localcontext) | ||
1997 | 361 | oo_parser.localcontext.update(xfunc.functions) | ||
1998 | 362 | |||
1999 | 363 | ###### Detect report_aeroo_ooo module ###### | ||
2000 | 364 | aeroo_ooo = False | ||
2001 | 365 | cr.execute("SELECT id, state FROM ir_module_module WHERE name='report_aeroo_ooo'") | ||
2002 | 366 | helper_module = cr.dictfetchone() | ||
2003 | 367 | if helper_module['state'] in ('installed', 'to upgrade'): | ||
2004 | 368 | aeroo_ooo = True | ||
2005 | 369 | ############################################ | ||
2006 | 370 | |||
2007 | 371 | oo_parser.localcontext['include_subreport'] = self._subreport(cr, uid, output='odt', aeroo_ooo=aeroo_ooo, context=context) | ||
2008 | 372 | oo_parser.localcontext['include_document'] = self._include_document(aeroo_ooo) | ||
2009 | 373 | |||
2010 | 374 | ####### Add counter functons to localcontext ####### | ||
2011 | 375 | oo_parser.localcontext.update({'def_inc':self._def_inc, | ||
2012 | 376 | 'get_inc':self._get_inc, | ||
2013 | 377 | 'prev':self._prev, | ||
2014 | 378 | 'next':self._next}) | ||
2015 | 379 | |||
2016 | 380 | user_name = pool.get('res.users').browse(cr, uid, uid, {}).name | ||
2017 | 381 | model_id = pool.get('ir.model').search(cr, uid, [('model','=',data['model'])])[0] | ||
2018 | 382 | model_name = pool.get('ir.model').browse(cr, uid, model_id).name | ||
2019 | 383 | |||
2020 | 384 | #basic = Template(source=None, filepath=odt_path) | ||
2021 | 385 | |||
2022 | 386 | basic.Serializer.add_title(model_name) | ||
2023 | 387 | basic.Serializer.add_creation_user(user_name) | ||
2024 | 388 | version = load_information_from_description_file('report_aeroo')['version'] | ||
2025 | 389 | basic.Serializer.add_generator_info('Aeroo Lib/%s Aeroo Reports/%s' % (aeroolib.__version__, version)) | ||
2026 | 390 | basic.Serializer.add_custom_property('Aeroo Reports %s' % version, 'Generator') | ||
2027 | 391 | basic.Serializer.add_custom_property('OpenERP %s' % release.version, 'Software') | ||
2028 | 392 | basic.Serializer.add_custom_property('http://www.alistek.com/', 'URL') | ||
2029 | 393 | basic.Serializer.add_creation_date(time.strftime('%Y-%m-%dT%H:%M:%S')) | ||
2030 | 394 | |||
2031 | 395 | try: | ||
2032 | 396 | data = basic.generate(**oo_parser.localcontext).render().getvalue() | ||
2033 | 397 | except Exception, e: | ||
2034 | 398 | tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) | ||
2035 | 399 | self.logger(tb_s, netsvc.LOG_ERROR) | ||
2036 | 400 | for sub_report in self.oo_subreports: | ||
2037 | 401 | os.unlink(sub_report) | ||
2038 | 402 | raise Exception(_("Aeroo Reports: Error while generating the report."), e, str(e), _("For more reference inspect error logs.")) | ||
2039 | 403 | #return False, output | ||
2040 | 404 | |||
2041 | 405 | ######### OpenOffice extras ######### | ||
2042 | 406 | DC = netsvc.Service._services.get('openoffice') | ||
2043 | 407 | if (output!=report_xml.in_format[3:] or self.oo_subreports): | ||
2044 | 408 | if aeroo_ooo and DC: | ||
2045 | 409 | try: | ||
2046 | 410 | DC.putDocument(data) | ||
2047 | 411 | if self.oo_subreports: | ||
2048 | 412 | DC.insertSubreports(self.oo_subreports) | ||
2049 | 413 | self.oo_subreports = [] | ||
2050 | 414 | data = DC.saveByStream(report_xml.out_format.filter_name) | ||
2051 | 415 | DC.closeDocument() | ||
2052 | 416 | #del DC | ||
2053 | 417 | except Exception, e: | ||
2054 | 418 | self.logger(str(e), netsvc.LOG_ERROR) | ||
2055 | 419 | output=report_xml.in_format[3:] | ||
2056 | 420 | self.oo_subreports = [] | ||
2057 | 421 | else: | ||
2058 | 422 | output=report_xml.in_format[3:] | ||
2059 | 423 | elif output in ('pdf', 'doc', 'xls'): | ||
2060 | 424 | output=report_xml.in_format[3:] | ||
2061 | 425 | ##################################### | ||
2062 | 426 | |||
2063 | 427 | if report_xml.content_fname: | ||
2064 | 428 | output = report_xml.content_fname | ||
2065 | 429 | return data, output | ||
2066 | 430 | |||
2067 | 431 | # override needed to keep the attachments' storing procedure | ||
2068 | 432 | def create_single_pdf(self, cr, uid, ids, data, report_xml, context=None): | ||
2069 | 433 | if not context: | ||
2070 | 434 | context={} | ||
2071 | 435 | if report_xml.report_type == 'aeroo': | ||
2072 | 436 | if report_xml.out_format.code.startswith('oo-'): | ||
2073 | 437 | output = report_xml.out_format.code[3:] | ||
2074 | 438 | return self.create_aeroo_report(cr, uid, ids, data, report_xml, context=context, output=output) | ||
2075 | 439 | elif report_xml.out_format.code =='genshi-raw': | ||
2076 | 440 | return self.create_genshi_raw_report(cr, uid, ids, data, report_xml, context=context, output='raw') | ||
2077 | 441 | logo = None | ||
2078 | 442 | context = context.copy() | ||
2079 | 443 | title = report_xml.name | ||
2080 | 444 | rml = report_xml.report_rml_content | ||
2081 | 445 | oo_parser = self.parser(cr, uid, self.name2, context=context) | ||
2082 | 446 | objs = self.getObjects(cr, uid, ids, context) | ||
2083 | 447 | oo_parser.set_context(objs, data, ids, report_xml.report_type) | ||
2084 | 448 | processed_rml = self.preprocess_rml(etree.XML(rml),report_xml.report_type) | ||
2085 | 449 | if report_xml.header: | ||
2086 | 450 | oo_parser._add_header(processed_rml) | ||
2087 | 451 | if oo_parser.logo: | ||
2088 | 452 | logo = base64.decodestring(oo_parser.logo) | ||
2089 | 453 | create_doc = self.generators[report_xml.report_type] | ||
2090 | 454 | pdf = create_doc(etree.tostring(processed_rml),oo_parser.localcontext,logo,title.encode('utf8')) | ||
2091 | 455 | return (pdf, report_xml.report_type) | ||
2092 | 456 | |||
2093 | 457 | def create_source_odt(self, cr, uid, ids, data, report_xml, context=None): | ||
2094 | 458 | if not context: | ||
2095 | 459 | context={} | ||
2096 | 460 | pool = pooler.get_pool(cr.dbname) | ||
2097 | 461 | results = [] | ||
2098 | 462 | attach = report_xml.attachment | ||
2099 | 463 | if attach: | ||
2100 | 464 | objs = self.getObjects(cr, uid, ids, context) | ||
2101 | 465 | for obj in objs: | ||
2102 | 466 | aname = eval(attach, {'object':obj, 'time':time}) | ||
2103 | 467 | result = False | ||
2104 | 468 | if report_xml.attachment_use and aname and context.get('attachment_use', True): | ||
2105 | 469 | aids = pool.get('ir.attachment').search(cr, uid, [('datas_fname','=',aname+'.odt'),('res_model','=',self.table),('res_id','=',obj.id)]) | ||
2106 | 470 | if aids: | ||
2107 | 471 | brow_rec = pool.get('ir.attachment').browse(cr, uid, aids[0]) | ||
2108 | 472 | if not brow_rec.datas: | ||
2109 | 473 | continue | ||
2110 | 474 | d = base64.decodestring(brow_rec.datas) | ||
2111 | 475 | results.append((d,'odt')) | ||
2112 | 476 | continue | ||
2113 | 477 | result = self.create_single_pdf(cr, uid, [obj.id], data, report_xml, context) | ||
2114 | 478 | try: | ||
2115 | 479 | if aname: | ||
2116 | 480 | name = aname+'.'+result[1] | ||
2117 | 481 | pool.get('ir.attachment').create(cr, uid, { | ||
2118 | 482 | 'name': aname, | ||
2119 | 483 | 'datas': base64.encodestring(result[0]), | ||
2120 | 484 | 'datas_fname': name, | ||
2121 | 485 | 'res_model': self.table, | ||
2122 | 486 | 'res_id': obj.id, | ||
2123 | 487 | }, context=context | ||
2124 | 488 | ) | ||
2125 | 489 | cr.commit() | ||
2126 | 490 | except Exception,e: | ||
2127 | 491 | self.logger(str(e), netsvc.LOG_ERROR) | ||
2128 | 492 | results.append(result) | ||
2129 | 493 | |||
2130 | 494 | return results and len(results)==1 and results[0] or self.create_single_pdf(cr, uid, ids, data, report_xml, context) | ||
2131 | 495 | |||
2132 | 496 | # override needed to intercept the call to the proper 'create' method | ||
2133 | 497 | def create(self, cr, uid, ids, data, context=None): | ||
2134 | 498 | pool = pooler.get_pool(cr.dbname) | ||
2135 | 499 | ir_obj = pool.get('ir.actions.report.xml') | ||
2136 | 500 | report_xml_ids = ir_obj.search(cr, uid, | ||
2137 | 501 | [('report_name', '=', self.name[7:])], context=context) | ||
2138 | 502 | if report_xml_ids: | ||
2139 | 503 | report_xml = ir_obj.browse(cr, uid, report_xml_ids[0], context=context) | ||
2140 | 504 | report_xml.report_rml = None | ||
2141 | 505 | report_xml.report_rml_content = None | ||
2142 | 506 | report_xml.report_sxw_content_data = None | ||
2143 | 507 | report_rml.report_sxw_content = None | ||
2144 | 508 | report_rml.report_sxw = None | ||
2145 | 509 | else: | ||
2146 | 510 | title = '' | ||
2147 | 511 | rml = tools.file_open(self.tmpl, subdir=None).read() | ||
2148 | 512 | report_type= data.get('report_type', 'pdf') | ||
2149 | 513 | class a(object): | ||
2150 | 514 | def __init__(self, *args, **argv): | ||
2151 | 515 | for key,arg in argv.items(): | ||
2152 | 516 | setattr(self, key, arg) | ||
2153 | 517 | report_xml = a(title=title, report_type=report_type, report_rml_content=rml, name=title, attachment=False, header=self.header) | ||
2154 | 518 | |||
2155 | 519 | report_type = report_xml.report_type | ||
2156 | 520 | if report_type in ['sxw','odt']: | ||
2157 | 521 | fnct = self.create_source_odt | ||
2158 | 522 | elif report_type in ['pdf','raw','txt','html']: | ||
2159 | 523 | fnct = self.create_source_pdf | ||
2160 | 524 | elif report_type=='html2html': | ||
2161 | 525 | fnct = self.create_source_html2html | ||
2162 | 526 | elif report_type=='mako2html': | ||
2163 | 527 | fnct = self.create_source_mako2html | ||
2164 | 528 | elif report_type=='aeroo': | ||
2165 | 529 | if report_xml.out_format.code in ['oo-pdf']: | ||
2166 | 530 | fnct = self.create_source_pdf | ||
2167 | 531 | elif report_xml.out_format.code in ['oo-odt','oo-ods','oo-doc','oo-xls','genshi-raw']: | ||
2168 | 532 | fnct = self.create_source_odt | ||
2169 | 533 | else: | ||
2170 | 534 | return super(Aeroo_report, self).create(cr, uid, ids, data, context) | ||
2171 | 535 | else: | ||
2172 | 536 | raise 'Unknown Report Type' | ||
2173 | 537 | return fnct(cr, uid, ids, data, report_xml, context) | ||
2174 | 538 | |||
2175 | 539 | class ReportTypeException(Exception): | ||
2176 | 540 | def __init__(self, value): | ||
2177 | 541 | self.parameter = value | ||
2178 | 542 | def __str__(self): | ||
2179 | 543 | return repr(self.parameter) | ||
2180 | 544 | |||
2181 | 545 | ######################################################################### | ||
2182 | 546 | |||
2183 | 547 | #import imp, sys | ||
2184 | 548 | #from tools.config import config | ||
2185 | 549 | |||
2186 | 550 | #def load_from_file(path, dbname, key): | ||
2187 | 551 | # class_inst = None | ||
2188 | 552 | # expected_class = 'Parser' | ||
2189 | 553 | |||
2190 | 554 | # try: | ||
2191 | 555 | # if path.find(config['addons_path'])==-1: | ||
2192 | 556 | # filepath=config['addons_path']+os.path.sep+path | ||
2193 | 557 | # filepath = os.path.normpath(filepath) | ||
2194 | 558 | # if not os.path.lexists(filepath): | ||
2195 | 559 | # filepath = os.path.normpath(config['root_path']+os.path.sep+path) | ||
2196 | 560 | # sys.path.append(os.path.dirname(filepath)) | ||
2197 | 561 | # mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) | ||
2198 | 562 | # mod_name = '%s_%s_%s' % (dbname,mod_name,key) | ||
2199 | 563 | |||
2200 | 564 | # if file_ext.lower() == '.py': | ||
2201 | 565 | # py_mod = imp.load_source(mod_name, filepath) | ||
2202 | 566 | |||
2203 | 567 | # elif file_ext.lower() == '.pyc': | ||
2204 | 568 | # py_mod = imp.load_compiled(mod_name, filepath) | ||
2205 | 569 | |||
2206 | 570 | # if expected_class in dir(py_mod): | ||
2207 | 571 | # class_inst = py_mod.Parser | ||
2208 | 572 | # return class_inst | ||
2209 | 573 | # except Exception, e: | ||
2210 | 574 | # return None | ||
2211 | 575 | |||
2212 | 576 | #def load_from_source(source): | ||
2213 | 577 | # expected_class = 'Parser' | ||
2214 | 578 | # context = {'Parser':None} | ||
2215 | 579 | # try: | ||
2216 | 580 | # exec source in context | ||
2217 | 581 | # return context['Parser'] | ||
2218 | 582 | # except Exception, e: | ||
2219 | 583 | # return None | ||
2220 | 584 | |||
2221 | 585 | #def delete_report_service(name): | ||
2222 | 586 | # name = 'report.%s' % name | ||
2223 | 587 | # if netsvc.Service.exists( name ): # change for OpenERP 6.0 - Service class usage | ||
2224 | 588 | # netsvc.Service.remove( name ) # change for OpenERP 6.0 - Service class usage | ||
2225 | 589 | |||
2226 | 590 | #def register_report(cr, name, model, tmpl_path, parser): | ||
2227 | 591 | # name = 'report.%s' % name | ||
2228 | 592 | # if netsvc.Service.exists( name ): # change for OpenERP 6.0 - Service class usage | ||
2229 | 593 | # netsvc.Service.remove( name ) # change for OpenERP 6.0 - Service class usage | ||
2230 | 594 | # Aeroo_report(cr, name, model, tmpl_path, parser=parser) | ||
2231 | 595 | |||
2232 | 596 | #old_register_all = report.interface.register_all | ||
2233 | 597 | #def new_register_all(db): | ||
2234 | 598 | # value = old_register_all(db) | ||
2235 | 599 | |||
2236 | 600 | # cr = db.cursor() | ||
2237 | 601 | |||
2238 | 602 | ########### Run OpenOffice service ########### | ||
2239 | 603 | # try: | ||
2240 | 604 | # from report_aeroo_ooo.report import OpenOffice_service | ||
2241 | 605 | # except Exception, e: | ||
2242 | 606 | # OpenOffice_service = False | ||
2243 | 607 | |||
2244 | 608 | # if OpenOffice_service: | ||
2245 | 609 | # cr.execute("SELECT id, state FROM ir_module_module WHERE name='report_aeroo_ooo'") | ||
2246 | 610 | # helper_module = cr.dictfetchone() | ||
2247 | 611 | # helper_installed = helper_module['state']=='installed' | ||
2248 | 612 | |||
2249 | 613 | # if OpenOffice_service and helper_installed: | ||
2250 | 614 | # cr.execute("SELECT host, port FROM oo_config") | ||
2251 | 615 | # host, port = cr.fetchone() | ||
2252 | 616 | # try: | ||
2253 | 617 | # OpenOffice_service(cr, host, port) | ||
2254 | 618 | # netsvc.Logger().notifyChannel('report_aeroo', netsvc.LOG_INFO, "OpenOffice connection successfully established") | ||
2255 | 619 | # except DocumentConversionException, e: | ||
2256 | 620 | # netsvc.Logger().notifyChannel('report_aeroo', netsvc.LOG_WARNING, e) | ||
2257 | 621 | ############################################## | ||
2258 | 622 | |||
2259 | 623 | # cr.execute("SELECT * FROM ir_act_report_xml WHERE report_type = 'aeroo' ORDER BY id") # change for OpenERP 6.0 | ||
2260 | 624 | # records = cr.dictfetchall() | ||
2261 | 625 | # for record in records: | ||
2262 | 626 | # parser=rml_parse | ||
2263 | 627 | # if record['parser_state']=='loc' and record['parser_loc']: | ||
2264 | 628 | # parser=load_from_file(record['parser_loc'], db.dbname, record['id']) or parser | ||
2265 | 629 | # elif record['parser_state']=='def' and record['parser_def']: | ||
2266 | 630 | # parser=load_from_source("from report import report_sxw\n"+record['parser_def']) or parser | ||
2267 | 631 | # register_report(cr, record['report_name'], record['model'], record['report_rml'], parser) | ||
2268 | 632 | # cr.close() | ||
2269 | 633 | # return value | ||
2270 | 634 | |||
2271 | 635 | #report.interface.register_all = new_register_all | ||
2272 | 636 | |||
2273 | 0 | 637 | ||
2274 | === added file 'report_view.xml' | |||
2275 | --- report_view.xml 1970-01-01 00:00:00 +0000 | |||
2276 | +++ report_view.xml 2012-07-05 12:25:24 +0000 | |||
2277 | @@ -0,0 +1,224 @@ | |||
2278 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
2279 | 2 | <openerp> | ||
2280 | 3 | <data> | ||
2281 | 4 | |||
2282 | 5 | <record model="ir.ui.view" id="act_report_xml_view1"> | ||
2283 | 6 | <field name="name">ir.actions.report.xml.aeroo.form</field> | ||
2284 | 7 | <field name="model">ir.actions.report.xml</field> | ||
2285 | 8 | <field name="priority">14</field> | ||
2286 | 9 | <field name="type">form</field> | ||
2287 | 10 | <field name="arch" type="xml"> | ||
2288 | 11 | <form string="Aeroo Report"> | ||
2289 | 12 | <group col="6" colspan="4"> | ||
2290 | 13 | <field name="name" select="1"/> | ||
2291 | 14 | <field name="model" select="1"/> | ||
2292 | 15 | <field name="type" select="1" invisible="1"/> | ||
2293 | 16 | |||
2294 | 17 | <field name="report_name" select="1"/> | ||
2295 | 18 | <field name="usage"/> | ||
2296 | 19 | <field name="report_type" invisible="1"/> | ||
2297 | 20 | </group> | ||
2298 | 21 | <group col="6" colspan="4"> | ||
2299 | 22 | <field name="in_format" required="1" on_change="change_input_format(in_format)"/> | ||
2300 | 23 | <field name="out_format" required="1" domain="[('compatible_types','=',in_format)]"/> | ||
2301 | 24 | <field name="content_fname"/> | ||
2302 | 25 | </group> | ||
2303 | 26 | |||
2304 | 27 | <notebook colspan="4"> | ||
2305 | 28 | <page string="Other Configuration"> | ||
2306 | 29 | <separator string="Template" colspan="4"/> | ||
2307 | 30 | <group colspan="4" col="8"> | ||
2308 | 31 | <field name="tml_source" colspan="2" required="1"/> | ||
2309 | 32 | <group colspan="6"> | ||
2310 | 33 | <field name="report_sxw_content_data" string="Template Content" attrs="{'invisible': [('tml_source','<>','database')],'required': [('tml_source','=','database')]}"/> | ||
2311 | 34 | <field name="report_rml" string="Template path" attrs="{'invisible': [('tml_source','<>','file')],'required': [('tml_source','=','file')]}"/> | ||
2312 | 35 | </group> | ||
2313 | 36 | </group> | ||
2314 | 37 | <group attrs="{'invisible': [('in_format','=','genshi-raw')]}" colspan="4"> | ||
2315 | 38 | <separator string="Stylesheet" colspan="4"/> | ||
2316 | 39 | <group colspan="4" col="8"> | ||
2317 | 40 | <field name="styles_mode" colspan="2"/> | ||
2318 | 41 | <group colspan="6"> | ||
2319 | 42 | <field name="stylesheet_id" attrs="{'invisible': [('styles_mode','<>','specified')]}"/> | ||
2320 | 43 | </group> | ||
2321 | 44 | </group> | ||
2322 | 45 | </group> | ||
2323 | 46 | <group attrs="{'invisible': [('in_format','<>','genshi-raw')]}" colspan="4" col="8"> | ||
2324 | 47 | <field name="charset" colspan="2"/> | ||
2325 | 48 | <separator colspan="2"/> | ||
2326 | 49 | </group> | ||
2327 | 50 | <group col="2" colspan="2"> | ||
2328 | 51 | <separator string="Attachments" colspan="2"/> | ||
2329 | 52 | <group colspan="2"> | ||
2330 | 53 | <group colspan="2"> | ||
2331 | 54 | <field name="attachment"/> | ||
2332 | 55 | </group> | ||
2333 | 56 | </group> | ||
2334 | 57 | <field name="attachment_use" colspan="2"/> | ||
2335 | 58 | </group> | ||
2336 | 59 | <group col="2" colspan="2"> | ||
2337 | 60 | <separator string="Miscellaneous" colspan="2"/> | ||
2338 | 61 | <field name="preload_mode" attrs="{'invisible': [('in_format','=','genshi-raw'),('tml_source','=','parser')]}"/> | ||
2339 | 62 | <field name="multi" colspan="2"/> | ||
2340 | 63 | </group> | ||
2341 | 64 | </page> | ||
2342 | 65 | <page string="Parser"> | ||
2343 | 66 | <group colspan="2"> | ||
2344 | 67 | <field name="parser_state"/> | ||
2345 | 68 | </group> | ||
2346 | 69 | <group attrs="{'invisible': [('parser_state','<>','def')]}" colspan="4" expand="1"> | ||
2347 | 70 | <separator string="Parser Definition" colspan="4"/> | ||
2348 | 71 | <field name="parser_def" nolabel="1"/> | ||
2349 | 72 | </group> | ||
2350 | 73 | <field name="parser_loc" attrs="{'invisible': [('parser_state','<>','loc')],'required': [('parser_state','=','loc')]}"/> | ||
2351 | 74 | </page> | ||
2352 | 75 | <page string="Security"> | ||
2353 | 76 | <separator string="Groups" colspan="4"/> | ||
2354 | 77 | <field colspan="4" name="groups_id" nolabel="1"/> | ||
2355 | 78 | </page> | ||
2356 | 79 | </notebook> | ||
2357 | 80 | |||
2358 | 81 | </form> | ||
2359 | 82 | </field> | ||
2360 | 83 | </record> | ||
2361 | 84 | |||
2362 | 85 | <record id="act_aeroo_report_xml_view_tree" model="ir.ui.view"> | ||
2363 | 86 | <field name="name">ir.actions.report.xml.tree</field> | ||
2364 | 87 | <field name="model">ir.actions.report.xml</field> | ||
2365 | 88 | <field name="type">tree</field> | ||
2366 | 89 | <field name="arch" type="xml"> | ||
2367 | 90 | <tree string="Report xml"> | ||
2368 | 91 | <field name="name"/> | ||
2369 | 92 | <field name="model"/> | ||
2370 | 93 | <field name="report_name"/> | ||
2371 | 94 | <field name="in_format"/> | ||
2372 | 95 | <field name="out_format"/> | ||
2373 | 96 | <field name="tml_source"/> | ||
2374 | 97 | </tree> | ||
2375 | 98 | </field> | ||
2376 | 99 | </record> | ||
2377 | 100 | |||
2378 | 101 | <record id="act_aeroo_report_xml_search_view" model="ir.ui.view"> | ||
2379 | 102 | <field name="name">ir.actions.report.xml.search</field> | ||
2380 | 103 | <field name="model">ir.actions.report.xml</field> | ||
2381 | 104 | <field name="type">search</field> | ||
2382 | 105 | <field name="arch" type="xml"> | ||
2383 | 106 | <search string="Report xml"> | ||
2384 | 107 | <group col="10" colspan="4"> | ||
2385 | 108 | <field name="name"/> | ||
2386 | 109 | <field name="model"/> | ||
2387 | 110 | <field name="type"/> | ||
2388 | 111 | <field name="in_format"/> | ||
2389 | 112 | <field name="out_format"/> | ||
2390 | 113 | </group> | ||
2391 | 114 | <newline/> | ||
2392 | 115 | <group expand="0" string="Group By" colspan="4"> | ||
2393 | 116 | <filter string="Template Mime-type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'in_format'}"/> | ||
2394 | 117 | <filter string="Output Mime-type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'out_format'}"/> | ||
2395 | 118 | <separator orientation="vertical"/> | ||
2396 | 119 | <filter string="Template Source" icon="gtk-copy" domain="[]" context="{'group_by':'tml_source'}"/> | ||
2397 | 120 | </group> | ||
2398 | 121 | </search> | ||
2399 | 122 | </field> | ||
2400 | 123 | </record> | ||
2401 | 124 | |||
2402 | 125 | <record id="view_company_form1" model="ir.ui.view"> | ||
2403 | 126 | <field name="name">res.company.form</field> | ||
2404 | 127 | <field name="model">res.company</field> | ||
2405 | 128 | <field name="type">form</field> | ||
2406 | 129 | <field name="inherit_id" ref="base.view_company_form"/> | ||
2407 | 130 | <field name="arch" type="xml"> | ||
2408 | 131 | <field name="rml_footer2" position="after"> | ||
2409 | 132 | <field name="stylesheet_id"/> | ||
2410 | 133 | </field> | ||
2411 | 134 | </field> | ||
2412 | 135 | </record> | ||
2413 | 136 | |||
2414 | 137 | <record id="view_report_stylesheets_form" model="ir.ui.view"> | ||
2415 | 138 | <field name="name">report.stylesheets.form</field> | ||
2416 | 139 | <field name="model">report.stylesheets</field> | ||
2417 | 140 | <field name="type">form</field> | ||
2418 | 141 | <field name="arch" type="xml"> | ||
2419 | 142 | <form string="Report Stylesheet"> | ||
2420 | 143 | <field name="name" select="1" colspan="4"/> | ||
2421 | 144 | <field name="report_styles"/> | ||
2422 | 145 | </form> | ||
2423 | 146 | </field> | ||
2424 | 147 | </record> | ||
2425 | 148 | |||
2426 | 149 | <record id="view_report_stylesheets_tree" model="ir.ui.view"> | ||
2427 | 150 | <field name="name">report.stylesheets.tree</field> | ||
2428 | 151 | <field name="model">report.stylesheets</field> | ||
2429 | 152 | <field name="type">tree</field> | ||
2430 | 153 | <field name="arch" type="xml"> | ||
2431 | 154 | <tree string="Report Stylesheets"> | ||
2432 | 155 | <field name="name"/> | ||
2433 | 156 | </tree> | ||
2434 | 157 | </field> | ||
2435 | 158 | </record> | ||
2436 | 159 | |||
2437 | 160 | <record model="ir.actions.act_window" id="action_report_stylesheets"> | ||
2438 | 161 | <field name="name">Report Stylesheets</field> | ||
2439 | 162 | <field name="res_model">report.stylesheets</field> | ||
2440 | 163 | <field name="view_type">form</field> | ||
2441 | 164 | <field name="view_mode">tree,form</field> | ||
2442 | 165 | </record> | ||
2443 | 166 | |||
2444 | 167 | <act_window name="Translations" | ||
2445 | 168 | domain="[('type', '=', 'report'),('res_id', '=', active_id)]" | ||
2446 | 169 | view_type="form" | ||
2447 | 170 | res_model="ir.translation" | ||
2448 | 171 | src_model="ir.actions.report.xml" | ||
2449 | 172 | id="act_translations"/> | ||
2450 | 173 | |||
2451 | 174 | <!-- For the original views --> | ||
2452 | 175 | <record model="ir.actions.act_window.view" id="act_report_xml_tree_view"> | ||
2453 | 176 | <field name="sequence" eval="1"/> | ||
2454 | 177 | <field name="view_mode">tree</field> | ||
2455 | 178 | <field name="view_id" ref="base.act_report_xml_view_tree"/> | ||
2456 | 179 | <field name="act_window_id" ref="base.ir_action_report_xml"/> | ||
2457 | 180 | </record> | ||
2458 | 181 | |||
2459 | 182 | <record model="ir.actions.act_window.view" id="act_report_xml_form_view"> | ||
2460 | 183 | <field name="sequence" eval="1"/> | ||
2461 | 184 | <field name="view_mode">form</field> | ||
2462 | 185 | <field name="view_id" ref="base.act_report_xml_view"/> | ||
2463 | 186 | <field name="act_window_id" ref="base.ir_action_report_xml"/> | ||
2464 | 187 | </record> | ||
2465 | 188 | <!--========================--> | ||
2466 | 189 | |||
2467 | 190 | <wizard string="Add Print Button" model="ir.actions.report.xml" name="aeroo.report_actions" menu="True" id="wizard_oo_report_actions" /> | ||
2468 | 191 | <wizard string="Remove Print Button" model="ir.actions.report.xml" name="aeroo.report_actions_remove" menu="True" id="wizard_oo_report_actions_remove" /> | ||
2469 | 192 | |||
2470 | 193 | <menuitem name="Aeroo Reports" id="menu_ir_action_aeroo_reports_xml" parent="base.menu_custom"/> | ||
2471 | 194 | |||
2472 | 195 | <record id="action_aeroo_report_xml_tree" model="ir.actions.act_window"> | ||
2473 | 196 | <field name="name">Reports</field> | ||
2474 | 197 | <field name="type">ir.actions.act_window</field> | ||
2475 | 198 | <field name="res_model">ir.actions.report.xml</field> | ||
2476 | 199 | <field name="view_type">form</field> | ||
2477 | 200 | <field name="view_mode">tree,form</field> | ||
2478 | 201 | <field name="domain">[('report_type','=','aeroo')]</field> | ||
2479 | 202 | <field name="view_id" ref="act_aeroo_report_xml_view_tree"/> | ||
2480 | 203 | <field name="search_view_id" ref="act_aeroo_report_xml_search_view"/> | ||
2481 | 204 | </record> | ||
2482 | 205 | |||
2483 | 206 | <record model="ir.actions.act_window.view" id="act_aeroo_report_xml_tree_view"> | ||
2484 | 207 | <field name="sequence" eval="1"/> | ||
2485 | 208 | <field name="view_mode">tree</field> | ||
2486 | 209 | <field name="view_id" ref="act_aeroo_report_xml_view_tree"/> | ||
2487 | 210 | <field name="act_window_id" ref="action_aeroo_report_xml_tree"/> | ||
2488 | 211 | </record> | ||
2489 | 212 | |||
2490 | 213 | <record model="ir.actions.act_window.view" id="act_aeroo_report_xml_form_view"> | ||
2491 | 214 | <field name="sequence" eval="1"/> | ||
2492 | 215 | <field name="view_mode">form</field> | ||
2493 | 216 | <field name="view_id" ref="act_report_xml_view1"/> | ||
2494 | 217 | <field name="act_window_id" ref="action_aeroo_report_xml_tree"/> | ||
2495 | 218 | </record> | ||
2496 | 219 | |||
2497 | 220 | <menuitem action="action_aeroo_report_xml_tree" id="menu_ir_action_aeroo_report_xml" parent="menu_ir_action_aeroo_reports_xml"/> | ||
2498 | 221 | <menuitem action="action_report_stylesheets" parent="menu_ir_action_aeroo_reports_xml" id="menu_report_stylesheets"/> | ||
2499 | 222 | |||
2500 | 223 | </data> | ||
2501 | 224 | </openerp> | ||
2502 | 0 | 225 | ||
2503 | === added file 'report_xml.py' | |||
2504 | --- report_xml.py 1970-01-01 00:00:00 +0000 | |||
2505 | +++ report_xml.py 2012-07-05 12:25:24 +0000 | |||
2506 | @@ -0,0 +1,365 @@ | |||
2507 | 1 | ############################################################################## | ||
2508 | 2 | # | ||
2509 | 3 | # Copyright (c) 2009-2010 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
2510 | 4 | # General contacts <info@kndati.lv> | ||
2511 | 5 | # | ||
2512 | 6 | # WARNING: This program as such is intended to be used by professional | ||
2513 | 7 | # programmers who take the whole responsability of assessing all potential | ||
2514 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
2515 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
2516 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
2517 | 11 | # Service Company | ||
2518 | 12 | # | ||
2519 | 13 | # This program is Free Software; you can redistribute it and/or | ||
2520 | 14 | # modify it under the terms of the GNU General Public License | ||
2521 | 15 | # as published by the Free Software Foundation; either version 2 | ||
2522 | 16 | # of the License, or (at your option) any later version. | ||
2523 | 17 | # | ||
2524 | 18 | # This program is distributed in the hope that it will be useful, | ||
2525 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2526 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2527 | 21 | # GNU General Public License for more details. | ||
2528 | 22 | # | ||
2529 | 23 | # You should have received a copy of the GNU General Public License | ||
2530 | 24 | # along with this program; if not, write to the Free Software | ||
2531 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2532 | 26 | # | ||
2533 | 27 | ############################################################################## | ||
2534 | 28 | |||
2535 | 29 | from osv import osv,fields | ||
2536 | 30 | import netsvc | ||
2537 | 31 | from report_aeroo import Aeroo_report | ||
2538 | 32 | from report.report_sxw import rml_parse | ||
2539 | 33 | import base64, binascii | ||
2540 | 34 | import tools | ||
2541 | 35 | import encodings | ||
2542 | 36 | from tools.translate import _ | ||
2543 | 37 | |||
2544 | 38 | import imp, sys, os | ||
2545 | 39 | from tools.config import config | ||
2546 | 40 | |||
2547 | 41 | class report_stylesheets(osv.osv): | ||
2548 | 42 | ''' | ||
2549 | 43 | Open ERP Model | ||
2550 | 44 | ''' | ||
2551 | 45 | _name = 'report.stylesheets' | ||
2552 | 46 | _description = 'Report Stylesheets' | ||
2553 | 47 | |||
2554 | 48 | _columns = { | ||
2555 | 49 | 'name':fields.char('Name', size=64, required=True), | ||
2556 | 50 | 'report_styles' : fields.binary('Template Stylesheet', help='OpenOffice.org stylesheet (.odt)'), | ||
2557 | 51 | |||
2558 | 52 | } | ||
2559 | 53 | |||
2560 | 54 | report_stylesheets() | ||
2561 | 55 | |||
2562 | 56 | class res_company(osv.osv): | ||
2563 | 57 | _name = 'res.company' | ||
2564 | 58 | _inherit = 'res.company' | ||
2565 | 59 | |||
2566 | 60 | _columns = { | ||
2567 | 61 | #'report_styles' : fields.binary('Report Styles', help='OpenOffice stylesheet (.odt)'), | ||
2568 | 62 | 'stylesheet_id':fields.many2one('report.stylesheets', 'Aeroo Global Stylesheet'), | ||
2569 | 63 | } | ||
2570 | 64 | |||
2571 | 65 | res_company() | ||
2572 | 66 | |||
2573 | 67 | class report_mimetypes(osv.osv): | ||
2574 | 68 | ''' | ||
2575 | 69 | Aeroo Report Mime-Type | ||
2576 | 70 | ''' | ||
2577 | 71 | _name = 'report.mimetypes' | ||
2578 | 72 | _description = 'Report Mime-Types' | ||
2579 | 73 | |||
2580 | 74 | _columns = { | ||
2581 | 75 | 'name':fields.char('Name', size=64, required=True, readonly=True), | ||
2582 | 76 | 'code':fields.char('Code', size=16, required=True, readonly=True), | ||
2583 | 77 | 'compatible_types':fields.char('Compatible Mime-Types', size=128, readonly=True), | ||
2584 | 78 | 'filter_name':fields.char('Filter Name', size=128, readonly=True), | ||
2585 | 79 | |||
2586 | 80 | } | ||
2587 | 81 | |||
2588 | 82 | report_mimetypes() | ||
2589 | 83 | |||
2590 | 84 | class report_xml(osv.osv): | ||
2591 | 85 | _name = 'ir.actions.report.xml' | ||
2592 | 86 | _inherit = 'ir.actions.report.xml' | ||
2593 | 87 | |||
2594 | 88 | def load_from_file(self, path, dbname, key): | ||
2595 | 89 | class_inst = None | ||
2596 | 90 | expected_class = 'Parser' | ||
2597 | 91 | |||
2598 | 92 | try: | ||
2599 | 93 | if path.find(config['addons_path'])==-1: | ||
2600 | 94 | filepath=config['addons_path']+os.path.sep+path | ||
2601 | 95 | filepath = os.path.normpath(filepath) | ||
2602 | 96 | if not os.path.lexists(filepath): | ||
2603 | 97 | filepath = os.path.normpath(config['root_path']+os.path.sep+path) | ||
2604 | 98 | sys.path.append(os.path.dirname(filepath)) | ||
2605 | 99 | mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) | ||
2606 | 100 | mod_name = '%s_%s_%s' % (dbname,mod_name,key) | ||
2607 | 101 | |||
2608 | 102 | if file_ext.lower() == '.py': | ||
2609 | 103 | py_mod = imp.load_source(mod_name, filepath) | ||
2610 | 104 | |||
2611 | 105 | elif file_ext.lower() == '.pyc': | ||
2612 | 106 | py_mod = imp.load_compiled(mod_name, filepath) | ||
2613 | 107 | |||
2614 | 108 | if expected_class in dir(py_mod): | ||
2615 | 109 | class_inst = py_mod.Parser | ||
2616 | 110 | return class_inst | ||
2617 | 111 | except Exception, e: | ||
2618 | 112 | return None | ||
2619 | 113 | |||
2620 | 114 | def load_from_source(self, source): | ||
2621 | 115 | expected_class = 'Parser' | ||
2622 | 116 | context = {'Parser':None} | ||
2623 | 117 | try: | ||
2624 | 118 | exec source in context | ||
2625 | 119 | return context['Parser'] | ||
2626 | 120 | except Exception, e: | ||
2627 | 121 | return None | ||
2628 | 122 | |||
2629 | 123 | def delete_report_service(self, name): | ||
2630 | 124 | name = 'report.%s' % name | ||
2631 | 125 | if netsvc.Service.exists( name ): # change for OpenERP 6.0 - Service class usage | ||
2632 | 126 | netsvc.Service.remove( name ) # change for OpenERP 6.0 - Service class usage | ||
2633 | 127 | |||
2634 | 128 | def register_report(self, cr, name, model, tmpl_path, parser): | ||
2635 | 129 | name = 'report.%s' % name | ||
2636 | 130 | if netsvc.Service.exists( name ): # change for OpenERP 6.0 - Service class usage | ||
2637 | 131 | netsvc.Service.remove( name ) # change for OpenERP 6.0 - Service class usage | ||
2638 | 132 | Aeroo_report(cr, name, model, tmpl_path, parser=parser) | ||
2639 | 133 | |||
2640 | 134 | def register_all(self, cr): | ||
2641 | 135 | ########### Run OpenOffice service ########### | ||
2642 | 136 | try: | ||
2643 | 137 | from report_aeroo_ooo.report import OpenOffice_service | ||
2644 | 138 | except Exception, e: | ||
2645 | 139 | OpenOffice_service = False | ||
2646 | 140 | |||
2647 | 141 | if OpenOffice_service: | ||
2648 | 142 | cr.execute("SELECT id, state FROM ir_module_module WHERE name='report_aeroo_ooo'") | ||
2649 | 143 | helper_module = cr.dictfetchone() | ||
2650 | 144 | helper_installed = helper_module['state']=='installed' | ||
2651 | 145 | |||
2652 | 146 | if OpenOffice_service and helper_installed: | ||
2653 | 147 | cr.execute("SELECT host, port FROM oo_config") | ||
2654 | 148 | host, port = cr.fetchone() | ||
2655 | 149 | try: | ||
2656 | 150 | OpenOffice_service(cr, host, port) | ||
2657 | 151 | netsvc.Logger().notifyChannel('report_aeroo', netsvc.LOG_INFO, "OpenOffice.org connection successfully established") | ||
2658 | 152 | except Exception, e: | ||
2659 | 153 | netsvc.Logger().notifyChannel('report_aeroo', netsvc.LOG_WARNING, e) | ||
2660 | 154 | ############################################## | ||
2661 | 155 | |||
2662 | 156 | cr.execute("SELECT * FROM ir_act_report_xml WHERE report_type = 'aeroo' ORDER BY id") # change for OpenERP 6.0 | ||
2663 | 157 | records = cr.dictfetchall() | ||
2664 | 158 | for record in records: | ||
2665 | 159 | parser=rml_parse | ||
2666 | 160 | if record['parser_state']=='loc' and record['parser_loc']: | ||
2667 | 161 | parser=self.load_from_file(record['parser_loc'], cr.dbname, record['id']) or parser | ||
2668 | 162 | elif record['parser_state']=='def' and record['parser_def']: | ||
2669 | 163 | parser=self.load_from_source("from report import report_sxw\n"+record['parser_def']) or parser | ||
2670 | 164 | self.register_report(cr, record['report_name'], record['model'], record['report_rml'], parser) | ||
2671 | 165 | |||
2672 | 166 | |||
2673 | 167 | def _report_content(self, cursor, user, ids, name, arg, context=None): | ||
2674 | 168 | res = {} | ||
2675 | 169 | for report in self.browse(cursor, user, ids, context=context): | ||
2676 | 170 | data = report[name + '_data']# and base64.decodestring(report[name + '_data']) | ||
2677 | 171 | if not data and report[name[:-8]]: | ||
2678 | 172 | try: | ||
2679 | 173 | fp = tools.file_open(report[name[:-8]], mode='rb') | ||
2680 | 174 | data = base64.encodestring(fp.read()) | ||
2681 | 175 | except: | ||
2682 | 176 | data = '' | ||
2683 | 177 | res[report.id] = data | ||
2684 | 178 | return res | ||
2685 | 179 | |||
2686 | 180 | def _get_encodings(self, cursor, user, context={}): | ||
2687 | 181 | l = list(set(encodings._aliases.values())) | ||
2688 | 182 | l.sort() | ||
2689 | 183 | return zip(l, l) | ||
2690 | 184 | |||
2691 | 185 | def _report_content_inv(self, cursor, user, id, name, value, arg, context=None): | ||
2692 | 186 | if value: | ||
2693 | 187 | self.write(cursor, user, id, {name+'_data': value}, context=context) | ||
2694 | 188 | |||
2695 | 189 | def change_input_format(self, cr, uid, ids, in_format): | ||
2696 | 190 | out_format = self.pool.get('report.mimetypes').search(cr, uid, [('code','=',in_format)]) | ||
2697 | 191 | return { | ||
2698 | 192 | 'value':{'out_format': out_format and out_format[0] or False} | ||
2699 | 193 | } | ||
2700 | 194 | |||
2701 | 195 | def _get_in_mimetypes(self, cr, uid, context={}): | ||
2702 | 196 | obj = self.pool.get('report.mimetypes') | ||
2703 | 197 | ids = obj.search(cr, uid, [('filter_name','=',False)], context=context) | ||
2704 | 198 | res = obj.read(cr, uid, ids, ['code', 'name'], context) | ||
2705 | 199 | return [(r['code'], r['name']) for r in res] + [('','')] | ||
2706 | 200 | |||
2707 | 201 | _columns = { | ||
2708 | 202 | 'charset':fields.selection(_get_encodings, string='Charset', required=True), | ||
2709 | 203 | 'content_fname': fields.char('Override Extension',size=64, help='Here you can override output file extension'), | ||
2710 | 204 | 'styles_mode': fields.selection([ | ||
2711 | 205 | ('default','Not used'), | ||
2712 | 206 | ('global', 'Global'), | ||
2713 | 207 | ('specified', 'Specified'), | ||
2714 | 208 | ], string='Stylesheet'), | ||
2715 | 209 | #'report_styles' : fields.binary('Template Styles', help='OpenOffice stylesheet (.odt)'), | ||
2716 | 210 | 'stylesheet_id':fields.many2one('report.stylesheets', 'Template Stylesheet'), | ||
2717 | 211 | 'preload_mode':fields.selection([ | ||
2718 | 212 | ('static',_('Static')), | ||
2719 | 213 | ('preload',_('Preload')), | ||
2720 | 214 | ],'Preload Mode'), | ||
2721 | 215 | 'tml_source':fields.selection([ | ||
2722 | 216 | ('database','Database'), | ||
2723 | 217 | ('file','File'), | ||
2724 | 218 | ('parser','Parser'), | ||
2725 | 219 | ],'Template source', select=True), | ||
2726 | 220 | 'parser_def': fields.text('Parser Definition'), | ||
2727 | 221 | 'parser_loc':fields.char('Parser location', size=128), | ||
2728 | 222 | 'parser_state':fields.selection([ | ||
2729 | 223 | ('default',_('Default')), | ||
2730 | 224 | ('def',_('Definition')), | ||
2731 | 225 | ('loc',_('Location')), | ||
2732 | 226 | ],'State of Parser', select=True), | ||
2733 | 227 | 'in_format': fields.selection(_get_in_mimetypes, 'Template Mime-type'), | ||
2734 | 228 | 'out_format':fields.many2one('report.mimetypes', 'Output Mime-type'), | ||
2735 | 229 | 'report_sxw_content': fields.function(_report_content, | ||
2736 | 230 | fnct_inv=_report_content_inv, method=True, | ||
2737 | 231 | type='binary', string='SXW content',), | ||
2738 | 232 | } | ||
2739 | 233 | |||
2740 | 234 | def unlink(self, cr, uid, ids, context=None): | ||
2741 | 235 | #TODO: process before delete resource | ||
2742 | 236 | trans_obj = self.pool.get('ir.translation') | ||
2743 | 237 | trans_ids = trans_obj.search(cr, uid, [('type','=','report'),('res_id','in',ids)]) | ||
2744 | 238 | trans_obj.unlink(cr, uid, trans_ids) | ||
2745 | 239 | #################################### | ||
2746 | 240 | reports = self.read(cr, uid, ids, ['report_name','model']) | ||
2747 | 241 | for r in reports: | ||
2748 | 242 | ir_value_ids = self.pool.get('ir.values').search(cr, uid, [('name','=',r['report_name']), | ||
2749 | 243 | ('value','=','ir.actions.report.xml,%s' % r['id']), | ||
2750 | 244 | ('model','=',r['model']) | ||
2751 | 245 | ]) | ||
2752 | 246 | if ir_value_ids: | ||
2753 | 247 | self.pool.get('ir.values').unlink(cr, uid, ir_value_ids) | ||
2754 | 248 | self.pool.get('ir.model.data')._unlink(cr, uid, 'ir.actions.report.xml', ids) | ||
2755 | 249 | #################################### | ||
2756 | 250 | res = super(report_xml, self).unlink(cr, uid, ids, context) | ||
2757 | 251 | return res | ||
2758 | 252 | |||
2759 | 253 | def create(self, cr, user, vals, context={}): | ||
2760 | 254 | #if context and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['model'])]): | ||
2761 | 255 | # raise osv.except_osv(_('Object model is not correct !'),_('Please check "Object" field !') ) | ||
2762 | 256 | if 'report_type' in vals and vals['report_type'] == 'aeroo': | ||
2763 | 257 | parser=rml_parse | ||
2764 | 258 | if vals['parser_state']=='loc' and vals['parser_loc']: | ||
2765 | 259 | parser=self.load_from_file(vals['parser_loc'], cr.dbname, vals['name'].lower().replace(' ','_')) or parser | ||
2766 | 260 | elif vals['parser_state']=='def' and vals['parser_def']: | ||
2767 | 261 | parser=self.load_from_source("from report import report_sxw\n"+vals['parser_def']) or parser | ||
2768 | 262 | |||
2769 | 263 | res_id = super(report_xml, self).create(cr, user, vals, context) | ||
2770 | 264 | try: | ||
2771 | 265 | self.register_report(cr, vals['report_name'], vals['model'], vals.get('report_rml', False), parser) | ||
2772 | 266 | except Exception, e: | ||
2773 | 267 | raise osv.except_osv(_('Report registration error !'), _('Report was not registered in system !')) | ||
2774 | 268 | return res_id | ||
2775 | 269 | |||
2776 | 270 | res_id = super(report_xml, self).create(cr, user, vals, context) | ||
2777 | 271 | return res_id | ||
2778 | 272 | |||
2779 | 273 | def write(self, cr, user, ids, vals, context=None): | ||
2780 | 274 | if 'report_sxw_content_data' in vals: | ||
2781 | 275 | if vals['report_sxw_content_data']: | ||
2782 | 276 | try: | ||
2783 | 277 | base64.decodestring(vals['report_sxw_content_data']) | ||
2784 | 278 | except binascii.Error: | ||
2785 | 279 | vals['report_sxw_content_data'] = False | ||
2786 | 280 | if type(ids)==list: | ||
2787 | 281 | ids = ids[0] | ||
2788 | 282 | record = self.read(cr, user, ids) | ||
2789 | 283 | #if context and 'model' in vals and not self.pool.get('ir.model').search(cr, user, [('model','=',vals['model'])]): | ||
2790 | 284 | # raise osv.except_osv(_('Object model is not correct !'),_('Please check "Object" field !') ) | ||
2791 | 285 | if vals.get('report_type', record['report_type']) == 'aeroo': | ||
2792 | 286 | parser=rml_parse | ||
2793 | 287 | if vals.get('parser_state', False)=='loc': | ||
2794 | 288 | parser = self.load_from_file(vals.get('parser_loc', False) or record['parser_loc'], cr.dbname, record['id']) or parser | ||
2795 | 289 | elif vals.get('parser_state', False)=='def': | ||
2796 | 290 | parser = self.load_from_source("from report import report_sxw\n"+(vals.get('parser_loc', False) or record['parser_def'] or '')) or parser | ||
2797 | 291 | elif vals.get('parser_state', False)=='default': | ||
2798 | 292 | parser = rml_parse | ||
2799 | 293 | elif record['parser_state']=='loc': | ||
2800 | 294 | parser = self.load_from_file(record['parser_loc'], cr.dbname, record['id']) or parser | ||
2801 | 295 | elif record['parser_state']=='def': | ||
2802 | 296 | parser = self.load_from_source("from report import report_sxw\n"+record['parser_def']) or parser | ||
2803 | 297 | elif record['parser_state']=='default': | ||
2804 | 298 | parser = rml_parse | ||
2805 | 299 | |||
2806 | 300 | if vals.get('parser_loc', False): | ||
2807 | 301 | parser=self.load_from_file(vals['parser_loc'], cr.dbname, record['id']) or parser | ||
2808 | 302 | elif vals.get('parser_def', False): | ||
2809 | 303 | parser=self.load_from_source("from report import report_sxw\n"+vals['parser_def']) or parser | ||
2810 | 304 | if vals.get('report_name', False) and vals['report_name']!=record['report_name']: | ||
2811 | 305 | self.delete_report_service(record['report_name']) | ||
2812 | 306 | report_name = vals['report_name'] | ||
2813 | 307 | else: | ||
2814 | 308 | self.delete_report_service(record['report_name']) | ||
2815 | 309 | report_name = record['report_name'] | ||
2816 | 310 | |||
2817 | 311 | res = super(report_xml, self).write(cr, user, ids, vals, context) | ||
2818 | 312 | try: | ||
2819 | 313 | self.register_report(cr, report_name, vals.get('model', record['model']), vals.get('report_rml', record['report_rml']), parser) | ||
2820 | 314 | except Exception, e: | ||
2821 | 315 | raise osv.except_osv(_('Report registration error !'), _('Report was not registered in system !')) | ||
2822 | 316 | return res | ||
2823 | 317 | |||
2824 | 318 | res = super(report_xml, self).write(cr, user, ids, vals, context) | ||
2825 | 319 | return res | ||
2826 | 320 | |||
2827 | 321 | def _get_default_outformat(self, cr, uid, context): | ||
2828 | 322 | obj = self.pool.get('report.mimetypes') | ||
2829 | 323 | res = obj.search(cr, uid, [('code','=','oo-odt')]) | ||
2830 | 324 | return res and res[0] or False | ||
2831 | 325 | |||
2832 | 326 | _defaults = { | ||
2833 | 327 | #'report_type' : lambda*a: 'oo-odt', | ||
2834 | 328 | 'tml_source': lambda*a: 'database', | ||
2835 | 329 | 'in_format' : lambda*a: 'oo-odt', | ||
2836 | 330 | 'out_format' : _get_default_outformat, | ||
2837 | 331 | 'charset': lambda*a: 'ascii', | ||
2838 | 332 | 'styles_mode' : lambda*a: 'default', | ||
2839 | 333 | 'preload_mode': lambda*a: 'static', | ||
2840 | 334 | 'parser_state': lambda*a: 'default', | ||
2841 | 335 | 'parser_def':lambda*a: """class Parser(report_sxw.rml_parse): | ||
2842 | 336 | def __init__(self, cr, uid, name, context): | ||
2843 | 337 | super(Parser, self).__init__(cr, uid, name, context) | ||
2844 | 338 | self.localcontext.update({})""" | ||
2845 | 339 | } | ||
2846 | 340 | |||
2847 | 341 | #def _object_check(self, cr, uid, ids): | ||
2848 | 342 | # for r in self.browse(cr, uid, ids, {}): | ||
2849 | 343 | # if not self.pool.get('ir.model').search(cr, uid, [('model','=',r.model)]): | ||
2850 | 344 | # return False | ||
2851 | 345 | # return True | ||
2852 | 346 | |||
2853 | 347 | #_constraints = [ | ||
2854 | 348 | # (_object_check, _('Object model is not correct')+' !\n'+_('Please check "Object" field')+' !', ['model']) | ||
2855 | 349 | # ] | ||
2856 | 350 | |||
2857 | 351 | report_xml() | ||
2858 | 352 | |||
2859 | 353 | class ir_translation(osv.osv): | ||
2860 | 354 | _name = 'ir.translation' | ||
2861 | 355 | _inherit = 'ir.translation' | ||
2862 | 356 | |||
2863 | 357 | def __init__(self, pool, cr): | ||
2864 | 358 | super(ir_translation, self).__init__(pool, cr) | ||
2865 | 359 | if ('report', 'Report') not in self._columns['type'].selection: | ||
2866 | 360 | self._columns['type'].selection.append( | ||
2867 | 361 | ('report', 'Report'), | ||
2868 | 362 | ) | ||
2869 | 363 | |||
2870 | 364 | ir_translation() | ||
2871 | 365 | |||
2872 | 0 | 366 | ||
2873 | === added directory 'wizard' | |||
2874 | === added file 'wizard/__init__.py' | |||
2875 | --- wizard/__init__.py 1970-01-01 00:00:00 +0000 | |||
2876 | +++ wizard/__init__.py 2012-07-05 12:25:24 +0000 | |||
2877 | @@ -0,0 +1,30 @@ | |||
2878 | 1 | ############################################################################## | ||
2879 | 2 | # | ||
2880 | 3 | # Copyright (c) 2008-2009 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
2881 | 4 | # General contacts <info@kndati.lv> | ||
2882 | 5 | # | ||
2883 | 6 | # WARNING: This program as such is intended to be used by professional | ||
2884 | 7 | # programmers who take the whole responsability of assessing all potential | ||
2885 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
2886 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
2887 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
2888 | 11 | # Service Company | ||
2889 | 12 | # | ||
2890 | 13 | # This program is Free Software; you can redistribute it and/or | ||
2891 | 14 | # modify it under the terms of the GNU General Public License | ||
2892 | 15 | # as published by the Free Software Foundation; either version 2 | ||
2893 | 16 | # of the License, or (at your option) any later version. | ||
2894 | 17 | # | ||
2895 | 18 | # This program is distributed in the hope that it will be useful, | ||
2896 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2897 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2898 | 21 | # GNU General Public License for more details. | ||
2899 | 22 | # | ||
2900 | 23 | # You should have received a copy of the GNU General Public License | ||
2901 | 24 | # along with this program; if not, write to the Free Software | ||
2902 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2903 | 26 | # | ||
2904 | 27 | ############################################################################## | ||
2905 | 28 | |||
2906 | 29 | import report_actions | ||
2907 | 30 | import report_actions_remove | ||
2908 | 0 | 31 | ||
2909 | === added file 'wizard/report_actions.py' | |||
2910 | --- wizard/report_actions.py 1970-01-01 00:00:00 +0000 | |||
2911 | +++ wizard/report_actions.py 2012-07-05 12:25:24 +0000 | |||
2912 | @@ -0,0 +1,118 @@ | |||
2913 | 1 | ############################################################################## | ||
2914 | 2 | # | ||
2915 | 3 | # Copyright (c) 2008-2010 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
2916 | 4 | # General contacts <info@kndati.lv> | ||
2917 | 5 | # | ||
2918 | 6 | # WARNING: This program as such is intended to be used by professional | ||
2919 | 7 | # programmers who take the whole responsability of assessing all potential | ||
2920 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
2921 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
2922 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
2923 | 11 | # Service Company | ||
2924 | 12 | # | ||
2925 | 13 | # This program is Free Software; you can redistribute it and/or | ||
2926 | 14 | # modify it under the terms of the GNU General Public License | ||
2927 | 15 | # as published by the Free Software Foundation; either version 2 | ||
2928 | 16 | # of the License, or (at your option) any later version. | ||
2929 | 17 | # | ||
2930 | 18 | # This program is distributed in the hope that it will be useful, | ||
2931 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2932 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2933 | 21 | # GNU General Public License for more details. | ||
2934 | 22 | # | ||
2935 | 23 | # You should have received a copy of the GNU General Public License | ||
2936 | 24 | # along with this program; if not, write to the Free Software | ||
2937 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2938 | 26 | # | ||
2939 | 27 | ############################################################################## | ||
2940 | 28 | |||
2941 | 29 | import wizard | ||
2942 | 30 | import pooler | ||
2943 | 31 | import ir | ||
2944 | 32 | from tools.translate import _ | ||
2945 | 33 | |||
2946 | 34 | class report_actions_wizard(wizard.interface): | ||
2947 | 35 | ''' | ||
2948 | 36 | Add Print Button | ||
2949 | 37 | ''' | ||
2950 | 38 | form = '''<?xml version="1.0"?> | ||
2951 | 39 | <form string="Add Print Button"> | ||
2952 | 40 | <!--<field name="print_button"/>--> | ||
2953 | 41 | <field name="open_action"/> | ||
2954 | 42 | </form>''' | ||
2955 | 43 | |||
2956 | 44 | ex_form = '''<?xml version="1.0"?> | ||
2957 | 45 | <form string="Add Print Button"> | ||
2958 | 46 | <label string="Report Action already exist for this report."/> | ||
2959 | 47 | </form>''' | ||
2960 | 48 | |||
2961 | 49 | done_form = '''<?xml version="1.0"?> | ||
2962 | 50 | <form string="Remove print button"> | ||
2963 | 51 | <label string="The print button is successfully added"/> | ||
2964 | 52 | </form>''' | ||
2965 | 53 | |||
2966 | 54 | fields = { | ||
2967 | 55 | #'print_button': {'string': 'Add print button', 'type': 'boolean', 'default': True, 'help':'Add action to menu context in print button.'}, | ||
2968 | 56 | 'open_action': {'string': 'Open added action', 'type': 'boolean', 'default': False}, | ||
2969 | 57 | } | ||
2970 | 58 | |||
2971 | 59 | def _do_action(self, cr, uid, data, context): | ||
2972 | 60 | pool = pooler.get_pool(cr.dbname) | ||
2973 | 61 | report = pool.get(data['model']).browse(cr, uid, data['id'], context=context) | ||
2974 | 62 | #if data['form']['print_button']: | ||
2975 | 63 | res = ir.ir_set(cr, uid, 'action', 'client_print_multi', report.report_name, [report.model], 'ir.actions.report.xml,%d' % data['id'], isobject=True) | ||
2976 | 64 | #else: | ||
2977 | 65 | # res = ir.ir_set(cr, uid, 'action', 'client_print_multi', report.report_name, [report.model,0], 'ir.actions.report.xml,%d' % data['id'], isobject=True) | ||
2978 | 66 | return {'value_id':res[0]} | ||
2979 | 67 | |||
2980 | 68 | def _check(self, cr, uid, data, context): | ||
2981 | 69 | pool = pooler.get_pool(cr.dbname) | ||
2982 | 70 | report = pool.get(data['model']).browse(cr, uid, data['id'], context=context) | ||
2983 | 71 | ids = pool.get('ir.values').search(cr, uid, [('value','=',report.type+','+str(data['id']))]) | ||
2984 | 72 | if not ids: | ||
2985 | 73 | return 'add' | ||
2986 | 74 | else: | ||
2987 | 75 | return 'exist' | ||
2988 | 76 | |||
2989 | 77 | def _action_open_window(self, cr, uid, data, context): | ||
2990 | 78 | form=data['form'] | ||
2991 | 79 | if not form['open_action']: | ||
2992 | 80 | return {} | ||
2993 | 81 | return { | ||
2994 | 82 | 'domain':"[('id','=',%d)]" % (form['value_id']), | ||
2995 | 83 | 'name': _('Client Actions Connections'), | ||
2996 | 84 | 'view_type': 'form', | ||
2997 | 85 | 'view_mode': 'tree,form', | ||
2998 | 86 | 'res_model': 'ir.values', | ||
2999 | 87 | 'view_id': False, | ||
3000 | 88 | 'type': 'ir.actions.act_window', | ||
3001 | 89 | } | ||
3002 | 90 | |||
3003 | 91 | states = { | ||
3004 | 92 | 'init': { | ||
3005 | 93 | 'actions': [], | ||
3006 | 94 | 'result': {'type':'choice','next_state':_check} | ||
3007 | 95 | }, | ||
3008 | 96 | 'add': { | ||
3009 | 97 | 'actions': [], | ||
3010 | 98 | 'result': {'type': 'form', 'arch': form, 'fields': fields, 'state': (('end', _('_Cancel')), ('process', _('_Ok')))}, | ||
3011 | 99 | }, | ||
3012 | 100 | 'exist': { | ||
3013 | 101 | 'actions': [], | ||
3014 | 102 | 'result': {'type': 'form', 'arch': ex_form, 'fields': {}, 'state': (('end', _('_Close')),)}, | ||
3015 | 103 | }, | ||
3016 | 104 | 'process': { | ||
3017 | 105 | 'actions': [_do_action], | ||
3018 | 106 | 'result': {'type': 'state', 'state': 'done'}, | ||
3019 | 107 | }, | ||
3020 | 108 | 'done': { | ||
3021 | 109 | 'actions': [], | ||
3022 | 110 | 'result': {'type': 'form', 'arch': done_form, 'fields': {}, 'state': (('exit', _('_Close')),)}, | ||
3023 | 111 | }, | ||
3024 | 112 | 'exit': { | ||
3025 | 113 | 'actions': [], | ||
3026 | 114 | 'result': {'type': 'action', 'action': _action_open_window, 'state': 'end'}, | ||
3027 | 115 | }, | ||
3028 | 116 | } | ||
3029 | 117 | report_actions_wizard('aeroo.report_actions') | ||
3030 | 118 | |||
3031 | 0 | 119 | ||
3032 | === added file 'wizard/report_actions_remove.py' | |||
3033 | --- wizard/report_actions_remove.py 1970-01-01 00:00:00 +0000 | |||
3034 | +++ wizard/report_actions_remove.py 2012-07-05 12:25:24 +0000 | |||
3035 | @@ -0,0 +1,97 @@ | |||
3036 | 1 | ############################################################################## | ||
3037 | 2 | # | ||
3038 | 3 | # Copyright (c) 2008-2010 SIA "KN dati". (http://kndati.lv) All Rights Reserved. | ||
3039 | 4 | # General contacts <info@kndati.lv> | ||
3040 | 5 | # | ||
3041 | 6 | # WARNING: This program as such is intended to be used by professional | ||
3042 | 7 | # programmers who take the whole responsability of assessing all potential | ||
3043 | 8 | # consequences resulting from its eventual inadequacies and bugs | ||
3044 | 9 | # End users who are looking for a ready-to-use solution with commercial | ||
3045 | 10 | # garantees and support are strongly adviced to contract a Free Software | ||
3046 | 11 | # Service Company | ||
3047 | 12 | # | ||
3048 | 13 | # This program is Free Software; you can redistribute it and/or | ||
3049 | 14 | # modify it under the terms of the GNU General Public License | ||
3050 | 15 | # as published by the Free Software Foundation; either version 2 | ||
3051 | 16 | # of the License, or (at your option) any later version. | ||
3052 | 17 | # | ||
3053 | 18 | # This program is distributed in the hope that it will be useful, | ||
3054 | 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3055 | 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3056 | 21 | # GNU General Public License for more details. | ||
3057 | 22 | # | ||
3058 | 23 | # You should have received a copy of the GNU General Public License | ||
3059 | 24 | # along with this program; if not, write to the Free Software | ||
3060 | 25 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
3061 | 26 | # | ||
3062 | 27 | ############################################################################## | ||
3063 | 28 | |||
3064 | 29 | import wizard | ||
3065 | 30 | import pooler | ||
3066 | 31 | import ir | ||
3067 | 32 | from tools.translate import _ | ||
3068 | 33 | |||
3069 | 34 | class report_actions_remove_wizard(wizard.interface): | ||
3070 | 35 | ''' | ||
3071 | 36 | Remove print button | ||
3072 | 37 | ''' | ||
3073 | 38 | form = '''<?xml version="1.0"?> | ||
3074 | 39 | <form string="Remove print button"> | ||
3075 | 40 | <label string="Or you want to remove print button for this report?"/> | ||
3076 | 41 | </form>''' | ||
3077 | 42 | |||
3078 | 43 | ex_form = '''<?xml version="1.0"?> | ||
3079 | 44 | <form string="Remove print button"> | ||
3080 | 45 | <label string="No Report Action to delete for this report"/> | ||
3081 | 46 | </form>''' | ||
3082 | 47 | |||
3083 | 48 | done_form = '''<?xml version="1.0"?> | ||
3084 | 49 | <form string="Remove print button"> | ||
3085 | 50 | <label string="The print button is successfully removed"/> | ||
3086 | 51 | </form>''' | ||
3087 | 52 | |||
3088 | 53 | def _do_action(self, cr, uid, data, context): | ||
3089 | 54 | pool = pooler.get_pool(cr.dbname) | ||
3090 | 55 | report = pool.get(data['model']).browse(cr, uid, data['id'], context=context) | ||
3091 | 56 | res = ir.ir_get(cr, uid, 'action', 'client_print_multi', [report.model]) | ||
3092 | 57 | id = res[0][0] | ||
3093 | 58 | res = ir.ir_del(cr, uid, id) | ||
3094 | 59 | return {} | ||
3095 | 60 | |||
3096 | 61 | def _check(self, cr, uid, data, context): | ||
3097 | 62 | pool = pooler.get_pool(cr.dbname) | ||
3098 | 63 | report = pool.get(data['model']).browse(cr, uid, data['id'], context=context) | ||
3099 | 64 | ids = pool.get('ir.values').search(cr, uid, [('value','=',report.type+','+str(data['id']))]) | ||
3100 | 65 | if not ids: | ||
3101 | 66 | return 'no_exist' | ||
3102 | 67 | else: | ||
3103 | 68 | return 'remove' | ||
3104 | 69 | |||
3105 | 70 | states = { | ||
3106 | 71 | 'init': { | ||
3107 | 72 | 'actions': [], | ||
3108 | 73 | 'result': {'type':'choice','next_state':_check} | ||
3109 | 74 | }, | ||
3110 | 75 | 'remove': { | ||
3111 | 76 | 'actions': [], | ||
3112 | 77 | 'result': {'type': 'form', 'arch': form, 'fields': {}, 'state': (('end', _('_No')), ('process', _('_Yes')))}, | ||
3113 | 78 | }, | ||
3114 | 79 | 'no_exist': { | ||
3115 | 80 | 'actions': [], | ||
3116 | 81 | 'result': {'type': 'form', 'arch': ex_form, 'fields': {}, 'state': (('end', _('_Close')),)}, | ||
3117 | 82 | }, | ||
3118 | 83 | 'process': { | ||
3119 | 84 | 'actions': [_do_action], | ||
3120 | 85 | 'result': {'type': 'state', 'state': 'done'}, | ||
3121 | 86 | }, | ||
3122 | 87 | 'done': { | ||
3123 | 88 | 'actions': [], | ||
3124 | 89 | 'result': {'type': 'form', 'arch': done_form, 'fields': {}, 'state': (('exit', _('_Close')),)}, | ||
3125 | 90 | }, | ||
3126 | 91 | 'exit': { | ||
3127 | 92 | 'actions': [], | ||
3128 | 93 | 'result': {'type': 'state', 'state': 'end'}, | ||
3129 | 94 | }, | ||
3130 | 95 | } | ||
3131 | 96 | report_actions_remove_wizard('aeroo.report_actions_remove') | ||
3132 | 97 |