[ADD] stock_picking_batch_custom: product summary
This commit is contained in:
parent
9c14e1dc1a
commit
ad8b759643
11 changed files with 348 additions and 10 deletions
127
stock_picking_batch_custom/tests/test_batch_summary.py
Normal file
127
stock_picking_batch_custom/tests/test_batch_summary.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# Copyright 2026 Criptomart
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo.tests.common import SavepointCase
|
||||
|
||||
|
||||
class TestBatchSummary(SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.uom_unit = cls.env.ref("uom.product_uom_unit")
|
||||
cls.uom_dozen = cls.env.ref("uom.product_uom_dozen")
|
||||
cls.location_src = cls.env.ref("stock.stock_location_stock")
|
||||
cls.location_dest = cls.env.ref("stock.stock_location_customers")
|
||||
cls.picking_type = cls.env.ref("stock.picking_type_out")
|
||||
|
||||
cls.product = cls.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"uom_id": cls.uom_unit.id,
|
||||
"uom_po_id": cls.uom_unit.id,
|
||||
}
|
||||
)
|
||||
|
||||
cls.batch = cls.env["stock.picking.batch"].create(
|
||||
{"name": "Batch Test", "picking_type_id": cls.picking_type.id}
|
||||
)
|
||||
|
||||
cls.picking1 = cls.env["stock.picking"].create(
|
||||
{
|
||||
"picking_type_id": cls.picking_type.id,
|
||||
"location_id": cls.location_src.id,
|
||||
"location_dest_id": cls.location_dest.id,
|
||||
"batch_id": cls.batch.id,
|
||||
}
|
||||
)
|
||||
cls.picking2 = cls.env["stock.picking"].create(
|
||||
{
|
||||
"picking_type_id": cls.picking_type.id,
|
||||
"location_id": cls.location_src.id,
|
||||
"location_dest_id": cls.location_dest.id,
|
||||
"batch_id": cls.batch.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Helpers
|
||||
def _add_move(self, picking, qty_demanded, qty_done, uom):
|
||||
move = self.env["stock.move"].create(
|
||||
{
|
||||
"name": self.product.name,
|
||||
"product_id": self.product.id,
|
||||
"product_uom_qty": qty_demanded,
|
||||
"product_uom": uom.id,
|
||||
"picking_id": picking.id,
|
||||
"location_id": self.location_src.id,
|
||||
"location_dest_id": self.location_dest.id,
|
||||
}
|
||||
)
|
||||
if qty_done:
|
||||
self.env["stock.move.line"].create(
|
||||
{
|
||||
"move_id": move.id,
|
||||
"picking_id": picking.id,
|
||||
"product_id": self.product.id,
|
||||
"product_uom_id": uom.id,
|
||||
"location_id": self.location_src.id,
|
||||
"location_dest_id": self.location_dest.id,
|
||||
"quantity": qty_done,
|
||||
}
|
||||
)
|
||||
return move
|
||||
|
||||
def _recompute_batch(self):
|
||||
self.batch.invalidate_cache()
|
||||
self.batch._compute_summary_line_ids()
|
||||
|
||||
# Tests
|
||||
def test_totals_and_pending_with_conversion(self):
|
||||
"""Totals aggregate per product with UoM conversion and pending."""
|
||||
|
||||
# demand 12 units, done 5 units
|
||||
self._add_move(self.picking1, qty_demanded=12, qty_done=5, uom=self.uom_unit)
|
||||
# demand 2 dozens (24 units), done 6 units
|
||||
self._add_move(self.picking2, qty_demanded=2, qty_done=6, uom=self.uom_dozen)
|
||||
|
||||
self._recompute_batch()
|
||||
|
||||
self.assertEqual(len(self.batch.summary_line_ids), 1)
|
||||
line = self.batch.summary_line_ids
|
||||
self.assertEqual(line.product_id, self.product)
|
||||
self.assertEqual(line.product_uom_id, self.uom_unit)
|
||||
self.assertAlmostEqual(line.qty_demanded, 36.0)
|
||||
self.assertAlmostEqual(line.qty_done, 11.0)
|
||||
self.assertAlmostEqual(line.qty_pending, 25.0)
|
||||
|
||||
def test_collected_flag_preserved_on_recompute(self):
|
||||
"""Collected stays checked after totals change."""
|
||||
|
||||
self._add_move(self.picking1, qty_demanded=1, qty_done=1, uom=self.uom_unit)
|
||||
self._recompute_batch()
|
||||
|
||||
line = self.batch.summary_line_ids
|
||||
line.is_collected = True
|
||||
|
||||
# Add more demand/done to trigger an update
|
||||
self._add_move(self.picking1, qty_demanded=3, qty_done=2, uom=self.uom_unit)
|
||||
self._recompute_batch()
|
||||
|
||||
self.assertTrue(self.batch.summary_line_ids.is_collected)
|
||||
|
||||
def test_cancelled_moves_are_ignored(self):
|
||||
"""Cancelled moves do not count in the summary and lines are removed."""
|
||||
|
||||
move1 = self._add_move(
|
||||
self.picking1, qty_demanded=4, qty_done=2, uom=self.uom_unit
|
||||
)
|
||||
move2 = self._add_move(
|
||||
self.picking2, qty_demanded=6, qty_done=3, uom=self.uom_unit
|
||||
)
|
||||
self._recompute_batch()
|
||||
self.assertEqual(len(self.batch.summary_line_ids), 1)
|
||||
|
||||
move1.write({"state": "cancel"})
|
||||
move2.write({"state": "cancel"})
|
||||
self._recompute_batch()
|
||||
|
||||
self.assertFalse(self.batch.summary_line_ids)
|
||||
Loading…
Add table
Add a link
Reference in a new issue