diff --git a/addons/report/__manifest__.py b/addons/report/__manifest__.py index aa2f81daa26..3a829020e23 100644 --- a/addons/report/__manifest__.py +++ b/addons/report/__manifest__.py @@ -9,16 +9,19 @@ Report """, 'depends': ['base', 'web', 'base_setup'], + 'demo': [ + 'data/report_demo.xml', + ], 'data': [ 'data/report_paperformat_data.xml', 'security/ir.model.access.csv', - 'views/layout_templates.xml', 'views/report_paperformat_views.xml', - 'views/report_templates.xml', 'views/base_config_settings_views.xml', 'views/ir_actions_report_views.xml', + 'views/res_company_view.xml', + 'views/templates.xml', ], - 'qweb' : [ + 'qweb': [ 'static/src/xml/*.xml', ], 'auto_install': True, diff --git a/addons/report/data/report_demo.xml b/addons/report/data/report_demo.xml new file mode 100644 index 00000000000..a46d8bca219 --- /dev/null +++ b/addons/report/data/report_demo.xml @@ -0,0 +1,8 @@ + + + + + standard + + + diff --git a/addons/report/models/base_config_settings.py b/addons/report/models/base_config_settings.py index be85e33210d..1a77bc56597 100644 --- a/addons/report/models/base_config_settings.py +++ b/addons/report/models/base_config_settings.py @@ -1,21 +1,40 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import fields, models +from odoo import fields, models, _ class BaseConfigSettings(models.TransientModel): _inherit = 'base.config.settings' paperformat_id = fields.Many2one(related="company_id.paperformat_id", string='Paper format') - default_custom_header_footer = fields.Boolean("Custom Layout", - help='Define your custom header & footer.', default_model='base.config.settings') + external_report_layout = fields.Selection(related="company_id.external_report_layout") + + def _prepare_report_view_action(self, template): + template_id = self.env.ref(template) + return { + 'type': 'ir.actions.act_window', + 'res_model': 'ir.ui.view', + 'view_type': 'form', + 'view_mode': 'form', + 'res_id': template_id.id, + } def edit_external_header(self): - return self.company_id.edit_external_header() + return self._prepare_report_view_action('report.layout_'+self.external_report_layout) - def edit_external_footer(self): - return self.company_id.edit_external_footer() + def change_report_template(self): + self.ensure_one() + template = self.env.ref('report.view_company_report_form', False) + return { + 'name': _('Choose Your Report Layout'), + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_id': self.env.user.company_id.id, + 'res_model': 'res.company', + 'views': [(template.id, 'form')], + 'view_id': template.id, + 'target': 'new', + } - def edit_internal_header(self): - return self.company_id.edit_internal_header() diff --git a/addons/report/models/report.py b/addons/report/models/report.py index 785240a2670..93a9cf3c809 100644 --- a/addons/report/models/report.py +++ b/addons/report/models/report.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models, _ +from odoo import api, fields, models, SUPERUSER_ID, _ from odoo.exceptions import AccessError from odoo.sql_db import TestCursor from odoo.tools import config @@ -224,7 +224,7 @@ class Report(models.Model): footer = render_minimal(dict(subst=True, body=body, base_url=base_url)) footerhtml.append(footer) - for node in root.xpath(match_klass.format('page')): + for node in root.xpath(match_klass.format('article')): # Previously, we marked some reports to be saved in attachment via their ids, so we # must set a relation between report ids and report's content. We use the QWeb # branding in order to do so: searching after a node having a data-oe-model @@ -266,12 +266,27 @@ class Report(models.Model): ) @api.noguess - def get_action(self, docids, report_name, data=None): + def get_action(self, docids, report_name, data=None, config=True): """Return an action of type ir.actions.report.xml. :param docids: id/ids/browserecord of the records to print (if not used, pass an empty list) :param report_name: Name of the template to generate an action for """ + if (self.env.uid == SUPERUSER_ID) and ((not self.env.user.company_id.external_report_layout) or (not self.env.user.company_id.logo)) and config: + template = self.env.ref('report.view_company_report_form', False) + return { + 'name': _('Choose Your Report Layout'), + 'type': 'ir.actions.act_window', + 'context': {'default_report_name': report_name}, + 'view_type': 'form', + 'view_mode': 'form', + 'res_id': self.env.user.company_id.id, + 'res_model': 'res.company', + 'views': [(template.id, 'form')], + 'view_id': template.id, + 'target': 'new', + } + context = self.env.context if docids: if isinstance(docids, models.Model): diff --git a/addons/report/models/res_company.py b/addons/report/models/res_company.py index 1a064a311b3..8f72b95546c 100644 --- a/addons/report/models/res_company.py +++ b/addons/report/models/res_company.py @@ -7,20 +7,29 @@ class ResCompany(models.Model): _inherit = 'res.company' paperformat_id = fields.Many2one('report.paperformat', 'Paper format') - report_footer_default = fields.Html('Standard Report Foorter', compute='_compute_report_footer_default', readonly=True) + external_report_layout = fields.Selection([ + ('background', 'Background'), + ('boxed', 'Boxed'), + ('clean', 'Clean'), + ('standard', 'Standard'), + ], string='Report Template') - @api.multi - def _compute_report_footer_default(self): - for company in self: - company.report_footer_default = self.env['ir.ui.view'].render_template('report.external_layout_footer_default', { - 'company': company, - }) + def open_company_edit_report(self): + self.ensure_one() + return self.env['base.config.settings'].open_company() + + def set_report_template(self): + self.ensure_one() + if self.env.context.get('report_template', False): + self.external_report_layout = self.env.context['report_template'] + if self.env.context.get('default_report_name'): + document = self.env.get(self.env.context['active_model']).browse(self.env.context['active_id']) + return self.env['report'].get_action(document, self.env.context['default_report_name'], config=False) + return False @api.model_cr def init(self): - # set a default paperformat based on rml one. - for company in self.search([('paperformat_id', '=', False)]): paperformat_euro = self.env.ref('report.paperformat_euro', False) paperformat_us = self.env.ref('report.paperformat_us', False) @@ -36,25 +45,4 @@ class ResCompany(models.Model): if hasattr(sup, 'init'): sup.init() - @api.model - def _prepare_report_view_action(self, template): - template_id = self.env.ref(template) - return { - 'type': 'ir.actions.act_window', - 'res_model': 'ir.ui.view', - 'view_type': 'form', - 'view_mode': 'form', - 'res_id': template_id.id, - } - @api.multi - def edit_external_header(self): - return self._prepare_report_view_action('report.external_layout_header') - - @api.multi - def edit_external_footer(self): - return self._prepare_report_view_action('report.external_layout_footer') - - @api.multi - def edit_internal_header(self): - return self._prepare_report_view_action('report.internal_layout') diff --git a/addons/report/static/src/img/bg_background_template.jpg b/addons/report/static/src/img/bg_background_template.jpg new file mode 100644 index 00000000000..be776b47c8f Binary files /dev/null and b/addons/report/static/src/img/bg_background_template.jpg differ diff --git a/addons/report/static/src/img/logo_sample.png b/addons/report/static/src/img/logo_sample.png new file mode 100644 index 00000000000..49090033fa3 Binary files /dev/null and b/addons/report/static/src/img/logo_sample.png differ diff --git a/addons/report/static/src/img/preview_background.png b/addons/report/static/src/img/preview_background.png new file mode 100644 index 00000000000..6ab7ee46456 Binary files /dev/null and b/addons/report/static/src/img/preview_background.png differ diff --git a/addons/report/static/src/img/preview_boxed.png b/addons/report/static/src/img/preview_boxed.png new file mode 100644 index 00000000000..758dc4640cc Binary files /dev/null and b/addons/report/static/src/img/preview_boxed.png differ diff --git a/addons/report/static/src/img/preview_clean.png b/addons/report/static/src/img/preview_clean.png new file mode 100644 index 00000000000..439082ceb37 Binary files /dev/null and b/addons/report/static/src/img/preview_clean.png differ diff --git a/addons/report/static/src/img/preview_standard.png b/addons/report/static/src/img/preview_standard.png new file mode 100644 index 00000000000..ef23a5300cc Binary files /dev/null and b/addons/report/static/src/img/preview_standard.png differ diff --git a/addons/report/static/src/less/layout_background.less b/addons/report/static/src/less/layout_background.less new file mode 100644 index 00000000000..1c7ffd8ae97 --- /dev/null +++ b/addons/report/static/src/less/layout_background.less @@ -0,0 +1,68 @@ +.o_background_footer, .o_background_header, .o_report_layout_background { + font-family: 'Lato'; + color: @gray; +} +.o_background_header { + border-bottom: 1px solid @gray-lighter; + .company_address { + min-width: 300px; + } + img { + max-height: 96px; + max-width: 300px; + margin-right: 16px; + } + h3 { + color: @odoo-brand-primary; + font-weight: 700; + max-width: 300px; + } +} +.o_background_footer { + ul { + border-top: 1px solid @odoo-brand-primary; + border-bottom: 1px solid @odoo-brand-primary; + padding: 4px 0; + margin: 0 0 4px 0; + li { + color: @odoo-brand-primary; + } + } +} +.o_report_layout_background { + background-image: url(/report/static/src/img/bg_background_template.jpg); + background-size: cover; + background-position: bottom center; + background-repeat: no-repeat; + min-height: 1000px; + thead tr th, h2 { + color: @odoo-brand-primary; + } + tbody { + color: @gray; + tr:nth-child(odd) { + background-color: rgba(184, 171, 180, 0.2); + } + tr td { + border-top: none; + } + } + /*Total table*/ + .row > .col-xs-4 > table { + tr:nth-child(odd) { + background-color: transparent !important; + } + tr:first-child td { + /*we could get rid of this rule if .border-black td would be terminated in report.less*/ + border-top: none !important; + } + tr:last-child td { + color: @odoo-brand-primary; + } + } + #total { + table tr:last-child td { + border-bottom: 1px solid black; + } + } +} diff --git a/addons/report/static/src/less/layout_boxed.less b/addons/report/static/src/less/layout_boxed.less new file mode 100644 index 00000000000..a81e09f347b --- /dev/null +++ b/addons/report/static/src/less/layout_boxed.less @@ -0,0 +1,72 @@ +.o_boxed_footer, .o_boxed_header, .o_report_layout_boxed { + font-family: 'Lato'; + color: @gray; + font-size: 12px; +} +.o_boxed_header { + border-bottom: 1px solid @gray-lighter; + img { + max-height: 100px; + } + h4 { + color: @o-we-color-text-normal; + font-weight: 700; + text-transform: uppercase; + } +} +.o_boxed_footer { + border-top: 3px solid @gray; + ul { + margin: 4px 0; + } +} +.o_report_layout_boxed { + // This is not a general rule since the id is not used in all the reports, + // we should make a general structure for report body to use it everywhere + #informations { + border: 1px solid @gray; + padding-top: 10px; + margin: 0; + } + > h2 { + text-transform: uppercase; + } + table { + border: 1px solid @gray; + thead { + tr th { + border-bottom: 3px solid @gray !important; + text-transform: uppercase; + } + } + tbody { + color: @gray; + tr { + td { + border-top: none; + border-right: 1px solid @gray; + } + td:last-child { + background-color: @gray-lighter; + } + } + } + } + /*Total table*/ + .row > .col-xs-4 > table { + td { + border-right: none; + } + tr:last-child td, tr:first-child td { + /*we could get rid of this rule if .border-black td would be terminated in report.less*/ + border-top: none !important; + } + tr:first-child td { + background-color: transparent; + } + tr:last-child td { + background-color: @gray; + color: #fff; + } + } +} diff --git a/addons/report/static/src/less/layout_clean.less b/addons/report/static/src/less/layout_clean.less new file mode 100644 index 00000000000..85e9c2d8491 --- /dev/null +++ b/addons/report/static/src/less/layout_clean.less @@ -0,0 +1,84 @@ +.o_clean_footer, .o_clean_header, .o_report_layout_clean { + font-family: 'Lato'; + color: #000; +} +.o_clean_header { + img { + max-height: 90px; + max-width: 300px; + } +} +.o_clean_footer { + margin: 0 3px; + border-top: 3px solid @odoo-brand-primary; + h4 { + color: @odoo-brand-primary; + font-weight: bolder; + } + .pagenumber { + width: 35px; + height: 35px; + border: 3px solid @odoo-brand-primary; + background-color: @odoo-brand-optional; + color: white; + padding-top: 6px; + text-align: center; + } +} +.o_report_layout_clean { + h1, h2, h3 { + color: @odoo-brand-optional; + font-weight: bolder; + } + strong { + color: @odoo-brand-primary; + } + table { + thead { + color: @odoo-brand-primary; + tr th { + text-align: left !important; + border-top: 3px solid @odoo-brand-primary !important; + text-transform: uppercase; + } + tr th:last-child { + text-align: right !important; + } + tr th:first-child { + width: 48%; + } + } + tbody { + color: #000; + tr:first-child td { + border-top: none; + } + tr:last-child td { + border-bottom: 3px solid @odoo-brand-primary; + } + tr { + td { + padding: 15px 5px; + text-align: left !important; + } + td:last-child { + text-align: right !important; + } + } + } + } + /*Total table*/ + .row > .col-xs-4 { + width: 43%; + margin-top: -20px; + > table { + tr:last-child td { + border-top: 1px solid @gray-lighter !important; + } + tr:first-child td { + /*we could get rid of this rule if .border-black td would be terminated in report.less*/ + border-top: none !important; + } + } + } +} diff --git a/addons/report/static/src/less/report.less b/addons/report/static/src/less/report.less index 4e319122d18..f34a2393fbe 100644 --- a/addons/report/static/src/less/report.less +++ b/addons/report/static/src/less/report.less @@ -9,13 +9,15 @@ body { .border-black td { border-top: 1px solid black !important; } + /* See https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1524 */ .table-condensed { > thead > tr > th { - border-bottom: 1px solid black !important; + border-bottom: none !important; } > tbody > tr { page-break-inside: avoid !important; + border-top: none !important; } } .zero_min_height { @@ -26,81 +28,8 @@ body { .jumbotron, .panel, .carousel, section{ page-break-inside: avoid; } + /* Wkhtmltopdf doesn't support very well the media-print CSS (depends on the version) */ .hidden-print{ display: none; } - -/* Missing css rules since the website/web_editor split */ -.mt128 { - margin-top: 128px!important; -} -.mt92 { - margin-top: 92px!important; -} -.mt64 { - margin-top: 64px!important; -} -.mt48 { - margin-top: 48px!important; -} -.mt32 { - margin-top: 32px!important; -} -.mt16 { - margin-top: 16px!important; -} -.mt8 { - margin-top: 8px!important; -} -.mt4 { - margin-top: 4px!important; -} -.mt0 { - margin-top: 0px!important; -} -.mb128 { - margin-bottom: 128px!important; -} -.mb92 { - margin-bottom: 92px!important; -} -.mb64 { - margin-bottom: 64px!important; -} -.mb48 { - margin-bottom: 48px!important; -} -.mb32 { - margin-bottom: 32px!important; -} -.mb16 { - margin-bottom: 16px!important; -} -.mb8 { - margin-bottom: 8px!important; -} -.mb4 { - margin-bottom: 4px!important; -} -.mb0 { - margin-bottom: 0px!important; -} -.ml8 { - margin-left: 8px!important; -} -.ml4 { - margin-left: 4px!important; -} -.ml0 { - margin-left: 0px!important; -} -.mr8 { - margin-right: 8px!important; -} -.mr4 { - margin-right: 4px!important; -} -.mr0 { - margin-right: 0px!important; -} diff --git a/addons/report/static/src/pdf/preview_background.pdf b/addons/report/static/src/pdf/preview_background.pdf new file mode 100644 index 00000000000..d33687c16b8 Binary files /dev/null and b/addons/report/static/src/pdf/preview_background.pdf differ diff --git a/addons/report/static/src/pdf/preview_boxed.pdf b/addons/report/static/src/pdf/preview_boxed.pdf new file mode 100644 index 00000000000..e73c1131d04 Binary files /dev/null and b/addons/report/static/src/pdf/preview_boxed.pdf differ diff --git a/addons/report/static/src/pdf/preview_clean.pdf b/addons/report/static/src/pdf/preview_clean.pdf new file mode 100644 index 00000000000..4f1c42b4814 Binary files /dev/null and b/addons/report/static/src/pdf/preview_clean.pdf differ diff --git a/addons/report/static/src/pdf/preview_standard.pdf b/addons/report/static/src/pdf/preview_standard.pdf new file mode 100644 index 00000000000..4d537376850 Binary files /dev/null and b/addons/report/static/src/pdf/preview_standard.pdf differ diff --git a/addons/report/views/base_config_settings_views.xml b/addons/report/views/base_config_settings_views.xml index 0b0bf1e7c8f..0253fde66b6 100644 --- a/addons/report/views/base_config_settings_views.xml +++ b/addons/report/views/base_config_settings_views.xml @@ -24,46 +24,21 @@
-
- -
-
-
-
- -
-
-
diff --git a/addons/report/views/report_templates.xml b/addons/report/views/report_templates.xml deleted file mode 100644 index ac49792e112..00000000000 --- a/addons/report/views/report_templates.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/addons/report/views/res_company_view.xml b/addons/report/views/res_company_view.xml new file mode 100644 index 00000000000..d67cd0e3a4c --- /dev/null +++ b/addons/report/views/res_company_view.xml @@ -0,0 +1,50 @@ + + + + + res.company.report.form + res.company + 1024 + +
+ +
+

+ No logo found! + To get a beautiful report, you might review your + company data: upload a logo, set + bank accounts, phone numbers, etc. +

+
+
+
+ + preview +
+ + preview +
+ + preview +
+ + preview +
+
+
+
+ +
+
+ +
diff --git a/addons/report/views/layout_templates.xml b/addons/report/views/templates.xml similarity index 50% rename from addons/report/views/layout_templates.xml rename to addons/report/views/templates.xml index c3236d4bec6..2ca0e586f9c 100644 --- a/addons/report/views/layout_templates.xml +++ b/addons/report/views/templates.xml @@ -1,5 +1,19 @@ + + + + + + +