From 38c5fca1eaead74d9840f1cf9757a5e0e318cdc7 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Fri, 3 Apr 2026 22:15:48 +0700 Subject: [PATCH] feat: add debug validation for product_id in stock.quant and remove redundant comments in stock.location --- models/stock_location.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/models/stock_location.py b/models/stock_location.py index 455814d..4de8db5 100644 --- a/models/stock_location.py +++ b/models/stock_location.py @@ -1,9 +1,38 @@ import logging +import inspect from odoo import api, fields, models, _ +from odoo.exceptions import UserError from odoo.osv import expression _logger = logging.getLogger(__name__) +class StockQuant(models.Model): + _inherit = 'stock.quant' + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if not vals.get('product_id'): + # Capture the calling stack to see who is trying to create a product-less quant + stack = "\n".join([str(s.filename.split('/')[-1]) + " line " + str(s.lineno) for s in inspect.stack()[:10]]) + _logger.error(f"DEBUG_RESTRICT: STOCK.QUANT CREATE with NO product_id! STACK:\n{stack}") + # Force visibility in browser + raise UserError(_( + "DEBUG_TRACEBACK: Detected STOCK.QUANT creation with no product_id.\n\n" + "Top calling files:\n%s" + ) % stack) + return super().create(vals_list) + + def write(self, vals): + if 'product_id' in vals and not vals.get('product_id'): + stack = "\n".join([str(s.filename.split('/')[-1]) + " line " + str(s.lineno) for s in inspect.stack()[:10]]) + _logger.error(f"DEBUG_RESTRICT: STOCK.QUANT WRITE with NO product_id! STACK:\n{stack}") + raise UserError(_( + "DEBUG_TRACEBACK: Detected STOCK.QUANT write with no product_id.\n\n" + "Top calling files:\n%s" + ) % stack) + return super().write(vals) + class StockLocation(models.Model): _inherit = 'stock.location' @@ -11,7 +40,6 @@ class StockLocation(models.Model): def get_allowed_locations_for_mo(self, mo_id=None, picking_type_id=None): """ Public helper for JS to fetch allowed locations. - Renamed to be public (no leading underscore) for Odoo 19 RPC accessibility. """ allowed_ids = [] source_name = "None" @@ -35,7 +63,6 @@ class StockLocation(models.Model): source_name = f"PT {pt.display_name} (M21)" if allowed_ids: - # log as ERROR to ensure it appears in the remote server console regardless of level settings _logger.error(f"DEBUG_RESTRICT: Identified {len(allowed_ids)} Allowed Locations for {source_name}: {allowed_ids}") return allowed_ids @@ -62,7 +89,6 @@ class StockLot(models.Model): @api.model def web_search_read(self, domain, specification, offset=0, limit=None, order=None, count_limit=None): - # We KEEP the Lot search override for the search catalogs as well. ctx = self.env.context if not ctx.get('skip_location_restriction') and ctx.get('uid'): mo_id = (ctx.get('active_mo_id') or ctx.get('default_production_id') or ctx.get('production_id'))