Browse Source

Merge pull request #211 from akretion/10-py3o-pdf-options

[10.0] report_py3o_fusion_server: Add support for PDF Export options of libreoffice
pull/232/head
Alexis de Lattre 7 years ago
committed by GitHub
parent
commit
8d08bba93c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      report_py3o/README.rst
  2. 41
      report_py3o_fusion_server/README.rst
  3. 2
      report_py3o_fusion_server/__manifest__.py
  4. 11
      report_py3o_fusion_server/demo/py3o_pdf_options.xml
  5. 1
      report_py3o_fusion_server/models/__init__.py
  6. 4
      report_py3o_fusion_server/models/ir_actions_report_xml.py
  7. 316
      report_py3o_fusion_server/models/py3o_pdf_options.py
  8. 22
      report_py3o_fusion_server/models/py3o_report.py
  9. 4
      report_py3o_fusion_server/models/py3o_server.py
  10. 6
      report_py3o_fusion_server/security/ir.model.access.csv
  11. 5
      report_py3o_fusion_server/tests/test_report_py3o_fusion_server.py
  12. 1
      report_py3o_fusion_server/views/ir_report.xml
  13. 149
      report_py3o_fusion_server/views/py3o_pdf_options.xml
  14. 2
      report_py3o_fusion_server/views/py3o_server.xml

2
report_py3o/README.rst

@ -19,6 +19,8 @@ The key advantages of a Libreoffice based reporting engine are:
* 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 to PDF (or ODT to DOCX, ..) document conversion. This is slow and can become a problem if you have a lot of reports to convert from ODT to another format. In this case, you should consider the additionnal module *report_py3o_fusion_server* which is designed to work with a libreoffice daemon. With *report_py3o_fusion_server*, the technical environnement is more complex to setup because you have to install additionnal software components and run 2 daemons, but you have much better performances and you can configure the libreoffice PDF export options in Odoo (allows to generate PDF forms, PDF/A documents, password-protected PDFs, watermarked PDFs, etc.).
This reporting engine is an alternative to `Aeroo <https://github.com/aeroo-community/aeroo_reports>`_: these two reporting engines have similar features but their implementation is entirely different. You cannot use aeroo templates as drop in replacement though, you'll have to change a few details.
Installation

41
report_py3o_fusion_server/README.rst

@ -6,7 +6,15 @@
Py3o Report Engine - Fusion server support
==========================================
This module was written to let a py3o fusion server handle format conversion instead of local libreoffice.
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 <http://fnfe-mpe.org/factur-x/>`_)
* watermarked PDF documents
* password-protected PDF documents
Installation
============
@ -23,30 +31,30 @@ It is also possible to use the Python driver for Libreoffice (PyUNO), but it is
The installation procedure below uses the Java driver. It has been successfully tested on Ubuntu 16.04 LTS ; if you use another OS, you may have to change a few details.
Installation of py3o.fusion:
Installation of Libreoffice, JRE and required Java libs on Debian/Ubuntu:
.. code::
pip install py3o.fusion
pip install service-identity
sudo apt-get install default-jre ure libgoogle-gson-java libreoffice-java-common libreoffice-writer
Installation of py3o.renderserver:
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:
.. code::
pip install py3o.renderserver
sudo apt-get install fonts-symbola
Installation of Libreoffice and JRE on Debian/Ubuntu:
Installation of py3o.fusion:
.. code::
sudo apt-get install default-jre ure libreoffice-java-common libreoffice-writer
pip install py3o.fusion
pip install service-identity
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:
Installation of py3o.renderserver:
.. code::
sudo apt-get install fonts-symbola
pip install py3o.renderserver
At the end, with the dependencies, you should have the following py3o python libs:
@ -54,11 +62,11 @@ At the end, with the dependencies, you should have the following py3o python lib
% pip freeze | grep py3o
py3o.formats==0.3
py3o.fusion==0.8.7
py3o.fusion==0.8.8
py3o.renderclient==0.2
py3o.renderers.juno==0.8
py3o.renderserver==0.5.1
py3o.template==0.9.11
py3o.template==0.9.12
py3o.types==0.1.1
Start the Py3o Fusion server:
@ -83,10 +91,17 @@ After **-Djava.class.path**, there is a list of Java libs with *.jar* extension
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:
.. code::
sudo apt-get install msttcorefonts
Known issues / Roadmap
======================
* none yet
* Add support for PDF signatures (possible, but no easy because the signature certificate is a very particular PDF export option)
Bug Tracker
===========

