from odoo import models, fields, api class ProductTemplate(models.Model): _inherit = 'product.template' recipe_id = fields.One2many( 'dine360.recipe', 'product_tmpl_id', string='Recipe' ) has_recipe = fields.Boolean( string='Has Recipe', compute='_compute_has_recipe', store=True ) recipe_cost = fields.Float( string='Ingredient Cost', related='recipe_id.total_cost', readonly=True ) profit_margin = fields.Float( string='Profit Margin (%)', compute='_compute_profit_margin' ) min_stock_level = fields.Float( string='Low Stock Threshold', default=0.0, help="Alert will be triggered when stock falls below this level." ) is_low_stock = fields.Boolean( string='Is Low Stock', compute='_compute_low_stock' ) def _compute_has_recipe(self): for product in self: product.has_recipe = bool(product.recipe_id) def _compute_profit_margin(self): for product in self: if product.list_price > 0: cost = product.recipe_cost or product.standard_price product.profit_margin = ((product.list_price - cost) / product.list_price) * 100 else: product.profit_margin = 0 @api.depends('qty_available', 'min_stock_level') def _compute_low_stock(self): for product in self: # Only check for physical products (ingredients) if product.type == 'product' and product.min_stock_level > 0: product.is_low_stock = product.qty_available < product.min_stock_level else: product.is_low_stock = False @api.model def get_low_stock_products(self, limit=5): """ Helper method for the dashboard to find low stock products without triggering recursion. """ # Find all physical products or consumables that have a threshold set # Using both 'type' and 'detailed_type' for Odoo version compatibility domain = ['|', ('type', 'in', ['product', 'consu']), ('detailed_type', 'in', ['product', 'consu']), ('min_stock_level', '>', 0)] products = self.search(domain) # Filter in memory since qty_available is computed # For consumables, qty_available is 0, so it will always trigger if min_stock > 0 low_stock = products.filtered(lambda p: p.qty_available < p.min_stock_level) return low_stock[:limit]