[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'. -- Add margin after the header and before the footer to look like the real printed document, without alterating the real printed version Task ID: 39876
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
# -*- 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.exceptions import AccessError
|
||||
@@ -113,9 +116,14 @@ class PortalAccount(CustomerPortal):
|
||||
return request.redirect('/my')
|
||||
|
||||
values = self._invoice_get_page_view_values(invoice_sudo, access_token, **kw)
|
||||
# force to hide orginal breadcrumbs if we have access_token or not
|
||||
values['no_breadcrumbs'] = True
|
||||
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 +132,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,58 @@
|
||||
odoo.define('account.AccountPortalSidebar', function (require) {
|
||||
"use strict";
|
||||
|
||||
require('web.dom_ready');
|
||||
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);
|
||||
},
|
||||
});
|
||||
|
||||
$(function () {
|
||||
if (!$('.o_portal_invoice_sidebar').length) {
|
||||
return $.Deferred().reject("DOM doesn't contain '.o_portal_invoice_sidebar'");
|
||||
}
|
||||
var account_portal_sidebar = new AccountPortalSidebar();
|
||||
account_portal_sidebar.attachTo($('.o_portal_invoice_sidebar'));
|
||||
});
|
||||
|
||||
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 id="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,81 @@
|
||||
</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 col-sm-4 hidden-print">
|
||||
<ol class="breadcrumb o_portal_submenu">
|
||||
<li><a href="/my/home"><i class="fa fa-home"/></a></li>
|
||||
<li t-if="page_name == 'invoice'" class="active">
|
||||
<a t-if="invoice" t-attf-href="/my/invoices?{{ keep_query() }}">Invoices</a>
|
||||
<t t-else="">Invoices</t>
|
||||
</li>
|
||||
<li t-if="invoice">
|
||||
<t t-esc="invoice.number"/>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="bs-sidebar mb16" id="sidebar_content">
|
||||
<div class="text-center o_account_portal_sidebar">
|
||||
<h2><strong><span t-field="invoice.amount_total"/></strong></h2>
|
||||
<div class="mb4" t-if="invoice.state != 'paid'"><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 mb8 o_download_pdf">
|
||||
<a class="btn btn-default 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 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="mb8 ml16 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 col-sm-8 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,80 +5,106 @@
|
||||
</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 ('authorized', 'done'))"/>
|
||||
<a t-if="not tx_ids and 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">
|
||||
<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[@id='tx_status']" position="replace">
|
||||
<td id="tx_status">
|
||||
<t t-if="invoice.state == 'open' and invoice.get_portal_last_transaction().state not in ['authorized', 'done', 'cancel']">
|
||||
<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 invoice.get_portal_last_transaction().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 == 'paid' or invoice.get_portal_last_transaction().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">
|
||||
<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>
|
||||
<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 ('authorized', 'done'))"/>
|
||||
<div class="mb8 ml16 mr16">
|
||||
<a t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total"
|
||||
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 invoice.state == 'paid') or (not tx_ids and 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 t-set="tx_ids" t-value="invoice.transaction_ids.filtered(lambda tx: tx.state in ('pending','authorized', 'done'))"/>
|
||||
<div t-if="tx_ids" class="o_tx_status mb8">
|
||||
<strong>Transactions</strong>
|
||||
<br/>
|
||||
<t t-foreach="tx_ids" t-as="tx">
|
||||
<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>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="tx.state == 'authorized'">
|
||||
<span class="label label-success orders_label_text_align"><i class="fa fa-fw fa-check"/> Authorized</span>
|
||||
</t>
|
||||
<t t-if="tx.state not in ('done', 'authorized')">
|
||||
<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>
|
||||
</t>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
@@ -112,6 +138,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
}
|
||||
}
|
||||
.o_background_footer {
|
||||
margin-top: 200px;
|
||||
ul {
|
||||
border-top: 1px solid $o-brand-primary;
|
||||
border-bottom: 1px solid $o-brand-primary;
|
||||
@@ -34,7 +35,6 @@
|
||||
background-size: cover;
|
||||
background-position: bottom center;
|
||||
background-repeat: no-repeat;
|
||||
min-height: 900px;
|
||||
thead tr th, h2 {
|
||||
color: $o-brand-primary;
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user