diff --git a/stock_cycle_count/models/stock_inventory.py b/stock_cycle_count/models/stock_inventory.py index bbbae6ed6..210c02dec 100644 --- a/stock_cycle_count/models/stock_inventory.py +++ b/stock_cycle_count/models/stock_inventory.py @@ -43,6 +43,34 @@ class StockInventory(models.Model): inv.cycle_count_id.state = "done" return True + def _domain_cycle_count_candidate(self): + return [ + ("state", "=", "draft"), + ("location_id", "in", self.location_ids.ids), + ] + + def _link_to_planned_cycle_count(self): + self.ensure_one() + domain = self._domain_cycle_count_candidate() + candidate = self.env["stock.cycle.count"].search( + domain, limit=1, order="date_deadline asc" + ) + # Also find inventories that do not exclude subloations but that are + # for a bin location (no childs). This makes the attachment logic more + # flexible and user friendly (no need to remember to tick the + # non-standard `exclude_sublocation` field). + if ( + candidate + and not self.product_ids + and ( + self.exclude_sublocation + or (len(self.location_ids) == 1 and not self.location_ids[0].child_ids) + ) + ): + candidate.state = "open" + self.write({"cycle_count_id": candidate.id, "exclude_sublocation": True}) + return True + def action_validate(self): res = super(StockInventory, self).action_validate() self._update_cycle_state() @@ -53,6 +81,13 @@ class StockInventory(models.Model): self._update_cycle_state() return res + @api.model + def create(self, vals): + res = super().create(vals) + if not res.cycle_count_id: + res._link_to_planned_cycle_count() + return res + def write(self, vals): for inventory in self: if ( diff --git a/stock_cycle_count/reports/report_stock_location_accuracy.py b/stock_cycle_count/reports/report_stock_location_accuracy.py index e207c10da..880efb661 100644 --- a/stock_cycle_count/reports/report_stock_location_accuracy.py +++ b/stock_cycle_count/reports/report_stock_location_accuracy.py @@ -14,6 +14,7 @@ class LocationAccuracyReport(models.AbstractModel): return [ ("location_id", "=", loc_id), ("exclude_sublocation", "=", exclude_sublocation), + ("filter", "=", "none"), ("state", "=", "done"), ] diff --git a/stock_cycle_count/tests/test_stock_cycle_count.py b/stock_cycle_count/tests/test_stock_cycle_count.py index 6bd6b9a17..914fd0ecf 100644 --- a/stock_cycle_count/tests/test_stock_cycle_count.py +++ b/stock_cycle_count/tests/test_stock_cycle_count.py @@ -293,3 +293,26 @@ class TestStockCycleCount(common.TransactionCase): zero2.warehouse_ids = [(4, self.big_wh.id)] with self.assertRaises(ValidationError): self.zero_rule.warehouse_ids = [(4, self.small_wh.id)] + + def test_auto_link_inventory_to_cycle_count_1(self): + """Create an inventory that could fit a planned cycle count should + auto-link it to that cycle count.""" + self.assertEqual(self.cycle_count_1.state, "draft") + inventory = self.inventory_model.create( + { + "name": "new inventory", + "location_ids": [(4, self.count_loc.id)], + "exclude_sublocation": True, + } + ) + self.assertEqual(inventory.cycle_count_id, self.cycle_count_1) + self.assertEqual(self.cycle_count_1.state, "open") + + def test_auto_link_inventory_to_cycle_count_2(self): + """Test auto-link when exclude sublocation is no set.""" + self.assertEqual(self.cycle_count_1.state, "draft") + inventory = self.inventory_model.create( + {"name": "new inventory", "location_ids": [(4, self.count_loc.id)]} + ) + self.assertEqual(inventory.cycle_count_id, self.cycle_count_1) + self.assertEqual(self.cycle_count_1.state, "open")