From b7e21cc2bf87134bec840aa4245c93a839c9996f Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Thu, 12 Feb 2026 16:55:49 +0700 Subject: [PATCH] refactor: Enhance MO production visibility logic with detailed logging, float comparison, and assigned move state handling. --- models/mrp_production.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/models/mrp_production.py b/models/mrp_production.py index 988a173..9ffc079 100644 --- a/models/mrp_production.py +++ b/models/mrp_production.py @@ -1,4 +1,8 @@ -from odoo import models, api +from odoo import models, api, _ +from odoo.tools import float_compare +import logging + +_logger = logging.getLogger(__name__) class MrpProduction(models.Model): _inherit = 'mrp.production' @@ -12,6 +16,9 @@ class MrpProduction(models.Model): super()._compute_show_produce() for production in self: + _logger.info("DEBUG MO_LOCK: MO %s state=%s qty_producing=%s product_qty=%s", production.name, production.state, production.qty_producing, production.product_qty) + _logger.info("DEBUG MO_LOCK: Start - show_produce=%s show_produce_all=%s", production.show_produce, production.show_produce_all) + # If standard logic says hidden, no need to check further if not production.show_produce and not production.show_produce_all: continue @@ -48,14 +55,22 @@ class MrpProduction(models.Model): # Check availability based on the ACTUAL 'Consumed' quantity qty_to_consume = move.quantity + _logger.info("DEBUG MO_LOCK: Move %s product=%s state=%s consumed=%s forecast=%s", move.id, move.product_id.display_name, move.state, qty_to_consume, move.forecast_availability) # Skip check if product is not storable (Service, etc.) if not move.product_id.is_storable: continue + # If the move is already assigned (Ready), we consider it safe to produce. + if move.state == 'assigned': + _logger.info("DEBUG MO_LOCK: Move is 'assigned', skipping negative check.") + continue + # Check availability # We use forecast_availability as it includes reservations - if move.forecast_availability < qty_to_consume: + # Use float_compare to avoid precision issues + if float_compare(move.forecast_availability, qty_to_consume, precision_rounding=move.product_uom.rounding) < 0: + _logger.info("DEBUG MO_LOCK: CRITICAL - potential negative stock detected for %s", move.product_id.display_name) potential_negative = True break @@ -63,6 +78,8 @@ class MrpProduction(models.Model): production.show_produce = False production.show_produce_all = False + _logger.info("DEBUG MO_LOCK: End - show_produce=%s show_produce_all=%s", production.show_produce, production.show_produce_all) + # Relaxed guard: Do not hide if qty_producing > 0 even if consumption is 0. # This allows users to trigger consumption by clicking the Produce button. # If they really want to block 0-consumption production, it should be a validation error on click,