[IMP] account_payment: use the new signal_xxx methods instead of trg_validate.
[odoo/odoo.git] / openerp / report / report_sxw.py
index e0a09a6..b1f1e3d 100644 (file)
@@ -33,13 +33,11 @@ import openerp.pooler as pooler
 import openerp.tools as tools
 import zipfile
 import common
-from openerp.osv.fields import float as float_class, function as function_class
-from openerp.osv.orm import browse_record
+from openerp.osv.fields import float as float_field, function as function_field, datetime as datetime_field
 from openerp.tools.translate import _
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
 
-DT_FORMAT = '%Y-%m-%d'
-DHM_FORMAT = '%Y-%m-%d %H:%M:%S'
-HM_FORMAT = '%H:%M:%S'
+_logger = logging.getLogger(__name__)
 
 rml_parents = {
     'tr':1,
@@ -68,7 +66,7 @@ rml2sxw = {
     'para': 'p',
 }
 
-def get_date_length(date_format=DT_FORMAT):
+def get_date_length(date_format=DEFAULT_SERVER_DATE_FORMAT):
     return len((datetime.now()).strftime(date_format))
 
 class _format(object):
@@ -109,7 +107,7 @@ class _date_format(str, _format):
     def __str__(self):
         if self.val:
             if getattr(self,'name', None):
-                date = datetime.strptime(self.name[:get_date_length()], DT_FORMAT)
+                date = datetime.strptime(self.name[:get_date_length()], DEFAULT_SERVER_DATE_FORMAT)
                 return date.strftime(str(self.lang_obj.date_format))
         return self.val
 
@@ -120,7 +118,7 @@ class _dttime_format(str, _format):
 
     def __str__(self):
         if self.val and getattr(self,'name', None):
-            return datetime.strptime(self.name, DHM_FORMAT)\
+            return datetime.strptime(self.name, DEFAULT_SERVER_DATETIME_FORMAT)\
                    .strftime("%s %s"%(str(self.lang_obj.date_format),
                                       str(self.lang_obj.time_format)))
         return self.val
@@ -170,6 +168,7 @@ class rml_parse(object):
             'setHtmlImage' : self.set_html_image,
             'strip_name' : self._strip_name,
             'time' : time,
+            'display_address': self.display_address,
             # more context members are setup in setCompany() below:
             #  - company_id
             #  - logo
@@ -262,7 +261,7 @@ class rml_parse(object):
             else:
                 d = res_digits(self.cr)[1]
         elif (hasattr(obj, '_field') and\
-                isinstance(obj._field, (float_class, function_class)) and\
+                isinstance(obj._field, (float_field, function_field)) and\
                 obj._field.digits):
                 d = obj._field.digits[1] or DEFAULT_DIGITS
         return d
@@ -293,16 +292,24 @@ class rml_parse(object):
                 return ''
 
             date_format = self.lang_dict['date_format']
-            parse_format = DT_FORMAT
+            parse_format = DEFAULT_SERVER_DATE_FORMAT
             if date_time:
-                value=value.split('.')[0]
+                value = value.split('.')[0]
                 date_format = date_format + " " + self.lang_dict['time_format']
-                parse_format = DHM_FORMAT
-            if not isinstance(value, time.struct_time):
-                return time.strftime(date_format, time.strptime(value[:get_date_length(parse_format)], parse_format))
-
+                parse_format = DEFAULT_SERVER_DATETIME_FORMAT
+            if isinstance(value, basestring):
+                # FIXME: the trimming is probably unreliable if format includes day/month names
+                #        and those would need to be translated anyway.
+                date = datetime.strptime(value[:get_date_length(parse_format)], parse_format)
+            elif isinstance(value, time.struct_time):
+                date = datetime(*value[:6])
             else:
                 date = datetime(*value.timetuple()[:6])
+            if date_time:
+                # Convert datetime values to the expected client/context timezone
+                date = datetime_field.context_timestamp(self.cr, self.uid,
+                                                        timestamp=date,
+                                                        context=self.localcontext)
             return date.strftime(date_format)
 
         res = self.lang_dict['lang_obj'].format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
@@ -313,6 +320,9 @@ class rml_parse(object):
                 res='%s %s'%(currency_obj.symbol, res)
         return res
 
+    def display_address(self, address_browse_record):
+        return self.pool.get('res.partner')._display_address(self.cr, self.uid, address_browse_record)
+
     def repeatIn(self, lst, name,nodes_parent=False):
         ret_lst = []
         for id in lst:
@@ -394,9 +404,9 @@ class report_sxw(report_rml, preprocess.report):
         if context is None:
             context = {}
         if self.internal_header:
-            context.update({'internal_header':self.internal_header})
-        #we ask osv.fields.sanitize_binary_value() not to encode the binary value"
-        context.update({'bin_raw':True})
+            context.update(internal_header=self.internal_header)
+        # skip osv.fields.sanitize_binary_value() because we want the raw bytes in all cases
+        context.update(bin_raw=True)
         pool = pooler.get_pool(cr.dbname)
         ir_obj = pool.get('ir.actions.report.xml')
         report_xml_ids = ir_obj.search(cr, uid,
@@ -431,7 +441,7 @@ class report_sxw(report_rml, preprocess.report):
             raise NotImplementedError(_('Unknown report type: %s') % report_type)
         fnct_ret = fnct(cr, uid, ids, data, report_xml, context)
         if not fnct_ret:
-            return (False,False)
+            return False, False
         return fnct_ret
 
     def create_source_odt(self, cr, uid, ids, data, report_xml, context=None):
@@ -469,17 +479,23 @@ class report_sxw(report_rml, preprocess.report):
                 if aname:
                     try:
                         name = aname+'.'+result[1]
+                        # Remove the default_type entry from the context: this
+                        # is for instance used on the account.account_invoices
+                        # and is thus not intended for the ir.attachment type
+                        # field.
+                        ctx = dict(context)
+                        ctx.pop('default_type', None)
                         pool.get('ir.attachment').create(cr, uid, {
                             'name': aname,
                             'datas': base64.encodestring(result[0]),
                             'datas_fname': name,
                             'res_model': self.table,
                             'res_id': obj.id,
-                            }, context=context
+                            }, context=ctx
                         )
                     except Exception:
                         #TODO: should probably raise a proper osv_except instead, shouldn't we? see LP bug #325632
-                        logging.getLogger('report').error('Could not create saved report attachment', exc_info=True)
+                        _logger.error('Could not create saved report attachment', exc_info=True)
                 results.append(result)
             if results:
                 if results[0][1]=='pdf':
@@ -515,7 +531,7 @@ class report_sxw(report_rml, preprocess.report):
             logo = base64.decodestring(rml_parser.logo)
         create_doc = self.generators[report_xml.report_type]
         pdf = create_doc(etree.tostring(processed_rml),rml_parser.localcontext,logo,title.encode('utf8'))
-        return (pdf, report_xml.report_type)
+        return pdf, report_xml.report_type
 
     def create_single_odt(self, cr, uid, ids, data, report_xml, context=None):
         if not context:
@@ -601,9 +617,7 @@ class report_sxw(report_rml, preprocess.report):
         create_doc = self.generators[mime_type]
         odt = etree.tostring(create_doc(rml_dom, rml_parser.localcontext),
                              encoding='utf-8', xml_declaration=True)
-        sxw_z = zipfile.ZipFile(sxw_io, mode='a')
-        sxw_z.writestr('content.xml', odt)
-        sxw_z.writestr('meta.xml', meta)
+        sxw_contents = {'content.xml':odt, 'meta.xml':meta}
 
         if report_xml.header:
             #Add corporate header/footer
@@ -622,13 +636,26 @@ class report_sxw(report_rml, preprocess.report):
                     rml_parser._add_header(odt)
                 odt = etree.tostring(odt, encoding='utf-8',
                                      xml_declaration=True)
-                sxw_z.writestr('styles.xml', odt)
+                sxw_contents['styles.xml'] = odt
             finally:
                 rml_file.close()
-        sxw_z.close()
-        final_op = sxw_io.getvalue()
+
+        #created empty zip writing sxw contents to avoid duplication
+        sxw_out = StringIO.StringIO()
+        sxw_out_zip = zipfile.ZipFile(sxw_out, mode='w')
+        sxw_template_zip = zipfile.ZipFile (sxw_io, 'r')
+        for item in sxw_template_zip.infolist():
+            if item.filename not in sxw_contents:
+                buffer = sxw_template_zip.read(item.filename)
+                sxw_out_zip.writestr(item.filename, buffer)
+        for item_filename, buffer in sxw_contents.iteritems():
+            sxw_out_zip.writestr(item_filename, buffer)
+        sxw_template_zip.close()
+        sxw_out_zip.close()
+        final_op = sxw_out.getvalue()
         sxw_io.close()
-        return (final_op, mime_type)
+        sxw_out.close()
+        return final_op, mime_type
 
     def create_single_html2html(self, cr, uid, ids, data, report_xml, context=None):
         if not context:
@@ -650,7 +677,7 @@ class report_sxw(report_rml, preprocess.report):
         create_doc = self.generators['html2html']
         html = etree.tostring(create_doc(html_dom, html_parser.localcontext))
 
-        return (html.replace('&amp;','&').replace('&lt;', '<').replace('&gt;', '>').replace('</br>',''), report_type)
+        return html.replace('&amp;','&').replace('&lt;', '<').replace('&gt;', '>').replace('</br>',''), report_type
 
     def create_single_mako2html(self, cr, uid, ids, data, report_xml, context=None):
         mako_html = report_xml.report_rml_content
@@ -659,7 +686,7 @@ class report_sxw(report_rml, preprocess.report):
         html_parser.set_context(objs, data, ids, 'html')
         create_doc = self.generators['makohtml2html']
         html = create_doc(mako_html,html_parser.localcontext)
-        return (html,'html')
+        return html,'html'
 
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: