[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:
@@ -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()
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user