Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][MIG][ADD] report_py3o_index #989

Open
wants to merge 2 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions report_py3o_index/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
==============================================
Py3o Report Engine: Update Indices (TOC, etc.)
==============================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:527b4bd77cfdd3ff1f069091cc2701f01df1c9cbbd7ffab7ab5a207b0fc7a58d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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/16.0/report_py3o_index
: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-16-0/reporting-engine-16-0-report_py3o_index
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/reporting-engine&target_branch=16.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module fills in the document indexes (e.g. a Table of Content) in a generated py3o document.

This is to work around the missing feature first reported in 2012: https://bugs.documentfoundation.org/show_bug.cgi?id=44448

It uses the workaround given in https://ask.libreoffice.org/t/update-toc-via-command-line/52518 and other similar threads.

Note that to work, the macro has to be installed in libreoffice first.
This is done at module install.
It assumes the macro files are stored at `~/.config/libreoffice/4/user/basic/Standard`.
If it fails, the function can be manually called with the real path using:
`self.env["py3o.report"]._install_update_index_macro(real_path)`
Make sure that this is correct as most failure paths of the macro application are silent.

Once this is done, py3o templates have an "has index" boolean.
If set, the macro is applied after generation (and before pdf conversion) to update all indices.

**Table of contents**

.. contents::
:local:

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 to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_py3o_index%0Aversion:%2016.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
~~~~~~~

* Lambdao

Contributors
~~~~~~~~~~~~

* Fanny He (`Lambdao <https://lambdao.dev/>`_) <fanny@lambdao.dev>,
* Nans Lefebvre (`Lambdao <https://lambdao.dev/>`_) <len@lambdao.dev>,

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/16.0/report_py3o_index>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
7 changes: 7 additions & 0 deletions report_py3o_index/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).


from . import models

from .hooks import post_init_hook
17 changes: 17 additions & 0 deletions report_py3o_index/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).


{
"name": "Py3o Report Engine: Update Indices (TOC, etc.)",
"summary": "Update indices (TOC, etc.) in Py3o reports",
"version": "16.0.1.0.0",
"category": "Reporting",
"license": "AGPL-3",
"author": "Lambdao, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine",
"depends": ["report_py3o"],
"data": ["views/ir_actions_report.xml", "views/py3o_template.xml"],
"installable": True,
"post_init_hook": "post_init_hook",
}
28 changes: 28 additions & 0 deletions report_py3o_index/data/ModuleUpdateIndex.xba
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="ModuleUpdateIndex" script:language="StarBasic">REM ***** BASIC *****

Option Explicit

Sub UpdateIndexes(path As String)
&apos;&apos;&apos;Update indexes, such as for the table of contents&apos;&apos;&apos;
Dim doc As Object
Dim args()

doc = StarDesktop.loadComponentFromUrl(convertToUrl(path), &quot;_default&quot;, 0, args())

Dim i As Integer

With doc &apos; Only process Writer documents
If .supportsService(&quot;com.sun.star.text.GenericTextDocument&quot;) Then
For i = 0 To .getDocumentIndexes().count - 1
.getDocumentIndexes().getByIndex(i).update()
Next i
End If
End With &apos; ThisComponent

doc.store()
doc.close(True)

End Sub &apos; UpdateIndexes
</script:module>
20 changes: 20 additions & 0 deletions report_py3o_index/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import logging

from odoo import SUPERUSER_ID, api

_logger = logging.getLogger(__name__)


def post_init_hook(cr, registry):
_logger.info("Install index update macro with default path.")
env = api.Environment(cr, SUPERUSER_ID, {})
try:
env["py3o.report"]._install_update_index_macro()
except Exception as e:
_logger.warn("Failed to install index update macro.")
_logger.warn("--------")
_logger.warn(e)
_logger.warn("--------")
7 changes: 7 additions & 0 deletions report_py3o_index/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).


from . import py3o_template
from . import ir_actions_report
from . import py3o_report
16 changes: 16 additions & 0 deletions report_py3o_index/models/ir_actions_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).


from odoo import fields, models


class IrActionsReport(models.Model):

_inherit = "ir.actions.report"
py3o_has_index_fallback = fields.Boolean(
"Has Py3o Index? (Fallback)",
default=False,
help="Check if the template fallback has a py3o index. "
"It needs to be compiled twice to get the index right.",
)
90 changes: 90 additions & 0 deletions report_py3o_index/models/py3o_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).


import logging
import os
import subprocess

import pkg_resources

from odoo import api, fields, models

logger = logging.getLogger(__name__)


class Py3oReport(models.TransientModel):
_inherit = "py3o.report"

py3o_has_index = fields.Boolean(
"Has Py3o Index?",
default=False,
compute="_compute_py3o_has_index",
help="Check if the template has a py3o index. "
"It needs to be compiled twice to get the index right.",
)

