feat: improve location restriction logic by expanding context key support and adding fallback to default source location
This commit is contained in:
parent
1bc628c4ed
commit
726034dcbf
@ -12,26 +12,45 @@ class StockLocation(models.Model):
|
|||||||
"""
|
"""
|
||||||
Helper to retrieve allowed locations based on the current context (picking type).
|
Helper to retrieve allowed locations based on the current context (picking type).
|
||||||
Used by UI-level overrides in StockQuant and StockLot.
|
Used by UI-level overrides in StockQuant and StockLot.
|
||||||
|
Returns:
|
||||||
|
list: IDs of allowed locations.
|
||||||
|
False: If no restriction should be applied (e.g. no picking type found).
|
||||||
"""
|
"""
|
||||||
ctx = self.env.context
|
ctx = self.env.context
|
||||||
# 1. Identify the Picking Type (Operation Type)
|
# 1. Identify the Picking Type (Operation Type)
|
||||||
picking_type_id = ctx.get('default_picking_type_id') or ctx.get('picking_type_id')
|
# Check multiple common context keys used by stock/mrp models
|
||||||
|
picking_type_id = (ctx.get('default_picking_type_id') or
|
||||||
|
ctx.get('picking_type_id') or
|
||||||
|
ctx.get('active_picking_type_id'))
|
||||||
|
|
||||||
# 2. Support for Manufacturing Orders: if we have an MO ID but no picking type, find it.
|
# 2. Advanced MO Support: find picking type from MO ID if needed
|
||||||
if not picking_type_id and ctx.get('active_mo_id'):
|
mo_id = (ctx.get('active_mo_id') or
|
||||||
mo = self.env['mrp.production'].browse(ctx.get('active_mo_id'))
|
ctx.get('default_mo_id') or
|
||||||
|
ctx.get('default_production_id') or
|
||||||
|
ctx.get('mo_id') or
|
||||||
|
ctx.get('production_id'))
|
||||||
|
|
||||||
|
if not picking_type_id and mo_id:
|
||||||
|
mo = self.env['mrp.production'].browse(mo_id)
|
||||||
if mo.exists():
|
if mo.exists():
|
||||||
picking_type_id = mo.picking_type_id.id
|
picking_type_id = mo.picking_type_id.id
|
||||||
|
|
||||||
if not picking_type_id:
|
if not picking_type_id:
|
||||||
return []
|
# NO identification of operation type = NO restriction (safe fallback)
|
||||||
|
return False
|
||||||
|
|
||||||
# 3. Retrieve allowed locations from the picking type
|
# 3. Retrieve allowed locations from the picking type
|
||||||
picking_type = self.env['stock.picking.type'].browse(picking_type_id)
|
picking_type = self.env['stock.picking.type'].browse(picking_type_id)
|
||||||
if picking_type.exists() and picking_type.default_location_src_ids:
|
if picking_type.exists():
|
||||||
|
# Priority 1: Use the M2M "Allowed Source Locations" if set
|
||||||
|
if picking_type.default_location_src_ids:
|
||||||
return picking_type.default_location_src_ids.ids
|
return picking_type.default_location_src_ids.ids
|
||||||
|
|
||||||
return []
|
# Priority 2: Fallback to the primary "Default Source Location" (M2O)
|
||||||
|
if picking_type.default_location_src_id:
|
||||||
|
return [picking_type.default_location_src_id.id]
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
class StockQuant(models.Model):
|
class StockQuant(models.Model):
|
||||||
_inherit = 'stock.quant'
|
_inherit = 'stock.quant'
|
||||||
@ -40,14 +59,12 @@ class StockQuant(models.Model):
|
|||||||
def web_search_read(self, domain, specification, offset=0, limit=None, order=None, count_limit=None):
|
def web_search_read(self, domain, specification, offset=0, limit=None, order=None, count_limit=None):
|
||||||
"""
|
"""
|
||||||
UI-SURFACE OVERRIDE: Applies location filtering ONLY for the web interface.
|
UI-SURFACE OVERRIDE: Applies location filtering ONLY for the web interface.
|
||||||
This method is called by the M2M Catalog and list view searches.
|
|
||||||
Internal search() and _gather() will NOT be affected.
|
|
||||||
"""
|
"""
|
||||||
ctx = self.env.context
|
ctx = self.env.context
|
||||||
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
|
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
|
||||||
allowed_location_ids = self.env['stock.location']._get_allowed_locations()
|
allowed_location_ids = self.env['stock.location']._get_allowed_locations()
|
||||||
if allowed_location_ids:
|
if allowed_location_ids:
|
||||||
# Add location filter to the domain
|
# Add location filter to the domain ONLY if we have an explicit list
|
||||||
domain = expression.AND([domain, [('location_id', 'in', allowed_location_ids)]])
|
domain = expression.AND([domain, [('location_id', 'in', allowed_location_ids)]])
|
||||||
|
|
||||||
return super().web_search_read(domain, specification, offset=offset, limit=limit, order=order, count_limit=count_limit)
|
return super().web_search_read(domain, specification, offset=offset, limit=limit, order=order, count_limit=count_limit)
|
||||||
@ -59,19 +76,17 @@ class StockLot(models.Model):
|
|||||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
||||||
"""
|
"""
|
||||||
UI-SURFACE OVERRIDE: Filters the many2one lot selection dropdown.
|
UI-SURFACE OVERRIDE: Filters the many2one lot selection dropdown.
|
||||||
This is ONLY used by the web client for autocomplete/dropdown lookups.
|
|
||||||
"""
|
"""
|
||||||
ctx = self.env.context
|
ctx = self.env.context
|
||||||
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
|
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
|
||||||
allowed_location_ids = self.env['stock.location']._get_allowed_locations()
|
allowed_location_ids = self.env['stock.location']._get_allowed_locations()
|
||||||
|
|
||||||
# If no explicit mapping found on the picking type,
|
# If our custom helper failed to find a picking-type restriction,
|
||||||
# check if a default_location_id was passed to the view context.
|
# we check if a simple default_location_id filter was passed directly.
|
||||||
if not allowed_location_ids and ctx.get('default_location_id'):
|
if not allowed_location_ids and ctx.get('default_location_id'):
|
||||||
allowed_location_ids = [ctx.get('default_location_id')]
|
allowed_location_ids = [ctx.get('default_location_id')]
|
||||||
|
|
||||||
if allowed_location_ids:
|
if allowed_location_ids:
|
||||||
# Find quants in the allowed locations that have positive stock for this product
|
|
||||||
quant_domain = [
|
quant_domain = [
|
||||||
('location_id', 'in', allowed_location_ids),
|
('location_id', 'in', allowed_location_ids),
|
||||||
('quantity', '>', 0),
|
('quantity', '>', 0),
|
||||||
@ -81,8 +96,6 @@ class StockLot(models.Model):
|
|||||||
if product_id:
|
if product_id:
|
||||||
quant_domain.append(('product_id', '=', product_id))
|
quant_domain.append(('product_id', '=', product_id))
|
||||||
|
|
||||||
# We sudo() the quant search to ensure we find quants even if there are record rules,
|
|
||||||
# as this is strictly for filtering the UI dropdown.
|
|
||||||
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 = quants.mapped('lot_id').ids
|
lot_ids = quants.mapped('lot_id').ids
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user