From 96922836201af364cfbb9d9e61b821374f42d49c Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Tue, 10 Mar 2026 11:50:06 +0700 Subject: [PATCH] feat: Add picking type to stock moves and enhance picking type and allowed source location inheritance for move lines, including production contexts. --- models/stock_move.py | 18 +++++++++++++++- models/stock_move_line.py | 45 +++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/models/stock_move.py b/models/stock_move.py index a61224e..05cf969 100644 --- a/models/stock_move.py +++ b/models/stock_move.py @@ -7,9 +7,25 @@ class StockMove(models.Model): allowed_source_location_ids = fields.Many2many( 'stock.location', string='Allowed Source Locations', compute='_compute_allowed_source_location_ids', - store=True, precompute=True, compute_sudo=True + store=True, compute_sudo=True ) + picking_type_id = fields.Many2one( + 'stock.picking.type', 'Operation Type', + compute='_compute_picking_type_id', store=True, readonly=False) + + @api.depends('picking_id.picking_type_id', 'raw_material_production_id.picking_type_id', 'production_id.picking_type_id') + def _compute_picking_type_id(self): + for move in self: + if move.picking_id: + move.picking_type_id = move.picking_id.picking_type_id + elif move.raw_material_production_id: + move.picking_type_id = move.raw_material_production_id.picking_type_id + elif move.production_id: + move.picking_type_id = move.production_id.picking_type_id + elif not move.picking_type_id: + move.picking_type_id = False + @api.depends('picking_type_id', 'picking_type_id.default_location_src_ids', 'picking_id.allowed_source_location_ids', 'raw_material_production_id.allowed_source_location_ids', 'production_id.allowed_source_location_ids') def _compute_allowed_source_location_ids(self): for move in self: diff --git a/models/stock_move_line.py b/models/stock_move_line.py index 0bd7a50..195d86a 100644 --- a/models/stock_move_line.py +++ b/models/stock_move_line.py @@ -8,39 +8,62 @@ class StockMoveLine(models.Model): picking_type_id = fields.Many2one( 'stock.picking.type', 'Operation type', compute='_compute_picking_type_id', - store=True, precompute=True, compute_sudo=True) + store=True, compute_sudo=True) allowed_source_location_ids = fields.Many2many( 'stock.location', string='Allowed Source Locations', - compute='_compute_allowed_source_location_ids', - store=True, precompute=True + compute='_compute_allowed_source_location_ids' ) - @api.depends('picking_id', 'move_id.picking_type_id') + @api.model + def default_get(self, fields_list): + res = super().default_get(fields_list) + if 'allowed_source_location_ids' in fields_list and not res.get('allowed_source_location_ids'): + move_id = res.get('move_id') or self.env.context.get('default_move_id') + if move_id: + move = self.env['stock.move'].browse(move_id) + if move.exists() and move.allowed_source_location_ids: + res['allowed_source_location_ids'] = [fields.Command.set(move.allowed_source_location_ids.ids)] + return res + + @api.depends('picking_id', 'move_id.picking_type_id', 'move_id.raw_material_production_id.picking_type_id', 'move_id.production_id.picking_type_id') def _compute_picking_type_id(self): for line in self: if line.picking_id: line.picking_type_id = line.picking_id.picking_type_id _logger.info(f"LOCATION_RESTRICT: Line {line.id} picking_type_id from picking: {line.picking_type_id.name if line.picking_type_id else 'None'}") elif line.move_id: - line.picking_type_id = line.move_id.picking_type_id - _logger.info(f"LOCATION_RESTRICT: Line {line.id} picking_type_id from move: {line.picking_type_id.name if line.picking_type_id else 'None'}") + line.picking_type_id = line.move_id.picking_type_id or \ + (line.move_id.raw_material_production_id.picking_type_id if line.move_id.raw_material_production_id else False) or \ + (line.move_id.production_id.picking_type_id if line.move_id.production_id else False) + _logger.info(f"LOCATION_RESTRICT: Line {line.id} picking_type_id from move/production: {line.picking_type_id.name if line.picking_type_id else 'None'}") else: line.picking_type_id = False _logger.info(f"LOCATION_RESTRICT: Line {line.id} NO picking_type_id") - @api.depends('picking_type_id', 'picking_type_id.default_location_src_ids') + @api.depends('picking_type_id', 'picking_type_id.default_location_src_ids', 'move_id.allowed_source_location_ids') def _compute_allowed_source_location_ids(self): for line in self: - line.allowed_source_location_ids = line.picking_type_id.default_location_src_ids + move = line.move_id + if not move and self.env.context.get('default_move_id'): + move = self.env['stock.move'].browse(self.env.context.get('default_move_id')) + + if move and move.exists() and move.allowed_source_location_ids: + line.allowed_source_location_ids = move.allowed_source_location_ids + else: + line.allowed_source_location_ids = line.picking_type_id.default_location_src_ids _logger.info(f"LOCATION_RESTRICT: Line {line.id} allowed locations: {[loc.complete_name for loc in line.allowed_source_location_ids]}") @api.onchange('move_id') def _onchange_move_id_restrict(self): """Populate allowed locations from move for virtual records""" - if self.move_id and self.move_id.picking_type_id: - self.allowed_source_location_ids = self.move_id.picking_type_id.default_location_src_ids - _logger.info(f"LOCATION_RESTRICT ONCHANGE: Setting allowed from move {self.move_id.id}: {[loc.complete_name for loc in self.allowed_source_location_ids]}") + if self.move_id: + if self.move_id.allowed_source_location_ids: + self.allowed_source_location_ids = self.move_id.allowed_source_location_ids + _logger.info(f"LOCATION_RESTRICT ONCHANGE: Setting allowed from move {self.move_id.id} (specific ids): {[loc.complete_name for loc in self.allowed_source_location_ids]}") + elif self.move_id.picking_type_id: + self.allowed_source_location_ids = self.move_id.picking_type_id.default_location_src_ids + _logger.info(f"LOCATION_RESTRICT ONCHANGE: Setting allowed from move {self.move_id.id} (picking type defaults): {[loc.complete_name for loc in self.allowed_source_location_ids]}") @api.onchange('picking_id') def _onchange_picking_id_restrict(self):