@api.depends(
"ir_actions_report_id.py3o_template_id.py3o_has_index",
"ir_actions_report_id.py3o_has_index_fallback",
)
def _compute_py3o_has_index(self):
for rec in self:
if rec.ir_actions_report_id.py3o_template_id:
value = rec.ir_actions_report_id.py3o_template_id.py3o_has_index

Check warning on line 34 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L34

Added line #L34 was not covered by tests
else:
value = rec.ir_actions_report_id.py3o_has_index_fallback
rec.py3o_has_index = value

Check warning on line 37 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L36-L37

Added lines #L36 - L37 were not covered by tests

@api.model
def _install_update_index_macro(self, path=None):
"""Install or update the py3o index macro"""
# the real path is an argument so that in case it fails it can be
# called again with the correct one; after that it's LO's internal
# macro naming that will be used
# we could also have a parameter for the macro name but
# is it worth the complexity?
if not path:
path = "~/.config/libreoffice/4/user/basic/Standard"
real_path = os.path.realpath(os.path.expanduser(path))
file_macro = "ModuleUpdateIndex.xba"
macro_path = os.path.join(real_path, file_macro)
if not os.path.exists(macro_path):
# copy the new macro to libreoffice macro folder
content_path = pkg_resources.resource_filename(
"odoo.addons.report_py3o_index", "data/ModuleUpdateIndex.xba"
)
with open(content_path, "r") as f:
content = f.read()
with open(macro_path, "w") as f:
f.write(content)
file_script = "script.xlb"
script_path = os.path.join(real_path, file_script)
mac = '<library:element library:name="ModuleUpdateIndex"/>'
with open(script_path, "r") as f:
script_content = f.read()

Check warning on line 65 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L60-L65

Added lines #L60 - L65 were not covered by tests
if mac not in script_content:
end_marker = "</library:library>"
marker_line = mac + "\n" + end_marker
new_content = script_content.replace(end_marker, marker_line)
with open(script_path, "w") as f:
f.write(new_content)

Check warning on line 71 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L67-L71

Added lines #L67 - L71 were not covered by tests

def _convert_single_report(self, result_path, model_instance, data):
# this needs to be done before the report is converted to pdf!
# data is an unused dict, the file is obtained from the result_path
if self.py3o_has_index:
self._update_index(result_path)
result = super(Py3oReport, self)._convert_single_report(

Check warning on line 78 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L77-L78

Added lines #L77 - L78 were not covered by tests
result_path, model_instance, data
)
return result

Check warning on line 81 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L81

Added line #L81 was not covered by tests

def _update_index(self, result_path):
"""Run a command to update the index"""
path = "macro:///Standard.ModuleUpdateIndex.UpdateIndexes(%s)" % result_path
lo_bin = self.ir_actions_report_id.lo_bin_path
cmd = [lo_bin, "--headless", path]

Check warning on line 87 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L85-L87

Added lines #L85 - L87 were not covered by tests
# if something goes wrong, it's not giving any error message...
subprocess.check_output(cmd, cwd=os.path.dirname(result_path))
return result_path

Check warning on line 90 in report_py3o_index/models/py3o_report.py

View check run for this annotation

Codecov / codecov/patch

report_py3o_index/models/py3o_report.py#L89-L90

Added lines #L89 - L90 were not covered by tests
16 changes: 16 additions & 0 deletions report_py3o_index/models/py3o_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2024 fah-mili/Lambdao
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).


from odoo import fields, models


class Py3oTemplate(models.Model):
_inherit = "py3o.template"

py3o_has_index = fields.Boolean(
"Has Py3o Index?",
default=False,
help="Check if the template has a py3o index. "
"It needs to be compiled twice to get the index right.",
)
2 changes: 2 additions & 0 deletions report_py3o_index/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Fanny He (`Lambdao <https://lambdao.dev/>`_) <fanny@lambdao.dev>,
* Nans Lefebvre (`Lambdao <https://lambdao.dev/>`_) <len@lambdao.dev>,
15 changes: 15 additions & 0 deletions report_py3o_index/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
This module fills in the document indexes (e.g. a Table of Content) in a generated py3o document.

This is to work around the missing feature first reported in 2012: https://bugs.documentfoundation.org/show_bug.cgi?id=44448

It uses the workaround given in https://ask.libreoffice.org/t/update-toc-via-command-line/52518 and other similar threads.

Note that to work, the macro has to be installed in libreoffice first.
This is done at module install.
It assumes the macro files are stored at `~/.config/libreoffice/4/user/basic/Standard`.
If it fails, the function can be manually called with the real path using:
`self.env["py3o.report"]._install_update_index_macro(real_path)`
Make sure that this is correct as most failure paths of the macro application are silent.

Once this is done, py3o templates have an "has index" boolean.
If set, the macro is applied after generation (and before pdf conversion) to update all indices.
Binary file added report_py3o_index/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading