fix: Standardize quantity calculations to 8 decimal places and refine decimal cleaning thresholds for improved precision.

This commit is contained in:
Suherdy Yacob 2026-03-16 09:44:44 +07:00
parent c25da22149
commit 4b9efd08a8
3 changed files with 15 additions and 11 deletions

View File

@ -9,14 +9,14 @@ class MrpBom(models.Model):
@api.onchange('packaging_qty')
def _onchange_packaging_qty(self):
if self.packaging_id and self.packaging_qty:
self.product_qty = self.packaging_id.qty * self.packaging_qty
self.product_qty = round(self.packaging_id.qty * self.packaging_qty, 8)
@api.onchange('packaging_id')
def _onchange_packaging_id(self):
if self.packaging_id and self.packaging_id.qty:
self.packaging_qty = self.product_qty / self.packaging_id.qty
self.packaging_qty = round(self.product_qty / self.packaging_id.qty, 8)
@api.onchange('product_qty')
def _onchange_product_qty(self):
if self.packaging_id and self.packaging_id.qty:
self.packaging_qty = self.product_qty / self.packaging_id.qty
self.packaging_qty = round(self.product_qty / self.packaging_id.qty, 8)

View File

@ -25,7 +25,8 @@ class MrpProduction(models.Model):
bom_line = production.env['mrp.bom.line'].browse(move_vals['bom_line_id'])
# Instead of Odoo's noisy exploded qty, use the clean factor
line_quantity = clean_factor * bom_line.product_qty
# Round to 8 decimals before applying the UoM rounding method (UP)
line_quantity = round(clean_factor * bom_line.product_qty, 8)
# It's important to use float_round rather than just python round
# so we respect the UOM rounding method (UP), but on the CLEANED number!
@ -66,7 +67,7 @@ class MrpProduction(models.Model):
for record in self:
if record.packaging_id and record.packaging_id.qty:
qty_in_base = record.product_uom_id._compute_quantity(record.product_qty, record.product_id.uom_id, round=False)
new_qty = qty_in_base / record.packaging_id.qty
new_qty = round(qty_in_base / record.packaging_id.qty, 8)
if float_compare(new_qty, record.packaging_qty, precision_digits=2) != 0:
record.packaging_qty = new_qty
else:
@ -76,7 +77,7 @@ class MrpProduction(models.Model):
for record in self:
if record.packaging_id and record.packaging_id.qty:
qty_in_base = record.packaging_qty * record.packaging_id.qty
record.product_qty = record.product_id.uom_id._compute_quantity(qty_in_base, record.product_uom_id, round=False)
record.product_qty = round(record.product_id.uom_id._compute_quantity(qty_in_base, record.product_uom_id, round=False), 8)
qty_producing_packaging = fields.Float('Quantity Producing Packaging', compute='_compute_qty_producing_packaging', inverse='_inverse_qty_producing_packaging', digits=(16, 2))
@ -86,7 +87,7 @@ class MrpProduction(models.Model):
for record in self:
if record.packaging_id and record.packaging_id.qty:
qty_in_base = record.product_uom_id._compute_quantity(record.qty_producing, record.product_id.uom_id, round=False)
record.qty_producing_packaging = qty_in_base / record.packaging_id.qty
record.qty_producing_packaging = round(qty_in_base / record.packaging_id.qty, 8)
else:
record.qty_producing_packaging = 0.0
@ -94,7 +95,7 @@ class MrpProduction(models.Model):
for record in self:
if record.packaging_id and record.packaging_id.qty:
qty_in_base = record.qty_producing_packaging * record.packaging_id.qty
record.qty_producing = record.product_id.uom_id._compute_quantity(qty_in_base, record.product_uom_id, round=False)
record.qty_producing = round(record.product_id.uom_id._compute_quantity(qty_in_base, record.product_uom_id, round=False), 8)
record._merge_finished_move_lines()
@api.onchange('qty_producing_packaging')
@ -132,14 +133,17 @@ class MrpProduction(models.Model):
def _clean_lingering_decimals(self):
for production in self:
for move in production.move_raw_ids:
rounding = move.product_uom.rounding
if move.product_uom_qty:
# Clean quantities that moved away from clean decimals by exactly the rounding amount
# E.g. 60.030 instead of 60.000 where component increment is 0.010
clean_qty = round(move.product_uom_qty, 2)
if 0.0001 < abs(move.product_uom_qty - clean_qty) < 0.01:
if 0.000001 < abs(move.product_uom_qty - clean_qty) < (rounding * 1.5):
move.product_uom_qty = clean_qty
for ml in move.move_line_ids:
if ml.quantity:
clean_done = round(ml.quantity, 2)
if 0.0001 < abs(ml.quantity - clean_done) < 0.01:
if 0.000001 < abs(ml.quantity - clean_done) < (rounding * 1.5):
ml.quantity = clean_done
def _merge_finished_move_lines(self):

View File

@ -19,7 +19,7 @@ class StockMove(models.Model):
bom_qty = bom.product_uom_id._compute_quantity(bom.product_qty, bom.product_tmpl_id.uom_id, round=False)
if bom_qty:
move.unit_factor = line_qty / bom_qty
move.unit_factor = round(line_qty / bom_qty, 8)
def _set_quantity_done_prepare_vals(self, qty):
# Workaround for Odoo UI onchange bug where move_line_ids (NewId) are sometimes passed