feat: implement backend operation bypass for location restrictions and add diagnostic logging to stock quant creation
This commit is contained in:
parent
255aaef265
commit
c036b7cb9c
@ -66,16 +66,45 @@ class StockQuant(models.Model):
|
|||||||
if picking_type.exists() and picking_type.default_location_src_ids:
|
if picking_type.exists() and picking_type.default_location_src_ids:
|
||||||
allowed_location_ids = picking_type.default_location_src_ids.ids
|
allowed_location_ids = picking_type.default_location_src_ids.ids
|
||||||
|
|
||||||
|
# 7. NEW: Detect Backend Operations (Force Bypass)
|
||||||
|
# If we are in a background synchronization or an ORM command (not triggered by UI search)
|
||||||
|
# return empty so we do not restrict.
|
||||||
|
is_ui_search = (ctx.get('params') or
|
||||||
|
ctx.get('bin_size') or
|
||||||
|
ctx.get('search_view_ref') or
|
||||||
|
ctx.get('list_view_ref'))
|
||||||
|
|
||||||
|
# If it's NOT a UI search (i.e. it's a Save, Post, Validate background call), bypass.
|
||||||
|
if not is_ui_search:
|
||||||
|
# Check for common background flags
|
||||||
|
if (ctx.get('mail_create_nolog') or
|
||||||
|
ctx.get('tracking_disable') or
|
||||||
|
not ctx.get('uid')): # System user
|
||||||
|
return []
|
||||||
|
|
||||||
return allowed_location_ids
|
return allowed_location_ids
|
||||||
|
|
||||||
|
@api.model_create_multi
|
||||||
|
def create(self, vals_list):
|
||||||
|
"""Diagnostic override to catch the 'Missing Product' error root cause"""
|
||||||
|
for vals in vals_list:
|
||||||
|
if not vals.get('product_id'):
|
||||||
|
# LOG THE CALLER for debugging
|
||||||
|
_logger.error("DEBUG_RESTRICT: Creating StockQuant WITHOUT product_id!")
|
||||||
|
_logger.error(f"DEBUG_RESTRICT: Vals: {vals}")
|
||||||
|
_logger.error(f"DEBUG_RESTRICT: Context: {self.env.context}")
|
||||||
|
# We do NOT raise here to avoid breaking Odoo's original error UX,
|
||||||
|
# but this will appear in logs or help us see the issue.
|
||||||
|
return super().create(vals_list)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_gather_domain(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False):
|
def _get_gather_domain(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False):
|
||||||
"""Override to apply location restrictions during reservation (gather)"""
|
"""Override to apply location restrictions during reservation (gather)"""
|
||||||
result_domain = super()._get_gather_domain(product_id, location_id, lot_id, package_id, owner_id, strict)
|
result_domain = super()._get_gather_domain(product_id, location_id, lot_id, package_id, owner_id, strict)
|
||||||
|
|
||||||
ctx = self.env.context
|
ctx = self.env.context
|
||||||
# 0. Bypass if skip flag is set
|
# 0. Bypass if skip flag is set OR we are in a system operation
|
||||||
if ctx.get('skip_location_restriction'):
|
if ctx.get('skip_location_restriction') or not ctx.get('uid'):
|
||||||
return result_domain
|
return result_domain
|
||||||
|
|
||||||
# 1. FIX: If reserving from a non-internal location, DO NOT apply internal restrictions.
|
# 1. FIX: If reserving from a non-internal location, DO NOT apply internal restrictions.
|
||||||
@ -107,9 +136,11 @@ class StockQuant(models.Model):
|
|||||||
def _search(self, domain, offset=0, limit=None, order=None, *args, **kwargs):
|
def _search(self, domain, offset=0, limit=None, order=None, *args, **kwargs):
|
||||||
"""Override to apply location restrictions during search (e.g. catalog or list selection)"""
|
"""Override to apply location restrictions during search (e.g. catalog or list selection)"""
|
||||||
ctx = self.env.context
|
ctx = self.env.context
|
||||||
# 0. CRITICAL FIX: If searching for specific IDs or skip flag set, bypass custom filtering
|
# 0. CRITICAL FIX: If searching for specific IDs OR skip flag set OR NOT UI Search, bypass custom filtering
|
||||||
search_by_id = any(isinstance(leaf, (list, tuple)) and leaf[0] == 'id' for leaf in domain)
|
search_by_id = any(isinstance(leaf, (list, tuple)) and leaf[0] == 'id' for leaf in domain)
|
||||||
if search_by_id or ctx.get('skip_location_restriction'):
|
is_ui_search = ctx.get('params') or ctx.get('search_view_ref') or ctx.get('list_view_ref')
|
||||||
|
|
||||||
|
if search_by_id or ctx.get('skip_location_restriction') or not is_ui_search:
|
||||||
return super()._search(domain, offset=offset, limit=limit, order=order, *args, **kwargs)
|
return super()._search(domain, offset=offset, limit=limit, order=order, *args, **kwargs)
|
||||||
|
|
||||||
allowed_location_ids = self._get_allowed_locations()
|
allowed_location_ids = self._get_allowed_locations()
|
||||||
@ -158,9 +189,12 @@ class StockLot(models.Model):
|
|||||||
def _search(self, domain, offset=0, limit=None, order=None, *args, **kwargs):
|
def _search(self, domain, offset=0, limit=None, order=None, *args, **kwargs):
|
||||||
ctx = self.env.context
|
ctx = self.env.context
|
||||||
|
|
||||||
# FIX: If we are searching for specific IDs, bypass custom filtering to avoid backend failures
|
# 0. NEW: Detect UI Search vs Backend Sync
|
||||||
search_by_id = any(isinstance(leaf, (list, tuple)) and leaf[0] == 'id' for leaf in domain)
|
search_by_id = any(isinstance(leaf, (list, tuple)) and leaf[0] == 'id' for leaf in domain)
|
||||||
if search_by_id or ctx.get('skip_location_restriction'):
|
is_ui_search = ctx.get('params') or ctx.get('search_view_ref') or ctx.get('list_view_ref')
|
||||||
|
|
||||||
|
# FIX: If we are searching for specific IDs OR skip flag set OR NOT UI search, bypass
|
||||||
|
if search_by_id or ctx.get('skip_location_restriction') or not is_ui_search:
|
||||||
return super()._search(domain, offset=offset, limit=limit, order=order, *args, **kwargs)
|
return super()._search(domain, offset=offset, limit=limit, order=order, *args, **kwargs)
|
||||||
|
|
||||||
# 1. Identify which locations we should look into for quants
|
# 1. Identify which locations we should look into for quants
|
||||||
@ -183,6 +217,7 @@ class StockLot(models.Model):
|
|||||||
quant_domain.append(('product_id', '=', product_id))
|
quant_domain.append(('product_id', '=', product_id))
|
||||||
|
|
||||||
# Use internal bypass when searching quants to filter lots
|
# Use internal bypass when searching quants to filter lots
|
||||||
|
# We use sudo() and skip_location_restriction to ensure we always find the quants
|
||||||
quants = self.env['stock.quant'].with_context(skip_location_restriction=True).sudo().search(quant_domain)
|
quants = self.env['stock.quant'].with_context(skip_location_restriction=True).sudo().search(quant_domain)
|
||||||
lot_ids = list(set(quants.mapped('lot_id').ids))
|
lot_ids = list(set(quants.mapped('lot_id').ids))
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user