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 authored and JoanSForgeFlow committed Jun 25, 2024
1 parent 4ce763f commit eb979ef
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 14 deletions.
37 changes: 23 additions & 14 deletions stock_cycle_count/models/stock_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,12 @@ class StockInventory(models.Model):
)
inventory_accuracy = fields.Float(
string="Accuracy",
compute="_compute_inventory_accuracy",
digits=(3, 2),
store=True,
group_operator="avg",
default=False,
)

@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

def _update_cycle_state(self):
for inv in self:
Expand All @@ -61,6 +48,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
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 @@ -85,11 +92,13 @@ def _link_to_planned_cycle_count(self):

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

def action_force_done(self):
res = super().action_force_done()
self._calculate_inventory_accuracy()
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 @@ -77,6 +77,9 @@ def setUpClass(cls):
cls.product1 = cls.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"}
)

@classmethod
def _create_user(cls, login, groups, company):
Expand Down Expand Up @@ -355,3 +358,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 eb979ef

Please sign in to comment.