[IMP] account: add invoice page view on customer portal

This commit adds a page view for invoices on the customer portal. Layout
is based on the invoice report to closely match what is already done in
Odoo. It replaces the old controller that returned only the pdf.
Customers should now be able to receive both.

Future commits will improve invoice page view notably in account_payment
while adding payment options in account customer portal.
This commit is contained in:
Thibault Delavallée
2017-08-25 15:33:18 +02:00
parent 6f39672eb6
commit 6c7e128b33
5 changed files with 230 additions and 7 deletions
+17 -1
View File
@@ -79,7 +79,23 @@ class PortalAccount(CustomerPortal):
return request.render("account.portal_my_invoices", values)
@http.route(['/my/invoices/<int:invoice_id>'], type='http', auth="public", website=True)
def portal_my_invoices_report(self, invoice_id, access_token=None, **kw):
def portal_my_invoice_detail(self, invoice_id, access_token=None, **kw):
invoice = request.env['account.invoice'].browse(invoice_id)
try:
invoice.check_access_rights('read')
invoice.check_access_rule('read')
except AccessError:
if not access_token or not consteq(invoice.sudo().access_token, access_token):
return request.redirect('/my')
values = {
'page_name': 'invoice',
'invoice': invoice.sudo(),
}
return request.render("account.portal_invoice_page", values)
@http.route(['/my/invoices/pdf/<int:invoice_id>'], type='http', auth="public", website=True)
def portal_my_invoice_report(self, invoice_id, access_token=None, **kw):
invoice = request.env['account.invoice'].browse(invoice_id)
try:
invoice.check_access_rights('read')
+1 -1
View File
@@ -20,7 +20,7 @@
<p>Dear ${object.partner_id.name}
% set access_action = object.with_context(force_website=True).get_access_action()
% set is_online = access_action and access_action['type'] == 'ir.actions.act_url'
% set access_url = is_online and object.get_mail_url() or '/report/pdf/account.report_invoice/' + str(object.id)
% set access_url = object.get_mail_url()
% if object.partner_id.parent_id:
(<i>${object.partner_id.parent_id.name}</i>)
+11 -2
View File
@@ -748,11 +748,19 @@ class AccountInvoice(models.Model):
try:
record.check_access_rule('read')
except exceptions.AccessError:
pass
if self.env.context.get('force_website'):
return {
'type': 'ir.actions.act_url',
'url': '/my/invoices/%s' % self.id,
'target': 'self',
'res_id': self.id,
}
else:
pass
else:
return {
'type': 'ir.actions.act_url',
'url': '/my/invoices?', # No controller /my/invoices/<int>, only a report pdf
'url': '/my/invoices/%s?access_token=%s' % (self.id, self.access_token),
'target': 'self',
'res_id': self.id,
}
@@ -1394,6 +1402,7 @@ class AccountInvoiceLine(models.Model):
ondelete='set null', index=True, oldname='uos_id')
product_id = fields.Many2one('product.product', string='Product',
ondelete='restrict', index=True)
product_image = fields.Binary('Product Image', related="product_id.image", store=False)
account_id = fields.Many2one('account.account', string='Account',
required=True, domain=[('deprecated', '=', False)],
default=_default_account,
@@ -4,6 +4,9 @@
<li t-if="page_name == 'invoice'" class="active">
Invoices
</li>
<li t-if="invoice">
<t t-esc="invoice.number"/>
</li>
</xpath>
</template>
@@ -38,7 +41,7 @@
<t t-foreach="invoices" t-as="invoice">
<tr>
<td>
<a t-att-href="'/my/invoices/'+str(invoice.id)" t-att-title="invoice.number"><t t-esc="invoice.number"/></a>
<a t-attf-href="/my/invoices/#{invoice.id}" t-att-title="invoice.number"><t t-esc="invoice.number"/></a>
</td>
<td><span t-field="invoice.date_invoice"/></td>
<td class='hidden-xs'><span t-field="invoice.date_due"/></td>
@@ -63,4 +66,199 @@
</div>
</t>
</template>
</odoo>
<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'/>
Invoice
<span t-esc="invoice.number"/>
</h4>
</div>
<div class="col-md-6 col-sm-6 col-xs-12 hidden-print" id="action_buttons">
<ul class="list-inline pull-right">
<li class="o_download_button">
<a target="_blank" t-att-href="'/my/invoices/pdf/%s' % invoice.id" title="Download">
<i class="fa fa-download fa-2x" aria-hidden="true"/>
</a>
</li>
<li class="o_print_button">
<a id="print_iframe" title="Print">
<i class="fa fa-print fa-2x" aria-hidden="true"/>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="panel-body">
<t t-call="account.portal_invoice_report"/>
</div>
</div>
</div>
<div class="oe_structure mb32"/>
</t>
</template>
<template id="portal_invoice_report" name="Invoice Portal Report">
<div class="row">
<div class="col-xs-5 col-xs-offset-7">
<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>
<h2>
<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"/>
</h2>
<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="product.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>&amp;nbsp;</td>
<td class="hidden"></td>
<td></td>
<td></td>
<td t-if="display_discount" groups="sale.group_discount_per_so_line"></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>
</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>
</template>
</odoo>
@@ -1,7 +1,7 @@
<odoo>
<template id="portal_my_invoices_payment" name="Payment on My Invoices" inherit_id="account.portal_my_invoices">
<xpath expr="//table[hasclass('o_portal_my_doc_table')]/thead/tr/th[last()]" position="before">
<th></th>
<th>Status</th>
</xpath>
<xpath expr="//t[@t-foreach='invoices']/tr/td[last()]" position="before">
<td>