[IMP] portal,*: /my counter async

Before this commit, the time to compute all counters was making the rendering
of the portal page slow.

Now the count is done in rpc after the loading of the page.

Now you can decide which part you want to show on the portal, and only compute
for these one.

It is not because you have purchase installed for your internal process, that
it means that your supplier use your portal and it avoid the computation for
all end users.

We parallelize the counters in arbitrary 3 rpcs.

closes odoo/odoo#55999

Related: odoo/enterprise#12456
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
Jeremy Kersten
2020-08-17 15:59:03 +00:00
parent 5da1b96fbf
commit 73b4e9b1b6
17 changed files with 126 additions and 72 deletions
+7 -6
View File
@@ -10,12 +10,13 @@ from odoo.http import request
class PortalAccount(CustomerPortal):
def _prepare_home_portal_values(self):
values = super(PortalAccount, self)._prepare_home_portal_values()
invoice_count = request.env['account.move'].search_count([
('move_type', 'in', ('out_invoice', 'in_invoice', 'out_refund', 'in_refund', 'out_receipt', 'in_receipt')),
])
values['invoice_count'] = invoice_count
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'invoice_count' in counters:
invoice_count = request.env['account.move'].search_count([
('move_type', 'in', ('out_invoice', 'in_invoice', 'out_refund', 'in_refund', 'out_receipt', 'in_receipt')),
])
values['invoice_count'] = invoice_count
return values
# ------------------------------------------------------------
@@ -12,12 +12,12 @@
</xpath>
</template>
<template id="portal_my_home_invoice" name="Portal My Home : invoice entries" inherit_id="portal.portal_my_home" priority="30">
<template id="portal_my_home_invoice" name="Show Invoices &amp; Bills" inherit_id="portal.portal_my_home" customize_show="True" priority="30">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="invoice_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Invoices &amp; Bills</t>
<t t-set="url" t-value="'/my/invoices'"/>
<t t-set="count" t-value="invoice_count"/>
<t t-set="placeholder_count" t-value="'invoice_count'"/>
</t>
</xpath>
</template>
+5 -4
View File
@@ -16,10 +16,11 @@ from odoo.addons.portal.controllers.portal import CustomerPortal, pager as porta
class TimesheetCustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self):
values = super(TimesheetCustomerPortal, self)._prepare_home_portal_values()
domain = request.env['account.analytic.line']._timesheet_get_portal_domain()
values['timesheet_count'] = request.env['account.analytic.line'].sudo().search_count(domain)
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'timesheet_count' in counters:
domain = request.env['account.analytic.line']._timesheet_get_portal_domain()
values['timesheet_count'] = request.env['account.analytic.line'].sudo().search_count(domain)
return values
@http.route(['/my/timesheets', '/my/timesheets/page/<int:page>'], type='http', auth="user", website=True)
@@ -9,12 +9,12 @@
</xpath>
</template>
<template id="portal_my_home_timesheet" name="Portal My Home : timesheets entries" inherit_id="portal.portal_my_home" priority="45">
<template id="portal_my_home_timesheet" name="Show Timesheets" customize_show="True" inherit_id="portal.portal_my_home" priority="45">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="timesheet_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Timesheets</t>
<t t-set="url" t-value="'/my/timesheets'"/>
<t t-set="count" t-value="timesheet_count"/>
<t t-set="placeholder_count" t-value="'timesheet_count'"/>
</t>
</xpath>
</template>
@@ -35,7 +35,7 @@
<t t-call="portal.portal_table">
<t t-foreach="grouped_timesheets" t-as="timesheets_with_hours">
<t t-set="timesheets" t-value="timesheets_with_hours[0]"/>
<t t-set="hours_spent" t-value="timesheets_with_hours[1]"/>
<t t-set="hours_spent" t-value="timesheets_with_hours[1]"/>
<thead>
<tr t-if="not groupby =='none'" t-attf-class="{{'thead-light'}}">
<th t-if="groupby == 'project'" colspan="5">
+9 -3
View File
@@ -159,16 +159,22 @@ class CustomerPortal(Controller):
'archive_groups': [],
}
def _prepare_home_portal_values(self):
def _prepare_home_portal_values(self, counters):
"""Values for /my & /my/home routes template rendering.
Includes the record count for the displayed badges.
where 'coutners' is the list of the displayed badges
and so the list to compute.
"""
return self._prepare_portal_layout_values()
return {}
@route(['/my/counters'], type='json', auth="user", website=True)
def counters(self, counters, **kw):
return self._prepare_home_portal_values(counters)
@route(['/my', '/my/home'], type='http', auth="user", website=True)
def home(self, **kw):
values = self._prepare_home_portal_values()
values = self._prepare_portal_layout_values()
return request.render("portal.portal_my_home", values)
@route(['/my/account'], type='http', auth='user', website=True)
+3 -1
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
from odoo import api, models, fields
from odoo.http import request
from odoo.addons.http_routing.models.ir_http import url_for
@@ -9,6 +9,8 @@ from odoo.addons.http_routing.models.ir_http import url_for
class View(models.Model):
_inherit = "ir.ui.view"
customize_show = fields.Boolean("Show As Optional Inherit", default=False)
@api.model
def _prepare_qcontext(self):
""" Returns the qcontext : rendering context with portal specific value (required
+40
View File
@@ -53,6 +53,46 @@ publicWidget.registry.portalDetails = publicWidget.Widget.extend({
},
});
publicWidget.registry.PortalHomeCounters = publicWidget.Widget.extend({
selector: '.o_portal_my_home',
/**
* @override
*/
start: function () {
var def = this._super.apply(this, arguments);
this._updateCounters();
return def;
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
*/
async _updateCounters(elem) {
const numberRpc = 3;
const needed = this.$('[data-placeholder_count]')
.map((i, o) => $(o).data('placeholder_count'))
.toArray();
const counterByRpc = Math.ceil(needed.length / numberRpc); // max counter, last can be less
const proms = [...Array(Math.min(numberRpc, needed.length)).keys()].map(async i => {
await this._rpc({
route: "/my/counters",
params: {
counters: needed.slice(i * counterByRpc, (i + 1) * counterByRpc)
},
}).then(data => {
Object.keys(data).map(k => this.$("[data-placeholder_count='" + k + "']").text(data[k]));
});
});
return Promise.all(proms);
},
});
publicWidget.registry.portalSearchPanel = publicWidget.Widget.extend({
selector: '.o_portal_search_panel',
events: {
+8 -1
View File
@@ -163,7 +163,14 @@
<template id="portal_docs_entry" name="My Portal Docs Entry">
<a t-att-href="url" t-att-title="title" class="list-group-item list-group-item-action d-flex align-items-center justify-content-between">
<t t-esc="title"/>
<span class="badge badge-secondary badge-pill" t-esc="count"/>
<t t-if='count'>
<span class="badge badge-secondary badge-pill" t-esc="count"/>
</t>
<t t-elif="placeholder_count">
<span class="badge badge-secondary badge-pill" t-att-data-placeholder_count="placeholder_count">
<i class="fa fa-spin fa-spinner"></i>
</span>
</t>
</a>
</template>
+6 -4
View File
@@ -15,10 +15,12 @@ from odoo.osv.expression import OR
class CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self):
values = super(CustomerPortal, self)._prepare_home_portal_values()
values['project_count'] = request.env['project.project'].search_count([])
values['task_count'] = request.env['project.task'].search_count([])
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'project_count' in counters:
values['project_count'] = request.env['project.project'].search_count([])
if 'task_count' in counters:
values['task_count'] = request.env['project.task'].search_count([])
return values
# ------------------------------------------------------------
@@ -19,17 +19,17 @@
</xpath>
</template>
<template id="portal_my_home" name="Portal My Home: project entries" inherit_id="portal.portal_my_home" priority="40">
<template id="portal_my_home" name="Show Projects / Tasks" customize_show="True" inherit_id="portal.portal_my_home" priority="40">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="project_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Projects</t>
<t t-set="url" t-value="'/my/projects'"/>
<t t-set="count" t-value="project_count"/>
<t t-set="placeholder_count" t-value="'project_count'"/>
</t>
<t t-if="task_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Tasks</t>
<t t-set="url" t-value="'/my/tasks'"/>
<t t-set="count" t-value="task_count"/>
<t t-set="placeholder_count" t-value="'task_count'"/>
</t>
</xpath>
</template>
+6 -6
View File
@@ -16,11 +16,12 @@ from odoo.addons.web.controllers.main import Binary
class CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self):
values = super(CustomerPortal, self)._prepare_home_portal_values()
values['purchase_count'] = request.env['purchase.order'].search_count([
('state', 'in', ['purchase', 'done', 'cancel'])
])
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'purchase_count' in counters:
values['purchase_count'] = request.env['purchase.order'].search_count([
('state', 'in', ['purchase', 'done', 'cancel'])
])
return values
def _purchase_order_get_page_view_values(self, order, access_token, **kwargs):
@@ -39,7 +40,6 @@ class CustomerPortal(CustomerPortal):
@http.route(['/my/purchase', '/my/purchase/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_purchase_orders(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
PurchaseOrder = request.env['purchase.order']
domain = []
+3 -3
View File
@@ -13,12 +13,12 @@
</xpath>
</template>
<template id="portal_my_home_purchase" name="Portal My Home : purchase entry" inherit_id="portal.portal_my_home" priority="25">
<template id="portal_my_home_purchase" name="Show Purchase Orders" customize_show="True" inherit_id="portal.portal_my_home" priority="25">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="purchase_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Purchase Orders</t>
<t t-set="url" t-value="'/my/purchase'"/>
<t t-set="count" t-value="purchase_count"/>
<t t-set="placeholder_count" t-value="'purchase_count'"/>
</t>
</xpath>
</template>
+12 -14
View File
@@ -14,24 +14,22 @@ from odoo.osv import expression
class CustomerPortal(CustomerPortal):
def _prepare_home_portal_values(self):
values = super(CustomerPortal, self)._prepare_home_portal_values()
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
quotation_count = SaleOrder.search_count([
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sent', 'cancel'])
])
order_count = SaleOrder.search_count([
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done'])
])
if 'quotation_count' in counters:
values['quotation_count'] = SaleOrder.search_count([
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sent', 'cancel'])
])
if 'order_count' in counters:
values['order_count'] = SaleOrder.search_count([
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done'])
])
values.update({
'quotation_count': quotation_count,
'order_count': order_count,
})
return values
#
+5 -5
View File
@@ -18,17 +18,17 @@
</xpath>
</template>
<template id="portal_my_home_sale" name="Portal My Home : sales entries" inherit_id="portal.portal_my_home" priority="20">
<template id="portal_my_home_sale" name="Show Quotations / Sales Orders" customize_show="True" inherit_id="portal.portal_my_home" priority="20">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="quotation_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Quotations</t>
<t t-set="url" t-value="'/my/quotes'"/>
<t t-set="count" t-value="quotation_count"/>
<t t-set="placeholder_count" t-value="'quotation_count'"/>
</t>
<t t-if="order_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Sales Orders</t>
<t t-set="url" t-value="'/my/orders'"/>
<t t-set="count" t-value="order_count"/>
<t t-set="placeholder_count" t-value="'order_count'"/>
</t>
</xpath>
</template>
-1
View File
@@ -21,7 +21,6 @@ class View(models.Model):
_name = "ir.ui.view"
_inherit = ["ir.ui.view", "website.seo.metadata"]
customize_show = fields.Boolean("Show As Optional Inherit", default=False)
website_id = fields.Many2one('website', ondelete='cascade', string="Website")
page_ids = fields.One2many('website.page', 'view_id')
first_page_id = fields.Many2one('website.page', string='Website Page', help='First page linked to this view', compute='_compute_first_page_id')
@@ -32,14 +32,12 @@ class WebsiteAccount(CustomerPortal):
('type', '=', 'opportunity')
]
def _prepare_home_portal_values(self):
values = super(WebsiteAccount, self)._prepare_home_portal_values()
lead_count = request.env['crm.lead'].search_count(self.get_domain_my_lead(request.env.user))
opp_count = request.env['crm.lead'].search_count(self.get_domain_my_opp(request.env.user))
values.update({
'lead_count': lead_count,
'opp_count': opp_count,
})
def _prepare_home_portal_values(self, counters):
values = super()._prepare_home_portal_values(counters)
if 'lead_count' in counters:
values['lead_count'] = request.env['crm.lead'].search_count(self.get_domain_my_lead(request.env.user))
if 'opp_count' in counters:
values['opp_count'] = request.env['crm.lead'].search_count(self.get_domain_my_opp(request.env.user))
return values
@http.route(['/my/leads', '/my/leads/page/<int:page>'], type='http', auth="user", website=True)
@@ -208,17 +208,17 @@
</xpath>
</template>
<template id="portal_my_home_lead" name="Portal My Home : lead entries" inherit_id="portal.portal_my_home" priority="15">
<template id="portal_my_home_lead" name="Show Leads / Opps" customize_show="True" inherit_id="portal.portal_my_home" priority="15">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-if="lead_count" t-call="portal.portal_docs_entry">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Leads</t>
<t t-set="url" t-value="'/my/leads'"/>
<t t-set="count" t-value="lead_count"/>
<t t-set="placeholder_count" t-value="'lead_count'"/>
</t>
<t t-call="portal.portal_docs_entry">
<t t-set="title">Opportunities</t>
<t t-set="url" t-value="'/my/opportunities'"/>
<t t-set="count" t-value="opp_count"/>
<t t-set="placeholder_count" t-value="'opp_count'"/>
</t>
</xpath>
</template>