2
report_py3o_fusion_server/__manifest__.py

@ -20,11 +20,13 @@
},
'demo': [
"demo/report_py3o.xml",
"demo/py3o_pdf_options.xml",
],
'data': [
"views/ir_report.xml",
'security/ir.model.access.csv',
'views/py3o_server.xml',
'views/py3o_pdf_options.xml',
],
'installable': True,
}

11
report_py3o_fusion_server/demo/py3o_pdf_options.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="py3o_pdf_options_pdfa" model="py3o.pdf.options">
<field name="name">PDF/A (for Factur-X invoices)</field>
<field name="pdfa" eval="True"/>
</record>
</odoo>

1
report_py3o_fusion_server/models/__init__.py

@ -2,5 +2,6 @@
# Copyright 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import ir_actions_report_xml
from . import py3o_pdf_options
from . import py3o_report
from . import py3o_server

4
report_py3o_fusion_server/models/ir_actions_report_xml.py

@ -39,3 +39,7 @@ class IrActionsReportXml(models.Model):
py3o_server_id = fields.Many2one(
"py3o.server",
"Fusion Server")
pdf_options_id = fields.Many2one(
'py3o.pdf.options', string='PDF Options', ondelete='restrict',
help="PDF options can be set per report, but also per Py3o Server. "
"If both are defined, the options on the report are used.")

316
report_py3o_fusion_server/models/py3o_pdf_options.py

