[ADD] report,base: custom report layouts

External layout for reports can be customized. 4 Layout are currently
proposed, selectable from General Settings.
An onboarding popup is shown to select the layout to used if none has
been shown nor a company logo chosen.

Joint works by Fabien Pinckaers, Antony Lesuisse and Christophe Simonis.
Design by Csaba Fazekas.
This commit is contained in:
Fabien Pinckaers
2017-01-04 18:51:17 +01:00
committed by Christophe Simonis
parent 1d6fa1b2fd
commit 3d04e44880
26 changed files with 625 additions and 310 deletions
+6 -3
View File
@@ -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,
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="base.main_company" model="res.company">
<field name="external_report_layout">standard</field>
</record>
</odoo>
+27 -8
View File
@@ -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()
+18 -3
View File
@@ -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):
+18 -30
View File
@@ -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')
Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
}
+4 -75
View File
@@ -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;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -24,46 +24,21 @@
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="default_custom_report_footer"/>
</div>
<div class="o_setting_right_pane">
<label string="Custom Footer" for="default_custom_report_footer"/>
<label string="Report Template"/>
<span class="fa fa-lg fa-building-o" title="Values set here are company-specific." groups="base.group_multi_company"/>
<div class="text-muted">
Set a custom footer
Choose your reports's header and footer layout.
</div>
<div class="content-group" attrs="{'invisible': [('default_custom_report_footer', '=', False)]}">
<div class="content-group">
<div class="mt16" groups="base.group_no_one">
<label for="external_report_layout" string="Template" class="col-xs-3 col-md-3 o_light_label"/>
<field name="external_report_layout" class="oe_inline"/>
</div>
<div class="mt16">
<field name="rml_footer"/>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" groups="base.group_no_one">
<div class="o_setting_left_pane">
<field name="default_custom_header_footer"/>
</div>
<div class="o_setting_right_pane">
<label for="default_custom_header_footer"/>
<div class="text-muted">
Customize header &amp; footer in HTML (advanced)
</div>
<div class="content-group" attrs="{'invisible': [('default_custom_header_footer', '=', False)]}">
<div class="mt16">
<button type="object" name="edit_external_header" string="External Header" icon="fa-arrow-right" class="btn-link"/>
</div>
<div>
<button type="object" name="edit_external_footer" string="External Footer" icon="fa-arrow-right" class="btn-link"/>
</div>
<div>
<button type="object" name="edit_internal_header" string="Internal Header" icon="fa-arrow-right" class="btn-link"/>
</div>
<div>
<button name="%(action_report_internalpreview)d" string="Preview Internal Report" type="action" icon="fa-arrow-right" class="btn-link"/>
</div>
<div>
<button name="%(action_report_externalpreview)d" string="Preview External Report" type="action" icon="fa-arrow-right" class="btn-link"/>
<button name="change_report_template" string="Change Report Template" type="object" class="oe_link"/>
<button name="edit_external_header" string="Edit Header" type="object" class="oe_link" groups="base.group_no_one"/>
<button name="%(action_report_externalpreview)d" string="Preview Report" type="action" class="oe_link" groups="base.group_no_one"/>
</div>
</div>
</div>
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="report assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/report/static/src/js/qwebactionmanager.js"></script>
<script type="text/javascript" src="/report/static/src/js/utils.js"></script>
<script type="text/javascript" src="/report/static/src/js/client_action.js"></script>
<link rel="stylesheet" type="text/less" href="/report/static/src/less/report_backend.less"/>
</xpath>
</template>
</odoo>
+50
View File
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_company_report_form" model="ir.ui.view">
<field name="name">res.company.report.form</field>
<field name="model">res.company</field>
<field name="priority">1024</field>
<field name="arch" type="xml">
<form string="Company">
<field name="logo" invisible="1"/>
<div class="alert alert-warning" attrs="{'invisible': [('logo','&lt;&gt;',False)]}">
<p>
<strong>No logo found!</strong>
To get a beautiful report, you might review your
company data: upload a logo, set
bank accounts, phone numbers, etc.
</p>
<button name="open_company_edit_report" type="object" string="⇒ Review Company Data" class="btn-link"/>
</div>
<div class="row mt16">
<div class="col-xs-3 text-center">
<button type="object" name="set_report_template" context="{'report_template': 'background'}">
<img src="/report/static/src/img/preview_background.png" class="img img-responsive img-thumbnail" alt="Preview Background Template"/>
</button>
<a href="/report/static/src/pdf/preview_background.pdf" target="_blank">preview</a>
</div><div class="col-xs-3 text-center">
<button type="object" name="set_report_template" context="{'report_template': 'boxed'}">
<img src="/report/static/src/img/preview_boxed.png" class="img img-responsive img-thumbnail" alt="Preview Boxed Template"/>
</button>
<a href="/report/static/src/pdf/preview_boxed.pdf" target="_blank">preview</a>
</div><div class="col-xs-3 text-center">
<button type="object" name="set_report_template" context="{'report_template': 'clean'}">
<img src="/report/static/src/img/preview_clean.png" class="img img-responsive img-thumbnail" alt="Preview Clean Template"/>
</button>
<a href="/report/static/src/pdf/preview_clean.pdf" target="_blank">preview</a>
</div><div class="col-xs-3 text-center">
<button type="object" name="set_report_template" context="{'report_template': 'standard'}">
<img src="/report/static/src/img/preview_standard.png" class="img img-responsive img-thumbnail" alt="Preview Minimalist Template"/>
</button>
<a href="/report/static/src/pdf/preview_standard.pdf" target="_blank">preview</a>
</div>
</div>
<footer>
<button string="Close" class="btn-default" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>
@@ -1,5 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Assets for webclient -->
<template id="assets_backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/report/static/src/js/qwebactionmanager.js"></script>
<script type="text/javascript" src="/report/static/src/js/utils.js"></script>
<script type="text/javascript" src="/report/static/src/js/client_action.js"></script>
<link rel="stylesheet" type="text/less" href="/report/static/src/less/report_backend.less"/>
</xpath>
</template>
<!-- Assets for reports -->
<template id="report.assets_common">
<t t-call="web.less_helpers"/>
@@ -12,8 +26,15 @@
<link href="/website/static/src/less/website.wrapwrap.less" rel="stylesheet" type="text/less"/>
<link href="/website/static/src/less/website.snippets.less" rel="stylesheet" type="text/less"/>
<link href="/report/static/src/less/report.less" rel="stylesheet" type="text/less"/>
<!-- TODO: Put in the right report ..? -->
<link href="https://fonts.googleapis.com/css?family=Work+Sans:thin,light,regular,medium,bold,semi-bold" rel="stylesheet"/>
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet" type="text/css"/>
<link href="/report/static/src/less/report.less" rel="stylesheet" type="text/less"/>
<link href="/report/static/src/less/layout_background.less" rel="stylesheet" type="text/less"/>
<link href="/report/static/src/less/layout_boxed.less" rel="stylesheet" type="text/less"/>
<link href="/report/static/src/less/layout_clean.less" rel="stylesheet" type="text/less"/>
</template>
<template id="report.assets_pdf">
@@ -30,6 +51,8 @@
<script type="text/javascript" src='/report/static/src/js/report.editor.js' />
</template>
<!-- Private templates used internally by reports -->
<template id="layout" name="Report layout">&lt;!DOCTYPE html&gt;
<html t-att-lang="lang and lang.replace('_', '-')"
t-att-data-editable="'1' if editable else None"
@@ -75,123 +98,6 @@
</t>
</template>
<template id="external_layout">
<!-- Multicompany -->
<t t-if="not o and doc">
<t t-set="o" t-value="doc"/>
</t>
<t t-if="o and 'company_id' in o">
<t t-set="company" t-value="o.company_id.sudo()"></t>
</t>
<t t-if="not o or not 'company_id' in o">
<t t-set="company" t-value="res_company"></t>
</t>
<t t-call="report.external_layout_header" />
<t t-raw="0" />
<t t-call="report.external_layout_footer" />
</template>
<template id="external_layout_header">
<div class="header">
<div class="row">
<div class="col-xs-3">
<img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % company.logo" style="max-height: 45px;"/>
</div>
<div class="col-xs-9 text-right" style="margin-top:20px;" t-field="company.rml_header1"/>
</div>
<div t-if="company.logo or company.rml_header1" class="row zero_min_height">
<div class="col-xs-12">
<div style="border-bottom: 1px solid black;"></div>
</div>
</div>
<div class="row">
<div class="col-xs-6" name="company_address">
<t t-if="company.street and company.zip">
<span t-field="company.partner_id"
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}'
style="border-bottom: 1px solid black; display:inline-block;"/>
</t>
<t t-if="not (company.street and company.zip)">
<p name="report_company_data_warning">
<i class="fa fa-warning"/> Company address is not defined. Please, got to <i>Settings > General Settings > configure your company data </i>, to set the missing informations.
</p>
</t>
</div>
</div>
</div>
</template>
<template id="external_layout_footer_default">
<ul class="list-inline">
<t t-set="company" t-value="company.sudo()"/>
<li t-if="company.phone">Phone: <span t-field="company.phone"/></li>
<li t-if="company.fax and company.phone">&amp;bull;</li>
<li t-if="company.fax">Fax: <span t-field="company.fax"/></li>
<li t-if="company.email and company.fax or company.email and company.phone">&amp;bull;</li>
<li t-if="company.email">Email: <span t-field="company.email"/></li>
<li t-if="company.website and company.email or company.website and company.fax or company.website and company.phone">&amp;bull;</li>
<li t-if="company.website">Website: <span t-field="company.website"/></li>
</ul>
<ul class="list-inline" name="financial_infos">
<li t-if="company.vat">TIN: <span t-field="company.vat"/></li>
</ul>
</template>
<template id="external_layout_footer">
<div class="footer">
<div class="text-center" style="border-top: 1px solid black;">
<t t-if="not company.custom_footer">
<t t-call="report.external_layout_footer_default"/>
</t>
<t t-if="company.custom_footer">
<span t-raw="company.rml_footer" style="white-space: pre-wrap;"/>
</t>
<ul class="list-inline">
<li>Page:</li>
<li><span class="page"/></li>
<li>/</li>
<li><span class="topage"/></li>
</ul>
</div>
</div>
</template>
<template id="internal_layout">
<!-- Multicompany -->
<t t-if="o and 'company_id' in o">
<t t-set="company" t-value="o.company_id"></t>
</t>
<t t-if="not o or not 'company_id' in o">
<t t-set="company" t-value="res_company"></t>
</t>
<div class="header">
<div class="row">
<div class="col-xs-3">
<span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"/>
</div>
<div class="col-xs-2 col-xs-offset-2 text-center">
<span t-esc="company.name"/>
</div>
<div class="col-xs-2 col-xs-offset-3 text-right">
<ul class="list-inline">
<li><span class="page"/></li>
<li>/</li>
<li><span class="topage"/></li>
</ul>
</div>
</div>
</div>
<t t-raw="0" />
</template>
<template id="minimal_layout">
<t t-raw="'&lt;base href=%s&gt;' % base_url"/>
&lt;!DOCTYPE html&gt;
@@ -227,4 +133,233 @@
</html>
</template>
<!-- External layouts styles -->
<template id="external_layout_background">
<div class="header o_background_header">
<div class="pull-right">
<h3 class="mt0 text-right" t-field="company.rml_header1"/>
</div>
<img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % company.logo" class="pull-left"/>
<div class="pull-left company_address">
<div>
<strong t-field="company.partner_id.name"/>
</div>
<span t-field="company.partner_id"
t-field-options='{"widget": "contact", "fields": ["address"], "no_marker": true}'/>
</div>
<div class="clearfix mb8"/>
</div>
<div class="article o_report_layout_background">
<t t-raw="0" />
</div>
<div class="footer o_background_footer">
<div class="text-center">
<ul class="list-inline">
<li t-if="company.phone"><i class="fa fa-phone"></i> <span t-field="company.phone"/></li>
<li t-if="company.fax"><i class="fa fa-fax"></i> <span t-field="company.fax"/></li>
<li t-if="company.email"><i class="fa fa-at"></i> <span t-field="company.email"/></li>
<li t-if="company.website"><i class="fa fa-globe"></i> <span t-field="company.website"/></li>
<li t-if="company.vat"><i class="fa fa-building-o"></i> VAT: <span t-field="company.vat"/></li>
</ul>
<div t-field="company.rml_footer"/>
<div class="text-muted">
Page:
<span class="page"/>
of
<span class="topage"/>
</div>
</div>
</div>
</template>
<template id="external_layout_boxed">
<div class="header o_boxed_header">
<div class="row mb8">
<div class="col-xs-6">
<img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % company.logo"/>
</div>
<div class="col-xs-6 text-right mb4">
<h4 class="mt0" t-field="company.rml_header1"/>
<div name="company_address" class="mb4">
<span class="company_address" t-field="company.partner_id"
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}'/>
</div>
</div>
</div>
</div>
<div class="article o_report_layout_boxed">
<t t-raw="0" />
</div>
<div class="footer o_boxed_footer">
<div class="text-center">
<ul class="list-inline">
<li t-if="company.phone">Tel: <span t-field="company.phone"/></li>
<li t-if="company.fax">Fax: <span t-field="company.fax"/></li>
<li t-if="company.email">Mail: <span t-field="company.email"/></li>
<li t-if="company.website">Web: <span t-field="company.website"/></li>
<li t-if="company.vat">VAT: <span t-field="company.vat"/></li>
</ul>
<div t-field="company.rml_footer"/>
<div>
Page: <span class="page"/> / <span class="topage"/>
</div>
</div>
</div>
</template>
<template id="external_layout_clean">
<div class="header o_clean_header">
<div class="row">
<div class="col-xs-6">
<img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % company.logo"/>
</div>
<div class="col-xs-5 col-xs-offset-1" name="company_address">
<ul class="list-unstyled">
<strong><li t-if="company.name"><span t-field="company.name"/></li></strong>
<li t-if="company.vat">VAT: <span t-field="company.vat"/></li>
<li t-if="company.phone">Tel: <span t-field="company.phone"/></li>
<li t-if="company.fax">Fax: <span t-field="company.fax"/></li>
<li t-if="company.email"><span t-field="company.email"/></li>
<li t-if="company.website"><span t-field="company.website"/></li>
</ul>
</div>
</div>
</div>
<div class="article o_report_layout_clean">
<t t-raw="0" />
</div>
<div class="footer o_clean_footer">
<div class="row mt8">
<div class="col-xs-3">
<span t-field="company.rml_footer"/>
</div>
<div class="col-xs-4 text-right">
<span class="company_address" t-field="company.partner_id"
t-field-options='{"widget": "contact", "fields": ["address"], "no_marker": true}'/>
</div>
<div class="col-xs-4">
<h4 class="mt0 mb0 text-uppercase" t-field="company.rml_header1"/>
</div>
<div class="col-xs-1">
<ul class="list-inline pagenumber pull-right text-center">
<li><strong><span class="page"/></strong></li>
</ul>
</div>
</div>
</div>
</template>
<template id="external_layout_standard">
<div class="header">
<div class="row">
<div class="col-xs-3 mb4">
<img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % company.logo" style="max-height: 45px;"/>
</div>
<div class="col-xs-9 text-right" style="margin-top:22px;" t-field="company.rml_header1" name="moto"/>
</div>
<div t-if="company.logo or company.rml_header1" class="row zero_min_height">
<div class="col-xs-12">
<div style="border-bottom: 1px solid black;"></div>
</div>
</div>
<div class="row">
<div class="col-xs-6" name="company_address">
<span t-field="company.partner_id"
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}'
style="border-bottom: 1px solid black; display:inline-block;"/>
</div>
</div>
</div>
<div class="article o_report_layout_standard">
<t t-raw="0" />
</div>
<div class="footer">
<div class="text-center" style="border-top: 1px solid black;">
<ul class="list-inline mb4">
<li t-if="company.phone">Phone: <span t-field="company.phone"/></li>
<li t-if="company.fax">Fax: <span t-field="company.fax"/></li>
<li t-if="company.email">Email: <span t-field="company.email"/></li>
<li t-if="company.website">Web: <span t-field="company.website"/></li>
<li t-if="company.vat">VAT: <span t-field="company.vat"/></li>
</ul>
<div name="financial_infos">
<span t-field="company.rml_footer"/>
</div>
<div class="text-muted">
Page: <span class="page"/> / <span class="topage"/>
</div>
</div>
</div>
</template>
<!-- Public api: layout to t-call from reports -->
<template id="external_layout">
<!-- Multicompany -->
<t t-if="not o and doc">
<t t-set="o" t-value="doc"/>
</t>
<t t-if="o and 'company_id' in o">
<t t-set="company" t-value="o.company_id.sudo()"></t>
</t>
<t t-if="not o or not 'company_id' in o">
<t t-set="company" t-value="res_company"></t>
</t>
<t t-if="company.external_report_layout == 'background'">
<t t-call="report.external_layout_background"><t t-raw="0"/></t>
</t>
<t t-if="company.external_report_layout == 'boxed'">
<t t-call="report.external_layout_boxed"><t t-raw="0"/></t>
</t>
<t t-if="company.external_report_layout == 'clean'">
<t t-call="report.external_layout_clean"><t t-raw="0"/></t>
</t>
<t t-if="company.external_report_layout in (False, 'standard')">
<t t-call="report.external_layout_standard"><t t-raw="0"/></t>
</t>
</template>
<template id="internal_layout">
<!-- Multicompany -->
<t t-if="o and 'company_id' in o">
<t t-set="company" t-value="o.company_id"></t>
</t>
<t t-if="not o or not 'company_id' in o">
<t t-set="company" t-value="res_company"></t>
</t>
<div class="header">
<div class="row">
<div class="col-xs-3">
<span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"/>
</div>
<div class="col-xs-2 col-xs-offset-2 text-center">
<span t-esc="company.name"/>
</div>
<div class="col-xs-2 col-xs-offset-3 text-right">
<ul class="list-inline">
<li><span class="page"/></li>
<li>/</li>
<li><span class="topage"/></li>
</ul>
</div>
</div>
</div>
<div class="article">
<t t-raw="0" />
</div>
</template>
</odoo>
+1
View File
@@ -26,6 +26,7 @@
<field name="phone">+1 555 123 8069</field>
<field name="email">info@yourcompany.example.com</field>
<field name="website">www.example.com</field>
<field name="image" type="base64" file="base/res/res_company_logo.png"/>
</record>
<record id="main_company" model="res.company">
+3 -22
View File
@@ -122,18 +122,14 @@ class Company(models.Model):
child_ids = fields.One2many('res.company', 'parent_id', string='Child Companies')
partner_id = fields.Many2one('res.partner', string='Partner', required=True)
rml_header = fields.Text(required=True, default=_get_header)
rml_header1 = fields.Char(string='Company Tagline', help="Appears by default on the top right corner of your printed documents (report header).")
rml_header1 = fields.Text(string='Company Tagline', help="Appears by default on the top right corner of your printed documents (report header).")
rml_header2 = fields.Text(string='RML Internal Header', required=True, default=_header2)
rml_header3 = fields.Text(string='RML Internal Header for Landscape Reports', required=True, default=_header3)
rml_footer = fields.Text(string='Custom Report Footer', translate=True, help="Footer text displayed at the bottom of all reports.")
custom_footer = fields.Selection([
(0, 'Use standard footer'),
(1, 'Use custom footer')
], "Report Footer", default=0, help="""Set to 'custom' this to define the report footer manually. Otherwise it will be filled in automatically.""")
rml_footer = fields.Text(string='Report Footer', translate=True, help="Footer text displayed at the bottom of all reports.")
font = fields.Many2one('res.font', string="Font", default=lambda self: self._get_font(),
domain=[('mode', 'in', ('Normal', 'Regular', 'all', 'Book'))],
help="Set the font into the report header, it will be used as default font in the RML reports of the user company")
logo = fields.Binary(related='partner_id.image', default=_get_logo)
logo = fields.Binary(related='partner_id.image', default=_get_logo, string="Company Logo")
# logo_web: do not store in attachments, since the image is retrieved in SQL for
# performance reasons (see addons/web/controllers/main.py, Binary.company_logo)
logo_web = fields.Binary(compute='_compute_logo_web', store=True)
@@ -208,21 +204,6 @@ class Company(models.Model):
for company in self:
company.logo_web = tools.image_resize_image(company.partner_id.image, (180, None))
@api.onchange('custom_footer', 'phone', 'fax', 'email', 'website', 'vat', 'company_registry')
def onchange_footer(self):
if not self.custom_footer:
# first line (notice that missing elements are filtered out before the join)
res = ' | '.join(filter(bool, [
self.phone and '%s: %s' % (_('Phone'), self.phone),
self.fax and '%s: %s' % (_('Fax'), self.fax),
self.email and '%s: %s' % (_('Email'), self.email),
self.website and '%s: %s' % (_('Website'), self.website),
self.vat and '%s: %s' % (_('TIN'), self.vat),
self.company_registry and '%s: %s' % (_('Reg'), self.company_registry),
]))
self.rml_footer_readonly = res
self.rml_footer = res
@api.onchange('state_id')
def _onchange_state(self):
self.country_id = self.state_id.country_id
+3 -5
View File
@@ -13,12 +13,8 @@
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" class="oe_inline"/>
<field name="name"/>
</h1>
<label for="rml_header1" class="oe_edit_only"/>
<h3>
<field name="rml_header1" placeholder="e.g. Global Business Solutions"/>
</h3>
</div>
<notebook colspan="4">
<page string="General Information">
@@ -35,6 +31,8 @@
<field name="country_id" placeholder="Country" class="o_address_country" options='{"no_open": True}'/>
</div>
<field name="website" widget="url" placeholder="e.g. www.odoo.com"/>
<field name="rml_footer" placeholder="e.g. Your Bank Accounts, one per line"/>
<field name="rml_header1" placeholder="e.g. Global Business Solutions"/>
</group>
<group>
<field name="phone"/>