-
-
Notifications
You must be signed in to change notification settings - Fork 795
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[14.0][ADD] report_xlsx_pdf: print directly to PDF from xlsx
- Loading branch information
Showing
20 changed files
with
920 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
============================================ | ||
Extend report xlsx to export directly to pdf | ||
============================================ | ||
|
||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Beta | ||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github | ||
:target: https://github.com/OCA/reporting-engine/tree/14.0/report_xlsx_pdf | ||
:alt: OCA/reporting-engine | ||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
:target: https://translation.odoo-community.org/projects/reporting-engine-14-0/reporting-engine-14-0-report_xlsx_pdf | ||
:alt: Translate me on Weblate | ||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png | ||
:target: https://runbot.odoo-community.org/runbot/143/14.0 | ||
:alt: Try me on Runbot | ||
|
||
|badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
||
This module extend xlsx report to convert in pdf using libreoffice | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Installation | ||
============ | ||
|
||
Make sure you have ``xlsxwriter`` Python module installed:: | ||
|
||
$ pip3 install xlsxwriter | ||
|
||
For testing it is also necessary ``xlrd`` Python module installed:: | ||
|
||
$ pip3 install xlrd | ||
|
||
Usage | ||
===== | ||
|
||
An example of XLSX report for partners on a module called `module_name`: | ||
|
||
A python class :: | ||
|
||
from odoo import models | ||
|
||
class PartnerXlsx(models.AbstractModel): | ||
_name = 'report.module_name.report_name' | ||
_inherit = 'report.report_xlsx.abstract' | ||
|
||
def generate_xlsx_report(self, workbook, data, partners): | ||
for obj in partners: | ||
report_name = obj.name | ||
# One sheet by partner | ||
sheet = workbook.add_worksheet(report_name[:31]) | ||
bold = workbook.add_format({'bold': True}) | ||
sheet.write(0, 0, obj.name, bold) | ||
|
||
To manipulate the ``workbook`` and ``sheet`` objects, refer to the | ||
`documentation <http://xlsxwriter.readthedocs.org/>`_ of ``xlsxwriter``. | ||
|
||
A report XML record :: | ||
|
||
<record id="partner_xlsx" model="ir.actions.report"> | ||
<field name="name">Print to XLSX</field> | ||
<field name="model">res.partner</field> | ||
<field name="report_type">xlsx</field> | ||
<field name="report_name">report_xlsx.partner_xlsx</field> | ||
<field name="report_xlsx_to_pdf">True</field> | ||
<field name="report_file">res_partner</field> | ||
</record> | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/reporting-engine/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us smashing it by providing a detailed and welcomed | ||
`feedback <https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_xlsx_pdf%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
~~~~~~~ | ||
|
||
* Openindustry.it | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
* Andrea Piovesana <[email protected]> | ||
* Marco Colombo <[email protected]> | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
||
This module is maintained by the OCA. | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
This module is part of the `OCA/reporting-engine <https://github.com/OCA/reporting-engine/tree/14.0/report_xlsx_pdf>`_ project on GitHub. | ||
|
||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Copyright 2022 Openindustry.it (<https://openindustry.it>) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import controllers | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright 2022 Openindustry.it (<https://openindustry.it>) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
{ | ||
"name": "Export xlsx report to pdf", | ||
"summary": "Extend report_xlsx to export directly to pdf", | ||
"author": "Openindustry.it," "Odoo Community Association (OCA)", | ||
"website": "https://github.com/OCA/reporting-engine", | ||
"category": "Reporting", | ||
"version": "14.0.1.0.0", | ||
"development_status": "Beta", | ||
"license": "AGPL-3", | ||
"depends": ["report_xlsx"], | ||
"external_dependencies": { | ||
"python": ["xlsxwriter"], | ||
"deb": ["libreoffice"], | ||
}, | ||
"data": ["views/ir_actions_report.xml"], | ||
"demo": ["demo/report.xml"], | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Copyright (C) 2017 Creu Blanca | ||
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). | ||
|
||
import json | ||
|
||
from odoo.http import content_disposition, request, route, serialize_exception | ||
from odoo.tools import html_escape | ||
from odoo.tools.safe_eval import safe_eval | ||
|
||
from odoo.addons.web.controllers import main as report | ||
|
||
|
||
class ReportController(report.ReportController): | ||
@route() | ||
def report_routes(self, reportname, docids=None, converter=None, **data): | ||
if converter == "xlsx": | ||
return self._report_routes_xlsx(reportname, docids, converter, **data) | ||
return super(ReportController, self).report_routes( | ||
reportname, docids, converter, **data | ||
) | ||
|
||
def _report_routes_xlsx(self, reportname, docids=None, converter=None, **data): | ||
try: | ||
report = request.env["ir.actions.report"]._get_report_from_name(reportname) | ||
context = dict(request.env.context) | ||
if docids: | ||
docids = [int(i) for i in docids.split(",")] | ||
if data.get("options"): | ||
data.update(json.loads(data.pop("options"))) | ||
if data.get("context"): | ||
# Ignore 'lang' here, because the context in data is the one | ||
# from the webclient *but* if the user explicitely wants to | ||
# change the lang, this mechanism overwrites it. | ||
data["context"] = json.loads(data["context"]) | ||
if data["context"].get("lang"): | ||
del data["context"]["lang"] | ||
context.update(data["context"]) | ||
xlsx = report.with_context(context)._render_xlsx(docids, data=data)[0] | ||
report_name = report.name | ||
if report.print_report_name and not len(docids) > 1: | ||
obj = request.env[report.model].browse(docids[0]) | ||
report_name = safe_eval(report.print_report_name, {"object": obj}) | ||
else: | ||
obj = request.env[report.model].browse(docids) | ||
if report.report_xlsx_to_pdf: | ||
xlsxpdf = report._create_single_report(obj, data, xlsx) | ||
xlsxpdfhttpheaders = [ | ||
("Content-Type", "application/pdf"), | ||
("Content-Length", len(xlsxpdf)), | ||
("Content-Disposition", content_disposition(report_name + ".pdf")), | ||
] | ||
return request.make_response(xlsxpdf, headers=xlsxpdfhttpheaders) | ||
else: | ||
xlsxhttpheaders = [ | ||
( | ||
"Content-Type", | ||
"application/vnd.openxmlformats-" | ||
"officedocument.spreadsheetml.sheet", | ||
), | ||
("Content-Length", len(xlsx)), | ||
("Content-Disposition", content_disposition(report_name + ".xlsx")), | ||
] | ||
return request.make_response(xlsx, headers=xlsxhttpheaders) | ||
except Exception as e: | ||
se = serialize_exception(e) | ||
error = {"code": 200, "message": "Odoo Server Error", "data": se} | ||
return request.make_response(html_escape(json.dumps(error))) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<odoo> | ||
<!-- | ||
© 2017 Creu Blanca | ||
License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). | ||
--> | ||
<record id="partner_xlsx" model="ir.actions.report"> | ||
<field name="name">Print to XLSX</field> | ||
<field name="model">res.partner</field> | ||
<field name="report_type">xlsx</field> | ||
<field name="report_name">report_xlsx.partner_xlsx</field> | ||
<field name="report_xlsx_to_pdf">True</field> | ||
<field name="report_file">res_partner</field> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright 2022 Openindustry.it (<https://openindustry.it>) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import ir_report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# Copyright 2022 Openindustry.it (<https://openindustry.it>) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
import logging | ||
import os | ||
import subprocess | ||
import tempfile | ||
|
||
from odoo import _, api, fields, models | ||
from odoo.tools.misc import find_in_path | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class ReportAction(models.Model): | ||
_inherit = "ir.actions.report" | ||
|
||
report_xlsx_to_pdf = fields.Boolean( | ||
string="Export to pdf format", | ||
default=False, | ||
) | ||
|
||
def _create_single_report(self, model_instance, data, xlsx): | ||
"""This function to generate our pdf report""" | ||
self.ensure_one() | ||
result_fd, result_path = tempfile.mkstemp( | ||
suffix=".xlsx", prefix="xlsx.report.tmp." | ||
) | ||
os.write(result_fd, xlsx) | ||
result_path = self._convert_single_report(result_path, model_instance, data) | ||
with open(result_path, "rb") as fh: | ||
file_data = fh.read() | ||
return file_data | ||
|
||
def _convert_single_report(self, result_path, model_instance, data): | ||
"""Run a command to convert to our target format""" | ||
with tempfile.TemporaryDirectory() as tmp_user_installation: | ||
command = self._convert_single_report_cmd( | ||
result_path, | ||
model_instance, | ||
data, | ||
user_installation=tmp_user_installation, | ||
) | ||
logger.debug("Running command %s", command) | ||
output = subprocess.check_output(command, cwd=os.path.dirname(result_path)) | ||
logger.debug("Output was %s", output) | ||
self._cleanup_tempfiles([result_path]) | ||
result_path, result_filename = os.path.split(result_path) | ||
result_path = os.path.join( | ||
result_path, | ||
"%s.%s" | ||
% ( | ||
os.path.splitext(result_filename)[0], | ||
"pdf", | ||
), | ||
) | ||
return result_path | ||
|
||
def _convert_single_report_cmd( | ||
self, result_path, model_instance, data, user_installation=None | ||
): | ||
"""Return a command list suitable for use in subprocess.call""" | ||
try: | ||
lo_bin = find_in_path("libreoffice") | ||
except IOError: | ||
lo_bin = None | ||
if not lo_bin: | ||
raise RuntimeError( | ||
_( | ||
"Libreoffice runtime not available. " | ||
"Please contact your administrator." | ||
) | ||
) | ||
cmd = [ | ||
lo_bin, | ||
"--headless", | ||
"--convert-to", | ||
"pdf", | ||
result_path, | ||
] | ||
return cmd | ||
|
||
@api.model | ||
def _cleanup_tempfiles(self, temporary_files): | ||
# Manual cleanup of the temporary files | ||
for temporary_file in temporary_files: | ||
try: | ||
os.unlink(temporary_file) | ||
except OSError: | ||
logger.error("Error when trying to remove file %s" % temporary_file) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
* Andrea Piovesana <[email protected]> | ||
* Marco Colombo <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This module extends report_xlsx to convert xlsx to pdf using libreoffice. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Make sure you have ``xlsxwriter`` Python module installed:: | ||
|
||
$ pip3 install xlsxwriter | ||
|
||
You also need ``libreoffice``, please refer to the documentation | ||
of your distribution for its installation. | ||
|
||
For testing it is also necessary ``xlrd`` Python module installed:: | ||
|
||
$ pip3 install xlrd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
An example of XLSX report for partners on a module called `module_name`: | ||
|
||
A python class :: | ||
|
||
from odoo import models | ||
|
||
class PartnerXlsx(models.AbstractModel): | ||
_name = 'report.module_name.report_name' | ||
_inherit = 'report.report_xlsx.abstract' | ||
|
||
def generate_xlsx_report(self, workbook, data, partners): | ||
for obj in partners: | ||
report_name = obj.name | ||
# One sheet by partner | ||
sheet = workbook.add_worksheet(report_name[:31]) | ||
bold = workbook.add_format({'bold': True}) | ||
sheet.write(0, 0, obj.name, bold) | ||
|
||
To manipulate the ``workbook`` and ``sheet`` objects, refer to the | ||
`documentation <http://xlsxwriter.readthedocs.org/>`_ of ``xlsxwriter``. | ||
|
||
A report XML record :: | ||
|
||
<record id="partner_xlsx" model="ir.actions.report"> | ||
<field name="name">Print to XLSX</field> | ||
<field name="model">res.partner</field> | ||
<field name="report_type">xlsx</field> | ||
<field name="report_name">report_xlsx.partner_xlsx</field> | ||
<field name="report_xlsx_to_pdf">True</field> | ||
<field name="report_file">res_partner</field> | ||
</record> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.