diff --git a/stock_dynamic_routing/models/stock_location.py b/stock_dynamic_routing/models/stock_location.py index 30177775f936..7d8a1244d3ac 100644 --- a/stock_dynamic_routing/models/stock_location.py +++ b/stock_dynamic_routing/models/stock_location.py @@ -14,3 +14,13 @@ def _location_parent_tree(self): # the recordset will be ordered bottom location to top location tree_ids.reverse() return self.browse(tree_ids) + + def is_sublocation_of(self, others): + """Return True if self is a sublocation of at least one other + + It is equivalent to the "child_of" operator, so it includes itself. + """ + self.ensure_one() + # Efficient way to verify that the current location is + # below one of the other location without using SQL. + return any(self.parent_path.startswith(other.parent_path) for other in others) diff --git a/stock_dynamic_routing/models/stock_move.py b/stock_dynamic_routing/models/stock_move.py index a3785f007492..4aefb18c4354 100644 --- a/stock_dynamic_routing/models/stock_move.py +++ b/stock_dynamic_routing/models/stock_move.py @@ -252,10 +252,9 @@ def _apply_routing_rule_pull(self, routing_details): __applying_routing_rule=True ).location_id = routing_rule.location_src_id move.picking_type_id = routing_rule.picking_type_id - location_path = move.location_dest_id.parent_path - rule_location_path = routing_rule.location_dest_id.parent_path - # if the move location is a parent of the rule's location - if rule_location_path.startswith(location_path): + dest_location = move.location_dest_id + rule_location = routing_rule.location_dest_id + if rule_location.is_sublocation_of(dest_location): # The destination of the move, as a parent of the destination # of the routing, goes to the correct place, but is not precise # enough: set the new destination to match the rule's one. @@ -263,8 +262,7 @@ def _apply_routing_rule_pull(self, routing_details): # which may reapply a new routing rule on the dest. move. move._routing_pull_switch_destination(routing_rule) - # if the move location is not a child of the rule's location - elif not location_path.startswith(rule_location_path): + elif not dest_location.is_sublocation_of(rule_location): # The destination of the move is unrelated (nor identical, nor # a parent or a child) to the routing destination: in this case # we have to add a routing move before the current move to @@ -352,11 +350,10 @@ def _apply_routing_rule_push(self, routing_details): # routing move after this one continue - rule_location_path = routing_rule.location_src_id.parent_path - location_path = move.location_id.parent_path - # if rule location is parent of location - if location_path.startswith(rule_location_path): - # The source is already correct (more precise than the routing), + rule_location = routing_rule.location_src_id + location = move.location_id + if location.is_sublocation_of(rule_location): + # The source is already correct (or more precise than the routing), # but we still want to classify the move in the routing's picking # type. # If the source location of the move is a child of the routing's diff --git a/stock_dynamic_routing/models/stock_routing_rule.py b/stock_dynamic_routing/models/stock_routing_rule.py index 56f3876a3574..2b7b91bd0009 100644 --- a/stock_dynamic_routing/models/stock_routing_rule.py +++ b/stock_dynamic_routing/models/stock_routing_rule.py @@ -61,9 +61,7 @@ def _constrains_picking_type_location(self): if record.method == "pull" and ( not record.location_src_id - or not record.location_src_id.parent_path.startswith( - base_location.parent_path - ) + or not record.location_src_id.is_sublocation_of(base_location) ): raise exceptions.ValidationError( _( @@ -73,9 +71,7 @@ def _constrains_picking_type_location(self): ) elif record.method == "push" and ( not record.location_dest_id - or not record.location_dest_id.parent_path.startswith( - base_location.parent_path - ) + or not record.location_dest_id.is_sublocation_of(base_location) ): raise exceptions.ValidationError(