@ -0,0 +1,316 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Akretion (http://www.akretion.com)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import logging
logger = logging.getLogger(__name__)
class Py3oPdfOptions(models.Model):
_name = 'py3o.pdf.options'
_description = 'Define PDF export options for Libreoffice'
name = fields.Char(required=True)
# GENERAL TAB
# UseLosslessCompression (bool)
image_compression = fields.Selection([
('lossless', 'Lossless Compression'),
('jpeg', 'JPEG Compression'),
], string='Image Compression', default='jpeg')
# Quality (int)
image_jpeg_quality = fields.Integer(
string='Image JPEG Quality', default=90,
help="Enter a percentage between 0 and 100.")
# ReduceImageResolution (bool) and MaxImageResolution (int)
image_reduce_resolution = fields.Selection([
('none', 'Disable'),
('75', '75 DPI'),
('150', '150 DPI'),
('300', '300 DPI'),
('600', '600 DPI'),
('1200', '1200 DPI'),
], string='Reduce Image Resolution', default='300')
watermark = fields.Boolean('Sign With Watermark')
# Watermark (string)
watermark_text = fields.Char('WaterMark Text')
# UseTaggedPDF (bool)
tagged_pdf = fields.Boolean('Tagged PDF (add document structure)')
# SelectPdfVersion (int)
# 0 = PDF 1.4 (default selection).
# 1 = PDF/A-1 (ISO 19005-1:2005)
pdfa = fields.Boolean(
'Archive PDF/A-1a (ISO 19005-1)',
help="If you enable this option, you will not be able to "
"password-protect the document or apply other security settings.")
# ExportFormFields (bool)
pdf_form = fields.Boolean('Create PDF Form', default=True)
# FormsType (int)
pdf_form_format = fields.Selection([
('0', 'FDF'),
('1', 'PDF'),
('2', 'HTML'),
('3', 'XML'),
], string='Submit Format', default='0')
# AllowDuplicateFieldNames (bool)
pdf_form_allow_duplicate = fields.Boolean('Allow Duplicate Field Names')
# ExportBookmarks (bool)
export_bookmarks = fields.Boolean('Export Bookmarks', default=True)
# ExportPlaceholders (bool)
export_placeholders = fields.Boolean('Export Placeholders', default=True)
# ExportNotes (bool)
export_comments = fields.Boolean('Export Comments')
# ExportHiddenSlides (bool) ??
export_hidden_slides = fields.Boolean(
'Export Automatically Insered Blank Pages')
# Doesn't make sense to have the option "View PDF after export" ! :)
# INITIAL VIEW TAB
# InitialView (int)
initial_view = fields.Selection([
('0', 'Page Only'),
('1', 'Bookmarks and Page'),
('2', 'Thumbnails and Page'),
], string='Panes', default='0')
# InitialPage (int)
initial_page = fields.Integer(string='Initial Page', default=1)
# Magnification (int)
magnification = fields.Selection([
('0', 'Default'),
('1', 'Fit in Window'),
('2', 'Fit Width'),
('3', 'Fit Visible'),
('4', 'Zoom'),
], string='Magnification', default='0')
# Zoom (int)
zoom = fields.Integer(
string='Zoom Factor', default=100,
help='Possible values: from 50 to 1600')
# PageLayout (int)
page_layout = fields.Selection([
('0', 'Default'),
('1', 'Single Page'),
('2', 'Continuous'),
('3', 'Continuous Facing'),
], string='Page Layout', default='0')
# USER INTERFACE TAB
# ResizeWindowToInitialPage (bool)
resize_windows_initial_page = fields.Boolean(
string='Resize Windows to Initial Page')
# CenterWindow (bool)
center_window = fields.Boolean(string='Center Window on Screen')
# OpenInFullScreenMode (bool)
open_fullscreen = fields.Boolean(string='Open in Full Screen Mode')
# DisplayPDFDocumentTitle (bool)
display_document_title = fields.Boolean(string='Display Document Title')
# HideViewerMenubar (bool)
hide_menubar = fields.Boolean(string='Hide Menubar')
# HideViewerToolbar (bool)
hide_toolbar = fields.Boolean(string='Hide Toolbar')
# HideViewerWindowControls (bool)
hide_window_controls = fields.Boolean(string='Hide Windows Controls')
# OpenBookmarkLevels (int) -1 = all (default) from 1 to 10
open_bookmark_levels = fields.Selection([
('-1', 'All Levels'),
('1', '1'),
('2', '2'),
('3', '3'),
('4', '4'),
('5', '5'),
('6', '6'),
('7', '7'),
('8', '8'),
('9', '9'),
('10', '10'),
], default='-1', string='Visible Bookmark Levels')
# LINKS TAB
# ExportBookmarksToPDFDestination (bool)
export_bookmarks_named_dest = fields.Boolean(
string='Export Bookmarks as Named Destinations')
# ConvertOOoTargetToPDFTarget (bool)
convert_doc_ref_to_pdf_target = fields.Boolean(
string='Convert Document References to PDF Targets')
# ExportLinksRelativeFsys (bool)
export_filesystem_urls = fields.Boolean(
string='Export URLs Relative to Filesystem')
# PDFViewSelection -> mnDefaultLinkAction (int)
cross_doc_link_action = fields.Selection([
('0', 'Default'),
('1', 'Open with PDF Reader Application'),
('2', 'Open with Internet Browser'),
], string='Cross-document Links', default='0')
# SECURITY TAB
# EncryptFile (bool)
encrypt = fields.Boolean('Encrypt')
# DocumentOpenPassword (char)
document_password = fields.Char(string='Document Password')
# RestrictPermissions (bool)
restrict_permissions = fields.Boolean('Restrict Permissions')
# PermissionPassword (char)
permission_password = fields.Char(string='Permission Password')
# TODO PreparedPasswords + PreparedPermissionPassword
# I don't see those fields in the LO interface !
# But they are used in the LO code...
# Printing (int)
printing = fields.Selection([
('0', 'Not Permitted'),
('1', 'Low Resolution (150 dpi)'),
('2', 'High Resolution'),
], string='Printing', default='2')
# Changes (int)
changes = fields.Selection([
('0', 'Not Permitted'),
('1', 'Inserting, Deleting and Rotating Pages'),
('2', 'Filling in Form Fields'),
('3', 'Commenting, Filling in Form Fields'),
('4', 'Any Except Extracting Pages'),
], string='Changes', default='4')
# EnableCopyingOfContent (bool)
content_copying_allowed = fields.Boolean(
string='Enable Copying of Content', default=True)
# EnableTextAccessForAccessibilityTools (bool)
text_access_accessibility_tools_allowed = fields.Boolean(
string='Enable Text Access for Accessibility Tools', default=True)
# DIGITAL SIGNATURE TAB
# This will be possible but not easy
# Because the certificate parameter is a pointer to a certificate
# already registered in LO
# On Linux LO reuses the Mozilla certificate store (on Windows the
# one from Windows)
# But there seems to be some possibilities to send this certificate via API
# It seems you can add temporary certificates during runtime:
# https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1security_1_1XCertificateContainer.html
# Here is an API to retrieve the known certificates:
# https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1xml_1_1crypto_1_1XSecurityEnvironment.html
# Thanks to 'samuel_m' on libreoffice-dev IRC chan for pointing me to this
@api.constrains(
'image_jpeg_quality', 'initial_page', 'pdfa',
'cross_doc_link_action', 'magnification', 'zoom')
def check_pdf_options(self):
for opt in self:
if opt.image_jpeg_quality > 100 or opt.image_jpeg_quality < 1:
raise ValidationError(_(
"The parameter Image JPEG Quality must be between 1 %%"
" and 100 %% (current value: %s %%)")
% opt.image_jpeg_quality)
if opt.initial_page < 1:
raise ValidationError(_(
"The initial page parameter must be strictly positive "
"(current value: %d)") % opt.initial_page)
if opt.pdfa and opt.cross_doc_link_action == '1':
raise ValidationError(_(
"The PDF/A option is not compatible with "
"'Cross-document Links' = "
"'Open with PDF Reader Application'."))
if opt.magnification == '4' and (opt.zoom < 50 or opt.zoom > 1600):
raise ValidationError(_(
"The value of the zoom factor must be between 50 and 1600 "
"(current value: %d)") % opt.zoom)
@api.onchange('encrypt')
def encrypt_change(self):
if not self.encrypt:
self.document_password = False
@api.onchange('restrict_permissions')
def restrict_permissions_change(self):
if not self.restrict_permissions:
self.permission_password = False
@api.onchange('pdfa')
def pdfa_change(self):
if self.pdfa:
self.pdf_form = False
self.encrypt = False
self.restrict_permissions = False
def odoo2libreoffice_options(self):
self.ensure_one()
options = {}
# GENERAL TAB
if self.image_compression == 'lossless':
options['UseLosslessCompression'] = True
else:
options['UseLosslessCompression'] = False
options['Quality'] = self.image_jpeg_quality
if self.image_reduce_resolution != 'none':
options['ReduceImageResolution'] = True
options['MaxImageResolution'] = int(self.image_reduce_resolution)
else:
options['ReduceImageResolution'] = False
if self.watermark and self.watermark_text:
options['Watermark'] = self.watermark_text
if self.pdfa:
options['SelectPdfVersion'] = 1
options['UseTaggedPDF'] = self.tagged_pdf
else:
options['SelectPdfVersion'] = 0
if self.pdf_form and self.pdf_form_format and not self.pdfa:
options['ExportFormFields'] = True
options['FormsType'] = int(self.pdf_form_format)
options['AllowDuplicateFieldNames'] = self.pdf_form_allow_duplicate
else:
options['ExportFormFields'] = False
options.update({
'ExportBookmarks': self.export_bookmarks,
'ExportPlaceholders': self.export_placeholders,
'ExportNotes': self.export_comments,
'ExportHiddenSlides': self.export_hidden_slides,
})
# INITIAL VIEW TAB
options.update({
'InitialView': int(self.initial_view),
'InitialPage': self.initial_page,
'Magnification': int(self.magnification),
'PageLayout': int(self.page_layout),
})
if self.magnification == '4':
options['Zoom'] = self.zoom
# USER INTERFACE TAB
options.update({
'ResizeWindowToInitialPage': self.resize_windows_initial_page,
'CenterWindow': self.center_window,
'OpenInFullScreenMode': self.open_fullscreen,
'DisplayPDFDocumentTitle': self.display_document_title,
'HideViewerMenubar': self.hide_menubar,
'HideViewerToolbar': self.hide_toolbar,
'HideViewerWindowControls': self.hide_window_controls,
})
if self.open_bookmark_levels:
options['OpenBookmarkLevels'] = int(self.open_bookmark_levels)
# LINKS TAB
options.update({
'ExportBookmarksToPDFDestination':
self.export_bookmarks_named_dest,
'ConvertOOoTargetToPDFTarget': self.convert_doc_ref_to_pdf_target,
'ExportLinksRelativeFsys': self.export_filesystem_urls,
'PDFViewSelection': int(self.cross_doc_link_action),
})
# SECURITY TAB
if not self.pdfa:
if self.encrypt and self.document_password:
options['EncryptFile'] = True
options['DocumentOpenPassword'] = self.document_password
if self.restrict_permissions and self.permission_password:
options.update({
'RestrictPermissions': True,
'PermissionPassword': self.permission_password,
'Printing': int(self.printing),
'Changes': int(self.changes),
'EnableCopyingOfContent': self.content_copying_allowed,
'EnableTextAccessForAccessibilityTools':
self.text_access_accessibility_tools_allowed,
})
logger.debug(
'Py3o PDF options ID %s converted to %s', self.id, options)
return options

22
report_py3o_fusion_server/models/py3o_report.py

@ -8,6 +8,7 @@ import logging
import os
import requests
import tempfile
from datetime import datetime
from contextlib import closing
from openerp import _, api, models
from openerp.exceptions import UserError
@ -75,10 +76,22 @@ class Py3oReport(models.TransientModel):
}
if report_xml.py3o_is_local_fusion:
fields['skipfusion'] = '1'
r = requests.post(
report_xml.py3o_server_id.url, data=fields, files=files)
url = report_xml.py3o_server_id.url
logger.info(
'Connecting to %s to convert report %s to %s',
url, report_xml.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)
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,
)
@ -87,6 +100,11 @@ class Py3oReport(models.TransientModel):
with open(result_path, 'w+') as fd:
for chunk in r.iter_content(chunk_size):
fd.write(chunk)
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, filetype, convert_seconds)
if len(model_instance) == 1:
self._postprocess_report(
result_path, model_instance.id, save_in_attachment)

