In this blog, we are going to discuss how to customize the templates on the Odoo website and add a search option to a page. So the main step in customizing a web page is inheriting its template. After inheriting, if you want to remove something from the existing template just remove the lines of code, or if you want to add something you can use xpath to determine where to add the new elements in that template.
So in this example, I am using the portal to customize. let me take the sale order page
From the figure, we can see that the table header columns contain only sale order, order date, and total. So here I am going to add the partner name of the related sale order.so we can do this by
1. Inheriting the template
2. Overriding the template
1) Inheriting the template
In the module, inside views create an xml file and inherit the template as follows
<odoo>
<data>
<template id="portal_my_orders_inherit" name="My Sales Orders Inherit" inherit_id="sale.portal_my_orders" >
<xpath expr="//tr[hasclass('active')]" position="replace">
<th>
<span class='d-none d-md-inline'>Sales Order #</span>
<span class='d-block d-md-none'>Ref.</span>
</th>
<th class="text-right">Order Date</th>
<th class="text-right">Partner</th>
<th class="text-center"/>
<th class="text-right">Total</th>
</xpath>
<xpath expr="//td[hasclass('text-center')]" position="before">
<td class="text-right"><span t-field="order.partner_id.name"/></td>
</xpath>
</template>
</data>
</odoo>
So from the above code ,it inherits the template portal_my_orders of sale module and is using xpath to go to a certain position.So after this, update the app list and install the module, then we will get as
So from the above image, we can see a new column named Partner has appeared.
2) Override the template
So Instead of using the above method, we can override the template as below.
<template id="sale.portal_my_orders" name="My Sales Orders">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">Sales Orders</t>
</t>
<t t-if="not orders">
<p>There are currently no orders for your account.</p>
</t>
<t t-if="orders" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>
<span class='d-none d-md-inline'>Sales Order #</span>
<span class='d-block d-md-none'>Ref.</span>
</th>
<th class="text-right">Partner</th>
<th class="text-right">Order Date</th>
<th class="text-center"/>
<th class="text-right">Total</th>
</tr>
</thead>
<t t-foreach="orders" t-as="order">
<tr>
<td><a t-att-href="order.get_portal_url()"><t t-esc="order.name"/></a></td>
<td class="text-right"><span t-field="order.partner_id.name"/></td>
<td class="text-right">
<span t-field="order.date_order" t-options="{'widget': 'date'}"/>&nbsp;
<span class='d-none d-md-inline' t-field="order.date_order" t-options="{'time_only': True}"/>
</td>
<td class="text-center">
<span t-if="order.state == 'done'" class="badge badge-pill badge-success">
<i class="fa fa-fw fa-check" role="img" aria-label="Done" title="Done"/>Done
</span>
</td>
<td class="text-right"><span t-field="order.amount_total"/></td>
</tr>
</t>
</t>
</t>
</template>
If we look at the first line, the template is overridden as the module name.template_id.So here all lines of templates are copied here and updating is done accordingly(highlighted lines)
After installing the module we can see as
How to add a search bar option in the website template?
Let's see how we can add search options(search bar) to this template.
If we look at the second t-call of the template,we can see it's calling another template(portal.portal_searchbar).So the only thing we need to do is to override the controller that calls this template.
from odoo import fields, http, _
from odoo.http import request
from odoo.addons.sale.controllers.portal import CustomerPortal
from odoo.addons.portal.controllers.portal import pager as portal_pager, get_records_pager
from odoo.osv.expression import OR
class CustomerPortal(CustomerPortal):
@http.route(['/my/orders', '/my/orders/page/<int:page>'], type='http', auth="user", website=True)
def portal_my_orders(self, page=1, date_begin=None, search=None, search_in='content', date_end=None, sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
domain = [
('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done'])
]
searchbar_inputs = {
'order': {'input': 'name', 'label': _('Search in Order')},
'all': {'input': 'all', 'label': _('Search in All')},
}
if search and search_in:
search_domain = []
if search_in in ('name', 'all'):
search_domain = OR([search_domain, [('name', 'ilike', search)]])
domain += search_domain
searchbar_sortings = {
'date': {'label': _('Order Date'), 'order': 'date_order desc'},
'name': {'label': _('Reference'), 'order': 'name'},
'stage': {'label': _('Stage'), 'order': 'state'},
}
# default sortby order
if not sortby:
sortby = 'date'
sort_order = searchbar_sortings[sortby]['order']
if date_begin and date_end:
domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]
# count for pager
order_count = SaleOrder.search_count(domain)
# pager
pager = portal_pager(
url="/my/orders",
url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby},
total=order_count,
page=page,
step=self._items_per_page
)
# content according to pager
orders = SaleOrder.search(domain, order=sort_order, limit=self._items_per_page, offset=pager['offset'])
request.session['my_orders_history'] = orders.ids[:100]
values.update({
'date': date_begin,
'orders': orders.sudo(),
'search': search,
'searchbar_inputs': searchbar_inputs,
'search_in': search_in,
'page_name': 'order',
'pager': pager,
'default_url': '/my/orders',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
})
return request.render("sale.portal_my_orders", values)
In the code , searchbar_inputs is an filter or domain in which area/condition the search should do.Here the lines,
searchbar_inputs = {
'order': {'input': 'name', 'label': _('Search in Order')},
'all': {'input': 'all', 'label': _('Search in All')},
}
defines the search filter option,ie just a name for filter.the changes can be seen as
Ie, on clicking the dropdown option on the search bar we can select the condition, and after that, we type the text for search .so the lines,
if search and search_in:
search_domain = []
if search_in in ('name', 'all'):
search_domain = OR([search_domain, [('name', 'ilike', search)]])
domain += search_domain
Here the search means the text we type in the search bar and the search_in means the search filter condition or searchbar_inputs selected. so here we are adding the domain to search and after its append to the main domain, and finally, on searching the text on the search bar, the domain is added and will get the result as below.
So in this ways, we can customize the templates on the website