[13.0][MIG] report_qweb_pdf_watermark
parent
5554601d7e
commit
929e2309a4
|
@ -62,6 +62,11 @@ Changelog
|
||||||
|
|
||||||
* [MIG] Migration to V12.
|
* [MIG] Migration to V12.
|
||||||
|
|
||||||
|
13.0.1.0.0 (2021-01-27)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* [MIG] Migration to V13.
|
||||||
|
|
||||||
Bug Tracker
|
Bug Tracker
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -87,6 +92,7 @@ Contributors
|
||||||
* Stefan Rijnhart <stefan@opener.am>
|
* Stefan Rijnhart <stefan@opener.am>
|
||||||
* Rod Schouteden <rod.schouteden@dynapps.be>
|
* Rod Schouteden <rod.schouteden@dynapps.be>
|
||||||
* Robin Goots <robin.goots@dynapps.be>
|
* Robin Goots <robin.goots@dynapps.be>
|
||||||
|
* Foram Shah <foram.shah@initos.com>
|
||||||
|
|
||||||
Maintainers
|
Maintainers
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# © 2016 Therp BV <http://therp.nl>
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
from . import models
|
from . import models # pyflakes.ignore
|
||||||
|
|
|
@ -2,28 +2,19 @@
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
{
|
{
|
||||||
"name": "Pdf watermark",
|
"name": "Pdf watermark",
|
||||||
"version": "12.0.1.0.1",
|
"version": "13.0.1.0.0",
|
||||||
"author": "Therp BV, "
|
"author": "Therp BV, " "Odoo Community Association (OCA)",
|
||||||
"Odoo Community Association (OCA)",
|
|
||||||
"license": "AGPL-3",
|
"license": "AGPL-3",
|
||||||
"category": "Technical Settings",
|
"category": "Technical Settings",
|
||||||
"summary": "Add watermarks to your QWEB PDF reports",
|
"summary": "Add watermarks to your QWEB PDF reports",
|
||||||
"website": "https://github.com/oca/reporting-engine",
|
"website": "https://github.com/oca/reporting-engine",
|
||||||
"depends": [
|
"depends": ["web"],
|
||||||
'web',
|
|
||||||
],
|
|
||||||
"data": [
|
"data": [
|
||||||
"demo/report.xml",
|
"demo/report.xml",
|
||||||
"views/ir_actions_report_xml.xml",
|
"views/ir_actions_report_xml.xml",
|
||||||
"views/layout_templates.xml",
|
"views/layout_templates.xml",
|
||||||
],
|
],
|
||||||
"demo": [
|
"demo": ["demo/report.xml"],
|
||||||
"demo/report.xml"
|
|
||||||
],
|
|
||||||
"installable": True,
|
"installable": True,
|
||||||
'external_dependencies': {
|
"external_dependencies": {"python": ["PyPDF2"]},
|
||||||
'python': [
|
|
||||||
'PyPDF2',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<report
|
<report
|
||||||
id="demo_report"
|
id="demo_report"
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
name="report_qweb_pdf_watermark.demo_report_view"
|
name="report_qweb_pdf_watermark.demo_report_view"
|
||||||
file="report_qweb_pdf_watermark.demo_report_view"
|
file="report_qweb_pdf_watermark.demo_report_view"
|
||||||
paperformat="base.paperformat_euro"
|
paperformat="base.paperformat_euro"
|
||||||
/>
|
/>
|
||||||
<record id="demo_report" model="ir.actions.report">
|
<record id="demo_report" model="ir.actions.report">
|
||||||
<field name="pdf_watermark_expression">docs[:1].company_id.logo</field>
|
<field name="pdf_watermark_expression">docs[:1].company_id.logo</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
# © 2016 Therp BV <http://therp.nl>
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
from . import report
|
from . import report
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
# © 2016 Therp BV <http://therp.nl>
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from logging import getLogger
|
|
||||||
from PIL import Image
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
from odoo import api, fields, models, tools
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# we need this to be sure PIL has loaded PDF support
|
# we need this to be sure PIL has loaded PDF support
|
||||||
from PIL import PdfImagePlugin # noqa: F401
|
from PIL import PdfImagePlugin # noqa: F401
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
from odoo import api, models, fields, tools
|
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
@ -18,42 +20,53 @@ try:
|
||||||
from PyPDF2 import PdfFileWriter, PdfFileReader # pylint: disable=W0404
|
from PyPDF2 import PdfFileWriter, PdfFileReader # pylint: disable=W0404
|
||||||
from PyPDF2.utils import PdfReadError # pylint: disable=W0404
|
from PyPDF2.utils import PdfReadError # pylint: disable=W0404
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.debug('Can not import PyPDF2')
|
logger.debug("Can not import PyPDF2")
|
||||||
|
|
||||||
|
|
||||||
class Report(models.Model):
|
class Report(models.Model):
|
||||||
_inherit = 'ir.actions.report'
|
_inherit = "ir.actions.report"
|
||||||
|
|
||||||
pdf_watermark = fields.Binary('Watermark')
|
pdf_watermark = fields.Binary("Watermark")
|
||||||
pdf_watermark_expression = fields.Char(
|
pdf_watermark_expression = fields.Char(
|
||||||
'Watermark expression', help='An expression yielding the base64 '
|
"Watermark expression",
|
||||||
'encoded data to be used as watermark. \n'
|
help="An expression yielding the base64 "
|
||||||
'You have access to variables `env` and `docs`')
|
"encoded data to be used as watermark. \n"
|
||||||
|
"You have access to variables `env` and `docs`",
|
||||||
|
)
|
||||||
|
|
||||||
@api.multi
|
|
||||||
def render_qweb_pdf(self, res_ids=None, data=None):
|
def render_qweb_pdf(self, res_ids=None, data=None):
|
||||||
if not self.env.context.get('res_ids'):
|
if not self.env.context.get("res_ids"):
|
||||||
return super(
|
return super(Report, self.with_context(res_ids=res_ids)).render_qweb_pdf(
|
||||||
Report, self.with_context(res_ids=res_ids)
|
res_ids=res_ids, data=data
|
||||||
).render_qweb_pdf(res_ids=res_ids, data=data)
|
)
|
||||||
return super(Report, self).render_qweb_pdf(res_ids=res_ids, data=data)
|
return super(Report, self).render_qweb_pdf(res_ids=res_ids, data=data)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _run_wkhtmltopdf(self, bodies, header=None, footer=None,
|
def _run_wkhtmltopdf(
|
||||||
landscape=False, specific_paperformat_args=None,
|
self,
|
||||||
set_viewport_size=False):
|
bodies,
|
||||||
|
header=None,
|
||||||
|
footer=None,
|
||||||
|
landscape=False,
|
||||||
|
specific_paperformat_args=None,
|
||||||
|
set_viewport_size=False,
|
||||||
|
):
|
||||||
result = super(Report, self)._run_wkhtmltopdf(
|
result = super(Report, self)._run_wkhtmltopdf(
|
||||||
bodies, header=header, footer=footer, landscape=landscape,
|
bodies,
|
||||||
|
header=header,
|
||||||
|
footer=footer,
|
||||||
|
landscape=landscape,
|
||||||
specific_paperformat_args=specific_paperformat_args,
|
specific_paperformat_args=specific_paperformat_args,
|
||||||
set_viewport_size=set_viewport_size)
|
set_viewport_size=set_viewport_size,
|
||||||
|
)
|
||||||
|
|
||||||
docids = self.env.context.get('res_ids', False)
|
docids = self.env.context.get("res_ids", False)
|
||||||
watermark = None
|
watermark = None
|
||||||
if self.pdf_watermark:
|
if self.pdf_watermark:
|
||||||
watermark = b64decode(self.pdf_watermark)
|
watermark = b64decode(self.pdf_watermark)
|
||||||
elif docids:
|
elif docids:
|
||||||
watermark = tools.safe_eval(
|
watermark = tools.safe_eval(
|
||||||
self.pdf_watermark_expression or 'None',
|
self.pdf_watermark_expression or "None",
|
||||||
dict(env=self.env, docs=self.env[self.model].browse(docids)),
|
dict(env=self.env, docs=self.env[self.model].browse(docids)),
|
||||||
)
|
)
|
||||||
if watermark:
|
if watermark:
|
||||||
|
@ -72,30 +85,28 @@ class Report(models.Model):
|
||||||
Image.init()
|
Image.init()
|
||||||
image = Image.open(BytesIO(watermark))
|
image = Image.open(BytesIO(watermark))
|
||||||
pdf_buffer = BytesIO()
|
pdf_buffer = BytesIO()
|
||||||
if image.mode != 'RGB':
|
if image.mode != "RGB":
|
||||||
image = image.convert('RGB')
|
image = image.convert("RGB")
|
||||||
resolution = image.info.get(
|
resolution = image.info.get("dpi", self.paperformat_id.dpi or 90)
|
||||||
'dpi', self.paperformat_id.dpi or 90
|
|
||||||
)
|
|
||||||
if isinstance(resolution, tuple):
|
if isinstance(resolution, tuple):
|
||||||
resolution = resolution[0]
|
resolution = resolution[0]
|
||||||
image.save(pdf_buffer, 'pdf', resolution=resolution)
|
image.save(pdf_buffer, "pdf", resolution=resolution)
|
||||||
pdf_watermark = PdfFileReader(pdf_buffer)
|
pdf_watermark = PdfFileReader(pdf_buffer)
|
||||||
except:
|
except Exception as e:
|
||||||
logger.exception('Failed to load watermark')
|
logger.exception("Failed to load watermark", e)
|
||||||
|
|
||||||
if not pdf_watermark:
|
if not pdf_watermark:
|
||||||
logger.error(
|
logger.error("No usable watermark found, got %s...", watermark[:100])
|
||||||
'No usable watermark found, got %s...', watermark[:100]
|
|
||||||
)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if pdf_watermark.numPages < 1:
|
if pdf_watermark.numPages < 1:
|
||||||
logger.error('Your watermark pdf does not contain any pages')
|
logger.error("Your watermark pdf does not contain any pages")
|
||||||
return result
|
return result
|
||||||
if pdf_watermark.numPages > 1:
|
if pdf_watermark.numPages > 1:
|
||||||
logger.debug('Your watermark pdf contains more than one page, '
|
logger.debug(
|
||||||
'all but the first one will be ignored')
|
"Your watermark pdf contains more than one page, "
|
||||||
|
"all but the first one will be ignored"
|
||||||
|
)
|
||||||
|
|
||||||
for page in PdfFileReader(BytesIO(result)).pages:
|
for page in PdfFileReader(BytesIO(result)).pages:
|
||||||
watermark_page = pdf.addBlankPage(
|
watermark_page = pdf.addBlankPage(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
# © 2016 Therp BV <http://therp.nl>
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
from . import test_report_qweb_pdf_watermark
|
from . import test_report_qweb_pdf_watermark
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# © 2016 Therp BV <http://therp.nl>
|
# © 2016 Therp BV <http://therp.nl>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from odoo.tests.common import HttpCase
|
from odoo.tests.common import HttpCase
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<record id="act_report_xml_view" model="ir.ui.view">
|
<record id="act_report_xml_view" model="ir.ui.view">
|
||||||
<field name="model">ir.actions.report</field>
|
<field name="model">ir.actions.report</field>
|
||||||
<field name="inherit_id" ref="base.act_report_xml_view" />
|
<field name="inherit_id" ref="base.act_report_xml_view" />
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="attachment" position="after">
|
<field name="attachment" position="after">
|
||||||
<field name="pdf_watermark" attrs="{'invisible': [('report_type', '!=', 'qweb-pdf')]}" />
|
<field
|
||||||
<field name="pdf_watermark_expression" attrs="{'invisible': [('report_type', '!=', 'qweb-pdf')]}" groups="base.group_no_one" />
|
name="pdf_watermark"
|
||||||
|
attrs="{'invisible': [('report_type', '!=', 'qweb-pdf')]}"
|
||||||
|
/>
|
||||||
|
<field
|
||||||
|
name="pdf_watermark_expression"
|
||||||
|
attrs="{'invisible': [('report_type', '!=', 'qweb-pdf')]}"
|
||||||
|
groups="base.group_no_one"
|
||||||
|
/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<!-- Include fix for https://github.com/odoo/odoo/issues/16610 -->
|
<!-- Include fix for https://github.com/odoo/odoo/issues/16610 -->
|
||||||
<template id="assets_pdf" inherit_id="web.report_assets_pdf">
|
<template id="assets_pdf" inherit_id="web.report_assets_pdf">
|
||||||
<link position="after">
|
<link position="after">
|
||||||
<link href="/report_qweb_pdf_watermark/static/src/css/report_qweb_pdf_watermark.css"
|
<link
|
||||||
rel="stylesheet"/>
|
href="/report_qweb_pdf_watermark/static/src/css/report_qweb_pdf_watermark.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
</link>
|
</link>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
Loading…
Reference in New Issue