from odoo import api, models class StockMove(models.Model): _inherit = 'stock.move' @api.depends('product_uom_qty', 'raw_material_production_id', 'raw_material_production_id.product_qty', 'raw_material_production_id.qty_producing') def _compute_unit_factor(self): super()._compute_unit_factor() for move in self: mo = move.raw_material_production_id or move.production_id # Prevent 3-decimal rounding drift if the move comes from a BOM Line! if mo and mo.bom_id and move.bom_line_id: # Use the exact, unrounded mathematical ratio directly from BOM line and UoMs. bom_line = move.bom_line_id bom = mo.bom_id # Fetch quantities directly converting to product matching formats without DB truncation line_qty = bom_line.product_uom_id._compute_quantity(bom_line.product_qty, bom_line.product_id.uom_id, round=False) 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 = 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 # from the browser without their product_id, causing "Expected singleton: uom.uom()" crashes. for ml in self.move_line_ids: if not ml.product_id and self.product_id: ml.product_id = self.product_id return super()._set_quantity_done_prepare_vals(qty)