Partner-Based Product Restriction
Odoo 18 ecommerce controller lets you limit storefront products per customer effortlessly. First, you will set up a custom module. Next, you will add partner fields and override the /shop route. Then, you will update QWeb templates to reflect filtered products. Moreover, you will test user flows and handle errors. Finally, you will follow best practices to maintain your code.
Understanding Odoo 18 ecommerce controller
First, Odoo processes web requests through controllers. Consequently, you can intercept and modify default behavior. In ecommerce, the website_sale module uses a controller to render product listings. Therefore, you override that controller to filter products by partner.
What Is an Ecommerce Controller?
An ecommerce controller is a Python class under controllers/ that defines routes (URLs). For instance, /shop maps to the product catalog. Moreover, the controller handles request context, user session, and rendering QWeb templates.
Why Override the Shop Controller?
By default, Odoo shows all products on /shop. However, you may need to show only specific products to certain customers. For example, wholesalers may see B2B-only items. Therefore, you override the shop controller to apply partner-based filters before rendering.
Prerequisites
Before you begin, ensure you have:
- Odoo 18 CE/EE installed and running.
- Developer Mode enabled (Settings → General Settings → Activate the developer mode).
- The website_sale module installed for ecommerce.
- A user account with Technical Features and Website access.
- Access to the file system and ability to restart the Odoo service.
Module Structure
First, create a new custom module directory under your addons path:
custom_addons/odoo18_ecommerce_controller/
├── init.py
├── manifest.py
├── controllers/
│ └── main.py
├── models/
│ └── partner.py
└── views/
└── ecommerce_templates.xml
- controllers/main.py Defines your custom route logic.
- models/partner.py Adds a Many2many field
allowed_product_idsonres.partner. - views/ecommerce_templates.xml Overrides QWeb templates to use filtered products.
Defining the Manifest
Next, open __manifest__.py and configure your module:
```python
{
'name': 'Ecommerce Controller Restrict Products',
'version': '1.0',
'summary': 'Odoo 18 ecommerce controller for partner-based product restriction',
'category': 'Website',
'author': 'Your Name',
'depends': ['website_sale'],
'data': [
'views/ecommerce_templates.xml',
],
'installable': True,
'application': False,
}
First, you set depends to website_sale. Then, you list your QWeb template file under data. Finally, you mark the module installable.
Extending the Partner Model
Then, add a new field to res.partner so you can assign allowed products:
models/partner.py
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
allowed_product_ids = fields.Many2many(
comodel_name='product.product',
string='Allowed Products',
help='Select products that this partner can view in the shop'
)
First, you inherit res.partner. Next, you declare allowed_product_ids as a Many2many to product.product. Then, you provide a label and help text for clarity.
Implementing the Ecommerce Controller
Now, override the shop controller to filter products before rendering:
controllers/main.py
from odoo import http
from odoo.http import request
class EcommerceRestrictController(http.Controller):
@http.route(['/shop'], type='http', auth='public', website=True)
def shop(self, **kwargs):
# Get the current user’s partner record
partner = request.env.user.partner_id
# Fetch all saleable products
Product = request.env['product.product'].sudo()
products = Product.search([('sale_ok', '=', True)])
# Filter by allowed_product_ids if set
allowed = partner.allowed_product_ids
if allowed:
products = products.filtered(lambda p: p in allowed)
# Prepare rendering context
values = {
'products': products,
'category': False,
'search': kwargs.get('search', False),
}
# Render the standard webshop template with filtered products
return request.render('website_sale.products', values)
- You define a route for
/shopwithauth='public'andwebsite=True. - You obtain the partner via
request.env.user.partner_id. - You search for products with
sale_ok=True. - If the partner has
allowed_product_ids, you filterproducts. - Finally, you call
request.renderon thewebsite_sale.productstemplate with your filtered list.
Overriding the QWeb Template
After overriding the controller, ensure your templates use the passed products:
views/ecommerce_templates.xml
<odoo>
<template id="products_inherit" inherit_id="website_sale.products">
<xpath expr="//t[@t-call='website_sale.products_list']" position="replace">
<!-- Use the filtered 'products' from our controller -->
<t t-call="website_sale.products_list"/>
</xpath>
</template>
</odoo>
First, you inherit the website_sale.products template. Then, you replace the call to website_sale.products_list with itself—this step ensures Odoo uses your products variable from the controller context.
Testing the Module
Now, install and test your module:
- Restart your Odoo server and update apps (
-u allor via UI). - Install “Ecommerce Controller Restrict Products” from the Apps menu.
- Navigate to Website → Configuration → Contacts.
- Edit a partner record and choose several Allowed Products.
- Log in as that partner (or create a portal user linked to the partner).
- Visit
/shopand confirm you see only the allowed products. - Test an unlisted partner to ensure they see the full catalog or no products.
Adding an Outgoing Link
Moreover, for advanced customization and best practices, refer to the official Odoo documentation on controllers and website development:
https://www.odoo.com/documentation/18.0/developer/howtos/website.html
Common Pitfalls & Troubleshooting
Controller Not Invoked
- Ensure no other module overrides
/shop. - Check that your controller file is under
controllers/and Python syntax is correct.
Products Still Show All Items
- Verify
sale_ok=Truefilter andallowed_product_idsassignment. - Clear Odoo cache: restart server and run with
--dev=reloador clearweb.assets_backend.
Access Rights Issues
- Ensure your portal users have group
Website / Portaland no conflicting record rules. - Test with a freshly created portal user linked to your partner.
Best Practices
- Use sudo() when reading
product.productin public routes to avoid access errors. - Cache filtered product lists if performance suffers under high traffic.
- Modularize by moving filter logic into a service class or method for reuse.
- Document each override clearly for future maintainers.
Conclusion
In this tutorial, you mastered how to use an Odoo 18 ecommerce controller to restrict products by partner. First, you set up the module and manifest. Next, you extended res.partner with a new field. Then, you overrode the /shop route and updated QWeb templates. Moreover, you tested user flows and handled common errors. Finally, you reviewed best practices and linked to the official Odoo docs.
With this implementation, you can tailor your e-commerce catalog per customer, boost B2B workflows, and maintain a clean codebase. Happy coding!
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.

