Skip to content

Commit

Permalink
[FIX] stock_quant_manual_assign: Correct handling of immediate transfers
Browse files Browse the repository at this point in the history
This commit fixes the following issues:

- The previous code does not handle the immediate transfer scenario when
  auto_fill_qty_done is selected in the operation type. This raises a missing-record
  error, trying to update qty_done on non-existing move line records.
- move._do_unreserve() keeps existing stock.move.line records if there is some
  qty_done set, which is not a desirable outcome. All the linked move line records
  should be unlinked before selected quants are assigned.
  • Loading branch information
yostashiro authored and AungKoKoLin1997 committed Oct 21, 2024
1 parent d5ebefb commit c7dc47b
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 75 deletions.
4 changes: 4 additions & 0 deletions stock_quant_manual_assign/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ Contributors

- Tony Gu [email protected]

* `Quartile <https://www.quartile.co>`_:

* Yoshi Tashiro

Maintainers
-----------

Expand Down
4 changes: 4 additions & 0 deletions stock_quant_manual_assign/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
* `Shine IT <https://www.openerp.cn>`_:

* Tony Gu <[email protected]>

* `Quartile <https://www.quartile.co>`_:

* Yoshi Tashiro
4 changes: 4 additions & 0 deletions stock_quant_manual_assign/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<li>Tony Gu <a class="reference external" href="mailto:tony&#64;openerp.cn">tony&#64;openerp.cn</a></li>
</ul>
</li>
<li><a class="reference external" href="https://www.quartile.co">Quartile</a>:<ul>
<li>Yoshi Tashiro</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
126 changes: 55 additions & 71 deletions stock_quant_manual_assign/tests/test_stock_quant_manual_assign.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,84 +9,74 @@ class TestStockQuantManualAssign(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.quant_model = cls.env["stock.quant"]
cls.picking_model = cls.env["stock.picking"]
cls.location_model = cls.env["stock.location"]
cls.move_model = cls.env["stock.move"]
cls.quant_assign_wizard = cls.env["assign.manual.quants"]
cls.ModelDataObj = cls.env["ir.model.data"]
cls.product = cls.env["product.product"].create(
{"name": "Product 4 test", "type": "product"}
)
cls.location_src = cls.env.ref("stock.stock_location_locations_virtual")
cls.location_dst = cls.env.ref("stock.stock_location_customers")
cls.picking_type_out = cls.ModelDataObj._xmlid_to_res_id(
cls.picking_type_out = cls.env["ir.model.data"]._xmlid_to_res_id(
"stock.picking_type_out"
)
cls.env["stock.picking.type"].browse(
cls.picking_type_out
).reservation_method = "manual"
cls.location1 = cls.location_model.create(
{
"name": "Location 1",
"usage": "internal",
"location_id": cls.location_src.id,
}
)
cls.location2 = cls.location_model.create(
{
"name": "Location 2",
"usage": "internal",
"location_id": cls.location_src.id,
}
)
cls.location3 = cls.location_model.create(
{
"name": "Location 3",
"usage": "internal",
"location_id": cls.location_src.id,
}
)
cls.location1 = cls._create_location(cls, "Location 1")
cls.location2 = cls._create_location(cls, "Location 2")
cls.location3 = cls._create_location(cls, "Location 3")
cls.picking_type = cls.env.ref("stock.picking_type_out")
cls.quant1 = cls.quant_model.sudo().create(
cls.quant1 = cls._create_quant(cls, cls.product, 100.0, cls.location1)
cls.quant2 = cls._create_quant(cls, cls.product, 100.0, cls.location2)
cls.quant3 = cls._create_quant(cls, cls.product, 100.0, cls.location3)
cls.picking = cls.env["stock.picking"].create(
{
"product_id": cls.product.id,
"quantity": 100.0,
"picking_type_id": cls.picking_type.id,
"location_id": cls.location1.id,
"location_dest_id": cls.location_dst.id,
}
)
cls.quant2 = cls.quant_model.sudo().create(
{
"product_id": cls.product.id,
"quantity": 100.0,
"location_id": cls.location2.id,
}
)
cls.quant3 = cls.quant_model.sudo().create(
{
"product_id": cls.product.id,
"quantity": 100.0,
"location_id": cls.location3.id,
}
)
cls.move = cls.move_model.create(
cls.move = cls.env["stock.move"].create(
{
"name": cls.product.name,
"product_id": cls.product.id,
"product_uom_qty": 400.0,
"product_uom": cls.product.uom_id.id,
"location_id": cls.location_src.id,
"location_dest_id": cls.location_dst.id,
"picking_type_id": cls.picking_type.id,
"picking_id": cls.picking.id,
}
)
cls.move._action_confirm()

def test_quant_assign_wizard(self):
wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
{}
def _create_location(self, name):
return self.env["stock.location"].create(
{"name": name, "usage": "internal", "location_id": self.location_src.id}
)

def _create_quant(self, product, qty, location):
return (
self.env["stock.quant"]
.sudo()
.create(
{"product_id": product.id, "quantity": qty, "location_id": location.id}
)
)

def _create_wizard(self):
return (
self.env["assign.manual.quants"]
.with_context(active_id=self.move.id)
.create({})
)

def _process_basic_manual_assign_steps(self, wizard):
wizard.quants_lines[0].write({"selected": True})
wizard.quants_lines[0]._onchange_selected()
wizard.quants_lines[1].write({"selected": True, "qty": 50.0})
self.assertEqual(wizard.lines_qty, 150.0)

def test_quant_assign_wizard(self):
wizard = self._create_wizard()
self.assertEqual(
len(wizard.quants_lines.ids),
3,
Expand All @@ -105,9 +95,7 @@ def test_quant_assign_wizard(self):
self.assertEqual(wizard.move_qty, self.move.product_uom_qty)

def test_quant_assign_wizard_constraint(self):
wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
{}
)
wizard = self._create_wizard()
self.assertEqual(
len(wizard.quants_lines.ids),
3,
Expand All @@ -129,18 +117,13 @@ def test_quant_assign_wizard_constraint(self):
)

def test_quant_manual_assign(self):
wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
{}
)
wizard = self._create_wizard()
self.assertEqual(
len(wizard.quants_lines.ids),
3,
"Three quants created, three quants got by default",
)
wizard.quants_lines[0].write({"selected": True})
wizard.quants_lines[0]._onchange_selected()
wizard.quants_lines[1].write({"selected": True, "qty": 50.0})
self.assertEqual(wizard.lines_qty, 150.0)
self._process_basic_manual_assign_steps(wizard)
self.assertEqual(wizard.move_qty, 250.0)
wizard.assign_quants()
self.assertAlmostEqual(
Expand All @@ -151,24 +134,25 @@ def test_quant_manual_assign(self):
self.assertFalse(self.move.picking_type_id.auto_fill_qty_done)
self.assertEqual(sum(self.move.move_line_ids.mapped("qty_done")), 0.0)

def test_quant_manual_assign_auto_fill_qty_done(self):
wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
{}
)
wizard.quants_lines[0].write({"selected": True})
wizard.quants_lines[0]._onchange_selected()
wizard.quants_lines[1].write({"selected": True, "qty": 50.0})
self.assertEqual(wizard.lines_qty, 150.0)
def _process_quant_manual_assign_auto_fill_qty_done(self):
wizard = self._create_wizard()
self._process_basic_manual_assign_steps(wizard)
self.picking_type.auto_fill_qty_done = True
wizard.assign_quants()
self.assertTrue(self.move.picking_type_id.auto_fill_qty_done)
self.assertEqual(sum(self.move.move_line_ids.mapped("qty_done")), 150.0)

def test_quant_manual_assign_auto_fill_qty_done_planned(self):
self.assertFalse(self.picking.immediate_transfer)
self._process_quant_manual_assign_auto_fill_qty_done()

def test_quant_manual_assign_auto_fill_qty_done_immediate(self):
self.picking.immediate_transfer = True
self._process_quant_manual_assign_auto_fill_qty_done()

def test_quant_assign_wizard_after_availability_check(self):
self.move._action_assign()
wizard = self.quant_assign_wizard.with_context(active_id=self.move.id).create(
{}
)
wizard = self._create_wizard()
self.assertEqual(
len(wizard.quants_lines.ids),
3,
Expand Down
11 changes: 7 additions & 4 deletions stock_quant_manual_assign/wizard/assign_manual_quants.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ def _compute_qties(self):

def assign_quants(self):
move = self.move_id
move._do_unreserve()
self.move_id.move_line_ids.unlink()
for line in self.quants_lines:
line._assign_quant_line()
if move.picking_type_id.auto_fill_qty_done:
# Auto-fill all lines as done
for ml in move.move_line_ids:
ml.qty_done = ml.reserved_uom_qty
if move.from_immediate_transfer:
move.quantity_done = self.lines_qty
else:
# Auto-fill all lines as done
for ml in move.move_line_ids:
ml.qty_done = ml.reserved_uom_qty
move._recompute_state()
move.mapped("picking_id")._compute_state()
return {}
Expand Down

0 comments on commit c7dc47b

Please sign in to comment.