[FIX] mrp: unbuild a decimal quantity

It is sometimes impossible to unbuild a product because of decimal
values.

To reproduce the issue:
(Enable debug mode)
1. In Settings, enable "Units of Measure"
2. Set the decimal accuracy of "Product Unit of Measure" to 4
3. Set the rounding precision of "Units" to 0.001
4. Create two products P1, P2
5. Create a BoM:
    - Product: P1
    - Quantity: 3
    - Type: Manufacture
    - Components: 5 x P2
6. Process a MO with 3 x P1
7. Create an unbuild order UO:
    - Manufacturing Order: MO
    - Quantity: 1
8. Unbuild

Error: An error message is displayed "The quantity done for the product
"P2" doesn't respect the rounding precision[...]"

At some point, for each SM associated to the UO, the modules uses the
value of `product_uom_qty` to write the done quantity of the SM. The
rounding of `product_uom_qty` is based on "Product Unit of Measure" so
the component's SM has its quantity equal to `1.6667`. Moreover, writing
the done quantity trigger the creation of the associated SML. As a
result, the SML has its done quantity equal to `1.6667` while the
rounding of the associated UoM is `0.001`. When calling `_action_done`
on such a SML, it will raise an error because the value doesn't respect
the rounding.

Side note: the error message is incorrectly written, the indents in the
file are displayed on the front-end.

OPW-2710038

closes odoo/odoo#83369

X-original-commit: c11d772f39179c5dec5eb431b6f4bc02c680643a
Signed-off-by: Adrien Widart <awt@odoo.com>
Signed-off-by: Arnold Moyaux <arm@odoo.com>
This commit is contained in:
Adrien Widart
2022-01-26 13:11:00 +00:00
parent 8bf5c66616
commit 7e950abc6c
4 changed files with 40 additions and 9 deletions
+2 -2
View File
@@ -3,7 +3,7 @@
from odoo import api, fields, models, _
from odoo.exceptions import AccessError, UserError
from odoo.tools import float_compare
from odoo.tools import float_compare, float_round
from odoo.osv import expression
@@ -182,7 +182,7 @@ class MrpUnbuild(models.Model):
})
needed_quantity -= taken_quantity
else:
move.quantity_done = move.product_uom_qty
move.quantity_done = float_round(move.product_uom_qty, precision_rounding=move.product_uom.rounding)
finished_moves._action_done()
consume_moves._action_done()
+33
View File
@@ -598,3 +598,36 @@ class TestUnbuild(TestMrpCommon):
self.assertEqual(StockQuant._get_available_quantity(finshed_product, self.stock_location), 0, 'Table should not be available in stock')
self.assertEqual(StockQuant._get_available_quantity(component1, self.stock_location), 1, 'Table head should be available in stock as the picking is transferred')
self.assertEqual(StockQuant._get_available_quantity(component2, self.stock_location), 1, 'Table stand should be available in stock as the picking is transferred')
def test_unbuild_decimal_qty(self):
"""
Use case:
- decimal accuracy of Product UoM > decimal accuracy of Units
- unbuild a product with a decimal quantity of component
"""
self.env['decimal.precision'].search([('name', '=', 'Product Unit of Measure')]).digits = 4
self.uom_unit.rounding = 0.001
self.bom_1.product_qty = 3
self.bom_1.bom_line_ids.product_qty = 5
self.env['stock.quant']._update_available_quantity(self.product_2, self.stock_location, 3)
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.bom_1.product_id
mo_form.bom_id = self.bom_1
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
mo_form = Form(mo)
mo_form.qty_producing = 3
mo_form.save()
mo.button_mark_done()
uo_form = Form(self.env['mrp.unbuild'])
uo_form.mo_id = mo
# Unbuilding one product means a decimal quantity equal to 1 / 3 * 5 for each component
uo_form.product_qty = 1
uo = uo_form.save()
uo.action_unbuild()
self.assertEqual(uo.state, 'done')
+2 -4
View File
@@ -7298,10 +7298,8 @@ msgstr ""
#, python-format
msgid ""
"The quantity done for the product \"%s\" doesn't respect the rounding "
"precision defined on the unit of measure "
"\"%s\". Please change the quantity done or the"
" rounding precision of your unit of "
"measure."
"precision defined on the unit of measure \"%s\". Please change the quantity "
"done or the rounding precision of your unit of measure."
msgstr ""
#. module: stock
+3 -3
View File
@@ -506,9 +506,9 @@ class StockMoveLine(models.Model):
precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure')
qty_done = float_round(ml.qty_done, precision_digits=precision_digits, rounding_method='HALF-UP')
if float_compare(uom_qty, qty_done, precision_digits=precision_digits) != 0:
raise UserError(_('The quantity done for the product "%s" doesn\'t respect the rounding precision \
defined on the unit of measure "%s". Please change the quantity done or the \
rounding precision of your unit of measure.') % (ml.product_id.display_name, ml.product_uom_id.name))
raise UserError(_('The quantity done for the product "%s" doesn\'t respect the rounding precision '
'defined on the unit of measure "%s". Please change the quantity done or the '
'rounding precision of your unit of measure.') % (ml.product_id.display_name, ml.product_uom_id.name))
qty_done_float_compared = float_compare(ml.qty_done, 0, precision_rounding=ml.product_uom_id.rounding)
if qty_done_float_compared > 0: