diff --git a/report_py3o/README.rst b/report_py3o/README.rst index f09d5b8399..7b260a8738 100644 --- a/report_py3o/README.rst +++ b/report_py3o/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ================== Py3o Report Engine ================== @@ -17,7 +13,7 @@ Py3o Report Engine .. |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/license-AGPL--3-blue.png +.. |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 @@ -35,29 +31,29 @@ Py3o Report Engine The py3o reporting engine is a reporting engine for Odoo based on [Libreoffice](http://www.libreoffice.org/): -- the report is created with Libreoffice (ODT or ODS), -- the report is stored on the server in OpenDocument format (.odt or - .ods file) -- the report is sent to the user in OpenDocument format or in any output - format supported by Libreoffice (PDF, HTML, DOC, DOCX, Docbook, XLS, - etc.) +- the report is created with Libreoffice (ODT or ODS), +- the report is stored on the server in OpenDocument format (.odt or + .ods file) +- the report is sent to the user in OpenDocument format or in any + output format supported by Libreoffice (PDF, HTML, DOC, DOCX, + Docbook, XLS, etc.) The key advantages of a Libreoffice based reporting engine are: -- no need to be a developer to create or modify a report: the report is - created and modified with Libreoffice. So this reporting engine has a - full WYSIWYG report development tool! -- For a PDF report in A4/Letter format, it's easier to develop it with a - tool such as Libreoffice that is designed to create A4/Letter - documents than to develop it in HTML/CSS, also some print - peculiarities (backgrounds, margin boxes) are not very well supported - by the HTML/CSS based solutions. -- If you want your users to be able to modify the document after its - generation by Odoo, just configure the document with ODT output (or - DOC or DOCX) and the user will be able to modify the document with - Libreoffice (or Word) after its generation by Odoo. -- Easy development of spreadsheet reports in ODS format (XLS output - possible). +- no need to be a developer to create or modify a report: the report is + created and modified with Libreoffice. So this reporting engine has a + full WYSIWYG report development tool! +- For a PDF report in A4/Letter format, it's easier to develop it with + a tool such as Libreoffice that is designed to create A4/Letter + documents than to develop it in HTML/CSS, also some print + peculiarities (backgrounds, margin boxes) are not very well supported + by the HTML/CSS based solutions. +- If you want your users to be able to modify the document after its + generation by Odoo, just configure the document with ODT output (or + DOC or DOCX) and the user will be able to modify the document with + Libreoffice (or Word) after its generation by Odoo. +- Easy development of spreadsheet reports in ODS format (XLS output + possible). This module *report_py3o* is the base module for the Py3o reporting engine. If used alone, it will spawn a libreoffice process for each ODT @@ -183,9 +179,9 @@ project Known issues / Roadmap ====================== -- generate barcode ? -- add more detailed example in demo file to showcase features -- add migration guide aeroo -> py3o +- generate barcode ? +- add more detailed example in demo file to showcase features +- add migration guide aeroo -> py3o Bug Tracker =========== @@ -209,14 +205,14 @@ Authors Contributors ------------ -- Florent Aide ([XCG Consulting](http://odoo.consulting/)) -- Laurent Mignon <>, -- Alexis de Lattre <>, -- Guewen Baconnier <> -- Omar Casti??eira <> -- Holger Brunn <> -- Phuc Tran Thanh <> -- Souheil Bejaoui <>, +- Florent Aide ([XCG Consulting](http://odoo.consulting/)) +- Laurent Mignon <>, +- Alexis de Lattre <>, +- Guewen Baconnier <> +- Omar Casti??eira <> +- Holger Brunn <> +- Phuc Tran Thanh <> +- Souheil Bejaoui <>, Maintainers ----------- diff --git a/report_py3o/__manifest__.py b/report_py3o/__manifest__.py index 2b11896126..4284c66228 100644 --- a/report_py3o/__manifest__.py +++ b/report_py3o/__manifest__.py @@ -11,7 +11,7 @@ "website": "https://github.com/OCA/reporting-engine", "depends": ["web"], "external_dependencies": { - "python": ["py3o.template", "py3o.formats"], + "python": ["py3o.template", "py3o.formats", "pypdf"], "deb": ["libreoffice"], }, "assets": { diff --git a/report_py3o/models/_py3o_parser_context.py b/report_py3o/models/_py3o_parser_context.py index ba14e37988..6c48428c8a 100644 --- a/report_py3o/models/_py3o_parser_context.py +++ b/report_py3o/models/_py3o_parser_context.py @@ -59,7 +59,6 @@ def _format_lang( lang_code=False, digits=None, grouping=True, - monetary=False, dp=False, currency_obj=False, no_break_space=True, @@ -73,7 +72,6 @@ def _format_lang( value, digits=digits, grouping=grouping, - monetary=monetary, dp=dp, currency_obj=currency_obj, ) @@ -104,7 +102,6 @@ def _old_format_lang( date=False, date_time=False, grouping=True, - monetary=False, dp=False, currency_obj=False, ): @@ -130,7 +127,6 @@ def _old_format_lang( value, digits=digits, grouping=grouping, - monetary=monetary, dp=dp, currency_obj=currency_obj, no_break_space=True, diff --git a/report_py3o/models/py3o_report.py b/report_py3o/models/py3o_report.py index e676f6aca4..04cf9dcd8f 100644 --- a/report_py3o/models/py3o_report.py +++ b/report_py3o/models/py3o_report.py @@ -232,7 +232,7 @@ def _create_single_report(self, model_instance, data): """This function to generate our py3o report""" self.ensure_one() result_fd, result_path = tempfile.mkstemp( - suffix=".ods", prefix="p3o.report.tmp." + suffix=".odt", prefix="py3o.report.tmp." ) tmpl_data = self.get_template(model_instance) diff --git a/report_py3o/static/description/index.html b/report_py3o/static/description/index.html index a2b0a153c6..e889a007be 100644 --- a/report_py3o/static/description/index.html +++ b/report_py3o/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Py3o Report Engine -
+
+

Py3o Report Engine

- - -Odoo Community Association - -
-

Py3o Report Engine

-

Beta License: AGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runboat

The py3o reporting engine is a reporting engine for Odoo based on [Libreoffice](http://www.libreoffice.org/):

  • the report is created with Libreoffice (ODT or ODS),
  • the report is stored on the server in OpenDocument format (.odt or .ods file)
  • -
  • the report is sent to the user in OpenDocument format or in any output -format supported by Libreoffice (PDF, HTML, DOC, DOCX, Docbook, XLS, -etc.)
  • +
  • the report is sent to the user in OpenDocument format or in any +output format supported by Libreoffice (PDF, HTML, DOC, DOCX, +Docbook, XLS, etc.)

The key advantages of a Libreoffice based reporting engine are:

  • no need to be a developer to create or modify a report: the report is created and modified with Libreoffice. So this reporting engine has a full WYSIWYG report development tool!
  • -
  • For a PDF report in A4/Letter format, it’s easier to develop it with a -tool such as Libreoffice that is designed to create A4/Letter +
  • For a PDF report in A4/Letter format, it’s easier to develop it with +a tool such as Libreoffice that is designed to create A4/Letter documents than to develop it in HTML/CSS, also some print peculiarities (backgrounds, margin boxes) are not very well supported by the HTML/CSS based solutions.
  • @@ -436,7 +431,7 @@

    Py3o Report Engine

-

Installation

+

Installation

Install the required python libs:

:literal:`` pip install py3o.template pip install py3o.formats``

To allow the conversion of ODT or ODS reports to other formats (PDF, @@ -444,7 +439,7 @@

Installation

:literal:`` apt-get –no-install-recommends install libreoffice``

-

Configuration

+

Configuration

For example, to replace the native invoice report by a custom py3o report, add the following XML file in your custom module:

:literal:`` <?xml version=”1.0” encoding=”utf-8”?> <odoo> <record id=”account.account_invoices” model=”ir.actions.report”> <field name=”report_type”>py3o</field> <field name=”py3o_filetype”>odt</field> <field name=”module”>my_custom_module_base</field> <field name=”py3o_template_fallback”>report/account_invoice.odt</field> </record> </odoo>``

@@ -473,7 +468,7 @@

Configuration

will be started in $file’s directory.

-

Usage

+

Usage

The templating language is [extensively documented](http://py3otemplate.readthedocs.io/en/latest/templating.html), the records are exposed in libreoffice as objects, on which you can also @@ -503,7 +498,7 @@

Usage

[odoo-py3o-report-templates](https://github.com/akretion/odoo-py3o-report-templates).

-

Known issues / Roadmap

+

Known issues / Roadmap

  • generate barcode ?
  • add more detailed example in demo file to showcase features
  • @@ -511,7 +506,7 @@

    Known issues / Roadmap

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -519,16 +514,16 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • XCG Consulting
  • ACSONE SA/NV
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -554,6 +549,5 @@

Maintainers

-
diff --git a/report_py3o/tests/test_report_py3o.py b/report_py3o/tests/test_report_py3o.py index 713fb25935..a54f9f80ae 100644 --- a/report_py3o/tests/test_report_py3o.py +++ b/report_py3o/tests/test_report_py3o.py @@ -11,14 +11,7 @@ from importlib.resources import as_file, files from unittest import mock -from PyPDF2 import PdfFileWriter - -try: - # For PyPDF2 <= 1.26.0 - from PyPDF2.pdf import PageObject -except ImportError: - # For PyPDF2 >= 2.0.0 - from PyPDF2 import PageObject +from pypdf import PageObject, PdfWriter from odoo import tools from odoo.exceptions import ValidationError @@ -50,12 +43,14 @@ def temporary_copy(path): class TestReportPy3o(TransactionCase): - def setUp(self): - super().setUp() - self.env.user.image_1920 = PNG - self.report = self.env.ref("report_py3o.res_users_report_py3o") - self.py3o_report = self.env["py3o.report"].create( - {"ir_actions_report_id": self.report.id} + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.env.user.image_1920 = PNG + cls.report = cls.env.ref("report_py3o.res_users_report_py3o") + cls.py3o_report = cls.env["py3o.report"].create( + {"ir_actions_report_id": cls.report.id} ) def test_required_py3_filetype(self): @@ -107,8 +102,8 @@ def test_reports_merge_pdf(self): reports_path = [] for _i in range(0, 3): result = tempfile.mktemp(".txt") - writer = PdfFileWriter() - writer.addPage(PageObject.createBlankPage(width=100, height=100)) + writer = PdfWriter() + writer.add_page(PageObject.create_blank_page(width=100, height=100)) with open(result, "wb") as fp: writer.write(fp) reports_path.append(result) diff --git a/report_py3o_fusion_server/README.rst b/report_py3o_fusion_server/README.rst index 1c14423ae5..51857e1abb 100644 --- a/report_py3o_fusion_server/README.rst +++ b/report_py3o_fusion_server/README.rst @@ -28,24 +28,21 @@ Py3o Report Engine - Fusion server support |badge1| |badge2| |badge3| |badge4| |badge5| -This module was written to let a py3o fusion server handle format -conversion instead of local libreoffice. If you install this module -above the *report_py3o* module, you will have to deploy additionnal -software components and run 3 daemons (libreoffice, py3o.fusion and -py3o.renderserver). This additionnal complexiy comes with several -advantages: - -- much better performances: Libreoffice runs permanently in the - background, no need to spawn a new Libreoffice instance upon every - document conversion. -- ability to configure PDF export options in Odoo. This brings many new - possibilities such as the ability to generate: - - - PDF forms - - PDF/A documents (required by some electronic invoicing standards - such as `Factur-X `__) - - watermarked PDF documents - - password-protected PDF documents +This module was written to connect to a local LibreOffice daemon that +handle format conversion instead of spawning a new LibreOffice for each +conversion. It has several advantages: + +- much better performances: Libreoffice runs permanently in the + background, no need to spawn a new Libreoffice instance upon every + document conversion. +- ability to configure PDF export options in Odoo. This brings many new + possibilities such as the ability to generate: + + - PDF forms + - PDF/A documents (required by some electronic invoicing standards + such as `Factur-X `__) + - watermarked PDF documents + - password-protected PDF documents **Table of contents** @@ -55,28 +52,11 @@ advantages: Installation ============ -Install several additional components and Python libs: - -- `Py3o Fusion server `__, -- `Py3o render - server `__, -- a Java Runtime Environment (JRE), which can be OpenJDK, -- Libreoffice started in the background in headless mode, -- the Java driver for Libreoffice (Juno). - -It is also possible to use the Python driver for Libreoffice (PyUNO), -but it is recommended to use the Java driver because it is more stable. - -The installation procedure below uses the Java driver. It has been -successfully tested on Ubuntu 18.04 LTS ; if you use another OS, you may -have to change a few details. - -Installation of Libreoffice, JRE and required Java libs on -Debian/Ubuntu: +Installation of Libreoffice: :: - sudo apt-get install default-jre ure libgoogle-gson-java libreoffice-java-common libreoffice-writer + sudo apt install libreoffice-writer python3-uno You may have to install additionnal fonts. For example, to have the special unicode symbols for phone/fax/email in the PDF reports generated @@ -84,75 +64,83 @@ by Py3o, you should install the following package: :: - sudo apt-get install fonts-symbola + sudo apt install fonts-symbola -Installation of py3o.fusion: +If you want to produce valid PDF/A documents with this module, +activating the corresponding option in the PDF Export Options may not be +enough, you also have to make sure that all the fonts used in the +document template are installed on the Odoo server, so that they can be +embedded in the PDF/A document. For example, if your document template +uses the Arial font, you should install that font on your Odoo server: :: - pip3 install py3o.fusion - pip3 install service-identity + sudo apt install msttcorefonts -Installation of py3o.renderserver: +The python libs **py3o.formats** and **py3o.template** are required +(they should already be installed for the module *report_py3o*). In the +virtualenv of your Odoo server, run: :: - pip3 install py3o.renderserver + % pip install --upgrade py3o.formats py3o.template -At the end, with the dependencies, you should have the following py3o -python libs: +Odoo will connect to the LibreOffice via the **uno** python lib which is +linked to LibreOffice. So you cannot install the uno lib in Odoo's +virtualenv like you do for all the other python libs required by Odoo. +Use the following procedure to make the uno lib installed by the package +of your Linux distribution available in Odoo's virtualenv. In the +virtualenv of your Odoo server, run: :: - % pip3 freeze | grep py3o - py3o.formats==0.3 - py3o.fusion==0.8.9 - py3o.renderclient==0.3 - py3o.renderers.juno==0.8.1 - py3o.renderserver==0.5.2 - py3o.template==0.10.0 - py3o.types==0.1.1 + % pip install oooenv + % oooenv cmd-link -a -Start the Py3o Fusion server: +Libreoffice must be run as a daemon. For that, create a file +**/etc/systemd/system/libreoffice.service** with the following content: :: - start-py3o-fusion --debug -s localhost -i localhost + [Unit] + Description=Libreoffice headless for Py3o + After=network.target -Start the Py3o render server: + [Service] + Type=simple + User=odoo + Group=odoo + ExecStart=nice -n 10 /usr/lib/libreoffice/program/soffice.bin --nologo --norestore --invisible --headless --nolockcheck --nodefault --accept="socket,host=localhost,port=8997;urp;" + stdout_logfile=/var/log/odoo/libreoffice.log + KillMode=mixed + Restart=always + # number of seconds to attempt restart after failure + RestartSec=5 -:: - - start-py3o-renderserver --java=/usr/lib/jvm/default-java/lib/server/libjvm.so --ure=/usr/share --office=/usr/lib/libreoffice --driver=juno --sofficeport=8997 -i localhost + [Install] + WantedBy=multi-user.target -On the output of the Py3o render server, the first line looks like: +The file content above is an example. You must adapt: -:: +- the system user and group that will be used to run libreoffice as a + daemon (*odoo* in the exemple) +- the path of the LibreOffice binary + (*/usr/lib/libreoffice/program/soffice.bin* in the example) +- the log file (*/var/log/odoo/libreoffice.log* in the example) +- the TCP port on which LibreOffice listens (*8997* in the example) - DEBUG:root:Starting JVM: /usr/lib/jvm/default-java/lib/server/libjvm.so with options: -Djava.class.path=/usr/local/lib/python2.7/dist-packages/py3o/renderers/juno/py3oconverter.jar:/usr/share/java/juh.jar:/usr/share/java/jurt.jar:/usr/share/java/ridl.jar:/usr/share/java/unoloader.jar:/usr/share/java/java_uno.jar:/usr/lib/libreoffice/program/classes/unoil.jar -Xmx150M +Then enable this service and start it: -After **-Djava.class.path**, there is a list of Java libs with *.jar* -extension ; check that each JAR file is really present on your -filesystem. If one of the jar files is present in another directory, -create a symlink that points to the real location of the file. If all -the jar files are present on another directory, adapt the *--ure=* -argument on the command line of Py3o render server. +:: -To check that the Py3o Fusion server is running fine, visit the URL -http://\ :8765/form. On this web page, under the section -*Target format*, make sure that you have a line *This server currently -supports these formats: ods, odt, docx, doc, html, docbook, pdf, xls.*. + sudo systemctl enable libreoffice + sudo systemctl start libreoffice -If you want to produce valid PDF/A documents with this module, -activating the corresponding option in the PDF Export Options may not be -enough, you also have to make sure that all the fonts used in the -document template are installed on the Odoo server, so that they can be -embedded in the PDF/A document. For example, if your document template -uses the Arial font, you should install that font on your Odoo server: +Check that LibreOffice runs in the background: :: - sudo apt-get install msttcorefonts + ps aux | grep soffice.bin Configuration ============= @@ -169,8 +157,8 @@ To configure the PDF export options: Known issues / Roadmap ====================== -- Add support for PDF signatures (possible, but no easy because the - signature certificate is a very particular PDF export option) +- Add support for PDF signatures (possible, but no easy because the + signature certificate is a very particular PDF export option) Bug Tracker =========== @@ -195,12 +183,12 @@ Authors Contributors ------------ -- Florent Aide (`XCG Consulting `__) -- Laurent Mignon , -- Alexis de Lattre , -- Guewen Baconnier -- Omar Castiñeira -- Holger Brunn +- Florent Aide (`XCG Consulting `__) +- Laurent Mignon , +- Alexis de Lattre , +- Guewen Baconnier +- Omar Castiñeira +- Holger Brunn Maintainers ----------- diff --git a/report_py3o_fusion_server/demo/report_py3o.xml b/report_py3o_fusion_server/demo/report_py3o.xml index 1a9f33d328..723c936804 100644 --- a/report_py3o_fusion_server/demo/report_py3o.xml +++ b/report_py3o_fusion_server/demo/report_py3o.xml @@ -1,6 +1,26 @@ - - + + localhost + + + Watermark for demo + + DEMO + + + Py3o Demo Report PDF + res.users + py3o_user_info_pdf + py3o + pdf + report_py3o + demo/res_user.odt + + + object.name.replace(' ', '_') + '-demo.pdf' + diff --git a/report_py3o_fusion_server/models/ir_actions_report.py b/report_py3o_fusion_server/models/ir_actions_report.py index 9c6ac85629..d20d3cbf79 100644 --- a/report_py3o_fusion_server/models/ir_actions_report.py +++ b/report_py3o_fusion_server/models/ir_actions_report.py @@ -4,7 +4,6 @@ import logging from odoo import _, api, fields, models -from odoo.exceptions import ValidationError logger = logging.getLogger(__name__) @@ -12,27 +11,7 @@ class IrActionsReport(models.Model): _inherit = "ir.actions.report" - @api.constrains("py3o_is_local_fusion", "py3o_server_id") - def _check_py3o_server_id(self): - for report in self: - if report.report_type != "py3o": - continue - if not report.py3o_is_local_fusion and not report.py3o_server_id: - raise ValidationError( - _( - "You can not use remote fusion without Fusion server. " - "Please specify a Fusion Server" - ) - ) - - py3o_is_local_fusion = fields.Boolean( - "Local Fusion", - help="Native formats will be processed without a server. " - "You must use this mode if you call methods on your model into " - "the template.", - default=True, - ) - py3o_server_id = fields.Many2one("py3o.server", "Fusion Server") + py3o_server_id = fields.Many2one("py3o.server", "LibreOffice for Py3o") pdf_options_id = fields.Many2one( "py3o.pdf.options", string="PDF Options", diff --git a/report_py3o_fusion_server/models/py3o_pdf_options.py b/report_py3o_fusion_server/models/py3o_pdf_options.py index cf560bfbba..aa80d85a3a 100644 --- a/report_py3o_fusion_server/models/py3o_pdf_options.py +++ b/report_py3o_fusion_server/models/py3o_pdf_options.py @@ -6,6 +6,7 @@ from odoo import _, api, fields, models from odoo.exceptions import ValidationError +from odoo.tools import file_open logger = logging.getLogger(__name__) @@ -43,6 +44,15 @@ class Py3oPdfOptions(models.Model): watermark = fields.Boolean("Sign With Watermark") # Watermark (string) watermark_text = fields.Char("WaterMark Text") + watermark_color = fields.Integer(string="Color") + watermark_font_size = fields.Integer(default=30, string="Font Size") + watermark_rotate_angle = fields.Integer( + default=90, + string="Rotate Angle", + help="Rotate angle in degree. 0 is horizontal. 90 is vertical.", + ) + watermark_repeat = fields.Boolean(string="Repeat") + # UseTaggedPDF (bool) tagged_pdf = fields.Boolean("Tagged PDF (add document structure)") # SelectPdfVersion (int) @@ -227,6 +237,7 @@ class Py3oPdfOptions(models.Model): "cross_doc_link_action", "magnification", "zoom", + "watermark_font_size", ) def check_pdf_options(self): for opt in self: @@ -262,6 +273,14 @@ def check_pdf_options(self): ) % opt.zoom ) + if opt.watermark_font_size < 1: + raise ValidationError( + _( + "The watermark font size must be strictly positive " + "(current value: %s).", + opt.watermark_font_size, + ) + ) @api.onchange("encrypt") def encrypt_change(self): @@ -295,7 +314,28 @@ def odoo2libreoffice_options(self): else: options["ReduceImageResolution"] = False if self.watermark and self.watermark_text: - options["Watermark"] = self.watermark_text + if self.watermark_repeat: + options["TiledWatermark"] = self.watermark_text + else: + options.update( + { + "Watermark": self.watermark_text, + "WatermarkFontHeight": self.watermark_font_size, + "WatermarkRotateAngle": self.watermark_rotate_angle * 10, + # WatermarkRotateAngle value is tenth of a degree + } + ) + + if self.watermark_color: + color_map = self._get_odoo_color_map() + if color_map and self.watermark_color in color_map: + options["WatermarkColor"] = color_map[self.watermark_color] + else: + # if no color has been set, we use color #192022 (grey) + # which is the color used for TiledWatermark + # cf https://git.libreoffice.org/core/+/refs/heads/master/filter/source/pdf/pdfexport.cxx#1513 + options["WatermarkColor"] = int("192022", 16) + if self.pdfa: options["SelectPdfVersion"] = 1 options["UseTaggedPDF"] = self.tagged_pdf @@ -378,3 +418,28 @@ def odoo2libreoffice_options(self): logger.debug("Py3o PDF options ID %s converted to %s", self.id, options) return options + + @api.model + def _get_odoo_color_map(self): + """return a dict where key is the odoo color index and value is + the decimal color value as expected by LibreOffice""" + res = {} + # The 3 variables below must be updated if odoo changes the color map definition + scss_path = "web/static/src/scss/secondary_variables.scss" + start_string = "$o-colors: " + end_string = "!default;" + with file_open(scss_path, "r") as f: + scss_content = f.read() + position = scss_content.find(start_string) + cutstart = scss_content[position + len(start_string) :] + end_position = cutstart.find(end_string) + cut = cutstart[:end_position] + index = 0 + for value in cut.split(","): + value = value.strip() + if value and value.startswith("#") and len(value) == 7: + res[index] = int(value[1:], 16) + index += 1 + # remove first value, see comment in secondary_variables.scss + res.pop(0) + return res diff --git a/report_py3o_fusion_server/models/py3o_report.py b/report_py3o_fusion_server/models/py3o_report.py index bf33030c7a..d2631debc2 100644 --- a/report_py3o_fusion_server/models/py3o_report.py +++ b/report_py3o_fusion_server/models/py3o_report.py @@ -2,26 +2,27 @@ # © 2016 ACSONE SA/NV # © 2017 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -import json import logging -import os import tempfile -from contextlib import closing from datetime import datetime -from io import BytesIO -import requests - -from odoo import _, models -from odoo.exceptions import UserError +from odoo import models logger = logging.getLogger(__name__) try: - from py3o.template import Template - from py3o.template.helpers import Py3oConvertor + from py3o.formats import Formats +except ImportError: + logger.debug("Cannot import py3o.formats") +try: + import uno +except ImportError: + logger.debug("Cannot import uno") + uno = False +try: + from com.sun.star.beans import PropertyValue except ImportError: - logger.debug("Cannot import py3o.template") + logger.debug("Cannot import com.sun.star.beans") class Py3oReport(models.TransientModel): @@ -30,77 +31,133 @@ class Py3oReport(models.TransientModel): def _create_single_report(self, model_instance, data): """This function to generate our py3o report""" self.ensure_one() - report_xml = self.ir_actions_report_id - filetype = report_xml.py3o_filetype - if not report_xml.py3o_server_id: + report = self.ir_actions_report_id + py3o_server = report.py3o_server_id + if not py3o_server or not uno: return super()._create_single_report(model_instance, data) - elif report_xml.py3o_is_local_fusion: - result_path = super( - Py3oReport, self.with_context(report_py3o_skip_conversion=True) - )._create_single_report(model_instance, data) - with closing(open(result_path, "rb")) as out_stream: - tmpl_data = out_stream.read() - datadict = {} - else: - result_fd, result_path = tempfile.mkstemp( - suffix="." + filetype, prefix="p3o.report.tmp." - ) - tmpl_data = self.get_template(model_instance) - - in_stream = BytesIO(tmpl_data) - with closing(os.fdopen(result_fd, "wb+")) as out_stream: - template = Template(in_stream, out_stream, escape_false=True) - localcontext = self._get_parser_context(model_instance, data) - expressions = template.get_all_user_python_expression() - py_expression = template.convert_py3o_to_python_ast(expressions) - convertor = Py3oConvertor() - data_struct = convertor(py_expression) - datadict = data_struct.render(localcontext) + filetype = report.py3o_filetype + uno_filter_data = [] + if filetype == "pdf": + options = report.pdf_options_id or py3o_server.pdf_options_id + if options: + pdf_options_dict = options.odoo2libreoffice_options() + logger.debug("PDF export options: %s", pdf_options_dict) + for pdf_opt_key, pdf_opt_val in pdf_options_dict.items(): + if isinstance(pdf_opt_val, bool | int | str) and isinstance( + pdf_opt_key, str + ): + uno_filter_data.append( + PropertyValue(Name=pdf_opt_key, Value=pdf_opt_val) + ) - # Call py3o.server to render the template in the desired format - files = {"tmpl_file": tmpl_data} - fields = { - "targetformat": filetype, - "datadict": json.dumps(datadict), - "image_mapping": "{}", - "escape_false": "on", - } - if report_xml.py3o_is_local_fusion: - fields["skipfusion"] = "1" - url = report_xml.py3o_server_id.url logger.info( - "Connecting to %s to convert report %s to %s", - url, - report_xml.report_name, + "Connecting to LibreOffice on %s to convert report %s to %s", + py3o_server.display_name, + report.report_name, filetype, ) - if filetype == "pdf": - options = ( - report_xml.pdf_options_id or report_xml.py3o_server_id.pdf_options_id - ) - if options: - pdf_options_dict = options.odoo2libreoffice_options() - fields["pdf_options"] = json.dumps(pdf_options_dict) - logger.debug("PDF Export options: %s", pdf_options_dict) start_chrono = datetime.now() - r = requests.post(url, data=fields, files=files, timeout=10) - if r.status_code != 200: - # server says we have an issue... let's tell that to enduser - logger.error("Py3o fusion server error: %s", r.text) - raise UserError(_("Fusion server error %s") % r.text) + uno_local_ctx = uno.getComponentContext() + uno_resolver = uno_local_ctx.ServiceManager.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", uno_local_ctx + ) + uno_url = ( + f"uno:socket,host={py3o_server.host.strip()}," + f"port={py3o_server.port};urp;StarOffice.ComponentContext" + ) + logger.debug("uno_url=%s", uno_url) + try: + uno_ctx = uno_resolver.resolve(uno_url) + logger.info( + "Connection to LibreOffice established on %s", py3o_server.display_name + ) + except Exception as e: + logger.warning( + "Failed to connect to LibreOffice on %s. Error: %s", + py3o_server.display_name, + e, + ) + return super()._create_single_report(model_instance, data) + + uno_desktop = uno_ctx.getByName("/singletons/com.sun.star.frame.theDesktop") + result_path = super( + Py3oReport, self.with_context(report_py3o_skip_conversion=True) + )._create_single_report(model_instance, data) + logger.debug("Input result_path=%s", result_path) + + uno_import_url = uno.systemPathToFileUrl(result_path) + uno_input_properties = [PropertyValue(Name="ReadOnly", Value=True)] + + try: + # API doc: https://api.libreoffice.org/docs/idl/ref/ + # interfacecom_1_1sun_1_1star_1_1frame_1_1XComponentLoader.html + uno_document = uno_desktop.loadComponentFromURL( + uno_import_url, "_default", 0, uno_input_properties + ) + logger.info("LibreOffice successfully loaded the document") + except Exception as e: + logger.warning( + "LibreOffice failed to load the document from %s. Error: %s", + uno_import_url, + e, + ) + return super()._create_single_report(model_instance, data) + if not uno_document: + logger.warning( + "LibreOffice failed to load the document from %s. No specific error.", + uno_import_url, + ) + return super()._create_single_report(model_instance, data) + # It doesn't work when the same path is used as input and output, + # so we create a file dedicated to the output + _out_fd, out_result_path = tempfile.mkstemp( + prefix="py3o.report.tmp.", suffix=f".{filetype}" + ) + logger.debug("out_result_path=%s", out_result_path) + uno_out_url = uno.systemPathToFileUrl(out_result_path) + # py3o.formats doesn't take into account the source format to decide + # the right filter. For pdf, il will always give "writer_pdf_Export" + # although we should use "calc_pdf_Export" if source document is ODS + # TODO stop using py3o.formats and re-write this mess + uno_filtername = Formats()._formats[filetype].odfname + logger.debug("uno_filtername=%s uno_out_url=%s", uno_filtername, uno_out_url) + uno_output_properties = [ + PropertyValue(Name="FilterName", Value=uno_filtername), + PropertyValue(Name="Overwrite", Value=True), + PropertyValue( + Name="FilterData", + Value=uno.Any("[]com.sun.star.beans.PropertyValue", uno_filter_data), + ), + ] + try: + uno_document.storeToURL(uno_out_url, uno_output_properties) + except Exception as err: + logger.warning( + "Conversion of report %s to %s with LibreOffice failed. Error: %s", + report.report_name, + filetype, + err, + ) + logger.warning( + "Make sure the source format can really be converted to %s.", filetype + ) + return super()._create_single_report(model_instance, data) + finally: + # Should we call uno_desktop.terminate() ?? + uno_document.close(True) + logger.debug("document has been closed.") - chunk_size = 1024 - with open(result_path, "w+b") as fd: - for chunk in r.iter_content(chunk_size): - fd.write(chunk) + # TODO: test that the output has the right format + # by analysing the beginning of the file + # To trigger the bug: change "FilterName" by "toto" in uno_output_properties end_chrono = datetime.now() convert_seconds = (end_chrono - start_chrono).total_seconds() logger.info( "Report %s converted to %s in %s seconds", - report_xml.report_name, + report.report_name, filetype, convert_seconds, ) if len(model_instance) == 1: - self._postprocess_report(model_instance, result_path) - return result_path + self._postprocess_report(model_instance, out_result_path) + return out_result_path diff --git a/report_py3o_fusion_server/models/py3o_server.py b/report_py3o_fusion_server/models/py3o_server.py index d7dd210f2e..1e103975c2 100644 --- a/report_py3o_fusion_server/models/py3o_server.py +++ b/report_py3o_fusion_server/models/py3o_server.py @@ -1,18 +1,26 @@ # Copyright 2013 XCG Consulting (http://odoo.consulting) +# Copyright 2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError class Py3oServer(models.Model): _name = "py3o.server" - _description = "Py3o server" - _rec_name = "url" + _description = "LibreOffice UNO Remote Protocol (URP) for Py3o" - url = fields.Char( - "Py3o Fusion Server URL", + host = fields.Char( + string="LibreOffice Hostname or IP address", + default="localhost", + required=True, + ) + port = fields.Integer( required=True, - help="If your Py3o Fusion server is on the same machine and runs " - "on the default port, the URL is http://localhost:8765/form", + default=8997, + help="TCP port on which LibreOffice listens. This port is written in the " + "--accept parameter of the soffice.bin command line.", ) is_active = fields.Boolean("Active", default=True) pdf_options_id = fields.Many2one( @@ -22,3 +30,23 @@ class Py3oServer(models.Model): help="PDF options can be set per Py3o Server but also per report. " "If both are defined, the options on the report are used.", ) + + @api.constrains("port") + def _check_port(self): + for rec in self: + if rec.port < 1 or rec.port > 65535: + raise ValidationError( + _( + "The port cannot be set to %(port)s. The value of a TCP port " + "must be between 1 and 65535.", + rec.port, + ) + ) + + @api.depends("host", "port") + def _compute_display_name(self): + for rec in self: + dname = rec.host + if dname and rec.port: + dname = f"{dname}:{rec.port}" + rec.display_name = dname diff --git a/report_py3o_fusion_server/readme/DESCRIPTION.md b/report_py3o_fusion_server/readme/DESCRIPTION.md index 077daaa218..7c62c1f018 100644 --- a/report_py3o_fusion_server/readme/DESCRIPTION.md +++ b/report_py3o_fusion_server/readme/DESCRIPTION.md @@ -1,9 +1,6 @@ -This module was written to let a py3o fusion server handle format -conversion instead of local libreoffice. If you install this module -above the *report_py3o* module, you will have to deploy additionnal -software components and run 3 daemons (libreoffice, py3o.fusion and -py3o.renderserver). This additionnal complexiy comes with several -advantages: +This module was written to connect to a local LibreOffice daemon that handle +format conversion instead of spawning a new LibreOffice for each conversion. +It has several advantages: - much better performances: Libreoffice runs permanently in the background, no need to spawn a new Libreoffice instance upon every diff --git a/report_py3o_fusion_server/readme/INSTALL.md b/report_py3o_fusion_server/readme/INSTALL.md index 7695ef86a0..2aab5d2394 100644 --- a/report_py3o_fusion_server/readme/INSTALL.md +++ b/report_py3o_fusion_server/readme/INSTALL.md @@ -1,97 +1,72 @@ -Install several additional components and Python libs: - -- [Py3o Fusion server](https://bitbucket.org/faide/py3o.fusion), -- [Py3o render server](https://bitbucket.org/faide/py3o.renderserver), -- a Java Runtime Environment (JRE), which can be OpenJDK, -- Libreoffice started in the background in headless mode, -- the Java driver for Libreoffice (Juno). - -It is also possible to use the Python driver for Libreoffice (PyUNO), -but it is recommended to use the Java driver because it is more stable. - -The installation procedure below uses the Java driver. It has been -successfully tested on Ubuntu 18.04 LTS ; if you use another OS, you may -have to change a few details. - -Installation of Libreoffice, JRE and required Java libs on -Debian/Ubuntu: +Installation of Libreoffice: ``` -sudo apt-get install default-jre ure libgoogle-gson-java libreoffice-java-common libreoffice-writer +sudo apt install libreoffice-writer python3-uno ``` -You may have to install additionnal fonts. For example, to have the -special unicode symbols for phone/fax/email in the PDF reports generated -by Py3o, you should install the following package: +You may have to install additionnal fonts. For example, to have the special unicode symbols for phone/fax/email in the PDF reports generated by Py3o, you should install the following package: ``` -sudo apt-get install fonts-symbola +sudo apt install fonts-symbola ``` -Installation of py3o.fusion: +If you want to produce valid PDF/A documents with this module, activating the corresponding option in the PDF Export Options may not be enough, you also have to make sure that all the fonts used in the document template are installed on the Odoo server, so that they can be embedded in the PDF/A document. For example, if your document template uses the Arial font, you should install that font on your Odoo server: ``` -pip3 install py3o.fusion -pip3 install service-identity +sudo apt install msttcorefonts ``` -Installation of py3o.renderserver: +The python libs **py3o.formats** and **py3o.template** are required (they should already be installed for the module *report_py3o*). In the virtualenv of your Odoo server, run: ``` -pip3 install py3o.renderserver +% pip install --upgrade py3o.formats py3o.template ``` -At the end, with the dependencies, you should have the following py3o -python libs: +Odoo will connect to the LibreOffice via the **uno** python lib which is linked to LibreOffice. So you cannot install the uno lib in Odoo's virtualenv like you do for all the other python libs required by Odoo. Use the following procedure to make the uno lib installed by the package of your Linux distribution available in Odoo's virtualenv. In the virtualenv of your Odoo server, run: ``` -% pip3 freeze | grep py3o -py3o.formats==0.3 -py3o.fusion==0.8.9 -py3o.renderclient==0.3 -py3o.renderers.juno==0.8.1 -py3o.renderserver==0.5.2 -py3o.template==0.10.0 -py3o.types==0.1.1 +% pip install oooenv +% oooenv cmd-link -a ``` -Start the Py3o Fusion server: +Libreoffice must be run as a daemon. For that, create a file **/etc/systemd/system/libreoffice.service** with the following content: ``` -start-py3o-fusion --debug -s localhost -i localhost +[Unit] +Description=Libreoffice headless for Py3o +After=network.target + +[Service] +Type=simple +User=odoo +Group=odoo +ExecStart=nice -n 10 /usr/lib/libreoffice/program/soffice.bin --nologo --norestore --invisible --headless --nolockcheck --nodefault --accept="socket,host=localhost,port=8997;urp;" +stdout_logfile=/var/log/odoo/libreoffice.log +KillMode=mixed +Restart=always +# number of seconds to attempt restart after failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target ``` -Start the Py3o render server: +The file content above is an example. You must adapt: -``` -start-py3o-renderserver --java=/usr/lib/jvm/default-java/lib/server/libjvm.so --ure=/usr/share --office=/usr/lib/libreoffice --driver=juno --sofficeport=8997 -i localhost -``` +- the system user and group that will be used to run libreoffice as a daemon (*odoo* in the exemple) +- the path of the LibreOffice binary (*/usr/lib/libreoffice/program/soffice.bin* in the example) +- the log file (*/var/log/odoo/libreoffice.log* in the example) +- the TCP port on which LibreOffice listens (*8997* in the example) -On the output of the Py3o render server, the first line looks like: +Then enable this service and start it: ``` -DEBUG:root:Starting JVM: /usr/lib/jvm/default-java/lib/server/libjvm.so with options: -Djava.class.path=/usr/local/lib/python2.7/dist-packages/py3o/renderers/juno/py3oconverter.jar:/usr/share/java/juh.jar:/usr/share/java/jurt.jar:/usr/share/java/ridl.jar:/usr/share/java/unoloader.jar:/usr/share/java/java_uno.jar:/usr/lib/libreoffice/program/classes/unoil.jar -Xmx150M +sudo systemctl enable libreoffice +sudo systemctl start libreoffice ``` -After **-Djava.class.path**, there is a list of Java libs with *.jar* -extension ; check that each JAR file is really present on your -filesystem. If one of the jar files is present in another directory, -create a symlink that points to the real location of the file. If all -the jar files are present on another directory, adapt the *--ure=* -argument on the command line of Py3o render server. - -To check that the Py3o Fusion server is running fine, visit the URL -\:8765/form. On this web page, under the section -*Target format*, make sure that you have a line *This server currently -supports these formats: ods, odt, docx, doc, html, docbook, pdf, xls.*. - -If you want to produce valid PDF/A documents with this module, -activating the corresponding option in the PDF Export Options may not be -enough, you also have to make sure that all the fonts used in the -document template are installed on the Odoo server, so that they can be -embedded in the PDF/A document. For example, if your document template -uses the Arial font, you should install that font on your Odoo server: +Check that LibreOffice runs in the background: ``` -sudo apt-get install msttcorefonts +ps aux | grep soffice.bin ``` diff --git a/report_py3o_fusion_server/static/description/index.html b/report_py3o_fusion_server/static/description/index.html index e50e3a87c4..d0b5a81d8f 100644 --- a/report_py3o_fusion_server/static/description/index.html +++ b/report_py3o_fusion_server/static/description/index.html @@ -370,12 +370,9 @@

Py3o Report Engine - Fusion server support

!! source digest: sha256:abe1267ad8b04d3171b35731fe78f8f1fd25c48420962cc8f5096462bb84fb66 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runboat

-

This module was written to let a py3o fusion server handle format -conversion instead of local libreoffice. If you install this module -above the report_py3o module, you will have to deploy additionnal -software components and run 3 daemons (libreoffice, py3o.fusion and -py3o.renderserver). This additionnal complexiy comes with several -advantages:

+

This module was written to connect to a local LibreOffice daemon that +handle format conversion instead of spawning a new LibreOffice for each +conversion. It has several advantages:

  • much better performances: Libreoffice runs permanently in the background, no need to spawn a new Libreoffice instance upon every @@ -407,82 +404,79 @@

    Py3o Report Engine - Fusion server support

    Installation

    -

    Install several additional components and Python libs:

    -
      -
    • Py3o Fusion server,
    • -
    • Py3o render -server,
    • -
    • a Java Runtime Environment (JRE), which can be OpenJDK,
    • -
    • Libreoffice started in the background in headless mode,
    • -
    • the Java driver for Libreoffice (Juno).
    • -
    -

    It is also possible to use the Python driver for Libreoffice (PyUNO), -but it is recommended to use the Java driver because it is more stable.

    -

    The installation procedure below uses the Java driver. It has been -successfully tested on Ubuntu 18.04 LTS ; if you use another OS, you may -have to change a few details.

    -

    Installation of Libreoffice, JRE and required Java libs on -Debian/Ubuntu:

    +

    Installation of Libreoffice:

    -sudo apt-get install default-jre ure libgoogle-gson-java libreoffice-java-common libreoffice-writer
    +sudo apt install libreoffice-writer python3-uno
     

    You may have to install additionnal fonts. For example, to have the special unicode symbols for phone/fax/email in the PDF reports generated by Py3o, you should install the following package:

    -sudo apt-get install fonts-symbola
    +sudo apt install fonts-symbola
     
    -

    Installation of py3o.fusion:

    -
    -pip3 install py3o.fusion
    -pip3 install service-identity
    -
    -

    Installation of py3o.renderserver:

    +

    If you want to produce valid PDF/A documents with this module, +activating the corresponding option in the PDF Export Options may not be +enough, you also have to make sure that all the fonts used in the +document template are installed on the Odoo server, so that they can be +embedded in the PDF/A document. For example, if your document template +uses the Arial font, you should install that font on your Odoo server:

    -pip3 install py3o.renderserver
    +sudo apt install msttcorefonts
     
    -

    At the end, with the dependencies, you should have the following py3o -python libs:

    +

    The python libs py3o.formats and py3o.template are required +(they should already be installed for the module report_py3o). In the +virtualenv of your Odoo server, run:

    -% pip3 freeze | grep py3o
    -py3o.formats==0.3
    -py3o.fusion==0.8.9
    -py3o.renderclient==0.3
    -py3o.renderers.juno==0.8.1
    -py3o.renderserver==0.5.2
    -py3o.template==0.10.0
    -py3o.types==0.1.1
    +% pip install --upgrade py3o.formats py3o.template
     
    -

    Start the Py3o Fusion server:

    +

    Odoo will connect to the LibreOffice via the uno python lib which is +linked to LibreOffice. So you cannot install the uno lib in Odoo’s +virtualenv like you do for all the other python libs required by Odoo. +Use the following procedure to make the uno lib installed by the package +of your Linux distribution available in Odoo’s virtualenv. In the +virtualenv of your Odoo server, run:

    -start-py3o-fusion --debug -s localhost -i localhost
    +% pip install oooenv
    +% oooenv cmd-link -a
     
    -

    Start the Py3o render server:

    +

    Libreoffice must be run as a daemon. For that, create a file +/etc/systemd/system/libreoffice.service with the following content:

    -start-py3o-renderserver --java=/usr/lib/jvm/default-java/lib/server/libjvm.so --ure=/usr/share --office=/usr/lib/libreoffice --driver=juno --sofficeport=8997 -i localhost
    +[Unit]
    +Description=Libreoffice headless for Py3o
    +After=network.target
    +
    +[Service]
    +Type=simple
    +User=odoo
    +Group=odoo
    +ExecStart=nice -n 10 /usr/lib/libreoffice/program/soffice.bin --nologo --norestore --invisible --headless --nolockcheck --nodefault --accept="socket,host=localhost,port=8997;urp;"
    +stdout_logfile=/var/log/odoo/libreoffice.log
    +KillMode=mixed
    +Restart=always
    +# number of seconds to attempt restart after failure
    +RestartSec=5
    +
    +[Install]
    +WantedBy=multi-user.target
     
    -

    On the output of the Py3o render server, the first line looks like:

    +

    The file content above is an example. You must adapt:

    +
      +
    • the system user and group that will be used to run libreoffice as a +daemon (odoo in the exemple)
    • +
    • the path of the LibreOffice binary +(/usr/lib/libreoffice/program/soffice.bin in the example)
    • +
    • the log file (/var/log/odoo/libreoffice.log in the example)
    • +
    • the TCP port on which LibreOffice listens (8997 in the example)
    • +
    +

    Then enable this service and start it:

    -DEBUG:root:Starting JVM: /usr/lib/jvm/default-java/lib/server/libjvm.so with options: -Djava.class.path=/usr/local/lib/python2.7/dist-packages/py3o/renderers/juno/py3oconverter.jar:/usr/share/java/juh.jar:/usr/share/java/jurt.jar:/usr/share/java/ridl.jar:/usr/share/java/unoloader.jar:/usr/share/java/java_uno.jar:/usr/lib/libreoffice/program/classes/unoil.jar -Xmx150M
    +sudo systemctl enable libreoffice
    +sudo systemctl start libreoffice
     
    -

    After -Djava.class.path, there is a list of Java libs with .jar -extension ; check that each JAR file is really present on your -filesystem. If one of the jar files is present in another directory, -create a symlink that points to the real location of the file. If all -the jar files are present on another directory, adapt the –ure= -argument on the command line of Py3o render server.

    -

    To check that the Py3o Fusion server is running fine, visit the URL -http://<IP_address>:8765/form. On this web page, under the section -Target format, make sure that you have a line This server currently -supports these formats: ods, odt, docx, doc, html, docbook, pdf, xls..

    -

    If you want to produce valid PDF/A documents with this module, -activating the corresponding option in the PDF Export Options may not be -enough, you also have to make sure that all the fonts used in the -document template are installed on the Odoo server, so that they can be -embedded in the PDF/A document. For example, if your document template -uses the Arial font, you should install that font on your Odoo server:

    +

    Check that LibreOffice runs in the background:

    -sudo apt-get install msttcorefonts
    +ps aux | grep soffice.bin
     
    diff --git a/report_py3o_fusion_server/tests/test_report_py3o_fusion_server.py b/report_py3o_fusion_server/tests/test_report_py3o_fusion_server.py index 300510f6c8..8b481a29b1 100644 --- a/report_py3o_fusion_server/tests/test_report_py3o_fusion_server.py +++ b/report_py3o_fusion_server/tests/test_report_py3o_fusion_server.py @@ -2,8 +2,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from unittest import mock -from odoo.exceptions import ValidationError - from odoo.addons.report_py3o.models.ir_actions_report import ( PY3O_CONVERSION_COMMAND_PARAMETER, ) @@ -19,35 +17,13 @@ ), ) class TestReportPy3oFusionServer(test_report_py3o.TestReportPy3o): - def setUp(self): - super().setUp() - py3o_server = self.env["py3o.server"].create({"url": "http://dummy"}) - # check the call to the fusion server - self.report.write({"py3o_server_id": py3o_server.id, "py3o_filetype": "pdf"}) - self.py3o_server = py3o_server - - def test_no_local_fusion_without_fusion_server(self): - self.assertTrue(self.report.py3o_is_local_fusion) - # Fusion server is only required if not local... - self.report.write({"py3o_server_id": None, "py3o_is_local_fusion": True}) - self.report.write( - {"py3o_server_id": self.py3o_server.id, "py3o_is_local_fusion": True} - ) - self.report.write( - {"py3o_server_id": self.py3o_server.id, "py3o_is_local_fusion": False} - ) - with self.assertRaises(ValidationError) as e: - self.report.write({"py3o_server_id": None, "py3o_is_local_fusion": False}) - self.assertEqual( - str(e.exception), - "You can not use remote fusion without Fusion server. " - "Please specify a Fusion Server", - ) - - def test_reports_no_local_fusion(self): - self.report.py3o_is_local_fusion = False - # TODO repair no local fusion - # self.test_reports() + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + py3o_server = cls.env["py3o.server"].create({}) + cls.report.write({"py3o_server_id": py3o_server.id, "py3o_filetype": "pdf"}) + cls.py3o_server = py3o_server def test_odoo2libreoffice_options(self): for options in self.env["py3o.pdf.options"].search([]): @@ -93,3 +69,9 @@ def test_py3o_report_availability(self): self.assertTrue(self.report.lo_bin_path) self.assertFalse(self.report.is_py3o_report_not_available) self.assertFalse(self.report.msg_py3o_report_not_available) + + def test_odoo_color_map(self): + color_map = self.env["py3o.pdf.options"]._get_odoo_color_map() + # check extreme values + self.assertEqual(color_map[1], int("ee2d2d", 16)) + self.assertEqual(color_map[11], int("9872e6", 16)) diff --git a/report_py3o_fusion_server/views/ir_actions_report.xml b/report_py3o_fusion_server/views/ir_actions_report.xml index d86cb38806..33002b7c88 100644 --- a/report_py3o_fusion_server/views/ir_actions_report.xml +++ b/report_py3o_fusion_server/views/ir_actions_report.xml @@ -5,7 +5,6 @@ - diff --git a/report_py3o_fusion_server/views/py3o_pdf_options.xml b/report_py3o_fusion_server/views/py3o_pdf_options.xml index b447ccbaba..ea99488213 100644 --- a/report_py3o_fusion_server/views/py3o_pdf_options.xml +++ b/report_py3o_fusion_server/views/py3o_pdf_options.xml @@ -42,6 +42,32 @@ invisible="not watermark" required="watermark" /> + + + +