stock_restrict_source_location/models/stock_location.py

125 lines
5.9 KiB
Python

import logging
from odoo import api, fields, models, _
from odoo.osv import expression
from odoo.exceptions import UserError, ValidationError
_logger = logging.getLogger(__name__)
class StockLocation(models.Model):
_inherit = 'stock.location'
def _get_allowed_locations(self):
"""
Exhaustive lookup for allowed locations with deep diagnostic logging.
"""
ctx = self.env.context
# 1. PRIORITY: Explicitly passed IDs from UI (Context / JS)
target_keys = [
'allowed_source_location_ids',
'default_allowed_source_location_ids',
'allowed_location_ids'
]
for key in target_keys:
val = ctx.get(key)
if not val:
continue
# Simple list of IDs
if isinstance(val, list) and all(isinstance(x, int) for x in val):
_logger.info(f"DEBUG_RESTRICT: Found IDs in context key '{key}': {val}")
return val
# Command format: [(6, 0, [IDs]), (4, ID, 0), ...]
if isinstance(val, list):
col_ids = []
for entry in val:
if isinstance(entry, (list, tuple)):
if entry[0] == 6: return entry[2]
if entry[0] == 4: col_ids.append(entry[1])
if col_ids:
_logger.info(f"DEBUG_RESTRICT: Extracted IDs from Command key '{key}': {col_ids}")
return col_ids
# Single integer
if isinstance(val, int):
_logger.info(f"DEBUG_RESTRICT: Found single ID in context key '{key}': {val}")
return [val]
# 2. FALLBACK: Operation Type (Picking Type)
picking_type_id = (ctx.get('default_picking_type_id') or
ctx.get('picking_type_id') or
ctx.get('active_picking_type_id'))
mo_id = (ctx.get('active_mo_id') or ctx.get('default_mo_id') or ctx.get('default_production_id'))
if not picking_type_id and mo_id:
mo = self.env['mrp.production'].browse(mo_id)
if mo.exists():
picking_type_id = mo.picking_type_id.id
if picking_type_id:
pt = self.env['stock.picking.type'].browse(picking_type_id)
if pt.exists():
if pt.default_location_src_ids:
_logger.info(f"DEBUG_RESTRICT: Found IDs via Picking Type M2M: {pt.default_location_src_ids.ids}")
return pt.default_location_src_ids.ids
if pt.default_location_src_id:
_logger.info(f"DEBUG_RESTRICT: Found ID via Picking Type M21: {pt.default_location_src_id.id}")
return [pt.default_location_src_id.id]
# 3. FINAL FALLBACK: Current Source Location
if ctx.get('default_location_id'):
_logger.info(f"DEBUG_RESTRICT: Falling back to default_location_id: {ctx.get('default_location_id')}")
return [ctx.get('default_location_id')]
return False
class StockQuant(models.Model):
_inherit = 'stock.quant'
@api.model
def web_search_read(self, domain, specification, offset=0, limit=None, order=None, count_limit=None):
ctx = self.env.context
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
allowed_ids = self.env['stock.location']._get_allowed_locations()
if allowed_ids:
# Add location filter; ensure no existing location_id filter blocks us
# Odoo's native JS often adds its own ["location_id", "child_of", ...]
# We prioritize our list.
domain = expression.AND([domain, [('location_id', 'child_of', allowed_ids)]])
_logger.error(f"DEBUG_RESTRICT: SEARCH QUANT - Allowed: {allowed_ids} - Final Domain: {domain}")
return super().web_search_read(domain, specification, offset=offset, limit=limit, order=order, count_limit=count_limit)
class StockLot(models.Model):
_inherit = 'stock.lot'
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
ctx = self.env.context
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
allowed_ids = self.env['stock.location']._get_allowed_locations()
if allowed_ids:
quant_domain = [('location_id', 'child_of', allowed_ids), ('quantity', '>', 0), ('lot_id', '!=', False)]
if ctx.get('default_product_id'):
quant_domain.append(('product_id', '=', ctx.get('default_product_id')))
quants = self.env['stock.quant'].with_context(skip_location_restriction=True).sudo().search(quant_domain)
args = expression.AND([args or [], [('id', 'in', quants.mapped('lot_id').ids)]])
return super().name_search(name, args=args, operator=operator, limit=limit)
@api.model
def web_search_read(self, domain, specification, offset=0, limit=None, order=None, count_limit=None):
ctx = self.env.context
if not ctx.get('skip_location_restriction') and ctx.get('uid'):
allowed_ids = self.env['stock.location']._get_allowed_locations()
if allowed_ids:
quant_domain = [('location_id', 'child_of', allowed_ids), ('quantity', '>', 0), ('lot_id', '!=', False)]
if ctx.get('default_product_id'):
quant_domain.append(('product_id', '=', ctx.get('default_product_id')))
quants = self.env['stock.quant'].with_context(skip_location_restriction=True).sudo().search(quant_domain)
domain = expression.AND([domain, [('id', 'in', quants.mapped('lot_id').ids)]])
return super().web_search_read(domain, specification, offset=offset, limit=limit, order=order, count_limit=count_limit)