[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:
@@ -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 & 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 & 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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
#
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user