diff options
| -rw-r--r-- | addons/account/views/report_invoice.xml | 2 | ||||
| -rw-r--r-- | addons/stock/static/tests/route_tour.js | 56 | ||||
| -rw-r--r-- | addons/stock/tests/__init__.py | 3 | ||||
| -rw-r--r-- | addons/stock/tests/test_ui.py | 10 | ||||
| -rw-r--r-- | addons/stock/views/stock_template.xml | 1 | ||||
| -rw-r--r-- | addons/web/static/src/js/report/report.editor.js | 24 | ||||
| -rw-r--r-- | addons/web/static/src/js/report/report.js | 40 | ||||
| -rw-r--r-- | addons/web/views/report_templates.xml | 26 | ||||
| -rw-r--r-- | odoo/addons/base/models/ir_actions_report.py | 26 |
9 files changed, 142 insertions, 46 deletions
diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml index b43f48eab9e..18fac77f256 100644 --- a/addons/account/views/report_invoice.xml +++ b/addons/account/views/report_invoice.xml @@ -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> diff --git a/addons/stock/static/tests/route_tour.js b/addons/stock/static/tests/route_tour.js new file mode 100644 index 00000000000..e75695a5f69 --- /dev/null +++ b/addons/stock/static/tests/route_tour.js @@ -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', + }, + ] +); + +}); diff --git a/addons/stock/tests/__init__.py b/addons/stock/tests/__init__.py index 25ae6888c7c..50780301d3d 100644 --- a/addons/stock/tests/__init__.py +++ b/addons/stock/tests/__init__.py @@ -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 diff --git a/addons/stock/tests/test_ui.py b/addons/stock/tests/test_ui.py new file mode 100644 index 00000000000..ef434ea678a --- /dev/null +++ b/addons/stock/tests/test_ui.py @@ -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') diff --git a/addons/stock/views/stock_template.xml b/addons/stock/views/stock_template.xml index fa3ae244ee2..3ca9f6783b2 100644 --- a/addons/stock/views/stock_template.xml +++ b/addons/stock/views/stock_template.xml @@ -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"/> diff --git a/addons/web/static/src/js/report/report.editor.js b/addons/web/static/src/js/report/report.editor.js index 15da9885e31..4955417a759 100644 --- a/addons/web/static/src/js/report/report.editor.js +++ b/addons/web/static/src/js/report/report.editor.js @@ -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({ diff --git a/addons/web/static/src/js/report/report.js b/addons/web/static/src/js/report/report.js new file mode 100644 index 00000000000..50d78a9d151 --- /dev/null +++ b/addons/web/static/src/js/report/report.js @@ -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); + }); +} +}); diff --git a/addons/web/views/report_templates.xml b/addons/web/views/report_templates.xml index 6f83ae6254c..bc84d62a065 100644 --- a/addons/web/views/report_templates.xml +++ b/addons/web/views/report_templates.xml @@ -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> diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py index 5e81443d2bb..eedcb4e8e2d 100644 --- a/odoo/addons/base/models/ir_actions_report.py +++ b/odoo/addons/base/models/ir_actions_report.py @@ -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, |
