summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRomain Derie <rde@odoo.com>2018-06-22 18:34:52 +0200
committerRomain Derie <rde@odoo.com>2018-06-22 18:34:52 +0200
commit864357203fc6222cc989b99a5e9f428cd53f413f (patch)
treed7e6f199573e2eb392631ad4835e48eead8fe4d6
parent07c111fa7255b28e901c21f2f9967bda0422ab8a (diff)
parentd6956db916f4de980864f750d0e873f311e73122 (diff)
[IMP] account*: update invoice page view on customer portal
*account_payment, l10_in(_sale), sale(_stock), web With this commit: The invoice preview in portal (/my/invoices..) is now the HTML version of the PDF report. The HTML preview is based on the invoice report to closely match what is already done in Odoo. The invoice preview is displayed in an 'iframe', it is mandatory since: 1. Reports are rendered as a separate page as it returns the whole page after rendering, which has tag <html>, <head> etc 2. Reports are having their own layouts and their own assets that we we cannot load in the page directly or it will break the website layout. 3. We can not use report template with t-call because internally reports are using extra params like context_timestamp, company, DateTime, user etc which is used in header/footer -- There will be a chatter (as a modal) to display/see the history of the document -- For responsive purpose, we use new tables with limited column (Description, Quantity and Amount) for responsive purpose (small screen). It also adds some bootstrap classes to reports for responsive purpose. -- The 'Pay Now' button remains if you already paid with 'wire transfer'. (It disappears for Credit Note) -- Add margin after the header and before the footer to look like the real printed document, without alterating the real printed version -- In every portal module, the pager is now generic in the generic breadcrump -- Task ID: 39876 Closes #24938
-rw-r--r--addons/account/controllers/portal.py38
-rw-r--r--addons/account/report/account_invoice_report.py14
-rw-r--r--addons/account/static/src/js/account_portal_sidebar.js68
-rw-r--r--addons/account/views/account.xml6
-rw-r--r--addons/account/views/account_portal_templates.xml234
-rw-r--r--addons/account/views/report_invoice.xml54
-rw-r--r--addons/account_payment/views/account_portal_templates.xml137
-rw-r--r--addons/l10n_in/views/report_invoice.xml2
-rw-r--r--addons/l10n_in_sale/views/report_invoice_view.xml2
-rw-r--r--addons/payment/models/account_invoice.py2
-rw-r--r--addons/payment/views/payment_portal_templates.xml8
-rw-r--r--addons/portal/static/src/js/portal_sidebar.js106
-rw-r--r--addons/portal/static/src/scss/portal.scss23
-rw-r--r--addons/portal/static/src/xml/portal_chatter.xml3
-rw-r--r--addons/portal/views/assets.xml1
-rw-r--r--addons/portal/views/portal_templates.xml19
-rw-r--r--addons/project/views/project_portal_templates.xml2
-rw-r--r--addons/purchase/views/portal_templates.xml1
-rw-r--r--addons/sale/report/invoice_report_templates.xml69
-rw-r--r--addons/sale/views/sale_portal_templates.xml1
-rw-r--r--addons/sale_stock/views/account_invoice_views.xml3
-rw-r--r--addons/web/static/src/scss/layout_boxed.scss1
-rw-r--r--addons/web/static/src/scss/layout_clean.scss2
-rw-r--r--addons/web/static/src/scss/layout_standard.scss3
-rw-r--r--addons/web/views/report_templates.xml13
-rw-r--r--addons/website_quote/views/website_quote_templates.xml3
26 files changed, 541 insertions, 274 deletions
diff --git a/addons/account/controllers/portal.py b/addons/account/controllers/portal.py
index 155c38d1a05..c59be47e588 100644
--- a/addons/account/controllers/portal.py
+++ b/addons/account/controllers/portal.py
@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import re
+from werkzeug.exceptions import NotFound
+
from odoo import http, _
-from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
+from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager, get_records_pager
from odoo.exceptions import AccessError
from odoo.http import request
from odoo.tools import consteq
@@ -46,7 +49,8 @@ class PortalAccount(CustomerPortal):
'invoice': invoice,
}
if access_token:
- values['no_breadcrumbs'] = True
+ # force breadcrumbs even if access_token to `invite` users to register if they click on it
+ values['no_breadcrumbs'] = False
values['access_token'] = access_token
if kwargs.get('error'):
@@ -56,6 +60,9 @@ class PortalAccount(CustomerPortal):
if kwargs.get('success'):
values['success'] = kwargs['success']
+ history = request.session.get('my_invoices_history', [])
+ values.update(get_records_pager(history, invoice))
+
return values
@http.route(['/my/invoices', '/my/invoices/page/<int:page>'], type='http', auth="user", website=True)
@@ -93,6 +100,8 @@ class PortalAccount(CustomerPortal):
)
# content according to pager and archive selected
invoices = AccountInvoice.search(domain, order=order, limit=self._items_per_page, offset=pager['offset'])
+ request.session['my_invoices_history'] = invoices.ids[:100]
+
values.update({
'date': date_begin,
'invoices': invoices,
@@ -115,7 +124,10 @@ class PortalAccount(CustomerPortal):
values = self._invoice_get_page_view_values(invoice_sudo, access_token, **kw)
return request.render("account.portal_invoice_page", values)
- @http.route(['/my/invoices/pdf/<int:invoice_id>'], type='http', auth="public", website=True)
+ @http.route([
+ '/my/invoices/pdf/<int:invoice_id>',
+ '/my/invoices/html/<int:invoice_id>/<string:access_token>'
+ ], type='http', auth="public", website=True)
def portal_my_invoice_report(self, invoice_id, access_token=None, **kw):
try:
invoice_sudo = self._invoice_check_access(invoice_id, access_token)
@@ -124,12 +136,20 @@ class PortalAccount(CustomerPortal):
# print report as sudo, since it require access to taxes, payment term, ... and portal
# does not have those access rights.
- pdf = request.env.ref('account.account_invoices').sudo().render_qweb_pdf([invoice_sudo.id])[0]
- pdfhttpheaders = [
- ('Content-Type', 'application/pdf'),
- ('Content-Length', len(pdf)),
- ]
- return request.make_response(pdf, headers=pdfhttpheaders)
+ accountInvoiceReport = request.env.ref('account.account_invoices').sudo()
+ report_type = kw.get('report_type', 'pdf')
+ method_name = 'render_qweb_%s' % (report_type)
+ if hasattr(accountInvoiceReport, method_name):
+ invoice_report = getattr(accountInvoiceReport, method_name)([invoice_sudo.id], data={'report_type': report_type})[0]
+ reporthttpheaders = [
+ ('Content-Type', 'application/pdf' if report_type == 'pdf' else 'text/html'),
+ ('Content-Length', len(invoice_report)),
+ ]
+ if report_type == 'pdf' and not kw.get('print'):
+ filename = "%s.pdf" % (re.sub('\W+', '-', invoice_sudo._get_printed_report_name()))
+ reporthttpheaders.append(('Content-Disposition', http.content_disposition(filename)))
+ return request.make_response(invoice_report, headers=reporthttpheaders)
+ raise NotFound()
# ------------------------------------------------------------
# My Home
diff --git a/addons/account/report/account_invoice_report.py b/addons/account/report/account_invoice_report.py
index 791d0820f63..0282010032e 100644
--- a/addons/account/report/account_invoice_report.py
+++ b/addons/account/report/account_invoice_report.py
@@ -171,3 +171,17 @@ class AccountInvoiceReport(models.Model):
)""" % (
self._table, self.env['res.currency']._select_companies_rates(),
self._select(), self._sub_select(), self._from(), self._group_by()))
+
+
+class ReportInvoiceWithPayment(models.AbstractModel):
+ _name = 'report.account.report_invoice_with_payments'
+
+ @api.model
+ def get_report_values(self, docids, data=None):
+ report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments')
+ return {
+ 'doc_ids': docids,
+ 'doc_model': report.model,
+ 'docs': self.env[report.model].browse(docids),
+ 'type_html': data and data.get('report_type') == 'html',
+ }
diff --git a/addons/account/static/src/js/account_portal_sidebar.js b/addons/account/static/src/js/account_portal_sidebar.js
new file mode 100644
index 00000000000..5323c09e0f3
--- /dev/null
+++ b/addons/account/static/src/js/account_portal_sidebar.js
@@ -0,0 +1,68 @@
+odoo.define('account.AccountPortalSidebar.instance', function (require) {
+"use strict";
+
+require('web.dom_ready');
+var AccountPortalSidebar = require('account.AccountPortalSidebar');
+
+if (!$('.o_portal_invoice_sidebar').length) {
+ return $.Deferred().reject("DOM doesn't contain '.o_portal_invoice_sidebar'");
+}
+
+var account_portal_sidebar = new AccountPortalSidebar();
+return account_portal_sidebar.attachTo($('.o_portal_invoice_sidebar')).then(function () {
+ return account_portal_sidebar;
+});
+});
+
+//==============================================================================
+
+odoo.define('account.AccountPortalSidebar', function (require) {
+"use strict";
+
+var PortalSidebar = require('portal.PortalSidebar');
+
+var AccountPortalSidebar = PortalSidebar.extend({
+ events: {
+ 'click .o_portal_invoice_print': '_onPrintInvoice',
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ var self = this;
+ this._super.apply(this, arguments);
+ var $invoiceHtml = this.$el.find('iframe#invoice_html');
+ $invoiceHtml.on('load', self._onLoadIframe.bind(self, $invoiceHtml));
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called when the iframe is load on custome portal
+ * here we set height and width of html preview (iframe)
+ *
+ * @private
+ */
+ _onLoadIframe: function ($el) {
+ var $body = $el.contents().find('body');
+ // expand iframe height for display full report on the custome portal (no scrollbar in iframe)
+ $el.height($body.scrollParent().height());
+ // removed extra space in html preview (specially left and right margin)
+ $body.width('100%');
+ },
+ /**
+ * @private
+ * @param {MouseEvent} ev
+ */
+ _onPrintInvoice: function (ev) {
+ ev.preventDefault();
+ var href = $(ev.currentTarget).attr('href');
+ this._printIframeContent(href);
+ },
+});
+
+
+return AccountPortalSidebar;
+});
diff --git a/addons/account/views/account.xml b/addons/account/views/account.xml
index d8153c82871..e7218152387 100644
--- a/addons/account/views/account.xml
+++ b/addons/account/views/account.xml
@@ -24,6 +24,12 @@
</xpath>
</template>
+ <template id="assets_frontend" name="account assets" inherit_id="web.assets_frontend">
+ <xpath expr="." position="inside">
+ <script type="text/javascript" src="/account/static/src/js/account_portal_sidebar.js"></script>
+ </xpath>
+ </template>
+
<template id="qunit_suite" name="account_reconciliation tests" inherit_id="web.qunit_suite">
<xpath expr="//script[contains(@src, '/web/static/tests/views/kanban_tests.js')]" position="after">
<script type="text/javascript" src="/account/static/tests/reconciliation_tests.js"></script>
diff --git a/addons/account/views/account_portal_templates.xml b/addons/account/views/account_portal_templates.xml
index c9d25b95aa9..21ac38d693e 100644
--- a/addons/account/views/account_portal_templates.xml
+++ b/addons/account/views/account_portal_templates.xml
@@ -46,7 +46,7 @@
</td>
<td><span t-field="invoice.date_invoice"/></td>
<td class='hidden-xs'><span t-field="invoice.date_due"/></td>
- <td>
+ <td class="tx_status">
<t t-if="invoice.state == 'open'">
<span class="label label-info"><i class="fa fa-fw fa-clock-o"></i><span class="hidden-xs"> Waiting for Payment</span></span>
</t>
@@ -68,188 +68,76 @@
</t>
</template>
- <template id="portal_invoice_page" name="Invoice Portal Template">
- <t t-call="portal.portal_layout">
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <div class="row">
- <div class="col-md-6">
- <h4>
- <t t-call='portal.record_pager'/>
- <span t-if="invoice.type == 'out_invoice' and (invoice.state == 'open' or invoice.state == 'paid')">Invoice</span>
- <span t-if="invoice.type == 'out_invoice' and invoice.state == 'draft'">Draft Invoice</span>
- <span t-if="invoice.type == 'out_invoice' and invoice.state == 'cancel'">Cancelled Invoice</span>
- <span t-if="invoice.type == 'out_refund'">Credit Note</span>
- <span t-if="invoice.type == 'in_refund'">Vendor Credit Note</span>
- <span t-if="invoice.type == 'in_invoice'">Vendor Bill</span>
- <span t-field="invoice.number"/>
- </h4>
+ <template id="portal_invoice_page" name="Invoice Portal Template" inherit_id="portal.portal_sidebar" primary="True">
+ <xpath expr="//div[hasclass('o_portal_sidebar')]" position="inside">
+ <div class="row mt16 o_portal_invoice_sidebar">
+ <!-- Sidebar -->
+ <div class="col-md-3 hidden-print">
+ <div class="bs-sidebar mb16" id="sidebar_content">
+ <div class="text-center pt16 o_account_portal_sidebar">
+ <h2 class="media-heading">
+ <strong>
+ <span t-if="invoice.residual > 0" t-field="invoice.residual"/>
+ <span t-else="1" t-field="invoice.amount_total"/>
+ </strong>
+ </h2>
+ <div class="mb4" t-if="invoice.state != 'paid' and invoice.type == 'out_invoice'"><i class="fa fa-clock-o"/><span class="o_portal_sidebar_timeago ml4" t-att-datetime="invoice.date_due"/></div>
+ </div>
+ <div class="o_payment_button">
+ <div class="text-center mb8 ml16 mr16 o_download_pdf">
+ <a class="btn btn-default btn-block btn-sm o_download_btn" t-att-href="'/my/invoices/pdf/%s?%s' % (invoice.id, keep_query())" title="Download"><i class="fa fa-download"/> Download</a>
+ <a class="btn btn-default btn-block btn-sm hidden-xs hidden-sm o_print_btn o_portal_invoice_print" t-att-href="'/my/invoices/pdf/%s?%s&amp;print=true' % (invoice.id, keep_query())" id="print_invoice_report" title="Print"><i class="fa fa-print"/> Print</a>
</div>
- <div class="col-md-6 col-sm-6 col-xs-12 hidden-print" id="o_portal_account_actions">
- <a target="_blank" t-att-href="'/my/invoices/pdf/%s?%s' % (invoice.id, keep_query())" class="pull-right" title="Download">
- <i class="fa fa-download fa-2x" aria-hidden="true"/>
- </a>
+ </div>
+ <hr t-if="invoice.user_id" class="mt0 mb0"/>
+ <div class="pb8 ml16 mr16 container">
+ <t t-if="invoice.user_id">
+ <div><strong>Your Contact:</strong></div>
+ <img class="img-circle mr4 pull-left o_portal_contact_img" t-if="invoice.user_id.image" t-attf-src="data:image/png;base64,#{invoice.user_id.image}"/>
+ <img class="img-circle mr4 pull-left o_portal_contact_img" t-if="not invoice.user_id.image" src="/web/static/src/img/placeholder.png"/>
+ <span t-field="invoice.user_id" t-field-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
+ <a data-toggle="modal" href="#" data-target="#invoice_chatter">Contact us</a>
+ </t>
+ <div t-if="not invoice.user_id" class="text-center mr16">
+ <a data-toggle="modal" href="#" data-target="#invoice_chatter">Contact us</a>
</div>
</div>
+ <div class="text-center hidden-xs mt4 o_portal_brand">
+ Powered by <a target="_blank" href="http://www.odoo.com">Odoo</a>
+ </div>
</div>
- <div class="panel-body">
- <t t-if="error or warning" t-call="account.portal_invoice_error"/>
- <t t-if="success and (not error and not warning)" t-call="account.portal_invoice_success"/>
- <t t-call="account.portal_invoice_report"/>
+ </div>
+ <!-- Page Content -->
+ <div id="invoice_content" class="col-md-9 o_portal_page_content hidden-print">
+ <t t-if="error or warning" t-call="account.portal_invoice_error"/>
+ <t t-if="success and (not error and not warning)" t-call="account.portal_invoice_success"/>
+ <div class="o_portal_html_view">
+ <iframe id="invoice_html" class="mt8 mb8" width="100%" height="100%" frameborder="0" scrolling="no" t-attf-src="/my/invoices/html/#{invoice.id}/#{invoice.access_token}?report_type=html"/>
</div>
</div>
</div>
- <div class="oe_structure mb32"/>
- </t>
+ </xpath>
</template>
- <template id="portal_invoice_report" name="Invoice Portal Report">
- <div class="row">
- <div class="col-xs-5" name="customer_address">
- <strong>Customer Address</strong>
- <address t-field="invoice.partner_id"
- t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}' />
- <div t-if="invoice.partner_id.vat" class="mt16">VAT: <span t-field="invoice.partner_id.vat"/></div>
- </div>
- </div>
-
- <div class="row mt32 mb32">
- <div class="col-xs-2" t-if="invoice.name">
- <strong>Description:</strong>
- <p t-field="invoice.name"/>
- </div>
- <div class="col-xs-2" t-if="invoice.date_invoice">
- <strong>Invoice Date:</strong>
- <p t-field="invoice.date_invoice"/>
- </div>
- <div class="col-xs-2" t-if="invoice.date_due and invoice.type == 'out_invoice' and (invoice.state == 'open' or invoice.state == 'paid')">
- <strong>Due Date:</strong>
- <p t-field="invoice.date_due"/>
- </div>
- <div class="col-xs-2" t-if="invoice.origin">
- <strong>Source:</strong>
- <p t-field="invoice.origin"/>
- </div>
- <div class="col-xs-2" t-if="invoice.partner_id.ref">
- <strong>Customer Code:</strong>
- <p t-field="invoice.partner_id.ref"/>
- </div>
- <div name="reference" class="col-xs-2" t-if="invoice.reference">
- <strong>Reference:</strong>
- <p t-field="invoice.reference"/>
- </div>
- </div>
-
- <!-- Is there a discount on at least one line? -->
- <t t-set="display_discount" t-value="any([l.discount for l in invoice.invoice_line_ids])"/>
-
- <table class="table table-condensed">
- <thead>
- <tr>
- <th>Description</th>
- <th class="hidden">Source Document</th>
- <th class="text-right">Quantity</th>
- <th class="text-right">Unit Price</th>
- <th t-if="display_discount" class="text-right">Disc.(%)</th>
- <th class="text-right">Taxes</th>
- <th class="text-right">Amount</th>
- </tr>
- </thead>
- <tbody class="o_portal_report_tbody">
- <tr t-foreach="invoice.invoice_line_ids" t-as="l">
- <td><span t-field="l.name"/></td>
- <td class="hidden"><span t-field="l.origin"/></td>
- <td class="text-right">
- <span t-field="l.quantity"/>
- <span t-field="l.uom_id" groups="uom.group_uom"/>
- </td>
- <td class="text-right">
- <span t-field="l.price_unit"/>
- </td>
- <td t-if="display_discount" class="text-right">
- <span t-field="l.discount"/>
- </td>
- <td class="text-right">
- <span t-esc="', '.join(map(lambda x: (x.description or x.name), l.invoice_line_tax_ids))"/>
- </td>
- <td class="text-right" id="subtotal">
- <span t-field="l.price_subtotal"
- t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
- </td>
- </tr>
- <tr t-foreach="range(max(5-len(invoice.invoice_line_ids),0))" t-as="l">
- <td t-translation="off">&amp;nbsp;</td>
- <td class="hidden"></td>
- <td></td>
- <td></td>
- <td t-if="display_discount"></td>
- <td></td>
- <td></td>
- </tr>
- </tbody>
- </table>
-
- <div id="total" class="row">
- <div class="col-xs-4 pull-right">
- <table class="table table-condensed">
- <tr class="border-black">
- <td><strong>Subtotal</strong></td>
- <td class="text-right">
- <span t-field="invoice.amount_untaxed" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
- </td>
- </tr>
- <t t-foreach="invoice._get_tax_amount_by_group()" t-as="amount_by_group">
- <tr>
- <td><span t-esc="amount_by_group[0] if len(invoice.tax_line_ids) &gt; 1 else (invoice.tax_line_ids.tax_id.description or invoice.tax_line_ids.tax_id.name)"/></td>
- <td class="text-right">
- <span t-esc="amount_by_group[1]" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
- </td>
- </tr>
- </t>
- <tr class="border-black">
- <td><strong>Total</strong></td>
- <td class="text-right">
- <span t-field="invoice.amount_total" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
- </td>
- </tr>
- </table>
- </div>
- </div>
- <!-- DO NOT REMOVE THIS TABLE. MANDATORY IN SOME COUNTRIES -->
- <div class="row" t-if="len(invoice.tax_line_ids) &gt; 0">
- <div class="col-xs-6">
- <table class="table table-condensed">
- <thead>
- <tr>
- <th>Tax</th>
- <th class="text-right">Base</th>
- <th class="text-right">Amount</th>
- </tr>
- </thead>
- <tbody>
- <tr t-foreach="invoice.tax_line_ids" t-as="t">
- <td><span t-field="t.tax_id.description"/></td>
- <td class="text-right">
- <span t-field="t.base" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
- </td>
- <td class="text-right">
- <span t-field="t.amount" t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
- </td>
- </tr>
- </tbody>
- </table>
+ <template id="portal_invoice_chatter" name="Allow Comments &amp; History" inherit_id="account.portal_invoice_page">
+ <xpath expr="//div[@id='invoice_content']//div[hasclass('o_portal_html_view')]" position="after">
+ <div class="modal fade" id="invoice_chatter" role="dialog" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
+ <h3 class="mt0 ml16 mb0">History</h3>
+ </div>
+ <div class="modal-body">
+ <t t-call="portal.message_thread">
+ <t t-set="token" t-value="invoice.access_token"/>
+ <t t-set="object" t-value="invoice"/>
+ </t>
+ </div>
+ </div>
+ </div>
</div>
- </div>
- <p t-if="invoice.comment">
- <span t-field="invoice.comment"/>
- </p>
- <p t-if="invoice.payment_term_id">
- <span t-field="invoice.payment_term_id.note"/>
- </p>
- <p t-if="invoice.fiscal_position_id.note">
- <span t-field="invoice.fiscal_position_id.note"/>
- </p>
+ </xpath>
</template>
<template id="portal_invoice_error" name="Invoice error/warning display">
diff --git a/addons/account/views/report_invoice.xml b/addons/account/views/report_invoice.xml
index f220b6d9059..09a88586281 100644
--- a/addons/account/views/report_invoice.xml
+++ b/addons/account/views/report_invoice.xml
@@ -23,28 +23,31 @@
<span t-field="o.number"/>
</h2>
+ <!-- HTML Preview for mobile responsive -->
+ <t t-set="o_grid_layout" t-value="'col-xs-2'"/>
+ <t t-if="type_html" t-set="o_grid_layout" t-value="'col-sm-2 col-xs-6'"/>
<div class="row mt32 mb32">
- <div class="col-xs-2" t-if="o.name" name="description">
+ <div t-att-class="o_grid_layout" t-if="o.name" name="description">
<strong>Description:</strong>
<p t-field="o.name"/>
</div>
- <div class="col-xs-2" t-if="o.date_invoice" name="invoice_date">
+ <div t-att-class="o_grid_layout" t-if="o.date_invoice" name="invoice_date">
<strong>Invoice Date:</strong>
<p t-field="o.date_invoice"/>
</div>
- <div class="col-xs-2" t-if="o.date_due and o.type == 'out_invoice' and (o.state == 'open' or o.state == 'paid')" name="due_date">
+ <div t-att-class="o_grid_layout" t-if="o.date_due and o.type == 'out_invoice' and (o.state == 'open' or o.state == 'paid')" name="due_date">
<strong>Due Date:</strong>
<p t-field="o.date_due"/>
</div>
- <div class="col-xs-2" t-if="o.origin" name="origin">
+ <div t-att-class="o_grid_layout" t-if="o.origin" name="origin">
<strong>Source:</strong>
<p t-field="o.origin"/>
</div>
- <div class="col-xs-2" t-if="o.partner_id.ref" name="customer_code">
+ <div t-att-class="o_grid_layout" t-if="o.partner_id.ref" name="customer_code">
<strong>Customer Code:</strong>
<p t-field="o.partner_id.ref"/>
</div>
- <div name="reference" class="col-xs-2" t-if="o.reference">
+ <div name="reference" t-att-class="o_grid_layout" t-if="o.reference">
<strong>Reference:</strong>
<p t-field="o.reference"/>
</div>
@@ -57,8 +60,43 @@
<!-- if Rounding Method is computed per line -->
<t t-set="display_taxamount"
t-value="o.company_id.tax_calculation_rounding_method == 'round_per_line'"/>
+ <!-- HTML Preview for mobile responsive -->
+ <div t-if="type_html" id="invoice_line" class="row mr0 ml0 visible-xs hidden-print">
+ <table class='table table-condensed'>
+ <colgroup>
+ <col width='50%' />
+ <col width='25%' />
+ <col width='25%' />
+ </colgroup>
+ <thead>
+ <tr>
+ <th>Description</th>
+ <th class="text-right">Quantity</th>
+ <th class="text-right">Amount</th>
+ </tr>
+ </thead>
+ <tr t-foreach="o.invoice_line_ids" t-as="line">
+ <td>
+ <span t-field="line.name"/>
+ <t t-if="display_discount">
+ <div>
+ With a <span t-field="l.discount"/>% discount
+ </div>
+ </t>
+ </td>
+ <td class="text-right">
+ <span t-field="line.quantity"/>
+ <span t-field="line.uom_id" groups="product.group_uom"/>
+ </td>
+ <td class="text-right">
+ <span t-field="line.price_subtotal"
+ t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
+ </td>
+ </tr>
+ </table>
+ </div>
- <table class="table table-condensed" name="invoice_line_table">
+ <table t-attf-class="table table-condensed #{'' if not type_html else 'hidden-xs'}" name="invoice_line_table">
<thead>
<tr>
<th>Description</th>
@@ -115,7 +153,7 @@
<div class="clearfix">
<div id="total" class="row">
- <div class="col-xs-4 pull-right">
+ <div t-attf-class="col-sm-4 pull-right #{'col-xs-4' if not type_html else ''}">
<table class="table table-condensed" style="min-width: 250px;max-width: 400px;">
<tr class="border-black" style="border-bottom:1px solid #dddddd;">
<td><strong>Subtotal</strong></td>
diff --git a/addons/account_payment/views/account_portal_templates.xml b/addons/account_payment/views/account_portal_templates.xml
index 36bab9558ea..3e97164577e 100644
--- a/addons/account_payment/views/account_portal_templates.xml
+++ b/addons/account_payment/views/account_portal_templates.xml
@@ -5,83 +5,101 @@
</xpath>
<xpath expr="//t[@t-foreach='invoices']/tr/td[last()]" position="before">
<td>
- <a t-if="invoice.state == 'open' and invoice.type == 'out_invoice'" t-att-href="'/my/invoices/%s#portal_pay' % invoice.id" alt="Pay Now" class="btn btn-xs btn-primary">
+ <t t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state in ('pending', 'authorized', 'done'))"/>
+ <t t-set="pending_manual_txs" t-value="tx_ids.filtered(lambda tx: tx.state == 'pending' and tx.acquirer_id.provider in ('transfer', 'manual'))"/>
+ <a t-if="invoice.state == 'open' and invoice.amount_total and invoice.type == 'out_invoice' and (pending_manual_txs or not tx_ids)"
+ t-att-href="'/my/invoices/%s#portal_pay' % invoice.id" alt="Pay Now" class="btn btn-xs btn-primary">
<i class="fa fa-arrow-circle-right"/><span class='hidden-xs'> Pay Now</span>
</a>
</td>
</xpath>
+ <xpath expr="//t[@t-foreach='invoices']/tr/td[hasclass('tx_status')]" position="replace">
+ <t t-set="last_tx" t-value="invoice.get_portal_last_transaction()"/>
+ <td class="tx_status">
+ <t t-if="invoice.state == 'open' and (last_tx.state not in ['pending', 'authorized', 'done', 'cancel'] or (last_tx.state == 'pending' and last_tx.acquirer_id.provider in ('transfer', 'manual')))">
+ <span class="label label-info"><i class="fa fa-fw fa-clock-o"></i><span class="hidden-xs"> Waiting for Payment</span></span>
+ </t>
+ <t t-if="invoice.state == 'open' and last_tx.state == 'authorized'">
+ <span class="label label-success"><i class="fa fa-fw fa-check"/><span class="hidden-xs"> Authorized</span></span>
+ </t>
+ <t t-if="invoice.state == 'open' and last_tx.state == 'pending' and last_tx.acquirer_id.provider not in ('transfer', 'manual')">
+ <span class="label label-warning"><span class="hidden-xs"> Pending</span></span>
+ </t>
+ <t t-if="invoice.state == 'paid' or last_tx.state == 'done'">
+ <span class="label label-default"><i class="fa fa-fw fa-check"></i><span class="hidden-xs"> Paid</span></span>
+ </t>
+ <t t-if="invoice.state == 'cancel'">
+ <span class="label label-default"><i class="fa fa-fw fa-remove"></i><span class="hidden-xs"> Cancelled</span></span>
+ </t>
+ </td>
+ </xpath>
+ </template>
+
+ <template id="portal_invoice_payment" name="Invoice Payment">
+ <div class="row" t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total" id="portal_pay">
+ <div class="modal fade" id="pay_with" role="dialog" aria-hidden="true">
+ <div class="modal-dialog modal-content">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&amp;times;</button>
+ <h3 class="modal-title">Pay with</h3>
+ </div>
+ <div class="modal-footer">
+ <div t-if="pms or s2s_acquirers or form_acquirers" id="payment_method" class="text-left col-md-13">
+ <t t-call="payment.payment_tokens_list">
+ <t t-set="mode" t-value="'payment'"/>
+ <t t-set="partner_id" t-value="invoice.partner_id.id"/>
+ <t t-set="success_url" t-value="'/my/invoices/%s?%s' % (invoice.id, keep_query())"/>
+ <t t-set="error_url" t-value="'/my/invoices/%s?%s' % (invoice.id, keep_query())"/>
+ <t t-set="access_token" t-value="access_token or ''"/>
+ <t t-set="callback_method" t-value="''"/>
+ <t t-set="form_action" t-value="'/invoice/pay/' + str(invoice.id) + '/s2s_token_tx/'"/>
+ <t t-set="prepare_tx_url" t-value="'/invoice/pay/' + str(invoice.id) + '/form_tx/'"/>
+ <t t-set="submit_txt" t-value="'Pay Now'"/>
+ <t t-set="icon_class" t-value="'fa-lock'"/>
+ </t>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
</template>
<template id="portal_invoice_page_inherit_payment" name="Payment on My Invoices" inherit_id="account.portal_invoice_page">
- <xpath expr="//div[@id='o_portal_account_actions']/a" position="before">
+ <xpath expr="//div[@id='sidebar_content']//div[hasclass('o_download_pdf')]" position="before">
<t t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state in ('pending', 'authorized', 'done'))"/>
- <a t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total"
- class="btn btn-primary pull-right ml8" href="#portal_pay">
- <i class="fa fa-arrow-circle-right"/> Pay Now
- </a>
- <a t-if="tx_ids and invoice.state != 'paid'"
- class="btn btn-warning ml8 pull-right" disabled="disabled">
- <i class="fa fa-check-circle"/> Pending
- </a>
- <a t-if="tx_ids and invoice.state == 'paid'"
- class="btn btn-success ml8 pull-right" disabled="disabled">
- <i class="fa fa-check-circle"/> Paid
- </a>
+ <t t-set="pending_manual_txs" t-value="tx_ids.filtered(lambda tx: tx.state == 'pending' and tx.acquirer_id.provider in ('transfer', 'manual'))"/>
+ <div class="mb8 ml16 mr16">
+ <a t-if="invoice.state == 'open' and invoice.amount_total and invoice.type == 'out_invoice' and (pending_manual_txs or not tx_ids)"
+ class="btn btn-primary btn-block" data-toggle="modal" data-target="#pay_with">
+ <i class="fa fa-arrow-circle-right"/> Pay Now
+ </a>
+ <a t-if="tx_ids and not pending_manual_txs and invoice.state != 'paid'"
+ class="btn btn-warning btn-block" disabled="disabled">
+ <i class="fa fa-check-circle"/> Pending
+ </a>
+ <a t-if="invoice.state == 'paid'"
+ class="btn btn-success btn-block" disabled="disabled">
+ <i class="fa fa-check-circle"/> Paid
+ </a>
+ </div>
</xpath>
- <xpath expr="//t[@t-call='account.portal_invoice_success']" position="after">
+ <xpath expr="//div[@id='invoice_content']//div[hasclass('o_portal_html_view')]" position="before">
<div t-if="invoice.transaction_ids and invoice.amount_total and not success and not error" class="o_account_payment_tx_status" t-att-data-invoice-id="invoice.id">
<t t-call="payment.payment_confirmation_status">
<t t-set="payment_tx_id" t-value="invoice.get_portal_last_transaction()"/>
</t>
</div>
- </xpath>
- <xpath expr="//div[hasclass('panel-body')]" position="after">
- <div class="panel-body" t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total" id="portal_pay">
- <div t-if="pms or s2s_acquirers or form_acquirers" id="payment_method" class="col-md-offset-3 col-md-6">
- <h4 class="mb24">Pay with</h4>
- <t t-call="payment.payment_tokens_list">
- <t t-set="mode" t-value="'payment'"/>
- <t t-set="partner_id" t-value="invoice.partner_id.id"/>
- <t t-set="success_url" t-value="'/my/invoices/%s%s' % (invoice.id, ('?access_token=%s' % (access_token)) if access_token else '')"/>
- <t t-set="error_url" t-value="'/my/invoices/%s%s' % (invoice.id, ('?access_token=%s' % (access_token)) if access_token else '')"/>
- <t t-set="access_token" t-value="access_token or ''"/>
- <t t-set="callback_method" t-value="''"/>
- <t t-set="form_action" t-value="'/invoice/pay/' + str(invoice.id) + '/s2s_token_tx/'"/>
- <t t-set="prepare_tx_url" t-value="'/invoice/pay/' + str(invoice.id) + '/form_tx/'"/>
- <t t-set="submit_txt" t-value="'Pay Now'"/>
- <t t-set="icon_class" t-value="'fa-lock'"/>
- </t>
+ <t t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state in ('authorized', 'done'))"/>
+ <div t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total" id="portal_pay">
+ <div t-if="pms or s2s_acquirers or form_acquirers" id="payment_method">
+ <t t-call="account_payment.portal_invoice_payment"/>
</div>
</div>
</xpath>
</template>
- <template id="portal_invoice_report" name="Invoice portal page inherit payment" inherit_id="account.portal_invoice_report">
- <xpath expr="//div[@name='customer_address']" position="after">
- <t t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state != 'draft')"/>
- <t t-if="tx_ids">
- <div>
- <strong>Transactions</strong>
- </div>
- <div>
- <t t-foreach="tx_ids" t-as="tx">
- <div>
- <span t-esc="tx.reference"/>
- <span class="text-muted" t-field="tx.create_date"/>
- <t t-if="tx.state == 'done'">
- <span class="label label-success orders_label_text_align"><i class="fa fa-fw fa-check"/> Done</span>
- </t>
- <t t-if="tx.state != 'done'">
- <span class="label label-info orders_label_text_align"><i class="fa fa-fw fa-clock-o"/> Waiting</span>
- <t t-if="tx.state_message"><br /><span t-esc="tx.state_message"/></t>
- </t>
- </div>
- </t>
- </div>
- </t>
- </xpath>
- </template>
-
<template id="portal_invoice_error" name="Invoice error display: payment errors"
inherit_id="account.portal_invoice_error">
<xpath expr="//t[@name='generic']" position="after">
@@ -112,6 +130,9 @@
<span t-if='payment_tx_id.acquirer_id.done_msg' t-raw="payment_tx_id.acquirer_id.done_msg"/>
<span t-if='payment_tx_id.acquirer_id.post_msg' t-raw="payment_tx_id.acquirer_id.post_msg"/>
</t>
+ <t t-if="success == 'pay_invoice' and invoice.state == 'paid' and not invoice.payment_acquirer_id">
+ Done, your online payment has been successfully processed. Thank you for your order.
+ </t>
</xpath>
</template>
</odoo>
diff --git a/addons/l10n_in/views/report_invoice.xml b/addons/l10n_in/views/report_invoice.xml
index 7fb7337becf..29ea050ca0c 100644
--- a/addons/l10n_in/views/report_invoice.xml
+++ b/addons/l10n_in/views/report_invoice.xml
@@ -26,7 +26,7 @@
</t>
</xpath>
<xpath expr="//table[@name='invoice_line_table']" position="replace">
- <table class="table table-condensed" name="invoice_line_table">
+ <table t-attf-class="table table-condensed #{'' if not type_html else 'hidden-xs'}" name="invoice_line_table">
<thead>
<tr>
<th>Description</th>
diff --git a/addons/l10n_in_sale/views/report_invoice_view.xml b/addons/l10n_in_sale/views/report_invoice_view.xml
index fc7de168ad4..bda24541673 100644
--- a/addons/l10n_in_sale/views/report_invoice_view.xml
+++ b/addons/l10n_in_sale/views/report_invoice_view.xml
@@ -4,7 +4,7 @@
<template id="gst_report_invoice_layouted_inherit" inherit_id="sale.report_invoice_layouted">
<xpath expr="//t[@name='lines_layouted']" position="replace">
<t groups="sale.group_sale_layout" t-foreach="o.order_lines_layouted()" t-as="page" name="lines_layouted">
- <table class="table table-condensed">
+ <table t-attf-class="table table-condensed #{'' if not type_html else 'hidden-xs'}">
<thead>
<th>Description</th>
<th class="text-right">Quantity</th>
diff --git a/addons/payment/models/account_invoice.py b/addons/payment/models/account_invoice.py
index 490ebd58cdf..54d9f9099b0 100644
--- a/addons/payment/models/account_invoice.py
+++ b/addons/payment/models/account_invoice.py
@@ -75,7 +75,7 @@ class AccountInvoice(models.Model):
vals['acquirer_id'] = acquirer.id
vals.update({
- 'amount': sum(self.mapped('amount_total')),
+ 'amount': sum(self.mapped('residual')),
'currency_id': currency.id,
'partner_id': partner.id,
'invoice_ids': [(6, 0, self.ids)],
diff --git a/addons/payment/views/payment_portal_templates.xml b/addons/payment/views/payment_portal_templates.xml
index cfa0ac19269..1cb4873d524 100644
--- a/addons/payment/views/payment_portal_templates.xml
+++ b/addons/payment/views/payment_portal_templates.xml
@@ -118,20 +118,22 @@
To be called with the 'payment_tx_id' value.
-->
+ <t t-set="thanks_msg" t-value="payment_tx_id.acquirer_id.post_msg"/>
+ <t t-set="thanks_msg" t-value="thanks_msg and thanks_msg != '&lt;p&gt;&lt;br&gt;&lt;/p&gt;' and thanks_msg"/>
<div t-if="payment_tx_id and payment_tx_id.state == 'pending'" class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&amp;times;</button>
<span t-if='payment_tx_id.acquirer_id.pending_msg' t-raw="payment_tx_id.acquirer_id.pending_msg"/>
- <span t-if='payment_tx_id.acquirer_id.post_msg' t-raw="payment_tx_id.acquirer_id.post_msg"/>
+ <span t-if='thanks_msg' t-raw="thanks_msg"/>
</div>
<div t-if="payment_tx_id and payment_tx_id.state == 'authorized'" class="alert alert-success alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&amp;times;</button>
Your payment has been authorized.
- <span t-if='payment_tx_id.acquirer_id.post_msg' t-raw="payment_tx_id.acquirer_id.post_msg"/>
+ <span t-if='thanks_msg' t-raw="thanks_msg"/>
</div>
<div t-if="payment_tx_id and payment_tx_id.state == 'done'" class="alert alert-success alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&amp;times;</button>
<span t-if='payment_tx_id.acquirer_id.done_msg' t-raw="payment_tx_id.acquirer_id.done_msg"/>
- <span t-if='payment_tx_id.acquirer_id.post_msg' t-raw="payment_tx_id.acquirer_id.post_msg"/>
+ <span t-if='thanks_msg' t-raw="thanks_msg"/>
</div>
<div t-if="payment_tx_id and payment_tx_id.state == 'cancel'" class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&amp;times;</button>
diff --git a/addons/portal/static/src/js/portal_sidebar.js b/addons/portal/static/src/js/portal_sidebar.js
new file mode 100644
index 00000000000..937655d1d97
--- /dev/null
+++ b/addons/portal/static/src/js/portal_sidebar.js
@@ -0,0 +1,106 @@
+odoo.define('portal.PortalSidebar', function (require) {
+"use strict";
+
+var config = require('web.config');
+var core = require('web.core');
+var Widget = require('web.Widget');
+var time = require('web.time');
+
+var _t = core._t;
+
+var PortalSidebar = Widget.extend({
+ /**
+ * @override
+ */
+ start: function () {
+ var self = this;
+ this._super.apply(this, arguments);
+ // Window Handlers
+ $(window).on('resize', _.throttle(self._onUpdateSidebarPosition.bind(self), 200, {leading: false}));
+ this._onUpdateSidebarPosition();
+ this._setAffix();
+ this._setDelayLabel();
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //---------------------------------------------------------------------------
+
+ /**
+ * Set the due/delay information according to the given date
+ * like : <span class="o_portal_sidebar_timeago" t-att-datetime="invoice.date_due"/>
+ * @private
+ */
+ _setDelayLabel : function () {
+ var $sidebarTimeago = this.$el.find('.o_portal_sidebar_timeago');
+ _.each($sidebarTimeago, function (el) {
+ var dateTime = moment(time.auto_str_to_date($(el).attr('datetime'))),
+ today = moment().startOf('day'),
+ diff = dateTime.diff(today, 'days', true),
+ displayStr;
+
+ if (diff === 0){
+ displayStr = _t('Due today');
+ } else if (diff > 0) {
+ displayStr = _.str.sprintf(_t('Due in %d days'), Math.abs(diff));
+ } else {
+ displayStr = _.str.sprintf(_t('%d days overdue'), Math.abs(diff));
+ }
+ $(el).text(displayStr);
+ });
+ },
+ /**
+ * updates affix status of sidebar for window scrolle
+ *
+ * @private
+ */
+ _setAffix : function () {
+ var $bsSidebar = this.$el.find('.bs-sidebar');
+ $bsSidebar.affix({
+ offset: {
+ top: 0,
+ bottom: $('#wrapwrap').outerHeight() - $('main').height(),
+ },
+ });
+ },
+ /**
+ * @private
+ * @param {string} href
+ */
+ _printIframeContent: function (href) {
+ // due to this issue : https://bugzilla.mozilla.org/show_bug.cgi?id=911444
+ // open a new window with pdf for print in Firefox (in other system: http://printjs.crabbly.com)
+ if ($.browser.mozilla) {
+ window.open(href, '_blank');
+ return ;
+ }
+ if (!this.printContent) {
+ this.printContent = $('<iframe id="print_iframe_content" src="'+ href +'" style="display:none"></iframe>');
+ this.$el.append(this.printContent);
+ this.printContent.on('load', function () {
+ $(this).get(0).contentWindow.print();
+ });
+ } else {
+ this.printContent.get(0).contentWindow.print();
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called when the window is resized or on loadoing widget
+ *
+ * @private
+ */
+ _onUpdateSidebarPosition: function () {
+ var $sidebar = this.$el.find('.bs-sidebar, .o_portal_brand');
+ $sidebar.css({
+ position: config.device.size_class >= config.device.SIZES.MD ? "fixed" : '',
+ width: config.device.size_class >= config.device.SIZES.MD ? $sidebar.outerWidth() : '',
+ });
+ },
+});
+return PortalSidebar;
+});
diff --git a/addons/portal/static/src/scss/portal.scss b/addons/portal/static/src/scss/portal.scss
index b49f50189c6..9a53d163936 100644
--- a/addons/portal/static/src/scss/portal.scss
+++ b/addons/portal/static/src/scss/portal.scss
@@ -255,10 +255,15 @@ img.o_we_custom_image {
// Portal specific
.o_portal {
.breadcrumb {
+ background-color: rgba(0, 0, 0, 0);
margin-bottom: 0px;
display: inline-block;
}
+ .record_pager {
+ padding: 8px 0px;
+ }
+
> tbody.o_portal_report_tbody {
vertical-align: middle;
}
@@ -392,3 +397,21 @@ img.o_we_custom_image {
.label-optional {
font-weight: normal;
}
+
+.o_portal_sidebar {
+ .bs-sidebar {
+ position: relative;
+ width: 100%;
+ border-radius: 5px;
+ background-color: $navbar-default-bg;
+ }
+ .o_portal_contact_img {
+ width: 3.7em;
+ height: 3.7em;
+ }
+ .o_portal_html_view {
+ border: 1px solid $gray-lighter-dark;
+ border-radius: 5px;
+ padding-right: 1px;
+ }
+}
diff --git a/addons/portal/static/src/xml/portal_chatter.xml b/addons/portal/static/src/xml/portal_chatter.xml
index 71a7088c3cc..7ff4c1acfd2 100644
--- a/addons/portal/static/src/xml/portal_chatter.xml
+++ b/addons/portal/static/src/xml/portal_chatter.xml
@@ -4,7 +4,8 @@
<t t-set="count" t-value="widget.get('message_count')"/>
<div class="o_message_counter">
<t t-if="count">
- <span class="o_message_count fa fa-comments"> <t t-esc="count"/></span>
+ <span class="fa fa-comments" />
+ <span class="o_message_count"> <t t-esc="count"/></span>
<t t-if="count == 1">comment</t>
<t t-else="">comments</t>
</t>
diff --git a/addons/portal/views/assets.xml b/addons/portal/views/assets.xml
index 44af4db1950..15a3de3d775 100644
--- a/addons/portal/views/assets.xml
+++ b/addons/portal/views/assets.xml
@@ -10,6 +10,7 @@
<script type="text/javascript" src="/portal/static/src/js/portal_tour.js"></script>
<script type="text/javascript" src="/portal/static/src/js/portal_chatter.js"></script>
<script type="text/javascript" src="/portal/static/src/js/portal_signature.js"></script>
+ <script type="text/javascript" src="/portal/static/src/js/portal_sidebar.js"></script>
</xpath>
</template>
diff --git a/addons/portal/views/portal_templates.xml b/addons/portal/views/portal_templates.xml
index 9522a1fcda4..b9d3c4b0707 100644
--- a/addons/portal/views/portal_templates.xml
+++ b/addons/portal/views/portal_templates.xml
@@ -57,7 +57,10 @@
<t t-raw="0"/>
</main>
<footer >
- <div id="footer">
+ <div class="container mt16 mb16" id="footer">
+ <div class="pull-right" t-ignore="true" t-if="not editable">
+ Powered by <a target="_blank" href="http://www.odoo.com">Odoo</a>
+ </div>
</div>
</footer>
</div>
@@ -69,11 +72,12 @@
<div class="container mt16 mb16 o_portal">
<div class="oe_structure">
<div t-if="not no_breadcrumbs" class="row">
- <div class="col-sm-12">
- <ol class="breadcrumb o_portal_submenu">
+ <div t-attf-class="col-sm-12">
+ <ol t-if="page_name != 'home'" class="breadcrumb o_portal_submenu">
<li><a href="/my/home"><i class="fa fa-home"/></a></li>
<li t-if="page_name == 'my_details'">Your Details</li>
</ol>
+ <t t-call='portal.record_pager'/>
</div>
</div>
</div>
@@ -412,4 +416,13 @@
t-att-data-sign-label="signLabel"
t-att-data-access-token="accessToken"/>
</template>
+
+ <template id="portal_sidebar" name="Sidebar">
+ <t t-call="portal.portal_layout">
+ <body data-spy="scroll" data-target=".navspy" data-offset="50">
+ <div class="container o_portal_sidebar"></div>
+ <div class="oe_structure mb32"/>
+ </body>
+ </t>
+ </template>
</odoo>
diff --git a/addons/project/views/project_portal_templates.xml b/addons/project/views/project_portal_templates.xml
index 02f4435e21f..391f46b38a7 100644
--- a/addons/project/views/project_portal_templates.xml
+++ b/addons/project/views/project_portal_templates.xml
@@ -78,7 +78,6 @@
<div class="row">
<div class="col-md-12">
<h4>
- <t t-call='portal.record_pager'/>
Project - <span t-field="project.name"/>
</h4>
</div>
@@ -169,7 +168,6 @@
<div class="row">
<div class="col-md-12">
<h4>
- <t t-call='portal.record_pager'/>
Task - <span t-field="task.name"/> (#<span t-esc="task.id"/>)
<span t-field="task.stage_id.name" class="pull-right label label-info" title="Current stage of this task"/>
<a class="btn btn-info" t-att-href="'/web#return_label=Website&amp;model=project.task&amp;id=%s&amp;view_type=form' % (task.id)" groups="project.group_project_user">Edit Task</a>
diff --git a/addons/purchase/views/portal_templates.xml b/addons/purchase/views/portal_templates.xml
index ee6190304ce..7e23f335940 100644
--- a/addons/purchase/views/portal_templates.xml
+++ b/addons/purchase/views/portal_templates.xml
@@ -73,7 +73,6 @@
<div class="row">
<div class="col-md-12">
<h4>
- <t t-call='portal.record_pager'/>
Purchase Order
<span t-esc="order.name"/>
</h4>
diff --git a/addons/sale/report/invoice_report_templates.xml b/addons/sale/report/invoice_report_templates.xml
index e7a3598ce0d..9fbc3ab8b66 100644
--- a/addons/sale/report/invoice_report_templates.xml
+++ b/addons/sale/report/invoice_report_templates.xml
@@ -9,12 +9,75 @@
<span t-field="l.price_total" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
</xpath>
- <xpath expr="//table" position="attributes">
+ <xpath expr="//table[@name='invoice_line_table']" position="attributes">
<attribute name="groups">!sale.group_sale_layout</attribute>
</xpath>
- <xpath expr="//table" position="after">
+ <xpath expr="//div[@id='invoice_line']/table" position="attributes">
+ <attribute name="groups">!sale.group_sale_layout</attribute>
+ </xpath>
+ <xpath expr="//div[@id='invoice_line']/table" position="after">
+ <t groups="sale.group_sale_layout" t-foreach="o.order_lines_layouted()" t-as="page" name="mobile_lines_layouted">
+ <!-- HTML Preview with order line section for mobile responsive -->
+ <div t-if="type_html" class="row mr0 ml0 visible-xs hidden-print">
+ <table class='table table-condensed'>
+ <colgroup>
+ <col width='50%' />
+ <col width='25%' />
+ <col width='25%' />
+ </colgroup>
+ <thead>
+ <tr>
+ <th>Description</th>
+ <th class="text-right">Quantity</th>
+ <th class="text-right">Price</th>
+ </tr>
+ </thead>
+ <t t-foreach="page" t-as="layout_sections">
+ <t t-if="layout_sections_size > 1 or page_size > 1" groups="sale.group_sale_layout">
+ <tr class="active">
+ <td colspan="7" style="font-weight: bold; border-bottom: 1px solid black;">&amp;bull;
+ <t t-esc="layout_sections['name']"/>
+ </td>
+ </tr>
+ </t>
+ <!-- Lines associated -->
+ <t t-foreach="layout_sections['lines']" t-as="line">
+ <tr>
+ <td>
+ <span t-field="line.name"/>
+ <t t-if="display_discount">
+ <div>
+ With a <span t-field="l.discount"/>% discount
+ </div>
+ </t>
+ </td>
+ <td class="text-right">
+ <span t-field="line.quantity"/>
+ <span t-field="line.uom_id" groups="product.group_uom"/>
+ </td>
+ <td class="text-right">
+ <span t-field="line.price_subtotal"
+ t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
+ </td>
+ </tr>
+ <t t-if="(layout_sections_size > 1 or page_size > 1) and layout_sections['subtotal']" groups="sale.group_sale_layout">
+ <tr class="text-right">
+ <td colspan="3">
+ <strong>Subtotal: </strong>
+ <t t-set="subtotal" t-value="sum(line.price_subtotal for line in layout_sections['lines'])"/>
+ <span t-esc="subtotal" t-options="{'widget': 'monetary', 'display_currency': o.currency_id}"/>
+ </td>
+ </tr>
+ </t>
+ </t>
+ </t>
+ </table>
+ </div>
+ </t>
+ </xpath>
+ <xpath expr="//table[@name='invoice_line_table']" position="after">
<t groups="sale.group_sale_layout" t-foreach="o.order_lines_layouted()" t-as="page" name="lines_layouted">
- <table class="table table-condensed">
+ <table t-attf-class="table table-condensed #{'' if not type_html else 'hidden-xs'}">
<thead>
<tr>
<th>Description</th>
diff --git a/addons/sale/views/sale_portal_templates.xml b/addons/sale/views/sale_portal_templates.xml
index 27a3da7516f..08441e9d6c5 100644
--- a/addons/sale/views/sale_portal_templates.xml
+++ b/addons/sale/views/sale_portal_templates.xml
@@ -134,7 +134,6 @@
<div class="row">
<div class="col-md-6 col-xs-9 col-sm-9">
<h4>
- <t t-call='portal.record_pager'/>
<t t-if="order.state in ('sent', 'cancel')">Quotation</t>
<t t-else="">Order</t>
<span t-esc="order.name"/>
diff --git a/addons/sale_stock/views/account_invoice_views.xml b/addons/sale_stock/views/account_invoice_views.xml
index b04ec1bf759..ed8e07b1a54 100644
--- a/addons/sale_stock/views/account_invoice_views.xml
+++ b/addons/sale_stock/views/account_invoice_views.xml
@@ -14,8 +14,9 @@
</record>
<template id="report_invoice_document_inherit_sale_stock" inherit_id="account.report_invoice_document">
+ <!-- HTML Preview for mobile responsive -->
<xpath expr="//div[@name='reference']" position="after">
- <div class="col-xs-2" t-if="o.incoterms_id" groups="sale_stock.group_display_incoterm">
+ <div t-att-class="o_grid_layout" t-if="o.incoterms_id" groups="sale_stock.group_display_incoterm">
<strong>Incoterms:</strong>
<p t-field="o.incoterms_id.code"/>
</div>
diff --git a/addons/web/static/src/scss/layout_boxed.scss b/addons/web/static/src/scss/layout_boxed.scss
index f3aa7601107..fae631cda6a 100644
--- a/addons/web/static/src/scss/layout_boxed.scss
+++ b/addons/web/static/src/scss/layout_boxed.scss
@@ -15,6 +15,7 @@
}
}
.o_boxed_footer {
+ margin-top: 200px;
white-space: nowrap;
border-top: 3px solid $gray;
ul {
diff --git a/addons/web/static/src/scss/layout_clean.scss b/addons/web/static/src/scss/layout_clean.scss
index ecbdb02153f..03ce4c993b9 100644
--- a/addons/web/static/src/scss/layout_clean.scss
+++ b/addons/web/static/src/scss/layout_clean.scss
@@ -3,6 +3,7 @@
color: #000;
}
.o_clean_header {
+ border-bottom: 1px solid $o-brand-primary;
img {
max-height: 90px;
max-width: 300px;
@@ -10,6 +11,7 @@
}
.o_clean_footer {
margin: 0 3px;
+ margin-top: 200px;
border-top: 3px solid $o-brand-primary;
h4 {
color: $o-brand-primary;
diff --git a/addons/web/static/src/scss/layout_standard.scss b/addons/web/static/src/scss/layout_standard.scss
new file mode 100644
index 00000000000..acc0e07bf1c
--- /dev/null
+++ b/addons/web/static/src/scss/layout_standard.scss
@@ -0,0 +1,3 @@
+.o_standard_footer {
+ margin-top: 200px;
+}
diff --git a/addons/web/views/report_templates.xml b/addons/web/views/report_templates.xml
index 9347dff1c07..5c08be5df9f 100644
--- a/addons/web/views/report_templates.xml
+++ b/addons/web/views/report_templates.xml
@@ -19,10 +19,13 @@
<link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet" type="text/css"/>
+
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/report.scss"/>
+ <link rel="stylesheet" type="text/scss" href="/web/static/src/scss/layout_standard.scss"/>
<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"/>
+
</template>
<template id="report_assets_pdf">
@@ -173,7 +176,7 @@
<li t-if="company.vat"><i class="fa fa-building-o"/><t t-esc="company.country_id.vat_label or 'TIN'"/>: <span t-field="company.vat"/></li>
</ul>
<div t-field="company.report_footer"/>
- <div class="text-muted">
+ <div t-if="not type_html" class="text-muted">
Page:
<span class="page"/>
of
@@ -212,7 +215,7 @@
<li t-if="company.vat"><t t-esc="company.country_id.vat_label or 'TIN'"/>: <span t-field="company.vat"/></li>
</ul>
<div t-field="company.report_footer"/>
- <div>
+ <div t-if="not type_html">
Page: <span class="page"/> / <span class="topage"/>
</div>
</div>
@@ -254,7 +257,7 @@
<h4 class="mt0 mb0 text-uppercase" t-field="company.report_header"/>
</div>
<div class="col-xs-1">
- <ul class="list-inline pagenumber pull-right text-center">
+ <ul t-if="not type_html" class="list-inline pagenumber pull-right text-center">
<li><strong><span class="page"/></strong></li>
</ul>
</div>
@@ -288,7 +291,7 @@
<t t-raw="0" />
</div>
- <div class="footer">
+ <div class="footer o_standard_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>
@@ -301,7 +304,7 @@
<span t-field="company.report_footer"/>
</div>
- <div class="text-muted">
+ <div t-if="not type_html" class="text-muted">
Page: <span class="page"/> / <span class="topage"/>
</div>
</div>
diff --git a/addons/website_quote/views/website_quote_templates.xml b/addons/website_quote/views/website_quote_templates.xml
index 1c033d59867..52f63e3faaa 100644
--- a/addons/website_quote/views/website_quote_templates.xml
+++ b/addons/website_quote/views/website_quote_templates.xml
@@ -451,9 +451,6 @@
<li>
<a class="btn btn-info" target="_blank" t-att-href="'/quote/%s/%s' % (quotation.id,quotation.access_token)+'?pdf=True'">Print</a>
</li>
- <li>
- <t t-call='portal.record_pager'/>
- </li>
</ul>
</div>
</h1>