In Odoo, we have an option for a Customer Portal on the Website module. It helps to access our documents from the website, like Quotations, Sale orders, Purchase Orders, and many more options. We can get these documents by clicking on each menu. You can refer to the following blog to learn about how to create customized menus inside a website portal: How to Add a Custom Menu in the Customer Portal of Odoo 16
Users can usually modify or reduce the displayed content in a website portal by using filters to suit their individual choices or needs. A customer portal may give users access to their order history, and filters may make it easier for them to sort and locate particular orders based on the date, status, or other relevant information. Filters are used to improve the user experience by making it simpler for users to discover the information they are looking for and saving time and effort when browsing through huge amounts of content.
Now in the blog, let us discuss how to apply the filter option for the customized menu on the website portal. For this purpose, we have created a custom menu called “Attendance” inside the customer portal.
We can add the custom menu inside the website customer portal using the following template in xml:
<template id="portal_my_home_menu_attendance"
name="Portal layout : Attendance menu entries"
inherit_id="portal.portal_breadcrumbs" priority="30">
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
<li t-if="page_name == 'attendance'"
t-attf-class="breadcrumb-item #{'active ' if not attendance else ''}">
<a t-if="attendance"
t-attf-href="/attendance/list?{{ keep_query() }}">
Attendance
</a>
<t t-else="">Attendance</t>
</li>
</xpath>
</template>
Then, after we need to define a function inside the Python controller to show and add the custom menu with the record count, we can use the following code for that.
class PortalAttendance(portal.CustomerPortal):
"""To get the values of portal attendance"""
def _prepare_home_portal_values(self, counters):
"""To get the count of the attendance in portal"""
values = super(PortalAttendance, self)._prepare_home_portal_values(
counters)
uid = request.session.id
user_id = request.env['res.users'].browse(uid)
employee_id = request.env['hr.employee'].search(
[('user_id', '=', user_id.id)])
attendance_count = request.env['hr.attendance'].search_count(
[('is_portal', '=', True), ('employee_id', '=', employee_id.id)])
values.update({
'attendance_count': attendance_count
})
return values
In this function, we override the _prepare_home_portal_values() function and fetch the attendance count and pass the value to the attendence_count. Overriding the function will allow you to add features to an existing function.
In the template, we specified the URL for the custom menu. It will trigger the corresponding URL while clicking our custom portal, and then, we need to define a function for the specific URL in a controller.
@http.route(['/attendance/list', '/attendance/list/page/<int:page>'],
type='http', website=True)
def attendance_search_sort_view(self, filterby="all", **kwargs):
"""To search and filter in the list view of attendance"""
uid = request.session.uid
user_id = request.env['res.users'].browse(uid)
employee_id = request.env['hr.employee'].search(
[('user_id', '=', user_id.id)])
today = fields.Date.today()
last_week = today + relativedelta(weeks=-1)
last_month = today + relativedelta(months=-1)
last_year = today + relativedelta(years=-1)
searchbar_filters = {
'all': {'label': 'All', 'domain': []},
'today': {
'label': 'Today',
'domain': [("check_in", ">=",
fields.Datetime.to_string(fields.Datetime.today())),
("check_in", "<=", fields.Datetime.to_string(
fields.Datetime.today().replace(hour=23,
minute=59,
second=59)))]},
'week': {
'label': 'Last Week',
'domain': [
('check_in', '>=', date_utils.start_of(last_week, "week")),
('check_in', '<=', date_utils.end_of(last_week, 'week'))]},
'month': {
'label': 'Last Month',
'domain': [('check_in', '>=',
date_utils.start_of(last_month, 'month')),
('check_in', '<=',
date_utils.end_of(last_month, 'month'))]},
'year': {
'label': 'Last Year',
'domain': [
('check_in', '>=', date_utils.start_of(last_year, 'year')),
('check_in', '<=', date_utils.end_of(last_year, 'year'))]}}
filter_domain = searchbar_filters[filterby]['domain']
attendance_obj = request.env['hr.attendance'].search(
[('is_portal', '=', True), ('employee_id', '=', employee_id.id)])
total_attendance = attendance_obj.search_count(
[('is_portal', '=', True),
('employee_id', '=',
employee_id.id)] + filter_domain)
page_detail = pager(url='/attendance/list',
total=total_attendance,
url_args={'filt’rby': filterby})
attendance_domain = [('is_portal', '=', True),
('employee_id', '=', employee_id.id)]
if filter_domain:
attendance_domain += filter_domain
attendance = attendance_obj.search(
attendance_domain,
)
vals = {
'attendance': attendance,
'page_name': 'attendance',
'pager': page_detail,
'default_url': '/attendance/list',
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
}
return request.render(
"web_portal_attendance.portal_list_attendance_order", vals)
The above controller will trigger while we click the custom menu that we created. In this, we added five filters that are ‘All’,‘Today’,’Last Week’,’Last Month’, ‘Last Year’. We set the “All’ filter option as a default option for the view. For the filter, we need to set the values of filter options using the relativedelta using the following code:
today = fields.Date.today()
last_week = today + relativedelta(weeks=-1)
last_month = today + relativedelta(months=-1)
last_year = today + relativedelta(years=-1)
Then after we need to set the label and filter domain for all filters. We can use the following code for that.
searchbar_filters = {
'all': {'label': 'All', 'domain': []},
'today': {
'label': 'Today',
'domain': [("check_in", ">=",
fields.Datetime.to_string(fields.Datetime.today())),
("check_in", "<=", fields.Datetime.to_string(
fields.Datetime.today().replace(hour=23,
minute=59,
second=59)))]},
'week': {
'label': 'Last Week',
'domain': [
('check_in', '>=', date_utils.start_of(last_week, "week")),
('check_in', '<=', date_utils.end_of(last_week, 'week'))]},
'month': {
'label': 'Last Month',
'domain': [('check_in', '>=',
date_utils.start_of(last_month, 'month')),
('check_in', '<=',
date_utils.end_of(last_month, 'month'))]},
'year': {
'label': 'Last Year',
'domain': [
('check_in', '>=', date_utils.start_of(last_year, 'year')),
('check_in', '<=', date_utils.end_of(last_year, 'year'))]}}
Then after we need to fetch the attendance record from the database based on the filter that we selected using the code:
filter_domain = searchbar_filters[filterby]['domain']
attendance_obj = request.env['hr.attendance'].search(
[('is_portal', '=', True), ('employee_id', '=', employee_id.id)])
total_attendance = attendance_obj.search_count(
[('is_portal', '=', True),
('employee_id', '=',
employee_id.id)] + filter_domain)
page_detail = pager(url='/attendance/list',
total=total_attendance,
url_args={'filterby': filterby})
attendance_domain = [('is_portal', '=', True),
('employee_id', '=', employee_id.id)]
if filter_domain:
attendance_domain += filter_domain
attendance = attendance_obj.search(
attendance_domain,
)
After fetching the attendance record, we need to pass the values to the template that we created for the view.
vals = {
'attendance': attendance,
'page_name': 'attendance',
'pager': page_detail,
'default_url': '/attendance/list',
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())),
'filterby': filterby,
}
return request.render(
"web_portal_attendance.portal_list_attendance_order", vals)
After providing code, we can see the filter by option is added inside the top right corner.
By default, we can see all records of the employee. We can apply the filters by clicking on the filter options.
In the customer portal on the website, we can add a custom filter by option in a custom menu in this way. By choosing proper filters, the filter by functionality enables users to access huge amounts of data.