4
report_py3o_fusion_server/models/py3o_server.py

@ -13,3 +13,7 @@ class Py3oServer(models.Model):
help="If your Py3o Fusion server is on the same machine and runs "
"on the default port, the URL is http://localhost:8765/form")
is_active = fields.Boolean("Active", default=True)
pdf_options_id = fields.Many2one(
'py3o.pdf.options', string='PDF Options', ondelete='restrict',
help="PDF options can be set per Py3o Server but also per report. "
"If both are defined, the options on the report are used.")

6
report_py3o_fusion_server/security/ir.model.access.csv

@ -1,3 +1,5 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_py3o_server_admin,access_py3o_server_admin,model_py3o_server,base.group_no_one,1,1,1,1
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_py3o_server_admin,access_py3o_server_admin,model_py3o_server,base.group_system,1,1,1,1
access_py3o_server_user,access_py3o_server_user,model_py3o_server,base.group_user,1,0,0,0
access_py3o_pdf_options_admin,Full access to PDF options to Settings grp,model_py3o_pdf_options,base.group_system,1,1,1,1
access_py3o_pdf_options_user,Read-only access to PDF options to employees,model_py3o_pdf_options,base.group_user,1,0,0,0

5
report_py3o_fusion_server/tests/test_report_py3o_fusion_server.py

