[FIX] web: Fixed the printing of reports.

A new exception has been added to detect inconsistent reports. However, many are not structured as expected. Thus, the change consists mainly of checking only when the print has to be separated in part to attach it to the respective documents.

We now take the page tag instead of the article, because the article tag is in the layout, so to separate the file, the t-call had to be inside the t-foreach (for the separation) and so possibly read the assets several times. Since all templates have the first tag (in the t-foreach) tag page, the choice is more sensible.

The javascripts files used in readonly were taken out of the editing assets.

A turn was made but not activated, it works locally, but on the runbot, an error is triggered when generating assets after choosing the settings.
This commit is contained in:
Christophe Matthieu
2018-09-04 19:01:20 +02:00
parent b67bb599b8
commit f29df7fb2e
9 changed files with 142 additions and 46 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
<address t-field="o.partner_id" t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}' />
<div t-if="o.partner_id.vat" class="mt16"><t t-esc="o.company_id.country_id.vat_label or 'Tax ID'"/>: <span t-field="o.partner_id.vat"/></div>
</t>
<div class="page">
<div class="page" t-att-data-model="o._name" t-att-data-id="o.id">
<h2>
<span t-if="o.type == 'out_invoice' and o.state in ('open', 'in_payment', 'paid')">Invoice</span>
<span t-if="o.type == 'out_invoice' and o.state == 'draft'">Draft Invoice</span>
+56
View File
@@ -0,0 +1,56 @@
odoo.define('stock.tour', function (require) {
'use strict';
var tour = require('web_tour.tour');
tour.register('stock', {
test: true,
url: '/web?debug=assets#action=stock.action_stock_config_settings',
},
[
{
content: "wait web client",
trigger: ".o_base_settings",
run: function() {}
},
{
content: "active 'Multi-Step Routes'",
trigger: '.o_field_boolean[name="group_stock_adv_location"]',
run: function() {
if (!this.$anchor.find('input').prop('checked')) {
this.$anchor.find('label').click();
$('.o_statusbar_buttons button[name="execute"]').click();
}
}
},
{
content: "list of product variants",
trigger: '.o_sub_menu .oe_secondary_submenu [data-menu-xmlid="stock.menu_product_variant_config_stock"]',
extra_trigger: '.o_sub_menu .oe_secondary_submenu:has(a[data-menu-xmlid="stock.menu_routes_config"])',
timeout: 5000,
},
{
content: "select a product variant",
trigger: '.oe_kanban_global_click:first',
},
{
content: "click on routes",
trigger: 'button.oe_stat_button i.fa-cogs',
},
{
content: "print the report",
trigger: 'button[name="print_report"]',
},
{
content: "print inside the report and check the breadcrum",
trigger: '.o_content iframe .o_report_stock_rule_rule_name',
extra_trigger: 'ol.breadcrumb li:eq(2).active',
},
{
content: "print the report",
trigger: 'ol.breadcrumb li:eq(3).active',
},
]
);
});
+3
View File
@@ -14,3 +14,6 @@ from . import test_packing
from . import test_packing_neg
from . import test_proc_rule
from . import test_wise_operator
# TODO enable this test: error on runbot to create asset and open the iframe
# from . import test_ui
+10
View File
@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
@odoo.tests.tagged('post_install', '-at_install')
class TestUi(odoo.tests.HttpCase):
def test_01_admin_stock_route(self):
self.phantom_js("/web", "odoo.__DEBUG__.services['web_tour.tour'].run('stock')", "odoo.__DEBUG__.services['web_tour.tour'].tours.stock.ready", login='admin')
+1
View File
@@ -3,6 +3,7 @@
<template id="stock_assets_backend" name="mrp_workorder assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/stock/static/tests/route_tour.js"></script>
<script type="text/javascript" src="/stock/static/src/js/stock_traceability_report_backend.js"></script>
<script type="text/javascript" src="/stock/static/src/js/stock_traceability_report_widgets.js"></script>
<link rel="stylesheet" type="text/scss" href="/stock/static/src/scss/stock_traceability_report.scss"/>
@@ -14,7 +14,6 @@ var trusted_origin = utils.build_origin(trusted_protocol, trusted_host);
// Patch the editor's behavior when it is launched inside an iframe.
if (window.self !== window.top) {
$(document.body).addClass('o_in_iframe'); // in order to apply css rules
// And now we chain some deferred to `save` and `cancel` in order to inform
// the report's client action that the actions are done.
@@ -60,29 +59,6 @@ if (window.self !== window.top) {
}
}
}, false);
// Allow to send commands to the webclient when the editor is disabled.
if (window.location.search.indexOf('enable_editor') === -1) {
// `do_action` command
$('[res-id][res-model][view-type]')
.wrap('<a/>')
.attr('href', '#')
.on('click', function (ev) {
ev.preventDefault();
var action = {
'type': 'ir.actions.act_window',
'view_type': $(this).attr('view-type'),
'view_mode': $(this).attr('view-mode') || $(this).attr('view-type'),
'res_id': Number($(this).attr('res-id')),
'res_model': $(this).attr('res-model'),
'views': [[$(this).attr('view-id') || false, $(this).attr('view-type')]],
};
window.parent.postMessage({
'message': 'report:do_action',
'action': action,
}, trusted_origin);
});
}
}
options.registry.many2one.include({
+40
View File
@@ -0,0 +1,40 @@
odoo.define('report', function (require) {
'use strict';
require('web.dom_ready');
var utils = require('report.utils');
if (window.self === window.top) {
return;
}
$(document.body).addClass('o_in_iframe'); // in order to apply css rules
var web_base_url = $('html').attr('web-base-url');
var trusted_host = utils.get_host_from_url(web_base_url);
var trusted_protocol = utils.get_protocol_from_url(web_base_url);
var trusted_origin = utils.build_origin(trusted_protocol, trusted_host);
// Allow to send commands to the webclient when the editor is disabled.
if (window.location.search.indexOf('enable_editor') === -1) {
// `do_action` command
$('[res-id][res-model][view-type]')
.wrap('<a/>')
.attr('href', '#')
.on('click', function (ev) {
ev.preventDefault();
var action = {
'type': 'ir.actions.act_window',
'view_type': $(this).attr('view-type'),
'view_mode': $(this).attr('view-mode') || $(this).attr('view-type'),
'res_id': Number($(this).attr('res-id')),
'res_model': $(this).attr('res-model'),
'views': [[$(this).attr('view-id') || false, $(this).attr('view-type')]],
};
window.parent.postMessage({
'message': 'report:do_action',
'action': action,
}, trusted_origin);
});
}
});
+14 -12
View File
@@ -25,6 +25,12 @@
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/layout_background.scss"/>
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/layout_boxed.scss"/>
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/layout_clean.scss"/>
<script type="text/javascript" src="web/static/src/js/services/session.js"/>
<script type="text/javascript" src="/web/static/src/js/report/utils.js"/>
<script type="text/javascript" src="/web_editor/static/src/js/content/body_manager.js"/>
<script type="text/javascript" src="/web_editor/static/src/js/root_widget.js"/>
<script type="text/javascript" src='/web/static/src/js/report/report.js' />
</template>
<template id="report_assets_pdf">
@@ -37,7 +43,6 @@
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/report.editor.scss"/>
<script type="text/javascript" src="/web/static/src/js/services/session.js"/>
<script type="text/javascript" src="/web/static/src/js/report/utils.js"/>
<script type="text/javascript" src='/web/static/src/js/report/report.editor.js' />
</template>
@@ -65,14 +70,13 @@
<t t-call-assets="web_editor.assets_editor" t-js="false"/>
<t t-call-assets="web.report_assets_editor" t-js="false"/>
</t>
<t t-call-assets="web.assets_common" t-css="false"/>
<t t-call-assets="web.report_assets_common" t-css="false"/>
<t t-if="editable">
<t t-call-assets="web.assets_common" t-css="false"/>
<t t-call-assets="web_editor.summernote" t-css="false"/>
<t t-call-assets="web_editor.assets_editor" t-css="false"/>
<t t-call-assets="web.report_assets_editor" t-css="false"/>
<script type="text/javascript" src="/web_editor/static/src/js/content/body_manager.js"/>
<script type="text/javascript" src="/web_editor/static/src/js/root_widget.js"/>
<script type="text/javascript" src="/web_editor/static/src/js/iframe.js"></script>
<script t-if="enable_editor and inline_mode" type="text/javascript" src="/web_editor/static/src/js/inline.js"></script>
</t>
@@ -178,7 +182,7 @@
<div class="clearfix mb8"/>
</div>
<div class="article o_report_layout_background" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
<div class="article o_report_layout_background">
<t t-call="web.address_layout"/>
<t t-raw="0"/>
</div>
@@ -218,7 +222,7 @@
</div>
</div>
<div class="article o_report_layout_boxed" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
<div class="article o_report_layout_boxed">
<t t-call="web.address_layout"/>
<t t-raw="0"/>
</div>
@@ -257,7 +261,7 @@
</div>
</div>
<div class="article o_report_layout_clean" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
<div class="article o_report_layout_clean">
<t t-call="web.address_layout"/>
<t t-raw="0"/>
</div>
@@ -305,7 +309,7 @@
</div>
</div>
<div class="article o_report_layout_standard" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
<div class="article o_report_layout_standard">
<t t-call="web.address_layout"/>
<t t-raw="0"/>
</div>
@@ -386,16 +390,14 @@
</div>
</div>
</div>
<div class="article" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
<div class="article">
<t t-raw="0"/>
</div>
</template>
<template id="basic_layout">
<t t-if="not o" t-set="o" t-value="doc"/>
<t t-call="web.html_container">
<div class="article" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
<div class="article">
<t t-raw="0"/>
</div>
</t>
+17 -9
View File
@@ -300,27 +300,31 @@ class IrActionsReport(models.Model):
bodies = []
res_ids = []
body_parent = root.xpath('//main')
# Retrieve headers
for node in root.xpath(match_klass.format('header')):
body_parent = node.getparent()
node.getparent().remove(node)
header_node.append(node)
# Retrieve footers
for node in root.xpath(match_klass.format('footer')):
body_parent = node.getparent()
node.getparent().remove(node)
footer_node.append(node)
# Retrieve bodies
for node in root.xpath(match_klass.format('article')):
if node.get('data-oe-model') == self.model:
body = layout.render(dict(subst=False, body=lxml.html.tostring(node), base_url=base_url))
bodies.append(body)
res_ids.append(int(node.get('data-oe-id', False)))
for node in root.xpath(match_klass.format('page')):
body = layout.render(dict(subst=False, body=lxml.html.tostring(node), base_url=base_url))
bodies.append(body)
if node.get('data-model') == self.model:
res_ids.append(int(node.get('data-id', 0)))
else:
_logger.warning("The report's template '%s' does not contains the attributes 'data-oe-model' and 'data-oe-id' on the container (with class 'article')", self.name)
raise UserError(_("The report's template is wrong, please contact your administrator"))
res_ids.append(None)
if not bodies:
_logger.warning("The report's template '%s' does not contains the container with the class 'article'", self.name)
raise UserError(_("The report's template is wrong, please contact your administrator"))
body = bytearray().join([lxml.html.tostring(c) for c in body_parent.getchildren()])
bodies.append(body)
# Get paperformat arguments set in the root html tag. They are prioritized over
# paperformat-record arguments.
@@ -660,6 +664,10 @@ class IrActionsReport(models.Model):
bodies, html_ids, header, footer, specific_paperformat_args = self.with_context(context)._prepare_html(html)
if self.attachment and set(res_ids) != set(html_ids):
raise UserError(_("The report's template '%s' is wrong, please contact your administrator. \n\n"
"Can not separate file to save as attachment because the report's template does not contains the attributes 'data-model' and 'data-id' on the div with 'page' classname.") % self.name)
pdf_content = self._run_wkhtmltopdf(
bodies,
header=header,