From 20fb9a40d0250aab2fe0097597740ee88b46df8c Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Fri, 3 Apr 2026 21:38:50 +0700 Subject: [PATCH] feat: prioritize context-based location filtering and sync allowed locations to modals --- models/stock_location.py | 41 ++++++++++++++----- .../js/stock_move_line_x2_many_field_patch.js | 8 ++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/models/stock_location.py b/models/stock_location.py index bf25642..97b1750 100644 --- a/models/stock_location.py +++ b/models/stock_location.py @@ -10,19 +10,41 @@ class StockLocation(models.Model): def _get_allowed_locations(self): """ - Helper to retrieve allowed locations based on the current context (picking type). - Used by UI-level overrides in StockQuant and StockLot. + Helper to retrieve allowed locations based on the current context. + PRIORITY 1: Use explicit IDs passed in context (from views). + PRIORITY 2: Manual lookup from picking type or MO. Returns: list: IDs of allowed locations. False: If no restriction should be applied. """ ctx = self.env.context - # 1. Identify the Picking Type (Operation Type) + + # 1. PRIORITY: Check the context for allowed locations (Passed by views) + # This is the most reliable source in the MO "Add line" catalog/details view. + # It handles both 'allowed_source_location_ids' and 'default_allowed_source_location_ids' + context_ids = (ctx.get('allowed_source_location_ids') or + ctx.get('default_allowed_source_location_ids')) + + if context_ids: + # Handle list of IDs, or Command tuples (e.g. [Command.set([ID1, ID2])]) + if isinstance(context_ids, list): + # Simple list of IDs + if all(isinstance(x, int) for x in context_ids): + return context_ids + # Command format: [(6, 0, [ID1, ID2])] + for cmd in context_ids: + if isinstance(cmd, (list, tuple)) and cmd[0] == 6: + return cmd[2] + # Single ID + if isinstance(context_ids, int): + return [context_ids] + + # 2. FALLBACK: Identify the Picking Type (Operation Type) picking_type_id = (ctx.get('default_picking_type_id') or ctx.get('picking_type_id') or ctx.get('active_picking_type_id')) - # 2. Advanced MO Support: find picking type from MO ID if needed + # MO IDs mo_id = (ctx.get('active_mo_id') or ctx.get('default_mo_id') or ctx.get('default_production_id') or @@ -37,14 +59,14 @@ class StockLocation(models.Model): if not picking_type_id: return False - # 3. Retrieve allowed locations from the picking type + # 3. Retrieve allowed locations from the identified picking type picking_type = self.env['stock.picking.type'].browse(picking_type_id) if picking_type.exists(): - # Priority 1: Use the M2M "Allowed Source Locations" if set + # Many-to-Many "Allowed Source Locations" if picking_type.default_location_src_ids: return picking_type.default_location_src_ids.ids - # Priority 2: Fallback to the primary "Default Source Location" (M2O) + # Many-to-One "Default Source Location" if picking_type.default_location_src_id: return [picking_type.default_location_src_id.id] @@ -63,7 +85,7 @@ class StockQuant(models.Model): if not ctx.get('skip_location_restriction') and ctx.get('uid'): allowed_location_ids = self.env['stock.location']._get_allowed_locations() if allowed_location_ids: - # FIX (Attempt 9): Switch to 'child_of' to support sub-locations + # Add location filter to the domain ONLY if we have an explicit list domain = expression.AND([domain, [('location_id', 'child_of', allowed_location_ids)]]) return super().web_search_read(domain, specification, offset=offset, limit=limit, order=order, count_limit=count_limit) @@ -80,12 +102,12 @@ class StockLot(models.Model): if not ctx.get('skip_location_restriction') and ctx.get('uid'): allowed_location_ids = self.env['stock.location']._get_allowed_locations() + # Safe Fallback for lots if not allowed_location_ids and ctx.get('default_location_id'): allowed_location_ids = [ctx.get('default_location_id')] if allowed_location_ids: quant_domain = [ - # FIX (Attempt 9): Switch to 'child_of' to support sub-locations ('location_id', 'child_of', allowed_location_ids), ('quantity', '>', 0), ('lot_id', '!=', False) @@ -115,7 +137,6 @@ class StockLot(models.Model): if allowed_location_ids: quant_domain = [ - # FIX (Attempt 9): Switch to 'child_of' to support sub-locations ('location_id', 'child_of', allowed_location_ids), ('quantity', '>', 0), ('lot_id', '!=', False) diff --git a/static/src/js/stock_move_line_x2_many_field_patch.js b/static/src/js/stock_move_line_x2_many_field_patch.js index 4b2cfa0..cb6860b 100644 --- a/static/src/js/stock_move_line_x2_many_field_patch.js +++ b/static/src/js/stock_move_line_x2_many_field_patch.js @@ -30,6 +30,14 @@ patch(SMLX2ManyField.prototype, { }; } + // Final Sync: ensure allowed locations from the parent view are passed to the modal + if (this.props.context.default_allowed_source_location_ids) { + context = { + ...context, + default_allowed_source_location_ids: this.props.context.default_allowed_source_location_ids, + }; + } + return super.onAdd({ context, editable }); } });