Odoo 17 introduced the advanced 'catalog' feature, which allows users to add goods, select product variations, filter product categories, and choose specific qualities directly from the catalog.
For example, in a sale order, the user can choose a product from the product catalog. Products can also be sorted and filtered in this catalog window.
Kanban cards feature an "Add" button to include items in the sale order line and a ‘Remove’ button to remove that product from the sale order line in the catalog view. Also, we have the "Back to Order" button that provides quick access to the sales order form, enhancing efficiency and productivity. To see how the catalog functions, we can see it in the sale order.
In this blog, we can explore how to add a catalog feature to our custom module. First, we have to create the model with fields and their corresponding view. We already discussed this in our previous blog , How to Add a Section and Note for a Custom Module in Odoo 17.
STEP: 1. Add inherits ‘product.catalog.mixin’ to handle product catalog functionalities.
class WarrantyRequest(models.Model):
_name = 'warranty.request'
_description = 'Warranty Request'
_inherit = ['mail.thread', 'mail.activity.mixin', 'product.catalog.mixin']
STEP: 2. Add Catalog button to XML
Add a button named ‘action_add_from_catalog’ inside the control tag of the one2many tree view.
<button name="action_add_from_catalog" type="object"
string="Catalog" class="px-4 btn-link"
context="{'order_id': parent.id}"/>
The final XML code is like as follows,
<notebook>
<page id="product" name="Product">
<field name="warranty_line_ids" mode="tree"
widget="section_and_note_one2many"
context="{'default_display_type': False}">
<tree editable='bottom'>
<control>
<create name="add_product_control"
string="Add a product"/>
<create name="add_section_control"
string="Add a section
context="{'default_display_type': 'line_section'}"/>
<create name="add_note_control" string="Add a note"
context="{'default_display_type': 'line_note'}"/>
<button name="action_add_from_catalog" type="object"
string="Catalog" class="px-4 btn-link"
context="{'order_id': parent.id}"/>
</control>
<field name="product_id" required="not display_type"/>
<field name="name"/>
<field name="display_type" column_invisible="1"/> <field name="quantity" required="not display_type"/>
<field name="uom_id"/>
<field name="lst_price"/>
<field name="warranty_charge" sum="Warranty Charge"/>
</tree></field>
</page>
Add a Catalog button named 'action_add_from_catalog' in the control tag.
STEP: 3. Define the ‘action_add_from_catalog’ function in the childs class warranty.request.line model.
def action_add_from_catalog(self):
warranty_request = self.env['warranty.request'].browse(
self.env.context.get('order_id'))
return warranty_request.action_add_from_catalog()
It results in the following screenshot.
STEP: 4. Add ‘_get_product_catalog_order_data’ function in parent model
It returns a dictionary containing the products' data. Those data are for products that aren't on record yet.
def _get_product_catalog_order_data(self, products, **kwargs):
res = super()._get_product_catalog_order_data(products, **kwargs)
for product in products:
res[product.id] |= {
'price': product.standard_price,
}
return res
Here, we can mention which price to display.
STEP: 5. Update the already added product in the catalog view.
Users can see the added products to the One2many model in the catalog view by using the following function.
a) Add ‘_get_product_catalog_record_lines’ method in the parent class.
Returns the record's lines grouped by product. We can override this function in our model.
def _get_product_catalog_record_lines(self, product_ids):
grouped_lines = defaultdict(lambda: self.env['warranty.request.line'])
for line in self.warranty_line_ids:
if line.product_id.id not in product_ids:
continue
grouped_lines[line.product_id] |= line
return grouped_lines
b) Add ‘_get_product_catalog_lines_data’ method in warranty.request.line
Return information about warranty request lines in `self`. If `self` is empty, this method returns only the default value(s) needed for the product
catalog. In this case, the quantity that equals 0. Otherwise, it returns a quantity and a price based on the product of the one2many model.
def _get_product_catalog_lines_data(self):
catalog_info = {
'quantity': self.quantity,
'price': self.product_id.standard_price,
}
return catalog_info
It results in the already added product in the warranty request line is to be selected in the product catalog view.
From here, we can remove and add the product to the warranty.request.line
STEP: 6. Update the newly added product from the catalog view to warranty line.
Add the ’_update_order_line_info’ function to the parent class to Update purchase order line information for a given product or create a new one if none exists yet.
def _update_order_line_info(self, product_id, quantity, **kwargs):
:param int product_id: The product, as a `product.product` id.
:return: The unit price of the product, based on the pricelist of the purchase order and the quantity selected.
"""
self.ensure_one()
pol = self.warranty_line_ids.filtered(
lambda line: line.product_id.id == product_id)
if pol:
if quantity != 0:
pol.quantity = quantity
else:
pol.unlink()
elif quantity > 0:
pol = self.env['warranty.request.line'].create({
'warranty_id': self.id,
'product_id': product_id,
'quantity': quantity,
})
return pol
Here we added a new product and changed the quantity of previously added products. it results in the updating of the warranty request line.
STEP: 7. Add the filtering of the product.
If we want to filter out the product-based condition by using the function ‘_get_product_catalog_domain’ in the parent class.
def _get_product_catalog_domain(self):
"""Get the domain to search for products in the catalog.
"""
return [('company_id', 'in', [self.company_id.id, False]),(['detailed_type', '=', 'product'])]
It results in only storable types of products being displayed in a catalog.
STEP: 8. Add extra context to the catalog view.
Add the ‘_get_action_add_from_catalog_extra_context’ method to the parent class. Here we added the search by the vendor.
def _get_action_add_from_catalog_extra_context(self):
return { **super()._get_action_add_from_catalog_extra_context(),
'search_default_seller_ids': self.partner_id.name}
It results in the catalog view search by the partner in the warranty form by default.
The advanced catalog feature in Odoo 17 simplifies product selection, enabling users to quickly find and choose items, thereby significantly improving productivity.