Skip to content

Commit

Permalink
[IMP] stock_cycle_count: improved inventory_accuracy calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnauCForgeFlow committed May 9, 2024
1 parent 09edb8a commit 28c1195
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 15 deletions.
38 changes: 23 additions & 15 deletions stock_cycle_count/models/stock_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@
class StockInventory(models.Model):
_inherit = "stock.inventory"

@api.depends("state", "stock_quant_ids")
def _compute_inventory_accuracy(self):
for inv in self:
theoretical = sum(inv.stock_quant_ids.mapped(lambda x: abs(x.quantity)))
abs_discrepancy = sum(
inv.stock_quant_ids.mapped(lambda x: abs(x.inventory_diff_quantity))
)
if theoretical:
inv.inventory_accuracy = max(
PERCENT * (theoretical - abs_discrepancy) / theoretical, 0.0
)
if not inv.stock_quant_ids and inv.state == "done":
inv.inventory_accuracy = PERCENT

prefill_counted_quantity = fields.Selection(
string="Counted Quantities",
help="Allows to start with a pre-filled counted quantity for each lines or "
Expand All @@ -43,10 +29,10 @@ def _compute_inventory_accuracy(self):
)
inventory_accuracy = fields.Float(
string="Accuracy",
compute="_compute_inventory_accuracy",
digits=(3, 2),
store=True,
group_operator="avg",
default=False,
)

def _get_default_counted_quantitites(self):
Expand Down Expand Up @@ -76,6 +62,26 @@ def _domain_cycle_count_candidate(self):
("location_id", "in", self.location_ids.ids),
]

def _calculate_inventory_accuracy(self):
for inv in self:
accuracy = 100
sum_line_accuracy = 0
sum_theoretical_qty = 0
if inv.stock_move_ids:
for line in inv.stock_move_ids:
sum_line_accuracy += line.theoretical_qty * line.line_accuracy
sum_theoretical_qty += line.theoretical_qty
if sum_theoretical_qty != 0:
accuracy = (sum_line_accuracy / sum_theoretical_qty) * 100
else:
accuracy = 0

Check warning on line 77 in stock_cycle_count/models/stock_inventory.py

View check run for this annotation

Codecov / codecov/patch

stock_cycle_count/models/stock_inventory.py#L77

Added line #L77 was not covered by tests
inv.update(
{
"inventory_accuracy": accuracy,
}
)
return False

def _link_to_planned_cycle_count(self):
self.ensure_one()
domain = self._domain_cycle_count_candidate()
Expand All @@ -100,11 +106,13 @@ def _link_to_planned_cycle_count(self):

def action_state_to_done(self):
res = super(StockInventory, self).action_state_to_done()
self._calculate_inventory_accuracy()
self._update_cycle_state()
return res

def action_force_done(self):
res = super(StockInventory, self).action_force_done()
self._calculate_inventory_accuracy()

Check warning on line 115 in stock_cycle_count/models/stock_inventory.py

View check run for this annotation

Codecov / codecov/patch

stock_cycle_count/models/stock_inventory.py#L115

Added line #L115 was not covered by tests
self._update_cycle_state()
return res

Expand Down
121 changes: 121 additions & 0 deletions stock_cycle_count/tests/test_stock_cycle_count.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ def setUp(self):
self.product1 = self.product_model.create(
{"name": "Test Product 1", "type": "product", "default_code": "PROD1"}
)
self.product2 = self.product_model.create(
{"name": "Test Product 2", "type": "product", "default_code": "PROD2"}
)

def _create_user(self, login, groups, company):
group_ids = [group.id for group in groups]
Expand Down Expand Up @@ -356,3 +359,121 @@ def test_cycle_count_contrains(self):
inventory.exclude_sublocation = False
company = self.env["res.company"].create({"name": "Test"})
inventory.company_id = company

def test_inventory_adjustment_accuracy(self):
date = datetime.today() - timedelta(days=1)
# Create location
loc = self.stock_location_model.create(
{"name": "Test Location", "usage": "internal"}
)
# Create stock quants for specific location
quant1 = self.quant_model.create(
{
"product_id": self.product1.id,
"location_id": loc.id,
"quantity": 10.0,
}
)
quant2 = self.quant_model.create(
{
"product_id": self.product2.id,
"location_id": loc.id,
"quantity": 15.0,
}
)
# Create adjustments for specific location
adjustment = self.inventory_model.create(
{
"name": "Pre-existing inventory",
"location_ids": [(4, loc.id)],
"date": date,
}
)
# Start the adjustment
adjustment.action_state_to_in_progress()
# Check that there are stock quants for the specific location
self.assertTrue(self.env["stock.quant"].search([("location_id", "=", loc.id)]))
# Make the count of the stock
quant1.update(
{
"inventory_quantity": 5,
}
)
quant2.update(
{
"inventory_quantity": 10,
}
)
# Apply the changes
quant1._apply_inventory()
quant2._apply_inventory()
# Check that line_accuracy is calculated properly
sml = self.env["stock.move.line"].search(
[("location_id", "=", loc.id), ("product_id", "=", self.product1.id)]
)
self.assertEqual(sml.line_accuracy, 0.5)
sml = self.env["stock.move.line"].search(
[("location_id", "=", loc.id), ("product_id", "=", self.product2.id)]
)
self.assertEqual(sml.line_accuracy, 0.6667000000000001)
# Set Inventory Adjustment to Done
adjustment.action_state_to_done()
# Check that accuracy is correctly calculated
self.assertEqual(adjustment.inventory_accuracy, 60)

def test_zero_inventory_adjustment_accuracy(self):
date = datetime.today() - timedelta(days=1)
# Create location
loc = self.stock_location_model.create(
{"name": "Test Location", "usage": "internal"}
)
# Create stock quants for specific location
quant1 = self.quant_model.create(
{
"product_id": self.product1.id,
"location_id": loc.id,
"quantity": 0.0,
}
)
quant2 = self.quant_model.create(
{
"product_id": self.product2.id,
"location_id": loc.id,
"quantity": 300.0,
}
)
# Create adjustment for specific location
adjustment = self.inventory_model.create(
{
"name": "Pre-existing inventory qty zero",
"location_ids": [(4, loc.id)],
"date": date,
}
)
# Start the adjustment
adjustment.action_state_to_in_progress()
# Check that there are stock quants for the specific location
self.assertTrue(self.env["stock.quant"].search([("location_id", "=", loc.id)]))
# Make the count of the stock
quant1.update(
{
"inventory_quantity": 5,
}
)
quant2.update(
{
"inventory_quantity": 0,
}
)
# Apply the changes
quant1._apply_inventory()
quant2._apply_inventory()
# Check that line_accuracy is calculated properly
sml = self.env["stock.move.line"].search(
[("location_id", "=", loc.id), ("product_id", "=", self.product1.id)]
)
self.assertEqual(sml.line_accuracy, 0)
# Set Inventory Adjustment to Done
adjustment.action_state_to_done()
# Check that accuracy is correctly calculated
self.assertEqual(adjustment.inventory_accuracy, 0)

0 comments on commit 28c1195

Please sign in to comment.