From ea6de2b0db5217d26a50d212be4f1a0d69cc8b7d Mon Sep 17 00:00:00 2001 From: les-adhoc Date: Thu, 13 Aug 2026 20:01:13 +0000 Subject: [PATCH] [18.0][FIX] purchase_all_shipments: list only pickings of the reception chain The all pickings field searched every picking sharing a procurement group with the order receipts. When that group is shared with other documents, as happens with dropshipping or with purchases generated from a sale order through a make to order route, the purchase order listed pickings belonging to those documents, including customer deliveries. Compute the field from the receipts of the order and the moves pushed by the reception route instead. This keeps the intermediate pickings of multi-step receptions and stops where the demand of another document pulls the goods. --- purchase_all_shipments/models/__init__.py | 1 + .../models/purchase_order.py | 7 +++---- purchase_all_shipments/models/stock_move.py | 18 ++++++++++++++++++ .../tests/test_three_step_reception.py | 15 +++++++++++++++ 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 purchase_all_shipments/models/stock_move.py diff --git a/purchase_all_shipments/models/__init__.py b/purchase_all_shipments/models/__init__.py index 9f03530643d..aa008762df2 100644 --- a/purchase_all_shipments/models/__init__.py +++ b/purchase_all_shipments/models/__init__.py @@ -1 +1,2 @@ from . import purchase_order +from . import stock_move diff --git a/purchase_all_shipments/models/purchase_order.py b/purchase_all_shipments/models/purchase_order.py index c54d10d2739..c063129b8bf 100644 --- a/purchase_all_shipments/models/purchase_order.py +++ b/purchase_all_shipments/models/purchase_order.py @@ -19,11 +19,10 @@ def _compute_all_picking_count(self): def _compute_all_pickings(self): for rec in self: - groups = rec.mapped("picking_ids.group_id") - all_picking_ids = self.env["stock.picking"].search( - [("group_id", "in", groups.ids)] + moves = rec.order_line.move_ids + rec.all_picking_ids = ( + rec.picking_ids | moves._get_reception_chain_moves().picking_id ) - rec.all_picking_ids = all_picking_ids def action_view_all_pickings(self): return self._get_action_view_all_pickings(self.all_picking_ids) diff --git a/purchase_all_shipments/models/stock_move.py b/purchase_all_shipments/models/stock_move.py new file mode 100644 index 00000000000..18674fefdd9 --- /dev/null +++ b/purchase_all_shipments/models/stock_move.py @@ -0,0 +1,18 @@ +# Copyright 2018 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +from odoo import models + + +class StockMove(models.Model): + _inherit = "stock.move" + + def _get_reception_chain_moves(self): + """Recursively get the destination moves that continue the reception. + + Moves pushed by the reception route are part of it, while moves pulled + by the demand of another document are not. + """ + res = self.move_dest_ids.filtered(lambda m: m.rule_id.action == "push") + if res: + res |= res._get_reception_chain_moves() + return res diff --git a/purchase_all_shipments/tests/test_three_step_reception.py b/purchase_all_shipments/tests/test_three_step_reception.py index fed78417343..b0cfa990616 100644 --- a/purchase_all_shipments/tests/test_three_step_reception.py +++ b/purchase_all_shipments/tests/test_three_step_reception.py @@ -29,6 +29,21 @@ def test_three_steps_generate_three_pickings(self): self.po._compute_all_picking_count() self.assertEqual(3, self.po.all_picking_count) + def test_picking_of_other_document_excluded(self): + self.po.button_confirm() + other_picking = self.env["stock.picking"].create( + { + "picking_type_id": self.wh.out_type_id.id, + "location_id": self.wh.lot_stock_id.id, + "location_dest_id": self.env.ref("stock.stock_location_customers").id, + "group_id": self.po.group_id.id, + } + ) + self.po._compute_all_pickings() + self.po._compute_all_picking_count() + self.assertNotIn(other_picking, self.po.all_picking_ids) + self.assertEqual(1, self.po.all_picking_count) + def test_action_view_all_pickings_one_step(self): self.po.button_confirm() action_data = self.po.action_view_all_pickings()