[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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
</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>
|
||||
<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&print=true' % (invoice.id, keep_query())" id="print_invoice_report" title="Print"><i class="fa fa-print"/> Print</a>
|
||||
</div>
|
||||
</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>
|
||||
<template id="portal_invoice_chatter" name="Allow Comments & 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">&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>
|
||||
|
||||
<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">&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) > 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) > 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>
|
||||
</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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">&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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)],
|
||||
|
||||
@@ -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 != '<p><br></p>' 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">&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">&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">&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">&times;</button>
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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&model=project.task&id=%s&view_type=form' % (task.id)" groups="project.group_project_user">Edit Task</a>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;">&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>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
}
|
||||
}
|
||||
.o_boxed_footer {
|
||||
margin-top: 200px;
|
||||
white-space: nowrap;
|
||||
border-top: 3px solid $gray;
|
||||
ul {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.o_standard_footer {
|
||||
margin-top: 200px;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user