Add support for single record report

A single report render each record separately and return them in a zip file.
To ensure the uniqueness of the file in the zip, it uses the id of the record
but also the record name to be user-friendly.

issue6640
review37581002
This commit is contained in:
Cédric Krier committed 2017-09-03 11:14:10 +02:00
1 parent de8c68c646
commit f110fccf44
5 files changed
+43 -12

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Add support for single record report
* Add support for Flat OpenDocument
* Add get_email in trytond.report
* Replace plain extension by txt
+10 -6
View File
@@ -50,6 +50,10 @@ When defining an `ir.action.report` the following attributes are available:
* ``template_extension``: The template format.
* ``single``: `True` if the template works only for one record. If such
report is called with more than one record, a zip file containing all the
reports will be generated.
Report Usage
============
@@ -129,12 +133,12 @@ Accessing models from within the report
---------------------------------------
By default instances of the models the report is for are passed in to the
report via a list of objects called `objects`. These objects behave just as
they would within trytond itself. You can access any of the models relations as
well. For example within the invoice report each object is an invoice and you
can access the name of the party of the invoice via `invoice.party.name`.
Additional objects can be passed to a report. This is discussed below in
`Passing custom data to a report`.
report via a list of objects called `records` (or `record` if `single` is
`True`). These records behave just as they would within trytond itself. You
can access any of the models relations as well. For example within the invoice
report each object is an invoice and you can access the name of the party of
the invoice via `invoice.party.name`. Additional objects can be passed to a
report. This is discussed below in `Passing custom data to a report`.
Within Tryton the underlying model the report can be found by following the
Menu to ``Administration > UI > Actions > Report``. Furthermore in tryton the
+6
View File
@@ -409,6 +409,8 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
action = fields.Many2One('ir.action', 'Action', required=True,
ondelete='CASCADE')
direct_print = fields.Boolean('Direct Print')
single = fields.Boolean("Single",
help="Check if the template works only for one record.")
template_extension = fields.Selection([
('odt', 'OpenDocument Text'),
('odp', 'OpenDocument Presentation'),
@@ -582,6 +584,10 @@ class ActionReport(ActionMixin, ModelSQL, ModelView):
def default_direct_print():
return False
@classmethod
def default_single(cls):
return False
@staticmethod
def default_template_extension():
return 'odt'
+2
View File
@@ -23,6 +23,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="template_extension"/>
<label name="extension"/>
<field name="extension"/>
<label name="single"/>
<field name="single"/>
<label name="direct_print"/>
<field name="direct_print"/>
<newline/>
+24 -6
View File
@@ -1,12 +1,14 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
import datetime
import os
import subprocess
import tempfile
import warnings
import subprocess
import zipfile
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from io import BytesIO
try:
import html2text
@@ -152,17 +154,32 @@ class Report(URLMixin, PoolBase):
else:
action_report = ActionReport(action_id)
records = None
records = []
model = action_report.model or data.get('model')
if model:
records = cls._get_records(ids, model, data)
report_context = cls.get_context(records, data)
oext, content = cls.convert(action_report,
cls.render(action_report, report_context))
if action_report.single and len(records) > 1:
content = BytesIO()
with zipfile.ZipFile(content, 'w') as content_zip:
for record in records:
oext, rcontent = cls._execute(
[record], data, action_report)
rfilename = '%s-%s.%s' % (
record.id, record.rec_name, oext)
content_zip.writestr(rfilename, rcontent)
content = content.getvalue()
oext = 'zip'
else:
oext, content = cls._execute(records, data, action_report)
if not isinstance(content, unicode):
content = bytearray(content) if bytes == str else bytes(content)
return (oext, content, action_report.direct_print, action_report.name)
@classmethod
def _execute(cls, records, data, action):
report_context = cls.get_context(records, data)
return cls.convert(action, cls.render(action, report_context))
@classmethod
def _get_records(cls, ids, model, data):
pool = Pool()
@@ -200,6 +217,7 @@ class Report(URLMixin, PoolBase):
report_context['context'] = Transaction().context
report_context['user'] = User(Transaction().user)
report_context['records'] = records
report_context['record'] = records[0] if records else None
report_context['format_date'] = cls.format_date
report_context['format_currency'] = cls.format_currency
report_context['format_number'] = cls.format_number