From 828278573dd1fcb78795d4b0dce542f126191818 Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 18 May 2026 16:07:39 +0200 Subject: [PATCH] Fix stock picking batch date and does not split batchs by consumer group --- website_sale_aplicoop/models/group_order.py | 44 ++++++------- .../tests/test_cron_picking_batch.py | 63 +++++++++---------- 2 files changed, 48 insertions(+), 59 deletions(-) diff --git a/website_sale_aplicoop/models/group_order.py b/website_sale_aplicoop/models/group_order.py index e0f4250..399e508 100644 --- a/website_sale_aplicoop/models/group_order.py +++ b/website_sale_aplicoop/models/group_order.py @@ -890,47 +890,41 @@ class GroupOrder(models.Model): self.ensure_one() StockPickingBatch = self.env["stock.picking.batch"].sudo() - # Group sale orders by consumer_group_id - groups = {} - for so in sale_orders: - group_id = so.consumer_group_id.id or False - if group_id not in groups: - groups[group_id] = self.env["sale.order"] - groups[group_id] |= so - - for consumer_group_id, group_sale_orders in groups.items(): - # Get pickings without batch - pickings = group_sale_orders.picking_ids.filtered( - lambda p: p.state not in ("done", "cancel") and not p.batch_id + # Create batches per group order, not per consumer group. + # If multiple picking types exist, keep one batch per picking type. + grouped_pickings = {} + pickings = sale_orders.picking_ids.filtered( + lambda p: p.state not in ("done", "cancel") and not p.batch_id + ) + for picking in pickings: + grouped_pickings.setdefault( + picking.picking_type_id.id, self.env["stock.picking"] ) + grouped_pickings[picking.picking_type_id.id] |= picking + scheduled_date = self.pickup_date + if not scheduled_date and self.delivery_date: + scheduled_date = self.delivery_date - timedelta(days=1) + + for picking_type_id, pickings in grouped_pickings.items(): if not pickings: continue - # Get consumer group name for batch description - consumer_group = self.env["res.partner"].browse(consumer_group_id) - batch_desc = ( - f"{self.name} - {consumer_group.name}" if consumer_group else self.name - ) - - # Create the batch + batch_desc = self.name batch = StockPickingBatch.create( { "description": batch_desc, "company_id": self.company_id.id, - "picking_type_id": pickings[0].picking_type_id.id, - "scheduled_date": self.pickup_date, + "picking_type_id": picking_type_id, + "scheduled_date": scheduled_date, } ) - # Assign pickings to the batch pickings.write({"batch_id": batch.id}) _logger.info( - "Cron: Created batch %s with %d pickings for group order %s, " - "consumer group %s", + "Cron: Created batch %s with %d pickings for group order %s", batch.name, len(pickings), self.name, - consumer_group.name if consumer_group else "N/A", ) diff --git a/website_sale_aplicoop/tests/test_cron_picking_batch.py b/website_sale_aplicoop/tests/test_cron_picking_batch.py index ae04036..f2cb3b5 100644 --- a/website_sale_aplicoop/tests/test_cron_picking_batch.py +++ b/website_sale_aplicoop/tests/test_cron_picking_batch.py @@ -227,8 +227,8 @@ class TestCronPickingBatch(TransactionCase): "Cron should snapshot and preserve the current cycle pickup_date when confirming", ) - def test_cron_creates_picking_batch_per_consumer_group(self): - """Test that cron creates separate picking batches per consumer group.""" + def test_cron_creates_single_picking_batch_for_group_order(self): + """Test that cron creates a single picking batch for the whole group order.""" # Create group order with cutoff yesterday (past) group_order = self._create_group_order(cutoff_in_past=True) @@ -247,39 +247,30 @@ class TestCronPickingBatch(TransactionCase): self.assertTrue(so1.picking_ids, "Sale order 1 should have pickings") self.assertTrue(so2.picking_ids, "Sale order 2 should have pickings") - # Check that pickings have batch_id assigned - for picking in so1.picking_ids: - self.assertTrue( - picking.batch_id, - "Picking from SO1 should be assigned to a batch", - ) - - for picking in so2.picking_ids: - self.assertTrue( - picking.batch_id, - "Picking from SO2 should be assigned to a batch", - ) - - # Check that batches are different (one per consumer group) + # Check that all pickings share the same batch batch_1 = so1.picking_ids[0].batch_id batch_2 = so2.picking_ids[0].batch_id - self.assertNotEqual( + self.assertEqual( batch_1.id, batch_2.id, - "Different consumer groups should have different batches", + "Different consumer groups in the same group order should share one batch", ) - # Check batch descriptions contain consumer group names - self.assertIn( - self.consumer_group_1.name, - batch_1.description, - "Batch 1 description should include consumer group 1 name", + # Check that there is only one batch record created + self.assertEqual( + self.env["stock.picking.batch"].search_count( + [("description", "=", group_order.name)] + ), + 1, + "Only one batch should be created for a single group order", ) - self.assertIn( - self.consumer_group_2.name, - batch_2.description, - "Batch 2 description should include consumer group 2 name", + + # Check batch description uses the group order name only + self.assertEqual( + batch_1.description, + group_order.name, + "Batch description should be the group order name", ) def test_cron_same_consumer_group_same_batch(self): @@ -342,10 +333,10 @@ class TestCronPickingBatch(TransactionCase): self.assertTrue(so.picking_ids, "Sale order should have pickings") batch = so.picking_ids[0].batch_id self.assertTrue(batch, "Picking should have a batch") - # scheduled_date should be set (not False/None) - self.assertTrue( - batch.scheduled_date, - "Batch should have a scheduled_date set", + self.assertEqual( + batch.scheduled_date.date(), + group_order.pickup_date, + "Batch scheduled_date should be the pickup date (day before delivery)", ) def test_cron_does_not_duplicate_batches(self): @@ -364,13 +355,17 @@ class TestCronPickingBatch(TransactionCase): self.assertTrue(so.picking_ids, "Sale order should have pickings") batch_first = so.picking_ids[0].batch_id - batch_count_first = self.env["stock.picking.batch"].search_count([]) + batch_count_first = self.env["stock.picking.batch"].search_count( + [("description", "=", group_order.name)] + ) # Call second time group_order._confirm_linked_sale_orders() batch_second = so.picking_ids[0].batch_id - batch_count_second = self.env["stock.picking.batch"].search_count([]) + batch_count_second = self.env["stock.picking.batch"].search_count( + [("description", "=", group_order.name)] + ) # Should be same batch, no duplicates self.assertEqual( @@ -427,7 +422,7 @@ class TestCronPickingBatch(TransactionCase): def _patched_action_confirm(recordset): should_fail = any(so.name == "SO-FAIL" for so in recordset) if should_fail and not recordset.env.context.get("from_orderpoint"): - raise UserError("Simulated stock route error") + raise UserError() return original_action_confirm(recordset) with patch.object(SaleOrderClass, "action_confirm", _patched_action_confirm):