[MERGE] account: add invoice page view on customer portal
This merge adds a real view of invoices on customer portal. It is based on the invoice report layout and replaces the pdf-only support of current customer portal. Future commits will add payment means notably in invoice portal and therefore further enhance the feature. Closes #19015.
This commit is contained in:
@@ -2,10 +2,10 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import http, _
|
||||
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
|
||||
from odoo.tools import consteq
|
||||
|
||||
|
||||
class PortalAccount(CustomerPortal):
|
||||
@@ -23,6 +23,10 @@ class PortalAccount(CustomerPortal):
|
||||
values['invoice_count'] = invoice_count
|
||||
return values
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# My Invoices
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@http.route(['/my/invoices', '/my/invoices/page/<int:page>'], type='http', auth="user", website=True)
|
||||
def portal_my_invoices(self, page=1, date_begin=None, date_end=None, sortby=None, **kw):
|
||||
values = self._prepare_portal_layout_values()
|
||||
@@ -74,15 +78,31 @@ class PortalAccount(CustomerPortal):
|
||||
})
|
||||
return request.render("account.portal_my_invoices", values)
|
||||
|
||||
@http.route(['/my/invoices/<int:invoice_id>'], type='http', auth="user", website=True)
|
||||
def portal_my_invoices_report(self, invoice_id, **kw):
|
||||
@http.route(['/my/invoices/<int:invoice_id>'], type='http', auth="public", website=True)
|
||||
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')
|
||||
# TDE FIXME: does not exist, or maybe, don't know
|
||||
except AccessError:
|
||||
return request.redirect('/my')
|
||||
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')
|
||||
invoice.check_access_rule('read')
|
||||
except AccessError:
|
||||
if not access_token or not consteq(invoice.sudo().access_token, access_token):
|
||||
return request.redirect('/my')
|
||||
|
||||
# print report as sudo, since it require access to taxes, payment term, ... and portal
|
||||
# does not have those access rights.
|
||||
@@ -93,6 +113,10 @@ class PortalAccount(CustomerPortal):
|
||||
]
|
||||
return request.make_response(pdf, headers=pdfhttpheaders)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# My Home
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def details_form_validate(self, data):
|
||||
error, error_message = super(PortalAccount, self).details_form_validate(data)
|
||||
# prevent VAT/name change if invoices exist
|
||||
|
||||
@@ -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>)
|
||||
|
||||
@@ -38,6 +38,7 @@ class AccountConfigSettings(models.TransientModel):
|
||||
module_account_asset = fields.Boolean(string='Assets Management')
|
||||
module_account_deferred_revenue = fields.Boolean(string="Revenue Recognition")
|
||||
module_account_budget = fields.Boolean(string='Budget Management')
|
||||
module_account_payment = fields.Boolean(string='Online Payment')
|
||||
module_account_reports = fields.Boolean("Dynamic Reports")
|
||||
module_account_reports_followup = fields.Boolean("Enable payment followup management")
|
||||
default_sale_tax_id = fields.Many2one('account.tax', string="Default Sale Tax",
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import json
|
||||
import re
|
||||
import uuid
|
||||
|
||||
from lxml import etree
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
@@ -38,10 +40,13 @@ MAGIC_COLUMNS = ('id', 'create_uid', 'create_date', 'write_uid', 'write_date')
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
_name = "account.invoice"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin']
|
||||
_description = "Invoice"
|
||||
_order = "date_invoice desc, number desc, id desc"
|
||||
|
||||
def _get_default_access_token(self):
|
||||
return str(uuid.uuid4())
|
||||
|
||||
@api.one
|
||||
@api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', 'currency_id', 'company_id', 'date_invoice', 'type')
|
||||
def _compute_amount(self):
|
||||
@@ -231,6 +236,9 @@ class AccountInvoice(models.Model):
|
||||
], readonly=True, index=True, change_default=True,
|
||||
default=lambda self: self._context.get('type', 'out_invoice'),
|
||||
track_visibility='always')
|
||||
access_token = fields.Char(
|
||||
'Security Token', copy=False,
|
||||
default=_get_default_access_token)
|
||||
|
||||
refund_invoice_id = fields.Many2one('account.invoice', string="Invoice for which this invoice is the credit note")
|
||||
number = fields.Char(related='move_id.name', store=True, readonly=True, copy=False)
|
||||
@@ -353,6 +361,11 @@ class AccountInvoice(models.Model):
|
||||
('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'),
|
||||
]
|
||||
|
||||
def _compute_portal_url(self):
|
||||
super(AccountInvoice, self)._compute_portal_url()
|
||||
for order in self:
|
||||
order.portal_url = '/my/invoices/%s' % (order.id)
|
||||
|
||||
def _no_existing_validated_invoice(self):
|
||||
self.ensure_one()
|
||||
if self.journal_id.refund_sequence:
|
||||
@@ -480,6 +493,27 @@ class AccountInvoice(models.Model):
|
||||
view_id = get_view_id('invoice_form', 'account.invoice.form').id
|
||||
return super(AccountInvoice, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
|
||||
@api.model_cr_context
|
||||
def _init_column(self, column_name):
|
||||
""" Initialize the value of the given column for existing rows.
|
||||
|
||||
Overridden here because we need to generate different access tokens
|
||||
and by default _init_column calls the default method once and applies
|
||||
it for every record.
|
||||
"""
|
||||
if column_name != 'access_token':
|
||||
super(AccountInvoice, self)._init_column(column_name)
|
||||
else:
|
||||
query = """UPDATE %(table_name)s
|
||||
SET %(column_name)s = md5(md5(random()::varchar || id::varchar) || clock_timestamp()::varchar)::uuid::varchar
|
||||
WHERE %(column_name)s IS NULL
|
||||
""" % {'table_name': self._name, 'column_name': column_name}
|
||||
self.env.cr.execute(query)
|
||||
|
||||
def _generate_access_token(self):
|
||||
for invoice in self:
|
||||
invoice.access_token = self._get_default_access_token()
|
||||
|
||||
@api.multi
|
||||
def invoice_print(self):
|
||||
""" Print the invoice and mark it as sent, so that we can see more
|
||||
@@ -692,7 +726,6 @@ class AccountInvoice(models.Model):
|
||||
raise UserError(_("Invoice must be in draft or open state in order to be cancelled."))
|
||||
return self.action_cancel()
|
||||
|
||||
|
||||
@api.multi
|
||||
def _notification_recipients(self, message, groups):
|
||||
groups = super(AccountInvoice, self)._notification_recipients(message, groups)
|
||||
@@ -715,24 +748,26 @@ 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,
|
||||
}
|
||||
return super(AccountInvoice, self).get_access_action(access_uid)
|
||||
|
||||
def get_mail_url(self):
|
||||
self.ensure_one()
|
||||
params = {
|
||||
'model': self._name,
|
||||
'res_id': self.id,
|
||||
}
|
||||
params.update(self.partner_id.signup_get_auth_param()[self.partner_id.id])
|
||||
return '/mail/view?' + url_encode(params)
|
||||
return self.get_share_url()
|
||||
|
||||
@api.multi
|
||||
def get_formview_id(self, access_uid=None):
|
||||
@@ -1367,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,
|
||||
|
||||
@@ -225,6 +225,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_account_payment"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label string="Online Payment"/>
|
||||
<div class="text-muted">
|
||||
Let your customers pay their invoices online
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 o_setting_box" groups="account.group_account_user">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_account_batch_deposit" widget="upgrade_boolean"/>
|
||||
|
||||
@@ -368,6 +368,8 @@
|
||||
</div>
|
||||
<field name="has_outstanding" invisible="1"/>
|
||||
<sheet string="Invoice">
|
||||
<div class="oe_button_box" name="button_box">
|
||||
</div>
|
||||
<label string="Credit Note" attrs="{'invisible': ['|',('state','=','draft'), ('type','!=','out_refund')]}"/>
|
||||
<h1 class="mt0">
|
||||
<div attrs="{'invisible': [('sequence_number_next_prefix','!=',False)]}">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -25,7 +28,7 @@
|
||||
<p>There are currently no invoices and payments for your account.</p>
|
||||
</t>
|
||||
<div t-if="invoices" class="panel panel-default">
|
||||
<div class="table-responsive"><table class="table table-hover o_my_status_table">
|
||||
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>Invoice #</th>
|
||||
@@ -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_my_status_table')]/thead/tr/th[last()]" position="before">
|
||||
<th></th>
|
||||
<xpath expr="//table[hasclass('o_portal_my_doc_table')]/thead/tr/th[last()]" position="before">
|
||||
<th>Status</th>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-foreach='invoices']/tr/td[last()]" position="before">
|
||||
<td>
|
||||
|
||||
@@ -1,31 +1,38 @@
|
||||
.o_portal {
|
||||
.breadcrumb {
|
||||
margin-bottom: 0px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.o_my_status_table {
|
||||
text-align: right;
|
||||
tr > :first-child {
|
||||
text-align: left;
|
||||
}
|
||||
tr th {
|
||||
text-align: center;
|
||||
|
||||
> tbody.o_portal_report_tbody {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.o_my_home_content > .page-header > a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.o_portal_wrap {
|
||||
.o_portal_my_home > .page-header > a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.portal-wrap table.table tr {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.o_portal_my_doc_table {
|
||||
td, th {
|
||||
text-align: right;
|
||||
}
|
||||
tr > :first-child {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.search_panel_fixed_width {
|
||||
overflow: hidden;
|
||||
max-width: 125px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
.o_portal_search_panel_fixed_width {
|
||||
overflow: hidden;
|
||||
max-width: 125px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
table.table tr {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.oe_attachments .o_image_small {
|
||||
@@ -33,10 +40,6 @@
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.o_portal_chatter {
|
||||
padding: 10px;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wrap" class='portal-wrap'>
|
||||
<div id="wrap" class='o_portal_wrap'>
|
||||
<div class="container mb64">
|
||||
<t t-if="my_details">
|
||||
<div class="row">
|
||||
@@ -117,7 +117,7 @@
|
||||
<template id="portal_my_home" name="My Portal">
|
||||
<t t-call="portal.portal_layout">
|
||||
<t t-set="my_details" t-value="True"/>
|
||||
<div class="o_my_home_content">
|
||||
<div class="o_portal_my_home">
|
||||
<div class="oe_structure"></div>
|
||||
<h3 class="page-header">Your Documents</h3>
|
||||
<ul class="o_portal_docs list-group">
|
||||
@@ -159,7 +159,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="text" class="form-control search_panel_fixed_width" t-att-value='search' name="search"/>
|
||||
<input type="text" class="form-control o_portal_search_panel_fixed_width" t-att-value='search' name="search"/>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default search-submit" type="button"><span class="fa fa-search"></span></button>
|
||||
</span>
|
||||
@@ -167,7 +167,7 @@
|
||||
</div>
|
||||
</t>
|
||||
<div t-if="searchbar_sortings" class="dropdown pull-right mr4">
|
||||
<button id="portal_searchbar_sortby" class="search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown">
|
||||
<button id="portal_searchbar_sortby" class="o_portal_search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown">
|
||||
<span class="fa fa-sort fa-lg" />
|
||||
<span class='hidden-xs hidden-sm hidden-md' t-esc="searchbar_sortings[sortby].get('label', 'Newest')"/>
|
||||
<span class="caret"></span>
|
||||
@@ -181,7 +181,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div t-if="searchbar_filters" class="dropdown pull-right mr4">
|
||||
<button id="portal_searchbar_filters" class="search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown">
|
||||
<button id="portal_searchbar_filters" class="o_portal_search_panel_fixed_width btn btn-default" type="button" data-toggle="dropdown">
|
||||
<span class="fa fa-filter fa-lg" />
|
||||
<span class='hidden-xs hidden-sm hidden-md' t-esc="searchbar_filters[filterby].get('label', 'All')"/>
|
||||
<span class="caret"></span>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
</div>
|
||||
</t>
|
||||
<div t-if="projects" class="panel panel-default">
|
||||
<div class="table-responsive"><table class="table table-hover o_my_status_table">
|
||||
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th class="col-md-6">Name</th>
|
||||
@@ -136,7 +136,7 @@
|
||||
</div>
|
||||
</t>
|
||||
<div t-if="tasks" class="panel panel-default">
|
||||
<div class="table-responsive"><table class="table table-hover o_my_status_table">
|
||||
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th class="col-md-10">Task</th>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<t t-call="portal.portal_searchbar"/>
|
||||
</h3>
|
||||
<div t-if="orders" class="panel panel-default">
|
||||
<div class="table-responsive"><table class="table table-hover o_my_status_table">
|
||||
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>Purchase Orders #</th>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<p>There are currently no quotations for your account.</p>
|
||||
</t>
|
||||
<div t-if="quotations" class="panel panel-default">
|
||||
<div class="table-responsive"><table class="table table-hover o_my_status_table">
|
||||
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>Quotation #</th>
|
||||
@@ -92,7 +92,7 @@
|
||||
<p>There are currently no orders for your account.</p>
|
||||
</t>
|
||||
<div t-if="orders" class="panel panel-default">
|
||||
<div class="table-responsive"><table class="table table-hover o_my_status_table">
|
||||
<div class="table-responsive"><table class="table table-hover o_portal_my_doc_table">
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>
|
||||
|
||||
@@ -32,7 +32,7 @@ class PaymentTransaction(models.Model):
|
||||
tx = getattr(self, tx_find_method_name)(data)
|
||||
_logger.info('<%s> transaction processed: tx ref:%s, tx amount: %s', acquirer_name, tx.reference if tx else 'n/a', tx.amount if tx else 'n/a')
|
||||
|
||||
if tx:
|
||||
if tx and tx.sale_order_id:
|
||||
# Auto-confirm SO if necessary
|
||||
tx._confirm_so()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user