forked from alaguraj/odoo-testing-addons
79 lines
2.5 KiB
Python
79 lines
2.5 KiB
Python
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]
|
|
|
|
|
|
|