[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:
@@ -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')
|
||||
|
||||
@@ -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>)
|
||||
|
||||
@@ -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>&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) > 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>
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user