fix: Adjust total consumed quantities for microscopic rounding errors by applying the difference to a single move line instead of individual lines.

This commit is contained in:
Suherdy Yacob 2026-03-19 13:19:35 +07:00
parent 12ec80e82c
commit 9d6044dd49

View File

@ -157,18 +157,28 @@ class MrpProduction(models.Model):
# 2. Fix "Consumed" (move_line_ids.quantity) # 2. Fix "Consumed" (move_line_ids.quantity)
# If the line is FULLY consumed (e.g. qty_producing == product_qty), # If the line is FULLY consumed (e.g. qty_producing == product_qty),
# then move lines should match the ideal quantity. # then total consumed should match the ideal quantity.
total_done = sum(move.move_line_ids.mapped('quantity'))
if production.qty_producing == production.product_qty: if production.qty_producing == production.product_qty:
diff = ideal_qty - total_done
# Only auto-fix if it's a microscopic rounding drift (not a user overriding quantity intentionally)
if 0.000001 < abs(diff) < (move.product_uom.rounding * 1.5):
for ml in move.move_line_ids: for ml in move.move_line_ids:
if abs(ml.quantity - ideal_qty) > 0.000001: # Safely apply the tiny difference to the first line that has enough quantity
ml.quantity = ideal_qty if ml.quantity and ml.quantity + diff >= 0:
ml.quantity += diff
break
else: else:
# Otherwise just round to 2 decimals if it's "close enough" to a clean decimal # Otherwise just round to 2 decimals if the total drifted by microscopic dust.
# but drifted by microscopic dust. # We shouldn't blindly round every single line if they are split in strange ways,
# but we can fix the tiny decimal dust on the first available line.
clean_total = round(total_done, 2)
diff = clean_total - total_done
if 0.000001 < abs(diff) < (move.product_uom.rounding * 1.5):
for ml in move.move_line_ids: for ml in move.move_line_ids:
clean_done = round(ml.quantity, 2) if ml.quantity and ml.quantity + diff >= 0:
if 0.000001 < abs(ml.quantity - clean_done) < (move.product_uom.rounding * 1.5): ml.quantity += diff
ml.quantity = clean_done break
def _merge_finished_move_lines(self): def _merge_finished_move_lines(self):
for production in self: for production in self: