diff --git a/product_main_seller/README.rst b/product_main_seller/README.rst
index 22ed7f8f350..954efacaab1 100644
--- a/product_main_seller/README.rst
+++ b/product_main_seller/README.rst
@@ -1,7 +1,3 @@
-.. image:: https://odoo-community.org/readme-banner-image
- :target: https://odoo-community.org/get-involved?utm_source=readme
- :alt: Odoo Community Association
-
===================
Product Main Vendor
===================
@@ -17,7 +13,7 @@ Product Main Vendor
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
-.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
+.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github
diff --git a/product_main_seller/__manifest__.py b/product_main_seller/__manifest__.py
index 76c768f1b89..f82ecbdeb12 100644
--- a/product_main_seller/__manifest__.py
+++ b/product_main_seller/__manifest__.py
@@ -13,6 +13,7 @@
"depends": ["purchase"],
"maintainers": ["legalsylvain", "quentinDupont"],
"data": [
+ "data/ir_cron.xml",
"views/view_product_product.xml",
"views/view_product_template.xml",
],
diff --git a/product_main_seller/data/ir_cron.xml b/product_main_seller/data/ir_cron.xml
new file mode 100644
index 00000000000..e55c9c7ed1b
--- /dev/null
+++ b/product_main_seller/data/ir_cron.xml
@@ -0,0 +1,12 @@
+
+
+
+ Recompute Main Vendor
+
+ code
+ model._cron_recompute_main_seller_id()
+ 1
+ days
+ True
+
+
diff --git a/product_main_seller/hooks.py b/product_main_seller/hooks.py
index 7643bd665b7..5fe251dd058 100644
--- a/product_main_seller/hooks.py
+++ b/product_main_seller/hooks.py
@@ -36,3 +36,48 @@ def pre_init_hook(env):
WHERE pt.id = first_supplierinfos.product_tmpl_id;
"""
)
+ cr.execute(
+ """
+ ALTER TABLE product_product
+ ADD COLUMN IF NOT EXISTS main_seller_id integer;
+ """
+ )
+ cr.execute(
+ """
+ WITH ranked_supplierinfos AS (
+ SELECT
+ p.id AS product_id,
+ psi.partner_id,
+ ROW_NUMBER() OVER (
+ PARTITION BY p.id
+ ORDER BY
+ CASE
+ WHEN psi.product_id = p.id THEN 0
+ ELSE 1
+ END,
+ psi.sequence,
+ psi.min_qty DESC,
+ psi.price,
+ psi.id
+ ) AS row_number
+ FROM product_product p
+ JOIN product_supplierinfo psi
+ ON psi.product_tmpl_id = p.product_tmpl_id
+ AND (
+ psi.product_id = p.id
+ OR psi.product_id IS NULL
+ )
+ JOIN res_partner rp
+ ON rp.id = psi.partner_id
+ AND rp.active
+ WHERE
+ (psi.date_start IS NULL OR psi.date_start <= CURRENT_DATE)
+ AND (psi.date_end IS NULL OR psi.date_end >= CURRENT_DATE)
+ )
+ UPDATE product_product p
+ SET main_seller_id = ranked_supplierinfos.partner_id
+ FROM ranked_supplierinfos
+ WHERE ranked_supplierinfos.product_id = p.id
+ AND ranked_supplierinfos.row_number = 1;
+ """
+ )
diff --git a/product_main_seller/models/__init__.py b/product_main_seller/models/__init__.py
index e8fa8f6bf1e..9dfaeffa955 100644
--- a/product_main_seller/models/__init__.py
+++ b/product_main_seller/models/__init__.py
@@ -1 +1,3 @@
from . import product_template
+from . import product_product
+from . import product_supplierinfo
diff --git a/product_main_seller/models/product_product.py b/product_main_seller/models/product_product.py
new file mode 100644
index 00000000000..d385a613d5a
--- /dev/null
+++ b/product_main_seller/models/product_product.py
@@ -0,0 +1,42 @@
+# Copyright 2026 Tecnativa - Andrii Kompaniiets
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from odoo import api, fields, models
+
+
+class ProductProduct(models.Model):
+ _inherit = "product.product"
+
+ main_seller_id = fields.Many2one(
+ comodel_name="res.partner",
+ string="Main Vendor",
+ help="Put your supplier info in first position to set as main vendor",
+ compute="_compute_main_seller_id",
+ store=True,
+ )
+
+ @api.depends(
+ "variant_seller_ids.sequence",
+ "variant_seller_ids.partner_id.active",
+ "variant_seller_ids.date_start",
+ "variant_seller_ids.date_end",
+ )
+ def _compute_main_seller_id(self):
+ for product in self:
+ if product.variant_seller_ids:
+ product.main_seller_id = fields.first(
+ product.variant_seller_ids.filtered(
+ lambda seller, p=product: seller.partner_id.active
+ and (
+ not seller.date_start
+ or seller.date_start <= fields.Date.today()
+ )
+ and (
+ not seller.date_end
+ or seller.date_end >= fields.Date.today()
+ )
+ and (not seller.product_id or seller.product_id == p)
+ )
+ ).partner_id
+ else:
+ product.main_seller_id = False
diff --git a/product_main_seller/models/product_supplierinfo.py b/product_main_seller/models/product_supplierinfo.py
new file mode 100644
index 00000000000..8af927a9b58
--- /dev/null
+++ b/product_main_seller/models/product_supplierinfo.py
@@ -0,0 +1,14 @@
+# Copyright 2026 Tecnativa
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from odoo import api, models
+
+
+class ProductSupplierinfo(models.Model):
+ _inherit = "product.supplierinfo"
+
+ @api.model
+ def _cron_recompute_main_seller_id(self):
+ products = self.env["product.product"].search([])
+ templates = self.env["product.template"].search([])
+ products._compute_main_seller_id()
+ templates._compute_main_seller_id()
diff --git a/product_main_seller/models/product_template.py b/product_main_seller/models/product_template.py
index 1d131dd8fa1..fa51ebea2b8 100644
--- a/product_main_seller/models/product_template.py
+++ b/product_main_seller/models/product_template.py
@@ -16,13 +16,26 @@ class ProductTemplate(models.Model):
store=True,
)
- @api.depends("variant_seller_ids.sequence", "variant_seller_ids.partner_id.active")
+ @api.depends(
+ "variant_seller_ids.sequence",
+ "variant_seller_ids.partner_id.active",
+ "variant_seller_ids.date_start",
+ "variant_seller_ids.date_end",
+ )
def _compute_main_seller_id(self):
for template in self:
if template.variant_seller_ids:
template.main_seller_id = fields.first(
template.variant_seller_ids.filtered(
lambda seller: seller.partner_id.active
+ and (
+ not seller.date_start
+ or seller.date_start <= fields.Date.today()
+ )
+ and (
+ not seller.date_end
+ or seller.date_end >= fields.Date.today()
+ )
)
).partner_id
else:
diff --git a/product_main_seller/static/description/index.html b/product_main_seller/static/description/index.html
index 8c4e691b586..8ee7d63a4e9 100644
--- a/product_main_seller/static/description/index.html
+++ b/product_main_seller/static/description/index.html
@@ -3,7 +3,7 @@
-README.rst
+Product Main Vendor
-
+
+
Product Main Vendor
-
-
-
-
-
-
Product Main Vendor
-

+

This module extends the Odoo Product module to compute and display the
main Vendor of each products. The main vendor is the first vendor in the
vendors list.
@@ -392,7 +387,7 @@
Product Main Vendor
-
+
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
@@ -400,21 +395,21 @@
Do not contact contributors directly about support or help with technical issues.
-