[REF][IMP] report module: merge the four report's routes into one; extra report arguments are passed json encoded (therefore removed the _eval_params method); added an abstract_report model to wrap old-style report without touching them; Removed formatLang method from report as it is embeded in the old-style report localcontext; moved the save_in_attachment logic in a method for readability; adapted the action manager to encode data and context of action if needed; fixed the post install test to test the generic report
bzr revid: sle@openerp.com-20140402162344-3lrako0jepmhasvl
This commit is contained in:
@@ -22,48 +22,43 @@
|
|||||||
from openerp.addons.web.http import Controller, route, request
|
from openerp.addons.web.http import Controller, route, request
|
||||||
|
|
||||||
import simplejson
|
import simplejson
|
||||||
import urlparse
|
from werkzeug import exceptions, url_decode
|
||||||
from werkzeug import exceptions
|
from werkzeug.test import Client
|
||||||
|
from werkzeug.wrappers import BaseResponse
|
||||||
|
from werkzeug.datastructures import Headers
|
||||||
from reportlab.graphics.barcode import createBarcodeDrawing
|
from reportlab.graphics.barcode import createBarcodeDrawing
|
||||||
|
|
||||||
|
|
||||||
class ReportController(Controller):
|
class ReportController(Controller):
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Generic reports controller
|
# Report controllers
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
@route('/report/<reportname>/<docids>', type='http', auth='user', website=True, multilang=True)
|
@route([
|
||||||
def report_html(self, reportname, docids):
|
'/report/<path:converter>/<reportname>',
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
'/report/<path:converter>/<reportname>/<docids>',
|
||||||
docids = self._eval_params(docids)
|
], type='http', auth='user', website=True, multilang=True)
|
||||||
return request.registry['report'].get_html(cr, uid, docids, reportname, context=context)
|
def report_routes(self, reportname, docids=None, converter=None, **data):
|
||||||
|
|
||||||
@route('/report/pdf/report/<reportname>/<docids>', type='http', auth="user", website=True)
|
|
||||||
def report_pdf(self, reportname, docids):
|
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
|
||||||
docids = self._eval_params(docids)
|
|
||||||
pdf = request.registry['report'].get_pdf(cr, uid, docids, reportname, context=context)
|
|
||||||
pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))]
|
|
||||||
return request.make_response(pdf, headers=pdfhttpheaders)
|
|
||||||
|
|
||||||
#------------------------------------------------------
|
|
||||||
# Particular reports controller
|
|
||||||
#------------------------------------------------------
|
|
||||||
@route('/report/<reportname>', type='http', auth='user', website=True, multilang=True)
|
|
||||||
def report_html_particular(self, reportname, **data):
|
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
|
||||||
report_obj = request.registry['report']
|
report_obj = request.registry['report']
|
||||||
data = self._eval_params(data) # Sanitizing
|
|
||||||
return report_obj.get_html(cr, uid, [], reportname, data=data, context=context)
|
|
||||||
|
|
||||||
@route('/report/pdf/report/<reportname>', type='http', auth='user', website=True, multilang=True)
|
|
||||||
def report_pdf_particular(self, reportname, **data):
|
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
report_obj = request.registry['report']
|
|
||||||
data = self._eval_params(data) # Sanitizing
|
if docids:
|
||||||
pdf = report_obj.get_pdf(cr, uid, [], reportname, data=data, context=context)
|
docids = [int(i) for i in docids.split(',')]
|
||||||
pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))]
|
options_data = None
|
||||||
return request.make_response(pdf, headers=pdfhttpheaders)
|
if data.get('options'):
|
||||||
|
options_data = simplejson.loads(data['options'])
|
||||||
|
if data.get('context'):
|
||||||
|
context.update(simplejson.loads(data['context']))
|
||||||
|
|
||||||
|
if converter == 'html':
|
||||||
|
html = report_obj.get_html(cr, uid, docids, reportname, data=options_data, context=context)
|
||||||
|
return request.make_response(html)
|
||||||
|
elif converter == 'pdf':
|
||||||
|
pdf = report_obj.get_pdf(cr, uid, docids, reportname, data=options_data, context=context)
|
||||||
|
pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))]
|
||||||
|
return request.make_response(pdf, headers=pdfhttpheaders)
|
||||||
|
else:
|
||||||
|
raise exceptions.HTTPException(description='Converter %s not implemented.' % converter)
|
||||||
|
|
||||||
#------------------------------------------------------
|
#------------------------------------------------------
|
||||||
# Misc. route utils
|
# Misc. route utils
|
||||||
@@ -94,7 +89,7 @@ class ReportController(Controller):
|
|||||||
@route(['/report/download'], type='http', auth="user", website=True)
|
@route(['/report/download'], type='http', auth="user", website=True)
|
||||||
def report_download(self, data, token):
|
def report_download(self, data, token):
|
||||||
"""This function is used by 'qwebactionmanager.js' in order to trigger the download of
|
"""This function is used by 'qwebactionmanager.js' in order to trigger the download of
|
||||||
a pdf report.
|
a pdf/controller report.
|
||||||
|
|
||||||
:param data: a javascript array JSON.stringified containg report internal url ([0]) and
|
:param data: a javascript array JSON.stringified containg report internal url ([0]) and
|
||||||
type [1]
|
type [1]
|
||||||
@@ -102,26 +97,26 @@ class ReportController(Controller):
|
|||||||
"""
|
"""
|
||||||
requestcontent = simplejson.loads(data)
|
requestcontent = simplejson.loads(data)
|
||||||
url, type = requestcontent[0], requestcontent[1]
|
url, type = requestcontent[0], requestcontent[1]
|
||||||
if type == 'qweb-pdf':
|
|
||||||
reportname = url.split('/report/pdf/report/')[1].split('?')[0].split('/')[0]
|
|
||||||
|
|
||||||
if '?' not in url:
|
if type == 'qweb-pdf':
|
||||||
|
reportname = url.split('/report/pdf/')[1].split('?')[0]
|
||||||
|
|
||||||
|
docids = None
|
||||||
|
if '/' in reportname:
|
||||||
|
reportname, docids = reportname.split('/')
|
||||||
|
|
||||||
|
if docids:
|
||||||
# Generic report:
|
# Generic report:
|
||||||
docids = url.split('/')[-1]
|
response = self.report_routes(reportname, docids=docids, converter='pdf')
|
||||||
response = self.report_pdf(reportname, docids)
|
|
||||||
else:
|
else:
|
||||||
# Particular report:
|
# Particular report:
|
||||||
querystring = url.split('?')[1]
|
data = url_decode(url.split('?')[1]).items() # decoding the args represented in JSON
|
||||||
querystring = dict(urlparse.parse_qsl(querystring))
|
response = self.report_routes(reportname, converter='pdf', **dict(data))
|
||||||
response = self.report_pdf_particular(reportname, **querystring)
|
|
||||||
|
|
||||||
response.headers.add('Content-Disposition', 'attachment; filename=%s.pdf;' % reportname)
|
response.headers.add('Content-Disposition', 'attachment; filename=%s.pdf;' % reportname)
|
||||||
response.set_cookie('fileToken', token)
|
response.set_cookie('fileToken', token)
|
||||||
return response
|
return response
|
||||||
elif type =='controller':
|
elif type =='controller':
|
||||||
from werkzeug.test import Client
|
|
||||||
from werkzeug.wrappers import BaseResponse
|
|
||||||
from werkzeug.datastructures import Headers
|
|
||||||
reqheaders = Headers(request.httprequest.headers)
|
reqheaders = Headers(request.httprequest.headers)
|
||||||
response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True)
|
response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True)
|
||||||
response.set_cookie('fileToken', token)
|
response.set_cookie('fileToken', token)
|
||||||
@@ -132,33 +127,3 @@ class ReportController(Controller):
|
|||||||
@route(['/report/check_wkhtmltopdf'], type='json', auth="user")
|
@route(['/report/check_wkhtmltopdf'], type='json', auth="user")
|
||||||
def check_wkhtmltopdf(self):
|
def check_wkhtmltopdf(self):
|
||||||
return request.registry['report']._check_wkhtmltopdf()
|
return request.registry['report']._check_wkhtmltopdf()
|
||||||
|
|
||||||
def _eval_params(self, param):
|
|
||||||
"""Parse a dict generated by the webclient (javascript) into a python dict.
|
|
||||||
"""
|
|
||||||
if isinstance(param, dict):
|
|
||||||
for key, value in param.iteritems():
|
|
||||||
if value.lower() == 'false':
|
|
||||||
param[key] = False
|
|
||||||
elif value.lower() == 'true':
|
|
||||||
param[key] = True
|
|
||||||
elif ',' in value:
|
|
||||||
try:
|
|
||||||
param[key] = [int(i) for i in value.split(',')]
|
|
||||||
except ValueError:
|
|
||||||
param[key] = value.split(',')
|
|
||||||
if len(param[key]) == 1:
|
|
||||||
param[key] = value
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
param[key] = int(value)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
if isinstance(param, (str, unicode)):
|
|
||||||
param = [int(i) for i in param.split(',')]
|
|
||||||
if isinstance(param, list):
|
|
||||||
param = list(set(param))
|
|
||||||
if isinstance(param, int):
|
|
||||||
param = [param]
|
|
||||||
return param
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
import report
|
import report
|
||||||
import report_paperformat
|
import report_paperformat
|
||||||
|
import abstract_report
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# Copyright (C) 2014-Today OpenERP SA (<http://www.openerp.com>).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
from openerp.osv import osv
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractReport(osv.AbstractModel):
|
||||||
|
"""Model used to embed old style reports"""
|
||||||
|
_name = 'report.abstract_report'
|
||||||
|
_template = None
|
||||||
|
_wrapped_report_class = None
|
||||||
|
|
||||||
|
def render_html(self, cr, uid, ids, data=None, context=None):
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
|
||||||
|
# If the key 'landscape' is present in data['form'], passing it into the context
|
||||||
|
if data and data.get('form', {}).get('landscape'):
|
||||||
|
context['landscape'] = True
|
||||||
|
|
||||||
|
if context and context.get('active_ids'):
|
||||||
|
# Browse the selected objects via their reference in context
|
||||||
|
model = context.get('active_model') or context.get('model')
|
||||||
|
objects_model = self.pool[model]
|
||||||
|
objects = objects_model.browse(cr, uid, context['active_ids'], context=context)
|
||||||
|
else:
|
||||||
|
# If no context is set (for instance, during test execution), build one
|
||||||
|
model = self.pool['report']._get_report_from_name(cr, uid, self._template).model
|
||||||
|
objects_model = self.pool[model]
|
||||||
|
objects = objects_model.browse(cr, uid, ids, context=context)
|
||||||
|
context['active_model'] = model
|
||||||
|
context['active_ids'] = ids
|
||||||
|
|
||||||
|
# Generate the old style report
|
||||||
|
wrapped_report = self._wrapped_report_class(cr, uid, '', context=context)
|
||||||
|
wrapped_report.set_context(objects, data, ids)
|
||||||
|
|
||||||
|
# Rendering self._template with the wrapped report instance localcontext as
|
||||||
|
# rendering environment
|
||||||
|
docargs = wrapped_report.localcontext
|
||||||
|
docargs['docs'] = docargs.get('objects')
|
||||||
|
return self.pool['report'].render(cr, uid, [], self._template, docargs, context=context)
|
||||||
+76
-192
@@ -20,9 +20,8 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from openerp.osv import osv
|
from openerp.osv import osv
|
||||||
|
from openerp.tools import config
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, config
|
|
||||||
from openerp.osv.fields import float as float_field, function as function_field, datetime as datetime_field
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@@ -34,8 +33,6 @@ import tempfile
|
|||||||
import lxml.html
|
import lxml.html
|
||||||
import cStringIO
|
import cStringIO
|
||||||
import subprocess
|
import subprocess
|
||||||
from datetime import datetime
|
|
||||||
from functools import partial
|
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
try:
|
try:
|
||||||
from pyPdf import PdfFileWriter, PdfFileReader
|
from pyPdf import PdfFileWriter, PdfFileReader
|
||||||
@@ -46,7 +43,7 @@ except ImportError:
|
|||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
"""Check the presence of wkhtmltopdf and return its version."""
|
"""Check the presence of wkhtmltopdf and return its version at OpnerERP start-up."""
|
||||||
wkhtmltopdf_state = 'install'
|
wkhtmltopdf_state = 'install'
|
||||||
try:
|
try:
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
@@ -70,106 +67,26 @@ class Report(osv.Model):
|
|||||||
|
|
||||||
public_user = None
|
public_user = None
|
||||||
|
|
||||||
|
MINIMAL_HTML_PAGE = """
|
||||||
|
<base href="{base_url}">
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html style="height: 0;">
|
||||||
|
<head>
|
||||||
|
<link href="/report/static/src/css/reset.min.css" rel="stylesheet"/>
|
||||||
|
<link href="/web/static/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
|
||||||
|
<link href="/website/static/src/css/website.css" rel="stylesheet"/>
|
||||||
|
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet"/>
|
||||||
|
<style type='text/css'>{css}</style>
|
||||||
|
{subst}
|
||||||
|
</head>
|
||||||
|
<body class="container" onload="subst()">
|
||||||
|
{body}
|
||||||
|
</body>
|
||||||
|
</html>"""
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
# Extension of ir_ui_view.render with arguments frequently used in reports
|
# Extension of ir_ui_view.render with arguments frequently used in reports
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
def _get_digits(self, cr=None, uid=None, obj=None, f=None, dp=None):
|
|
||||||
d = DEFAULT_DIGITS = 2
|
|
||||||
if dp:
|
|
||||||
decimal_precision_obj = self.pool['decimal.precision']
|
|
||||||
ids = decimal_precision_obj.search(cr, uid, [('name', '=', dp)])
|
|
||||||
if ids:
|
|
||||||
d = decimal_precision_obj.browse(cr, uid, ids)[0].digits
|
|
||||||
elif obj and f:
|
|
||||||
res_digits = getattr(obj._columns[f], 'digits', lambda x: ((16, DEFAULT_DIGITS)))
|
|
||||||
if isinstance(res_digits, tuple):
|
|
||||||
d = res_digits[1]
|
|
||||||
else:
|
|
||||||
d = res_digits(cr)[1]
|
|
||||||
elif (hasattr(obj, '_field') and
|
|
||||||
isinstance(obj._field, (float_field, function_field)) and
|
|
||||||
obj._field.digits):
|
|
||||||
d = obj._field.digits[1] or DEFAULT_DIGITS
|
|
||||||
return d
|
|
||||||
|
|
||||||
def _get_lang_dict(self, cr, uid):
|
|
||||||
pool_lang = self.pool['res.lang']
|
|
||||||
lang = self.localcontext.get('lang', 'en_US') or 'en_US'
|
|
||||||
lang_ids = pool_lang.search(cr, uid, [('code', '=', lang)])[0]
|
|
||||||
lang_obj = pool_lang.browse(cr, uid, lang_ids)
|
|
||||||
lang_dict = {
|
|
||||||
'lang_obj': lang_obj,
|
|
||||||
'date_format': lang_obj.date_format,
|
|
||||||
'time_format': lang_obj.time_format
|
|
||||||
}
|
|
||||||
self.lang_dict.update(lang_dict)
|
|
||||||
self.default_lang[lang] = self.lang_dict.copy()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False, dp=False, currency_obj=False, cr=None, uid=None):
|
|
||||||
"""
|
|
||||||
Assuming 'Account' decimal.precision=3:
|
|
||||||
formatLang(value) -> digits=2 (default)
|
|
||||||
formatLang(value, digits=4) -> digits=4
|
|
||||||
formatLang(value, dp='Account') -> digits=3
|
|
||||||
formatLang(value, digits=5, dp='Account') -> digits=5
|
|
||||||
"""
|
|
||||||
def get_date_length(date_format=DEFAULT_SERVER_DATE_FORMAT):
|
|
||||||
return len((datetime.now()).strftime(date_format))
|
|
||||||
|
|
||||||
# In case we use formatLang on the model (and not in the rendering environment).
|
|
||||||
if not hasattr(self, 'land_ditct'):
|
|
||||||
self.localcontext = {}
|
|
||||||
self.lang_dict = {}
|
|
||||||
self.default_lang = {}
|
|
||||||
self._get_lang_dict(cr, uid)
|
|
||||||
self.lang_dict_called = True
|
|
||||||
|
|
||||||
if digits is None:
|
|
||||||
if dp:
|
|
||||||
digits = self._get_digits(cr, uid, dp=dp)
|
|
||||||
else:
|
|
||||||
digits = self._get_digits(cr, uid, value)
|
|
||||||
|
|
||||||
if isinstance(value, (str, unicode)) and not value:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
if not self.lang_dict_called:
|
|
||||||
self._get_lang_dict(cr, uid)
|
|
||||||
self.lang_dict_called = True
|
|
||||||
|
|
||||||
if date or date_time:
|
|
||||||
if not str(value):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
date_format = self.lang_dict['date_format']
|
|
||||||
parse_format = DEFAULT_SERVER_DATE_FORMAT
|
|
||||||
if date_time:
|
|
||||||
value = value.split('.')[0]
|
|
||||||
date_format = date_format + " " + self.lang_dict['time_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(cr, uid, timestamp=date, context=self.localcontext)
|
|
||||||
return date.strftime(date_format.encode('utf-8'))
|
|
||||||
|
|
||||||
res = self.lang_dict['lang_obj'].format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
|
|
||||||
if currency_obj:
|
|
||||||
if currency_obj.position == 'after':
|
|
||||||
res = '%s %s' % (res, currency_obj.symbol)
|
|
||||||
elif currency_obj and currency_obj.position == 'before':
|
|
||||||
res = '%s %s' % (currency_obj.symbol, res)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def render(self, cr, uid, ids, template, values=None, context=None):
|
def render(self, cr, uid, ids, template, values=None, context=None):
|
||||||
"""Allow to render a QWeb template python-side. This function returns the 'ir.ui.view'
|
"""Allow to render a QWeb template python-side. This function returns the 'ir.ui.view'
|
||||||
render but embellish it with some variables/methods used in reports.
|
render but embellish it with some variables/methods used in reports.
|
||||||
@@ -183,15 +100,6 @@ class Report(osv.Model):
|
|||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
self.lang_dict = self.default_lang = {}
|
|
||||||
self.lang_dict_called = False
|
|
||||||
self.localcontext = {
|
|
||||||
'lang': context.get('lang'),
|
|
||||||
'tz': context.get('tz'),
|
|
||||||
'uid': context.get('uid'),
|
|
||||||
}
|
|
||||||
self._get_lang_dict(cr, uid)
|
|
||||||
|
|
||||||
view_obj = self.pool['ir.ui.view']
|
view_obj = self.pool['ir.ui.view']
|
||||||
|
|
||||||
def render_doc(doc_id, model, template):
|
def render_doc(doc_id, model, template):
|
||||||
@@ -217,22 +125,20 @@ class Report(osv.Model):
|
|||||||
qcontext['o'] = self.pool[model].browse(cr, uid, doc_id, context=ctx)
|
qcontext['o'] = self.pool[model].browse(cr, uid, doc_id, context=ctx)
|
||||||
return view_obj.render(cr, uid, template, qcontext, context=ctx)
|
return view_obj.render(cr, uid, template, qcontext, context=ctx)
|
||||||
|
|
||||||
|
user = self.pool['res.users'].browse(cr, uid, uid)
|
||||||
values.update({
|
values.update({
|
||||||
'time': time,
|
'time': time,
|
||||||
'formatLang': partial(self.formatLang, cr=cr, uid=uid),
|
|
||||||
'get_digits': partial(self._get_digits, cr=cr, uid=uid),
|
|
||||||
'render_doc': render_doc,
|
'render_doc': render_doc,
|
||||||
'editable': True, # Will active inherit_branding
|
'editable': True, # Will active inherit_branding
|
||||||
'res_company': self.pool['res.users'].browse(cr, uid, uid).company_id,
|
'user': user,
|
||||||
|
'res_company': user.company_id,
|
||||||
'website': False, # Will be overidden by ir.ui.view if the request has website enabled
|
'website': False, # Will be overidden by ir.ui.view if the request has website enabled
|
||||||
})
|
})
|
||||||
|
|
||||||
return view_obj.render(cr, uid, template, values, context=context)
|
return view_obj.render(cr, uid, template, values, context=context)
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
# Main reports methods
|
# Main report methods
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
def get_html(self, cr, uid, ids, report_name, data=None, context=None):
|
def get_html(self, cr, uid, ids, report_name, data=None, context=None):
|
||||||
"""This method generates and returns html version of a report.
|
"""This method generates and returns html version of a report.
|
||||||
"""
|
"""
|
||||||
@@ -241,7 +147,7 @@ class Report(osv.Model):
|
|||||||
try:
|
try:
|
||||||
report_model_name = 'report.%s' % report_name
|
report_model_name = 'report.%s' % report_name
|
||||||
particularreport_obj = self.pool[report_model_name]
|
particularreport_obj = self.pool[report_model_name]
|
||||||
return particularreport_obj.render_html(cr, uid, ids, data={'form': data}, context=context)
|
return particularreport_obj.render_html(cr, uid, ids, data=data, context=context)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
report = self._get_report_from_name(cr, uid, report_name)
|
report = self._get_report_from_name(cr, uid, report_name)
|
||||||
report_obj = self.pool[report.model]
|
report_obj = self.pool[report.model]
|
||||||
@@ -262,41 +168,12 @@ class Report(osv.Model):
|
|||||||
if html is None:
|
if html is None:
|
||||||
html = self.get_html(cr, uid, ids, report_name, data=data, context=context)
|
html = self.get_html(cr, uid, ids, report_name, data=data, context=context)
|
||||||
|
|
||||||
html = html.decode('utf-8')
|
html = html.decode('utf-8') # Ensure the current document is utf-8 encoded.
|
||||||
|
|
||||||
# Get the ir.actions.report.xml record we are working on.
|
# Get the ir.actions.report.xml record we are working on.
|
||||||
report = self._get_report_from_name(cr, uid, report_name)
|
report = self._get_report_from_name(cr, uid, report_name)
|
||||||
|
# Check if we have to save the report or if we have to get one from the db.
|
||||||
# Check attachment_use field. If set to true and an existing pdf is already saved, load
|
save_in_attachment = self._check_attachment_use(cr, uid, ids, report)
|
||||||
# this one now. Else, mark save it.
|
|
||||||
save_in_attachment = {}
|
|
||||||
|
|
||||||
if report.attachment_use is True:
|
|
||||||
save_in_attachment['model'] = report.model
|
|
||||||
save_in_attachment['loaded_documents'] = {}
|
|
||||||
|
|
||||||
for record_id in ids:
|
|
||||||
obj = self.pool[report.model].browse(cr, uid, record_id)
|
|
||||||
filename = eval(report.attachment, {'object': obj, 'time': time})
|
|
||||||
|
|
||||||
if filename is False: # May be false if, for instance, the record is in draft state
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
alreadyindb = [('datas_fname', '=', filename),
|
|
||||||
('res_model', '=', report.model),
|
|
||||||
('res_id', '=', record_id)]
|
|
||||||
|
|
||||||
attach_ids = self.pool['ir.attachment'].search(cr, uid, alreadyindb)
|
|
||||||
if attach_ids:
|
|
||||||
# Add the loaded pdf in the loaded_documents list
|
|
||||||
pdf = self.pool['ir.attachment'].browse(cr, uid, attach_ids[0]).datas
|
|
||||||
pdf = base64.decodestring(pdf)
|
|
||||||
save_in_attachment['loaded_documents'][record_id] = pdf
|
|
||||||
_logger.info('The PDF document %s was loaded from the database' % filename)
|
|
||||||
else:
|
|
||||||
# Mark current document to be saved
|
|
||||||
save_in_attachment[id] = filename
|
|
||||||
|
|
||||||
# Get the paperformat associated to the report, otherwise fallback on the company one.
|
# Get the paperformat associated to the report, otherwise fallback on the company one.
|
||||||
if not report.paperformat_id:
|
if not report.paperformat_id:
|
||||||
user = self.pool['res.users'].browse(cr, uid, uid)
|
user = self.pool['res.users'].browse(cr, uid, uid)
|
||||||
@@ -305,34 +182,15 @@ class Report(osv.Model):
|
|||||||
paperformat = report.paperformat_id
|
paperformat = report.paperformat_id
|
||||||
|
|
||||||
# Preparing the minimal html pages
|
# Preparing the minimal html pages
|
||||||
#subst = self._get_url_content('/report/static/src/js/subst.js')[0] # Used in age numbering
|
|
||||||
subst = "<script src='/report/static/src/js/subst.js'></script> "
|
subst = "<script src='/report/static/src/js/subst.js'></script> "
|
||||||
css = '' # Will contain local css
|
css = '' # Will contain local css
|
||||||
|
|
||||||
headerhtml = []
|
headerhtml = []
|
||||||
contenthtml = []
|
contenthtml = []
|
||||||
footerhtml = []
|
footerhtml = []
|
||||||
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||||
|
|
||||||
minimalhtml = """
|
# The received html report must be simplified. We convert it in a xml tree
|
||||||
<base href="{base_url}">
|
# in order to extract headers, bodies and footers.
|
||||||
<!DOCTYPE html>
|
|
||||||
<html style="height: 0;">
|
|
||||||
<head>
|
|
||||||
<link href="/report/static/src/css/reset.min.css" rel="stylesheet"/>
|
|
||||||
<link href="/web/static/lib/bootstrap/css/bootstrap.css" rel="stylesheet"/>
|
|
||||||
<link href="/website/static/src/css/website.css" rel="stylesheet"/>
|
|
||||||
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet"/>
|
|
||||||
<style type='text/css'>{css}</style>
|
|
||||||
{subst}
|
|
||||||
</head>
|
|
||||||
<body class="container" onload='subst()'>
|
|
||||||
{body}
|
|
||||||
</body>
|
|
||||||
</html>"""
|
|
||||||
|
|
||||||
# The retrieved html report must be simplified. We convert it into a xml tree
|
|
||||||
# via lxml in order to extract headers, footers and content.
|
|
||||||
try:
|
try:
|
||||||
root = lxml.html.fromstring(html)
|
root = lxml.html.fromstring(html)
|
||||||
|
|
||||||
@@ -341,12 +199,12 @@ class Report(osv.Model):
|
|||||||
|
|
||||||
for node in root.xpath("//div[@class='header']"):
|
for node in root.xpath("//div[@class='header']"):
|
||||||
body = lxml.html.tostring(node)
|
body = lxml.html.tostring(node)
|
||||||
header = minimalhtml.format(css=css, subst=subst, body=body, base_url=base_url)
|
header = self.MINIMAL_HTML_PAGE.format(css=css, subst=subst, body=body, base_url=base_url)
|
||||||
headerhtml.append(header)
|
headerhtml.append(header)
|
||||||
|
|
||||||
for node in root.xpath("//div[@class='footer']"):
|
for node in root.xpath("//div[@class='footer']"):
|
||||||
body = lxml.html.tostring(node)
|
body = lxml.html.tostring(node)
|
||||||
footer = minimalhtml.format(css=css, subst=subst, body=body, base_url=base_url)
|
footer = self.MINIMAL_HTML_PAGE.format(css=css, subst=subst, body=body, base_url=base_url)
|
||||||
footerhtml.append(footer)
|
footerhtml.append(footer)
|
||||||
|
|
||||||
for node in root.xpath("//div[@class='page']"):
|
for node in root.xpath("//div[@class='page']"):
|
||||||
@@ -363,7 +221,7 @@ class Report(osv.Model):
|
|||||||
reportid = False
|
reportid = False
|
||||||
|
|
||||||
body = lxml.html.tostring(node)
|
body = lxml.html.tostring(node)
|
||||||
reportcontent = minimalhtml.format(css=css, subst='', body=body, base_url=base_url)
|
reportcontent = self.MINIMAL_HTML_PAGE.format(css=css, subst='', body=body, base_url=base_url)
|
||||||
contenthtml.append(tuple([reportid, reportcontent]))
|
contenthtml.append(tuple([reportid, reportcontent]))
|
||||||
|
|
||||||
except lxml.etree.XMLSyntaxError:
|
except lxml.etree.XMLSyntaxError:
|
||||||
@@ -390,37 +248,60 @@ class Report(osv.Model):
|
|||||||
|
|
||||||
:param report_name: Name of the template to generate an action for
|
:param report_name: Name of the template to generate an action for
|
||||||
"""
|
"""
|
||||||
# TODO: return the action for the ids passed in args
|
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
if data is None:
|
report_obj = self.pool['ir.actions.report.xml']
|
||||||
data = {}
|
|
||||||
|
|
||||||
report_obj = self.pool.get('ir.actions.report.xml')
|
|
||||||
idreport = report_obj.search(cr, uid, [('report_name', '=', report_name)], context=context)
|
idreport = report_obj.search(cr, uid, [('report_name', '=', report_name)], context=context)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
report = report_obj.browse(cr, uid, idreport[0], context=context)
|
report = report_obj.browse(cr, uid, idreport[0], context=context)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise osv.except_osv(_('Bad Report'),
|
raise osv.except_osv(_('Bad Report'), _('This report is not loaded into the database.'))
|
||||||
_('This report is not loaded into the database.'))
|
|
||||||
|
|
||||||
action = {
|
action = {
|
||||||
|
'context': context,
|
||||||
|
'data': data,
|
||||||
'type': 'ir.actions.report.xml',
|
'type': 'ir.actions.report.xml',
|
||||||
'report_name': report.report_name,
|
'report_name': report.report_name,
|
||||||
'report_type': report.report_type,
|
'report_type': report.report_type,
|
||||||
'report_file': report.report_file,
|
'report_file': report.report_file,
|
||||||
}
|
}
|
||||||
|
|
||||||
if data:
|
|
||||||
action['datas'] = data
|
|
||||||
|
|
||||||
return action
|
return action
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
# Report generation helpers
|
# Report generation helpers
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
def _check_attachment_use(self, cr, uid, ids, report):
|
||||||
|
""" Check attachment_use field. If set to true and an existing pdf is already saved, load
|
||||||
|
this one now. Else, mark save it.
|
||||||
|
"""
|
||||||
|
save_in_attachment = {}
|
||||||
|
if report.attachment_use is True:
|
||||||
|
save_in_attachment['model'] = report.model
|
||||||
|
save_in_attachment['loaded_documents'] = {}
|
||||||
|
|
||||||
|
for record_id in ids:
|
||||||
|
obj = self.pool[report.model].browse(cr, uid, record_id)
|
||||||
|
filename = eval(report.attachment, {'object': obj, 'time': time})
|
||||||
|
|
||||||
|
if filename is False: # May be false if, for instance, the record is in draft state
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
alreadyindb = [('datas_fname', '=', filename),
|
||||||
|
('res_model', '=', report.model),
|
||||||
|
('res_id', '=', record_id)]
|
||||||
|
|
||||||
|
attach_ids = self.pool['ir.attachment'].search(cr, uid, alreadyindb)
|
||||||
|
if attach_ids:
|
||||||
|
# Add the loaded pdf in the loaded_documents list
|
||||||
|
pdf = self.pool['ir.attachment'].browse(cr, uid, attach_ids[0]).datas
|
||||||
|
pdf = base64.decodestring(pdf)
|
||||||
|
save_in_attachment['loaded_documents'][record_id] = pdf
|
||||||
|
_logger.info('The PDF document %s was loaded from the database' % filename)
|
||||||
|
else:
|
||||||
|
# Mark current document to be saved
|
||||||
|
save_in_attachment[record_id] = filename
|
||||||
|
return save_in_attachment
|
||||||
|
|
||||||
def _check_wkhtmltopdf(self):
|
def _check_wkhtmltopdf(self):
|
||||||
return wkhtmltopdf_state
|
return wkhtmltopdf_state
|
||||||
@@ -445,7 +326,8 @@ class Report(osv.Model):
|
|||||||
# Passing the cookie to wkhtmltopdf in order to resolve URL.
|
# Passing the cookie to wkhtmltopdf in order to resolve URL.
|
||||||
try:
|
try:
|
||||||
from openerp.addons.web.http import request
|
from openerp.addons.web.http import request
|
||||||
command_args.extend(['--cookie', 'session_id', request.session.sid])
|
if request:
|
||||||
|
command_args.extend(['--cookie', 'session_id', request.session.sid])
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -453,6 +335,8 @@ class Report(osv.Model):
|
|||||||
if paperformat:
|
if paperformat:
|
||||||
command_args.extend(self._build_wkhtmltopdf_args(paperformat, spec_paperformat_args))
|
command_args.extend(self._build_wkhtmltopdf_args(paperformat, spec_paperformat_args))
|
||||||
|
|
||||||
|
command_args.extend(['--load-error-handling', 'ignore'])
|
||||||
|
|
||||||
if landscape and '--orientation' in command_args:
|
if landscape and '--orientation' in command_args:
|
||||||
command_args_copy = list(command_args)
|
command_args_copy = list(command_args)
|
||||||
for index, elem in enumerate(command_args_copy):
|
for index, elem in enumerate(command_args_copy):
|
||||||
@@ -472,7 +356,7 @@ class Report(osv.Model):
|
|||||||
# Directly load the document if we have it
|
# Directly load the document if we have it
|
||||||
if save_in_attachment and save_in_attachment['loaded_documents'].get(reporthtml[0]):
|
if save_in_attachment and save_in_attachment['loaded_documents'].get(reporthtml[0]):
|
||||||
pdfreport.write(save_in_attachment['loaded_documents'].get(reporthtml[0]))
|
pdfreport.write(save_in_attachment['loaded_documents'].get(reporthtml[0]))
|
||||||
pdfreport.flush()
|
pdfreport.seek(0)
|
||||||
pdfdocuments.append(pdfreport)
|
pdfdocuments.append(pdfreport)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -481,7 +365,7 @@ class Report(osv.Model):
|
|||||||
head_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.header.tmp.',
|
head_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.header.tmp.',
|
||||||
dir=tmp_dir, mode='w+')
|
dir=tmp_dir, mode='w+')
|
||||||
head_file.write(headers[index])
|
head_file.write(headers[index])
|
||||||
head_file.flush()
|
head_file.seek(0)
|
||||||
command_arg_local.extend(['--header-html', head_file.name])
|
command_arg_local.extend(['--header-html', head_file.name])
|
||||||
|
|
||||||
# Footer stuff
|
# Footer stuff
|
||||||
@@ -489,14 +373,14 @@ class Report(osv.Model):
|
|||||||
foot_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.footer.tmp.',
|
foot_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.footer.tmp.',
|
||||||
dir=tmp_dir, mode='w+')
|
dir=tmp_dir, mode='w+')
|
||||||
foot_file.write(footers[index])
|
foot_file.write(footers[index])
|
||||||
foot_file.flush()
|
foot_file.seek(0)
|
||||||
command_arg_local.extend(['--footer-html', foot_file.name])
|
command_arg_local.extend(['--footer-html', foot_file.name])
|
||||||
|
|
||||||
# Body stuff
|
# Body stuff
|
||||||
content_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.body.tmp.',
|
content_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.body.tmp.',
|
||||||
dir=tmp_dir, mode='w+')
|
dir=tmp_dir, mode='w+')
|
||||||
content_file.write(reporthtml[1])
|
content_file.write(reporthtml[1])
|
||||||
content_file.flush()
|
content_file.seek(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If the server is running with only one worker, ask to create a secund to be able
|
# If the server is running with only one worker, ask to create a secund to be able
|
||||||
@@ -533,7 +417,7 @@ class Report(osv.Model):
|
|||||||
_logger.info('The PDF document %s is now saved in the '
|
_logger.info('The PDF document %s is now saved in the '
|
||||||
'database' % attachment['name'])
|
'database' % attachment['name'])
|
||||||
|
|
||||||
pdfreport.flush()
|
pdfreport.seek(0)
|
||||||
pdfdocuments.append(pdfreport)
|
pdfdocuments.append(pdfreport)
|
||||||
|
|
||||||
if headers:
|
if headers:
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ openerp.report = function(instance) {
|
|||||||
var self = this;
|
var self = this;
|
||||||
instance.web.blockUI();
|
instance.web.blockUI();
|
||||||
action = _.clone(action);
|
action = _.clone(action);
|
||||||
var eval_contexts = ([instance.session.user_context] || []).concat([action.context]);
|
|
||||||
action.context = instance.web.pyeval.eval('contexts',eval_contexts);
|
|
||||||
_t = instance.web._t;
|
_t = instance.web._t;
|
||||||
|
|
||||||
// QWeb reports
|
// QWeb reports
|
||||||
@@ -15,43 +13,33 @@ openerp.report = function(instance) {
|
|||||||
var report_url = '';
|
var report_url = '';
|
||||||
switch (action.report_type) {
|
switch (action.report_type) {
|
||||||
case 'qweb-html':
|
case 'qweb-html':
|
||||||
report_url = '/report/' + action.report_name;
|
report_url = '/report/html/' + action.report_name;
|
||||||
break;
|
break;
|
||||||
case 'qweb-pdf':
|
case 'qweb-pdf':
|
||||||
report_url = '/report/pdf/report/' + action.report_name;
|
report_url = '/report/pdf/' + action.report_name;
|
||||||
break;
|
break;
|
||||||
case 'controller':
|
case 'controller':
|
||||||
report_url = action.report_file;
|
report_url = action.report_file;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
report_url = '/report/' + action.report_name;
|
report_url = '/report/html/' + action.report_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// single/multiple id(s): no query string
|
// generic report: no query string
|
||||||
// wizard: query string of action.datas.form
|
// particular: query string of action.data.form and context
|
||||||
if (!('datas' in action)) {
|
if (!('data' in action) || !(action.data)) {
|
||||||
if ('active_ids' in action.context) {
|
if ('active_ids' in action.context) {
|
||||||
report_url += "/" + action.context.active_ids.join(',');
|
report_url += "/" + action.context.active_ids.join(',');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_.each(action.datas.form, function(value, key) {
|
report_url += "?options=" + encodeURI(JSON.stringify(action.data));
|
||||||
// will be erased when all wizards are rewritten
|
report_url += "&context=" + encodeURI(JSON.stringify(action.context));
|
||||||
if (key.substring(0, 12) === 'used_context') {
|
|
||||||
delete action.datas.form[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($.type(value) === 'array') {
|
|
||||||
action.datas.form[key] = value.join(',');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
report_url += "?" + $.param(action.datas.form);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.report_type == 'qweb-html') {
|
if (action.report_type == 'qweb-html') {
|
||||||
// Open the html report in a popup
|
|
||||||
window.open(report_url, '_blank', 'height=900,width=1280');
|
window.open(report_url, '_blank', 'height=900,width=1280');
|
||||||
instance.web.unblockUI();
|
instance.web.unblockUI();
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
// Trigger the download of the pdf/controller report
|
// Trigger the download of the pdf/controller report
|
||||||
var c = openerp.webclient.crashmanager;
|
var c = openerp.webclient.crashmanager;
|
||||||
@@ -68,6 +56,7 @@ openerp.report = function(instance) {
|
|||||||
wkhtmltopdf.org</a>'), true);
|
wkhtmltopdf.org</a>'), true);
|
||||||
window.open(report_url.substring(12), '_blank', 'height=768,width=1024');
|
window.open(report_url.substring(12), '_blank', 'height=768,width=1024');
|
||||||
instance.web.unblockUI();
|
instance.web.unblockUI();
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (presence == 'upgrade') {
|
if (presence == 'upgrade') {
|
||||||
self.do_notify(_t('Report'), _t('You should upgrade your version of\
|
self.do_notify(_t('Report'), _t('You should upgrade your version of\
|
||||||
@@ -75,22 +64,15 @@ openerp.report = function(instance) {
|
|||||||
support for table-breaking between pages.<br><br><a href="http://wkhtmltopdf.org/" \
|
support for table-breaking between pages.<br><br><a href="http://wkhtmltopdf.org/" \
|
||||||
target="_blank">wkhtmltopdf.org</a>'), true);
|
target="_blank">wkhtmltopdf.org</a>'), true);
|
||||||
}
|
}
|
||||||
self.session.get_file({
|
|
||||||
url: '/report/download',
|
|
||||||
data: {data: JSON.stringify(response)},
|
|
||||||
complete: openerp.web.unblockUI,
|
|
||||||
error: c.rpc_error.bind(c)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
self.session.get_file({
|
self.session.get_file({
|
||||||
url: '/report/download',
|
url: '/report/download',
|
||||||
data: {data: JSON.stringify(response)},
|
data: {data: JSON.stringify(response)},
|
||||||
complete: openerp.web.unblockUI,
|
complete: openerp.web.unblockUI,
|
||||||
error: c.rpc_error.bind(c)
|
error: c.rpc_error.bind(c)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return self._super(action, options);
|
return self._super(action, options);
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# Copyright (C) 2014-Today OpenERP SA (<http://www.openerp.com>).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
import logging
|
import logging
|
||||||
import openerp
|
import openerp
|
||||||
|
|
||||||
@@ -11,26 +29,24 @@ _logger = logging.getLogger(__name__)
|
|||||||
@openerp.tests.common.post_install(True)
|
@openerp.tests.common.post_install(True)
|
||||||
class TestReports(openerp.tests.TransactionCase):
|
class TestReports(openerp.tests.TransactionCase):
|
||||||
def test_reports(self):
|
def test_reports(self):
|
||||||
return # commented out until post_install tests are working
|
|
||||||
|
|
||||||
registry, cr, uid = self.registry, self.cr, self.uid
|
registry, cr, uid = self.registry, self.cr, self.uid
|
||||||
r_model = registry('ir.actions.report.xml')
|
r_model = registry('ir.actions.report.xml')
|
||||||
domain = [('report_type', 'like', 'qweb')]
|
domain = [('report_type', 'like', 'qweb')]
|
||||||
for r in r_model.browse(cr, uid, r_model.search(cr, uid, domain)):
|
for r in r_model.browse(cr, uid, r_model.search(cr, uid, domain)):
|
||||||
report_model = 'report.%s' % r.report_name
|
report_model = 'report.%s' % r.report_name
|
||||||
particular_model = registry('ir.model').search(cr, uid, [('model', '=', report_model)])
|
try:
|
||||||
|
registry(report_model)
|
||||||
|
except KeyError:
|
||||||
# Only test the generic reports here
|
# Only test the generic reports here
|
||||||
if particular_model:
|
_logger.info("testing report %s", r.report_name)
|
||||||
|
report_model = registry(r.model)
|
||||||
|
report_model_ids = report_model.search(cr, uid, [], limit=10)
|
||||||
|
if not report_model_ids:
|
||||||
|
_logger.info("no record found skipping report %s", r.report_name)
|
||||||
|
if not r.multi:
|
||||||
|
report_model_ids = report_model_ids[:1]
|
||||||
|
|
||||||
|
# Test report generation
|
||||||
|
registry('report').get_html(cr, uid, report_model_ids, r.report_name)
|
||||||
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
_logger.info("testing report %s", r.report_name)
|
|
||||||
report_model = registry(r.model)
|
|
||||||
report_model_ids = report_model.search(cr, uid, [], limit=10)
|
|
||||||
if not report_model_ids:
|
|
||||||
_logger.info("no record found skipping report %s", r.report_name)
|
|
||||||
if not r.multi:
|
|
||||||
report_model_ids = report_model_ids[:1]
|
|
||||||
|
|
||||||
# Test report generation
|
|
||||||
registry('report').get_html(cr, uid, report_model_ids, r.report_name)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user