[IMP] Added the possibility to define ultra-specific reports outputing any king of file. These reports are of type 'controller' because they redirects to a controller that must returns a response containing the http headers 'content-type' and 'content-disposition'. The route for this controller is specified in the report_file field. Added an XLS version of the tax report for the POC (testable by setting 'report_vat' type to controller and setting '/report/account.report_vat_xls' in the 'report_file' field).
bzr revid: sle@openerp.com-20140221163320-g5ouoywsuduoi0qe
This commit is contained in:
parent
65dc368cdd
commit
ffa475afcd
|
@ -22,6 +22,11 @@
|
||||||
from openerp.addons.web import http
|
from openerp.addons.web import http
|
||||||
from openerp.addons.web.http import request
|
from openerp.addons.web.http import request
|
||||||
from common_report_header import common_report_header
|
from common_report_header import common_report_header
|
||||||
|
try:
|
||||||
|
import cStringIO as StringIO
|
||||||
|
except ImportError:
|
||||||
|
import StringIO
|
||||||
|
import xlwt
|
||||||
|
|
||||||
|
|
||||||
class tax_report(http.Controller, common_report_header):
|
class tax_report(http.Controller, common_report_header):
|
||||||
|
@ -224,4 +229,43 @@ class tax_report(http.Controller, common_report_header):
|
||||||
|
|
||||||
return result_accounts
|
return result_accounts
|
||||||
|
|
||||||
|
@http.route(['/report/account.report_vat_xls'], type='http', auth='user', website=True, multilang=True)
|
||||||
|
def report_account_tax_xls(self, **data):
|
||||||
|
report_obj = request.registry['report']
|
||||||
|
self.cr, self.uid, self.pool = request.cr, request.uid, request.registry
|
||||||
|
|
||||||
|
data = report_obj.eval_params(data)
|
||||||
|
|
||||||
|
res = {}
|
||||||
|
self.period_ids = []
|
||||||
|
period_obj = self.pool.get('account.period')
|
||||||
|
self.display_detail = data['form']['display_detail']
|
||||||
|
res['periods'] = ''
|
||||||
|
res['fiscalyear'] = data['form'].get('fiscalyear_id', False)
|
||||||
|
|
||||||
|
if data['form'].get('period_from', False) and data['form'].get('period_to', False):
|
||||||
|
self.period_ids = period_obj.build_ctx_periods(self.cr, self.uid, data['form']['period_from'], data['form']['period_to'])
|
||||||
|
|
||||||
|
content = ''
|
||||||
|
lines = self._get_lines(self._get_basedon(data), company_id=data['form']['company_id'])
|
||||||
|
|
||||||
|
if lines:
|
||||||
|
xls = StringIO.StringIO()
|
||||||
|
xls_workbook = xlwt.Workbook()
|
||||||
|
vat_sheet = xls_workbook.add_sheet('report_vat')
|
||||||
|
|
||||||
|
for x in range(0, len(lines)):
|
||||||
|
for y in range(0, len(lines[0])):
|
||||||
|
vat_sheet.write(x, y, lines[x].values()[y])
|
||||||
|
|
||||||
|
xls_workbook.save(xls)
|
||||||
|
xls.seek(0)
|
||||||
|
content = xls.read()
|
||||||
|
|
||||||
|
response = request.make_response(content, headers=[
|
||||||
|
('Content-Type', 'application/vnd.ms-excel'),
|
||||||
|
('Content-Disposition', 'attachment; filename=report_vat.xls;')
|
||||||
|
])
|
||||||
|
return response
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<h2>Tax Statement</h2>
|
<h2>Tax Statement</h2>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row mt32 mb32">
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<strong>Chart of Tax:</strong>
|
<strong>Chart of Tax:</strong>
|
||||||
<p t-esc="account"/>
|
<p t-esc="account"/>
|
||||||
|
|
|
@ -83,11 +83,18 @@ class Report(http.Controller):
|
||||||
'docs': docs,
|
'docs': docs,
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.registry['report'].render(request.cr, request.uid, [], report.report_file,
|
return request.registry['report'].render(request.cr, request.uid, [], report.report_name,
|
||||||
docargs, context=request.context)
|
docargs, context=request.context)
|
||||||
|
|
||||||
@http.route(['/report/pdf/<path:path>'], type='http', auth="user", website=True)
|
@http.route(['/report/pdf/<path:path>'], type='http', auth="user", website=True)
|
||||||
def report_pdf(self, path=None, landscape=False, **post):
|
def report_pdf(self, path=None, landscape=False, **post):
|
||||||
|
"""Route converting any reports to pdf. It will get the html-rendered report, extract
|
||||||
|
header, page and footer in order to prepare minimal html pages that will be further passed
|
||||||
|
to wkhtmltopdf.
|
||||||
|
|
||||||
|
:param path: URL of the report (e.g. /report/account.report_invoice/1)
|
||||||
|
:returns: a response with 'application/pdf' headers and the pdf as content
|
||||||
|
"""
|
||||||
cr, uid, context = request.cr, request.uid, request.context
|
cr, uid, context = request.cr, request.uid, request.context
|
||||||
|
|
||||||
# Get the report we are working on.
|
# Get the report we are working on.
|
||||||
|
@ -136,14 +143,14 @@ class Report(http.Controller):
|
||||||
paperformat = report.paperformat_id
|
paperformat = report.paperformat_id
|
||||||
|
|
||||||
# Get the html report.
|
# Get the html report.
|
||||||
html = self._get_url_content('/' + path, post)
|
html = self._get_url_content('/' + path, post)[0]
|
||||||
|
|
||||||
# Get some css and script in order to build a minimal html page for the report.
|
# Get some css and script in order to build a minimal html page for the report.
|
||||||
# This page will later be sent to wkhtmltopdf.
|
# This page will later be sent to wkhtmltopdf.
|
||||||
css = self._get_url_content('/report/static/src/css/reset.min.css')
|
css = self._get_url_content('/report/static/src/css/reset.min.css')[0]
|
||||||
css += self._get_url_content('/web/static/lib/bootstrap/css/bootstrap.css')
|
css += self._get_url_content('/web/static/lib/bootstrap/css/bootstrap.css')[0]
|
||||||
css += self._get_url_content('/website/static/src/css/website.css')
|
css += self._get_url_content('/website/static/src/css/website.css')[0]
|
||||||
subst = self._get_url_content('/report/static/src/js/subst.js')
|
subst = self._get_url_content('/report/static/src/js/subst.js')[0]
|
||||||
|
|
||||||
headerhtml = []
|
headerhtml = []
|
||||||
contenthtml = []
|
contenthtml = []
|
||||||
|
@ -240,7 +247,7 @@ class Report(http.Controller):
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return content
|
return tuple([content, response.headers])
|
||||||
|
|
||||||
def _generate_wkhtml_pdf(self, headers, footers, bodies, landscape,
|
def _generate_wkhtml_pdf(self, headers, footers, bodies, landscape,
|
||||||
paperformat, spec_paperformat_args=None, save_in_attachment=None):
|
paperformat, spec_paperformat_args=None, save_in_attachment=None):
|
||||||
|
@ -440,31 +447,19 @@ class Report(http.Controller):
|
||||||
merged.close()
|
merged.close()
|
||||||
return content
|
return content
|
||||||
|
|
||||||
@http.route('/report/downloadpdf/', type='http', auth="user")
|
|
||||||
def report_pdf_attachment(self, data, token):
|
|
||||||
"""This function is only used by 'qwebactionmanager.js' in order to trigger the download of
|
|
||||||
a pdf report.
|
|
||||||
|
|
||||||
:param data: The JSON.stringified report internal url
|
|
||||||
:returns: Response with a filetoken cookie and an attachment header
|
|
||||||
"""
|
|
||||||
url = simplejson.loads(data)
|
|
||||||
pdf = self._get_url_content(url)
|
|
||||||
response = self._make_pdf_response(pdf)
|
|
||||||
response.set_cookie('fileToken', token)
|
|
||||||
response.headers.add('Content-Disposition', 'attachment; filename=report.pdf;')
|
|
||||||
return response
|
|
||||||
|
|
||||||
@http.route(['/report/barcode', '/report/barcode/<type>/<value>'], type='http', auth="user")
|
@http.route(['/report/barcode', '/report/barcode/<type>/<value>'], type='http', auth="user")
|
||||||
def barcode(self, type, value, width=300, height=50):
|
def barcode(self, type, value, width=300, height=50):
|
||||||
"""Contoller able to render barcode images thanks to reportlab.
|
"""Contoller able to render barcode images thanks to reportlab.
|
||||||
Sample: <img t-att-src="'/report/barcode/QR/%s' % o.name"/>
|
Samples:
|
||||||
|
<img t-att-src="'/report/barcode/QR/%s' % o.name"/>
|
||||||
|
<img t-att-src="'/report/barcode/?type=%s&value=%s&width=%s&height=%s' % ('QR', o.name, 200, 200)"/>
|
||||||
|
|
||||||
:param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39',
|
:param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39',
|
||||||
'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93',
|
'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93',
|
||||||
'UPCA', 'USPS_4State'
|
'UPCA', 'USPS_4State'
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
width, height = int(width), int(height)
|
||||||
barcode = createBarcodeImageInMemory(
|
barcode = createBarcodeImageInMemory(
|
||||||
type, value=value, format='png', width=width, height=height
|
type, value=value, format='png', width=width, height=height
|
||||||
)
|
)
|
||||||
|
@ -474,3 +469,29 @@ class Report(http.Controller):
|
||||||
raise exceptions.HTTPException(description='Please upgrade reportlab to at least 3.0.')
|
raise exceptions.HTTPException(description='Please upgrade reportlab to at least 3.0.')
|
||||||
|
|
||||||
return request.make_response(barcode, headers=[('Content-Type', 'image/png')])
|
return request.make_response(barcode, headers=[('Content-Type', 'image/png')])
|
||||||
|
|
||||||
|
@http.route('/report/download/', type='http', auth="user")
|
||||||
|
def report_attachment(self, data, token):
|
||||||
|
"""This function is only used by 'qwebactionmanager.js' in order to trigger the download of
|
||||||
|
a report.
|
||||||
|
|
||||||
|
:param data: The JSON.stringified report internal url
|
||||||
|
:returns: Response with a filetoken cookie and an attachment header
|
||||||
|
"""
|
||||||
|
requestcontent = simplejson.loads(data)
|
||||||
|
url, type = requestcontent[0], requestcontent[1]
|
||||||
|
file, fileheaders = self._get_url_content(url)
|
||||||
|
|
||||||
|
if type == 'qweb-pdf':
|
||||||
|
response = self._make_pdf_response(file)
|
||||||
|
response.headers.add('Content-Disposition', 'attachment; filename=report.pdf;')
|
||||||
|
elif type == 'controller':
|
||||||
|
response = request.make_response(file)
|
||||||
|
response.headers.add('Content-Disposition', fileheaders['Content-Disposition'])
|
||||||
|
response.headers.add('Content-Type', fileheaders['Content-Type'])
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
response.headers.add('Content-Length', len(file))
|
||||||
|
response.set_cookie('fileToken', token)
|
||||||
|
return response
|
||||||
|
|
|
@ -241,6 +241,7 @@ class report(osv.Model):
|
||||||
'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,
|
||||||
}
|
}
|
||||||
|
|
||||||
if datas:
|
if datas:
|
||||||
|
|
|
@ -9,13 +9,22 @@ openerp.report = function(instance) {
|
||||||
action.context = instance.web.pyeval.eval('contexts',eval_contexts);
|
action.context = instance.web.pyeval.eval('contexts',eval_contexts);
|
||||||
|
|
||||||
// QWeb reports
|
// QWeb reports
|
||||||
if ('report_type' in action && (action.report_type == 'qweb-html' || action.report_type == 'qweb-pdf')) {
|
if ('report_type' in action && (action.report_type == 'qweb-html' || action.report_type == 'qweb-pdf' || action.report_type == 'controller')) {
|
||||||
var report_url = '';
|
|
||||||
|
|
||||||
if (action.report_type == 'qweb-html') {
|
var report_url = ''
|
||||||
|
switch (action.report_type) {
|
||||||
|
case 'qweb-html':
|
||||||
report_url = '/report/' + action.report_name;
|
report_url = '/report/' + action.report_name;
|
||||||
} else {
|
break;
|
||||||
|
case 'qweb-pdf':
|
||||||
report_url = '/report/pdf/report/' + action.report_name;
|
report_url = '/report/pdf/report/' + action.report_name;
|
||||||
|
break;
|
||||||
|
case 'controller':
|
||||||
|
report_url = action.report_file;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
report_url = '/report/' + action.report_name;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// single/multiple id(s): no query string
|
// single/multiple id(s): no query string
|
||||||
|
@ -27,7 +36,7 @@ openerp.report = function(instance) {
|
||||||
} else {
|
} else {
|
||||||
_.each(action.datas.form, function(value, key) {
|
_.each(action.datas.form, function(value, key) {
|
||||||
// will be erased when all wizards are rewritten
|
// will be erased when all wizards are rewritten
|
||||||
if(key.substring(0, 12) === 'used_context') {
|
if (key.substring(0, 12) === 'used_context') {
|
||||||
delete action.datas.form[key];
|
delete action.datas.form[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,11 +52,15 @@ openerp.report = function(instance) {
|
||||||
instance.web.unblockUI();
|
instance.web.unblockUI();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Trigger the download of the pdf report
|
// Trigger the download of the pdf/custom controller report
|
||||||
var c = openerp.webclient.crashmanager;
|
var c = openerp.webclient.crashmanager;
|
||||||
|
var response = new Array()
|
||||||
|
response[0] = report_url
|
||||||
|
response[1] = action.report_type
|
||||||
|
|
||||||
this.session.get_file({
|
this.session.get_file({
|
||||||
url: '/report/downloadpdf',
|
url: '/report/download',
|
||||||
data: {data: JSON.stringify(report_url)},
|
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)
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue