Fix stock picking batch date and does not split batchs by consumer group

This commit is contained in:
snt 2026-05-18 16:07:39 +02:00 committed by GitHub Copilot
parent b73f031dfb
commit 828278573d
2 changed files with 48 additions and 59 deletions

View file

@ -890,47 +890,41 @@ class GroupOrder(models.Model):
self.ensure_one() self.ensure_one()
StockPickingBatch = self.env["stock.picking.batch"].sudo() StockPickingBatch = self.env["stock.picking.batch"].sudo()
# Group sale orders by consumer_group_id # Create batches per group order, not per consumer group.
groups = {} # If multiple picking types exist, keep one batch per picking type.
for so in sale_orders: grouped_pickings = {}
group_id = so.consumer_group_id.id or False pickings = sale_orders.picking_ids.filtered(
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 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: if not pickings:
continue continue
# Get consumer group name for batch description batch_desc = self.name
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 = StockPickingBatch.create( batch = StockPickingBatch.create(
{ {
"description": batch_desc, "description": batch_desc,
"company_id": self.company_id.id, "company_id": self.company_id.id,
"picking_type_id": pickings[0].picking_type_id.id, "picking_type_id": picking_type_id,
"scheduled_date": self.pickup_date, "scheduled_date": scheduled_date,
} }
) )
# Assign pickings to the batch
pickings.write({"batch_id": batch.id}) pickings.write({"batch_id": batch.id})
_logger.info( _logger.info(
"Cron: Created batch %s with %d pickings for group order %s, " "Cron: Created batch %s with %d pickings for group order %s",
"consumer group %s",
batch.name, batch.name,
len(pickings), len(pickings),
self.name, self.name,
consumer_group.name if consumer_group else "N/A",
) )

View file

@ -227,8 +227,8 @@ class TestCronPickingBatch(TransactionCase):
"Cron should snapshot and preserve the current cycle pickup_date when confirming", "Cron should snapshot and preserve the current cycle pickup_date when confirming",
) )
def test_cron_creates_picking_batch_per_consumer_group(self): def test_cron_creates_single_picking_batch_for_group_order(self):
"""Test that cron creates separate picking batches per consumer group.""" """Test that cron creates a single picking batch for the whole group order."""
# Create group order with cutoff yesterday (past) # Create group order with cutoff yesterday (past)
group_order = self._create_group_order(cutoff_in_past=True) 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(so1.picking_ids, "Sale order 1 should have pickings")
self.assertTrue(so2.picking_ids, "Sale order 2 should have pickings") self.assertTrue(so2.picking_ids, "Sale order 2 should have pickings")
# Check that pickings have batch_id assigned # Check that all pickings share the same batch
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)
batch_1 = so1.picking_ids[0].batch_id batch_1 = so1.picking_ids[0].batch_id
batch_2 = so2.picking_ids[0].batch_id batch_2 = so2.picking_ids[0].batch_id
self.assertNotEqual( self.assertEqual(
batch_1.id, batch_1.id,
batch_2.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 # Check that there is only one batch record created
self.assertIn( self.assertEqual(
self.consumer_group_1.name, self.env["stock.picking.batch"].search_count(
batch_1.description, [("description", "=", group_order.name)]
"Batch 1 description should include consumer group 1 name", ),
1,
"Only one batch should be created for a single group order",
) )
self.assertIn(
self.consumer_group_2.name, # Check batch description uses the group order name only
batch_2.description, self.assertEqual(
"Batch 2 description should include consumer group 2 name", batch_1.description,
group_order.name,
"Batch description should be the group order name",
) )
def test_cron_same_consumer_group_same_batch(self): 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") self.assertTrue(so.picking_ids, "Sale order should have pickings")
batch = so.picking_ids[0].batch_id batch = so.picking_ids[0].batch_id
self.assertTrue(batch, "Picking should have a batch") self.assertTrue(batch, "Picking should have a batch")
# scheduled_date should be set (not False/None) self.assertEqual(
self.assertTrue( batch.scheduled_date.date(),
batch.scheduled_date, group_order.pickup_date,
"Batch should have a scheduled_date set", "Batch scheduled_date should be the pickup date (day before delivery)",
) )
def test_cron_does_not_duplicate_batches(self): 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") self.assertTrue(so.picking_ids, "Sale order should have pickings")
batch_first = so.picking_ids[0].batch_id 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 # Call second time
group_order._confirm_linked_sale_orders() group_order._confirm_linked_sale_orders()
batch_second = so.picking_ids[0].batch_id 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 # Should be same batch, no duplicates
self.assertEqual( self.assertEqual(
@ -427,7 +422,7 @@ class TestCronPickingBatch(TransactionCase):
def _patched_action_confirm(recordset): def _patched_action_confirm(recordset):
should_fail = any(so.name == "SO-FAIL" for so in recordset) should_fail = any(so.name == "SO-FAIL" for so in recordset)
if should_fail and not recordset.env.context.get("from_orderpoint"): if should_fail and not recordset.env.context.get("from_orderpoint"):
raise UserError("Simulated stock route error") raise UserError()
return original_action_confirm(recordset) return original_action_confirm(recordset)
with patch.object(SaleOrderClass, "action_confirm", _patched_action_confirm): with patch.object(SaleOrderClass, "action_confirm", _patched_action_confirm):