diff --git a/.gitignore b/.gitignore
index 6148a29a95d..4b38dc02ac7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,4 +25,4 @@ install/win32/meta.py
/lib/
/man/
/share/
-/src/
+/src/
\ No newline at end of file
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 29692992341..a163094b928 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -60,7 +60,7 @@
-
+
diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index 4f3b5f43945..0f52361ce14 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -956,7 +956,6 @@
-
diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py
index 3fd83c19207..2e3c9b7c374 100644
--- a/addons/account/report/account_aged_partner_balance.py
+++ b/addons/account/report/account_aged_partner_balance.py
@@ -161,7 +161,7 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
dates_query += ' < %s)'
args_list += (form[str(i)]['stop'],)
args_list += (self.date_from,)
- self.cr.execute('''SELECT l.partner_id, SUM(l.debit-l.credit)
+ self.cr.execute('''SELECT l.partner_id, SUM(l.debit-l.credit), l.reconcile_partial_id
FROM account_move_line AS l, account_account, account_move am
WHERE (l.account_id = account_account.id) AND (l.move_id=am.id)
AND (am.state IN %s)
@@ -173,12 +173,24 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
AND account_account.active
AND ''' + dates_query + '''
AND (l.date <= %s)
- GROUP BY l.partner_id''', args_list)
- t = self.cr.fetchall()
- d = {}
- for i in t:
- d[i[0]] = i[1]
- history.append(d)
+ GROUP BY l.partner_id, l.reconcile_partial_id''', args_list)
+ partners_partial = self.cr.fetchall()
+ partners_amount = dict((i[0],0) for i in partners_partial)
+ for partner_info in partners_partial:
+ if partner_info[2]:
+ # in case of partial reconciliation, we want to keep the left amount in the oldest period
+ self.cr.execute('''SELECT MIN(COALESCE(date_maturity,date)) FROM account_move_line WHERE reconcile_partial_id = %s''', (partner_info[2],))
+ date = self.cr.fetchall()
+ if date and args_list[-3] <= date[0][0] <= args_list[-2]:
+ # partial reconcilation
+ self.cr.execute('''SELECT SUM(l.debit-l.credit)
+ FROM account_move_line AS l
+ WHERE l.reconcile_partial_id = %s''', (partner_info[2],))
+ unreconciled_amount = self.cr.fetchall()
+ partners_amount[partner_info[0]] += unreconciled_amount[0][0]
+ else:
+ partners_amount[partner_info[0]] += partner_info[1]
+ history.append(partners_amount)
for partner in partners:
values = {}
diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml
index 6c4b701c6cf..a250eb9ebf7 100644
--- a/addons/account/views/report_invoice.xml
+++ b/addons/account/views/report_invoice.xml
@@ -5,7 +5,7 @@
diff --git a/addons/report/controllers/main.py b/addons/report/controllers/main.py
index de3bbd63db6..c6bc13d38f8 100644
--- a/addons/report/controllers/main.py
+++ b/addons/report/controllers/main.py
@@ -66,7 +66,7 @@ class ReportController(Controller):
# Misc. route utils
#------------------------------------------------------
@route(['/report/barcode', '/report/barcode//'], type='http', auth="user")
- def report_barcode(self, type, value, width=300, height=50):
+ def report_barcode(self, type, value, width=600, height=100):
"""Contoller able to render barcode images thanks to reportlab.
Samples:
diff --git a/addons/report/data/report_paperformat.xml b/addons/report/data/report_paperformat.xml
index 275d65edd13..f05e0afb6f0 100644
--- a/addons/report/data/report_paperformat.xml
+++ b/addons/report/data/report_paperformat.xml
@@ -9,7 +9,7 @@
0Portrait40
- 20
+ 2377
diff --git a/addons/report/models/report.py b/addons/report/models/report.py
index d8a51387cb7..cbbee7fcebd 100644
--- a/addons/report/models/report.py
+++ b/addons/report/models/report.py
@@ -25,10 +25,8 @@ from openerp.tools.translate import _
from openerp.addons.web.http import request
from openerp.tools.safe_eval import safe_eval as eval
-import os
+import re
import time
-import psutil
-import signal
import base64
import logging
import tempfile
@@ -52,15 +50,19 @@ try:
['wkhtmltopdf', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
except OSError:
- _logger.error('You need wkhtmltopdf to print a pdf version of the reports.')
+ _logger.info('You need wkhtmltopdf to print a pdf version of the reports.')
else:
out, err = process.communicate()
- version = out.splitlines()[1].strip()
- version = version.split(' ')[1]
+ version = re.search('([0-9.]+)', out).group(0)
if LooseVersion(version) < LooseVersion('0.12.0'):
- _logger.warning('Upgrade wkhtmltopdf to (at least) 0.12.0')
+ _logger.info('Upgrade wkhtmltopdf to (at least) 0.12.0')
wkhtmltopdf_state = 'upgrade'
- wkhtmltopdf_state = 'ok'
+ else:
+ wkhtmltopdf_state = 'ok'
+
+ if config['workers'] == 1:
+ _logger.info('You need to start OpenERP with at least two workers to print a pdf version of the reports.')
+ wkhtmltopdf_state = 'workers'
class Report(osv.Model):
@@ -343,19 +345,20 @@ class Report(osv.Model):
command_args = []
tmp_dir = tempfile.gettempdir()
- # Passing the cookie to wkhtmltopdf in order to resolve URL.
+ # Passing the cookie to wkhtmltopdf in order to resolve internal links.
try:
if request:
command_args.extend(['--cookie', 'session_id', request.session.sid])
except AttributeError:
pass
- # Display arguments
+ # Wkhtmltopdf arguments
+ command_args.extend(['--quiet']) # Less verbose error messages
if paperformat:
+ # Convert the paperformat record into arguments
command_args.extend(self._build_wkhtmltopdf_args(paperformat, spec_paperformat_args))
- command_args.extend(['--load-error-handling', 'ignore'])
-
+ # Force the landscape orientation if necessary
if landscape and '--orientation' in command_args:
command_args_copy = list(command_args)
for index, elem in enumerate(command_args_copy):
@@ -366,61 +369,46 @@ class Report(osv.Model):
elif landscape and not '--orientation' in command_args:
command_args.extend(['--orientation', 'landscape'])
+ # Execute WKhtmltopdf
pdfdocuments = []
- # HTML to PDF thanks to WKhtmltopdf
for index, reporthtml in enumerate(bodies):
- command_arg_local = []
- pdfreport = tempfile.NamedTemporaryFile(suffix='.pdf', prefix='report.tmp.',
- mode='w+b')
- # Directly load the document if we have it
+ local_command_args = []
+ pdfreport = tempfile.NamedTemporaryFile(suffix='.pdf', prefix='report.tmp.', mode='w+b')
+
+ # Directly load the document if we already have it
if save_in_attachment and save_in_attachment['loaded_documents'].get(reporthtml[0]):
pdfreport.write(save_in_attachment['loaded_documents'].get(reporthtml[0]))
pdfreport.seek(0)
pdfdocuments.append(pdfreport)
continue
- # Header stuff
+ # Wkhtmltopdf handles header/footer as separate pages. Create them if necessary.
if headers:
- head_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.header.tmp.',
- dir=tmp_dir, mode='w+')
+ head_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.header.tmp.', dir=tmp_dir, mode='w+')
head_file.write(headers[index])
head_file.seek(0)
- command_arg_local.extend(['--header-html', head_file.name])
-
- # Footer stuff
+ local_command_args.extend(['--header-html', head_file.name])
if footers:
- foot_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.footer.tmp.',
- dir=tmp_dir, mode='w+')
+ foot_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.footer.tmp.', dir=tmp_dir, mode='w+')
foot_file.write(footers[index])
foot_file.seek(0)
- command_arg_local.extend(['--footer-html', foot_file.name])
+ local_command_args.extend(['--footer-html', foot_file.name])
# Body stuff
- content_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.body.tmp.',
- dir=tmp_dir, mode='w+')
+ content_file = tempfile.NamedTemporaryFile(suffix='.html', prefix='report.body.tmp.', dir=tmp_dir, mode='w+')
content_file.write(reporthtml[1])
content_file.seek(0)
try:
- # If the server is running with only one worker, ask to create a secund to be able
- # to serve the http request of wkhtmltopdf subprocess.
- if config['workers'] == 1:
- ppid = psutil.Process(os.getpid()).ppid
- os.kill(ppid, signal.SIGTTIN)
-
- wkhtmltopdf = command + command_args + command_arg_local
+ wkhtmltopdf = command + command_args + local_command_args
wkhtmltopdf += [content_file.name] + [pdfreport.name]
- process = subprocess.Popen(wkhtmltopdf, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ process = subprocess.Popen(wkhtmltopdf, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
- if config['workers'] == 1:
- os.kill(ppid, signal.SIGTTOU)
-
- if process.returncode != 0:
+ if process.returncode not in [0, 1]:
raise osv.except_osv(_('Report (PDF)'),
- _('wkhtmltopdf failed with error code = %s. '
+ _('Wkhtmltopdf failed (error code: %s). '
'Message: %s') % (str(process.returncode), err))
# Save the pdf in attachment if marked
@@ -446,7 +434,7 @@ class Report(osv.Model):
except:
raise
- # Get and return the full pdf
+ # Return the entire document
if len(pdfdocuments) == 1:
content = pdfdocuments[0].read()
pdfdocuments[0].close()
diff --git a/addons/report/static/src/js/qwebactionmanager.js b/addons/report/static/src/js/qwebactionmanager.js
index 37a0fae6ea6..cb0f3921482 100644
--- a/addons/report/static/src/js/qwebactionmanager.js
+++ b/addons/report/static/src/js/qwebactionmanager.js
@@ -54,33 +54,35 @@ openerp.report = function(instance) {
if (action.report_type == 'qweb-html') {
window.open(report_url, '_blank', 'height=900,width=1280');
instance.web.unblockUI();
- } else {
+ } else if (action.report_type === 'qweb-pdf') {
// Trigger the download of the pdf/controller report
-
- if (action.report_type == 'qweb-pdf') {
- (wkhtmltopdf_state = wkhtmltopdf_state || openerp.session.rpc('/report/check_wkhtmltopdf')).then(function (presence) {
- // Fallback of qweb-pdf if wkhtmltopdf is not installed
- if (presence == 'install' && action.report_type == 'qweb-pdf') {
- self.do_notify(_t('Report'), _t('Unable to find Wkhtmltopdf on this \
- system. The report will be shown in html.
\
- wkhtmltopdf.org'), true);
- report_url = report_url.substring(12)
- window.open('/report/html/' + report_url, '_blank', 'height=768,width=1024');
- instance.web.unblockUI();
- return;
- } else {
- if (presence == 'upgrade') {
- self.do_notify(_t('Report'), _t('You should upgrade your version of\
- Wkhtmltopdf to at least 0.12.0 in order to get a correct display of headers and footers as well as\
- support for table-breaking between pages.
wkhtmltopdf.org'), true);
- }
- }
- return trigger_download(self.session, response, c);
- });
- } else if (action.report_type == 'controller') {
+ (wkhtmltopdf_state = wkhtmltopdf_state || openerp.session.rpc('/report/check_wkhtmltopdf')).then(function (presence) {
+ // Fallback on html if wkhtmltopdf is not installed or if OpenERP is started with one worker
+ if (presence === 'install') {
+ self.do_notify(_t('Report'), _t('Unable to find Wkhtmltopdf on this \
+system. The report will be shown in html.
\
+wkhtmltopdf.org'), true);
+ report_url = report_url.substring(12)
+ window.open('/report/html/' + report_url, '_blank', 'height=768,width=1024');
+ instance.web.unblockUI();
+ return;
+ } else if (presence === 'workers') {
+ self.do_notify(_t('Report'), _t('You need to start OpenERP with at least two \
+workers to print a pdf version of the reports.'), true);
+ report_url = report_url.substring(12)
+ window.open('/report/html/' + report_url, '_blank', 'height=768,width=1024');
+ instance.web.unblockUI();
+ return;
+ } else if (presence === 'upgrade') {
+ self.do_notify(_t('Report'), _t('You should upgrade your version of\
+ Wkhtmltopdf to at least 0.12.0 in order to get a correct display of headers and footers as well as\
+ support for table-breaking between pages.