@ -36,3 +36,8 @@ class TestReportPy3oFusionServer(test_report_py3o.TestReportPy3o):
def test_reports_no_local_fusion(self):
self.report.py3o_is_local_fusion = False
self.test_reports()
def test_odoo2libreoffice_options(self):
for options in self.env['py3o.pdf.options'].search([]):
options_dict = options.odoo2libreoffice_options()
self.assertIsInstance(options_dict, dict)

1
report_py3o_fusion_server/views/ir_report.xml

@ -7,6 +7,7 @@
<field name="py3o_multi_in_one" position="after">
<field name="py3o_is_local_fusion"/>
<field name="py3o_server_id" />
<field name="pdf_options_id" attrs="{'invisible': [('py3o_filetype', '!=', 'pdf')]}"/>
</field>
</field>
</record>

149
report_py3o_fusion_server/views/py3o_pdf_options.xml

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="py3o_pdf_options_form" model="ir.ui.view">
<field name="name">py3o.pdf.options.form</field>
<field name="model">py3o.pdf.options</field>
<field name="arch" type="xml">
<form string="Py3o PDF Export Options">
<div class="oe_title">
<label for="name"/>
<h1>
<field name="name" placeholder="Give a name to the set of PDF export options"/>
</h1>
</div>
<notebook>
<page name="general" string="General">
<group name="general">
<group name="general-left" col="1">
<group name="general-image" string="Image">
<field name="image_compression" widget="radio"/>
<label for="image_jpeg_quality" attrs="{'invisible': [('image_compression', '!=', 'jpeg')]}"/>
<div name="image_jpeg_quality" attrs="{'invisible': [('image_compression', '!=', 'jpeg')]}">
<field name="image_jpeg_quality" class="oe_inline"/>
<label string=" %"/>
</div>
<field name="image_reduce_resolution"/>
</group>
<group name="general-watermark" string="Watermark">
<field name="watermark"/>
<field name="watermark_text" attrs="{'invisible': [('watermark', '!=', True)], 'required': [('watermark', '=', True)]}"/>
</group>
</group>
<group name="general-right" string="General">
<field name="pdfa"/>
<field name="tagged_pdf" attrs="{'invisible': [('pdfa', '=', True)]}"/>
<field name="pdf_form" attrs="{'invisible': [('pdfa', '=', True)]}"/>
<field name="pdf_form_format" attrs="{'invisible': [('pdf_form', '!=', True)], 'required': [('pdf_form', '=', True)]}"/>
<field name="pdf_form_allow_duplicate" attrs="{'invisible': [('pdf_form', '!=', True)]}"/>
<field name="export_bookmarks"/>
<field name="export_placeholders"/>
<field name="export_comments"/>
<field name="export_hidden_slides"/>
</group>
</group>
</page>
<page name="initial_view" string="Initial View">
<group name="initial_view">
<group name="initial_view-left" col="1">
<group name="panes" string="Panes">
<field name="initial_view" widget="radio"/>
<field name="initial_page"/>
</group>
<group name="magnification" string="Magnification">
<field name="magnification" widget="radio"/>
<field name="zoom" attrs="{'invisible': [('magnification', '!=', '4')]}"/>
</group>
</group>
<group name="initial_view-right">
<field name="page_layout" widget="radio"/>
</group>
</group>
</page>
<page name="user_intf" string="User Interface">
<group name="user_intf">
<group name="user_intf-left" col="1">
<group name="user_intf-window-options" string="Window Options">
<field name="resize_windows_initial_page"/>
<field name="center_window"/>
<field name="open_fullscreen"/>
<field name="display_document_title"/>
</group>
</group>
<group name="user_intf-right" col="1">
<group name="user_intf-options" string="User Interface Options">
<field name="hide_menubar"/>
<field name="hide_toolbar"/>
<field name="hide_window_controls"/>
</group>
<group string="Bookmarks" name="bookmarks">
<field name="open_bookmark_levels"/>
</group>
</group>
</group>
</page>
<page string="Links" name="links">
<group name="links" col="1">
<group name="links-general" string="General">
<field name="export_bookmarks_named_dest"/>
<field name="convert_doc_ref_to_pdf_target"/>
<field name="export_filesystem_urls"/>
</group>
<group name="links-cross-doc" string="Cross-document Links">
<field name="cross_doc_link_action" widget="radio"/>
</group>
</group>
</page>
<page string="Security" name="security">
<group name="security">
<group name="security-left" attrs="{'invisible': [('pdfa', '=', True)]}">
<field name="encrypt"/>
<field name="document_password" password="True" attrs="{'invisible': [('encrypt', '!=', True)], 'required': [('encrypt', '=', True)]}"/>
<field name="restrict_permissions"/>
<field name="permission_password" password="True" attrs="{'invisible': [('restrict_permissions', '!=', True)], 'required': [('restrict_permissions', '=', True)]}"/>
</group>
<group name="security-right" attrs="{'invisible': ['|', ('pdfa', '=', True), ('restrict_permissions', '=', False)]}">
<field name="printing" widget="radio"/>
<field name="changes" widget="radio"/>
<field name="content_copying_allowed"/>
<field name="text_access_accessibility_tools_allowed"/>
</group>
<group name="security-pdfa" attrs="{'invisible': [('pdfa', '=', False)]}" colspan="2">
<div><p>The security settings are incompatible with the <b>PDF/A-1a</b> option in the <em>General</em> tab.</p></div>
</group>
</group>
</page>
</notebook>
</form>
</field>
</record>
<record id="py3o_pdf_options_tree" model="ir.ui.view">
<field name="name">py3o.pdf.options.tree</field>
<field name="model">py3o.pdf.options</field>
<field name="arch" type="xml">
<tree string="Py3o PDF Export Options">
<field name="name"/>
</tree>
</field>
</record>
<record id="py3o_pdf_options_action" model="ir.actions.act_window">
<field name="name">Py3o PDF Export Options</field>
<field name="res_model">py3o.pdf.options</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="py3o_pdf_options_menu"
parent="report_py3o.py3o_config_menu"
action="py3o_pdf_options_action"
sequence="40" />
</odoo>

2
report_py3o_fusion_server/views/py3o_server.xml

@ -8,6 +8,7 @@
<form string="Py3o Server Configuration">
<group name="main">
<field name="url" widget="url"/>
<field name="pdf_options_id"/>
<field name="is_active" />
</group>
</form>
@ -20,6 +21,7 @@
<field name="arch" type="xml">
<tree string="Py3o Servers Configuration">
<field name="url" />
<field name="pdf_options_id"/>
<field name="is_active" />
</tree>
</field>

Loading…
Cancel
Save