diff --git a/deltatech_product_reordering_limit/__init__.py b/deltatech_product_reordering_limit/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/deltatech_product_reordering_limit/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/deltatech_product_reordering_limit/__manifest__.py b/deltatech_product_reordering_limit/__manifest__.py new file mode 100644 index 000000000..23f4fc92e --- /dev/null +++ b/deltatech_product_reordering_limit/__manifest__.py @@ -0,0 +1,16 @@ +{ + "name": "Product Reordering Limit", + "summary": "Custom reordering limits for products", + "version": "18.0.1.0.0", + "author": "Terrabit, Voicu Stefan", + "website": "https://www.terrabit.ro", + "category": "Inventory", + "depends": ["product", "stock"], + "license": "OPL-1", + "data": [ + "views/product_template_view.xml", + ], + "installable": True, + "development_status": "Beta", + "maintainers": ["VoicuStefan2001"], +} diff --git a/deltatech_product_reordering_limit/models/__init__.py b/deltatech_product_reordering_limit/models/__init__.py new file mode 100644 index 000000000..e8fa8f6bf --- /dev/null +++ b/deltatech_product_reordering_limit/models/__init__.py @@ -0,0 +1 @@ +from . import product_template diff --git a/deltatech_product_reordering_limit/models/product_template.py b/deltatech_product_reordering_limit/models/product_template.py new file mode 100644 index 000000000..09bce35a8 --- /dev/null +++ b/deltatech_product_reordering_limit/models/product_template.py @@ -0,0 +1,57 @@ +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + total_minimum = fields.Float(string="Total Minimum", default=0.0) + total_maximum = fields.Float(string="Total Maximum", default=0.0) + + def _search_is_below_min(self, operator, value): + if operator not in ("=", "!=") or not isinstance(value, bool): + raise NotImplementedError("Unsupported operator or value for _search_is_below_min") + + # We need to find templates where qty_available < total_minimum. + # Since we can't do this easily in a domain with a computed field vs another field, + # and a raw SQL might miss Odoo's complex stock logic (locations, etc.), + # but for a general "Below Minimum" filter, we can use a reasonable SQL approximation + # that aggregates variant quantities to the template level. + + # We use a subquery to sum quantities from stock_quant grouped by product, + # then join with product_product to group by template. + # We only count internal locations as per requirement. + self.env.cr.execute(""" + SELECT pt.id + FROM product_template pt + JOIN ( + SELECT pp.product_tmpl_id, SUM(sq.qty) as total_qty_available + FROM product_product pp + LEFT JOIN ( + SELECT sq.product_id, SUM(sq.quantity) as qty + FROM stock_quant sq + JOIN stock_location sl ON sl.id = sq.location_id + WHERE sl.usage = 'internal' + GROUP BY sq.product_id + ) sq ON sq.product_id = pp.id + GROUP BY pp.product_tmpl_id + ) t_qty ON t_qty.product_tmpl_id = pt.id + WHERE pt.total_minimum > 0 AND COALESCE(t_qty.total_qty_available, 0.0) < pt.total_minimum + """) + ids = [r[0] for r in self.env.cr.fetchall()] + + if (operator == "=" and value) or (operator == "!=" and not value): + return [("id", "in", ids)] + else: + return [("id", "not in", ids)] + + is_below_min = fields.Boolean( + string="Is Below Minimum", compute="_compute_is_below_min", search="_search_is_below_min" + ) + + @api.depends("qty_available", "total_minimum") + def _compute_is_below_min(self): + for template in self: + # qty_available on template level in Odoo 18 (when called without specific context) + # aggregates qty_available of all its variants. + # Product variants' qty_available already filters by internal locations by default. + template.is_below_min = template.total_minimum > 0 and template.qty_available < template.total_minimum diff --git a/deltatech_product_reordering_limit/pyproject.toml b/deltatech_product_reordering_limit/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/deltatech_product_reordering_limit/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/deltatech_product_reordering_limit/views/product_template_view.xml b/deltatech_product_reordering_limit/views/product_template_view.xml new file mode 100644 index 000000000..1c3dc7954 --- /dev/null +++ b/deltatech_product_reordering_limit/views/product_template_view.xml @@ -0,0 +1,26 @@ + + + + product.template.reordering.limit.form + product.template + + + + + + + + + + + product.template.reordering.limit.search + product.template + + + + + + + + +