[IMP] uom: change default rounding to two

Change the default rouning digits of all UoMs to be two, also change the
decimal.precision of UoM to be two. Adapt all the tests.
Also to avoid hardcoded digits in `should_consume_qty` widget.

PR #56000

X-original-commit: 460ec0402a2352a5b179d81935f7230f6bc97cb7
This commit is contained in:
yhu-odoo
2020-09-09 09:21:12 +00:00
parent 7110999213
commit 2c5ce41c42
17 changed files with 26 additions and 92 deletions
+1 -1
View File
@@ -102,7 +102,7 @@ class MrpProduction(models.Model):
lot_producing_id = fields.Many2one(
'stock.production.lot', string='Lot/Serial Number', copy=False,
domain="[('product_id', '=', product_id), ('company_id', '=', company_id)]", check_company=True)
qty_producing = fields.Float(string="Quantity Producing", copy=False)
qty_producing = fields.Float(string="Quantity Producing", digits='Product Unit of Measure', copy=False)
product_uom_category_id = fields.Many2one(related='product_id.uom_id.category_id')
product_uom_qty = fields.Float(string='Total Quantity', compute='_compute_product_uom_qty', store=True)
picking_type_id = fields.Many2one(
+1 -1
View File
@@ -107,7 +107,7 @@ class StockMove(models.Model):
store=True,
help='Technical Field to order moves')
order_finished_lot_ids = fields.Many2many('stock.production.lot', string="Finished Lot/Serial Number", compute='_compute_order_finished_lot_ids')
should_consume_qty = fields.Float('Quantity To Consume', compute='_compute_should_consume_qty')
should_consume_qty = fields.Float('Quantity To Consume', compute='_compute_should_consume_qty', digits='Product Unit of Measure')
def _unreserve_initial_demand(self, new_move):
# If you were already putting stock.move.lots on the next one in the work order, transfer those to the new move
@@ -20,8 +20,7 @@ const MrpShouldConsume = FieldFloat.extend({
init: function (parent, name, params) {
this._super.apply(this, arguments);
this.displayShouldConsume = !['done', 'draft', 'cancel'].includes(params.data.state);
const options = {'digits': [false, 3]};
this.should_consume_qty = field_utils.format.float(params.data.should_consume_qty, false, options);
this.should_consume_qty = field_utils.format.float(params.data.should_consume_qty, params.fields.should_consume_qty, this.nodeOptions);
},
//--------------------------------------------------------------------------
-63
View File
@@ -1118,69 +1118,6 @@ class TestMrpOrder(TestMrpCommon):
details_operation_form.save()
mo2.button_mark_done()
def test_product_produce_uom(self):
""" Produce a finished product tracked by serial number. Set another
UoM on the bom. The produce wizard should keep the UoM of the product (unit)
and quantity = 1."""
dozen = self.env.ref('uom.product_uom_dozen')
unit = self.env.ref('uom.product_uom_unit')
plastic_laminate = self.env['product.product'].create({
'name': 'Plastic Laminate',
'type': 'product',
'uom_id': unit.id,
'uom_po_id': unit.id,
'tracking': 'serial',
})
ply_veneer = self.env['product.product'].create({
'name': 'Ply Veneer',
'type': 'product',
'uom_id': unit.id,
'uom_po_id': unit.id,
})
bom = self.env['mrp.bom'].create({
'product_tmpl_id': plastic_laminate.product_tmpl_id.id,
'product_uom_id': unit.id,
'sequence': 1,
'bom_line_ids': [(0, 0, {
'product_id': ply_veneer.id,
'product_qty': 1,
'product_uom_id': unit.id,
'sequence': 1,
})]
})
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = plastic_laminate
mo_form.bom_id = bom
mo_form.product_uom_id = dozen
mo_form.product_qty = 1
mo = mo_form.save()
final_product_lot = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': plastic_laminate.id,
'company_id': self.env.company.id,
})
mo.action_confirm()
mo.action_assign()
self.assertEqual(mo.move_raw_ids.product_qty, 12, '12 units should be reserved.')
# produce product
mo_form = Form(mo)
mo_form.qty_producing = 1/12.0
mo_form.lot_producing_id = final_product_lot
mo = mo_form.save()
move_line_raw = mo.move_raw_ids.mapped('move_line_ids').filtered(lambda m: m.qty_done)
self.assertEqual(move_line_raw.qty_done, 1)
self.assertEqual(move_line_raw.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.')
mo._post_inventory()
move_line_finished = mo.move_finished_ids.mapped('move_line_ids').filtered(lambda m: m.qty_done)
self.assertEqual(move_line_finished.qty_done, 1)
self.assertEqual(move_line_finished.product_uom_id, unit, 'Should be 1 unit since the tracking is serial.')
def test_product_type_service_1(self):
# Create finished product
finished_product = self.env['product.product'].create({
+1 -1
View File
@@ -107,7 +107,7 @@ class TestTraceability(TestMrpCommon):
for line in lines:
tracking = line['columns'][1].split(' ')[1]
self.assertEqual(
line['columns'][-1], "1.000 Units", 'Part with tracking type "%s", should have quantity = 1' % (tracking)
line['columns'][-1], "1.00 Units", 'Part with tracking type "%s", should have quantity = 1' % (tracking)
)
unfoldable = False if tracking == 'none' else True
self.assertEqual(
+1 -1
View File
@@ -151,7 +151,7 @@
<label for="product_qty" string="Quantity"/>
<div class="o_row no-gutters d-flex">
<div attrs="{'invisible': [('state', '=', 'draft')]}" class="o_row">
<field name="qty_producing" digits="[12,3]" class="text-left" attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}"/>
<field name="qty_producing" class="text-left" attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}"/>
/
</div>
<field name="product_qty" class="oe_inline text-left" attrs="{'readonly': [('state', '!=', 'draft')], 'invisible': [('state', 'not in', ('draft', 'done'))]}"/>
@@ -408,10 +408,8 @@ odoo.define('point_of_sale.tour.acceptance', function (require) {
steps = steps.concat(selected_orderline_has({product: 'Desk Organizer', quantity: '0.9', price: '4.59'}));
steps = steps.concat(press_product_numpad('9'))
steps = steps.concat(selected_orderline_has({product: 'Desk Organizer', quantity: '0.99', price: '5.05'}));
steps = steps.concat(press_product_numpad('9'))
steps = steps.concat(selected_orderline_has({product: 'Desk Organizer', quantity: '0.999', price: '5.09'}));
steps = steps.concat(goto_payment_screen_and_select_payment_method());
steps = steps.concat(selected_payment_has('Cash', '5.09'));
steps = steps.concat(selected_payment_has('Cash', '5.05'));
steps = steps.concat(finish_order());
// Test fiscal position one2many map (align with backend)
+1 -1
View File
@@ -34,7 +34,7 @@
</record>
<record forcecreate="True" id="decimal_product_uom" model="decimal.precision">
<field name="name">Product Unit of Measure</field>
<field name="digits" eval="3"/>
<field name="digits" eval="2"/>
</record>
<!--
@@ -69,7 +69,7 @@ tour.register('purchase_matrix_tour', {
run: 'click' // apply the matrix
}, {
trigger: '.o_form_button_save:contains("Save")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("4.000")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("4.00")',
run: 'click' // SAVE Sales Order, after matrix has been applied (extra_trigger).
}, {
trigger: '.o_form_button_edit:contains("Edit")',
@@ -102,7 +102,7 @@ tour.register('purchase_matrix_tour', {
run: 'click' // apply the matrix
}, {
trigger: '.o_form_button_save:contains("Save")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("8.200")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("8.20")',
run: 'click' // SAVE Sales Order, after matrix has been applied (extra_trigger).
},
]);
+4 -4
View File
@@ -304,22 +304,22 @@ class TestSaleToInvoice(TestSaleCommon):
self.assertEqual(sol_prod_deliver.qty_invoiced, 5.0)
# We would have to change the digits of the field to
# test a greater decimal precision.
quantity = 5.003
quantity = 5.13
move_form = Form(sale_order.invoice_ids)
with move_form.invoice_line_ids.edit(0) as line_form:
line_form.quantity = quantity
move_form.save()
# Default uom rounding to 0.001
# Default uom rounding to 0.01
qty_invoiced_field = sol_prod_deliver._fields.get('qty_invoiced')
sol_prod_deliver.env.add_to_compute(qty_invoiced_field, sol_prod_deliver)
self.assertEqual(sol_prod_deliver.qty_invoiced, quantity)
# Rounding to 0.01, should be rounded with UP (ceil) rounding_method
# Rounding to 0.1, should be rounded with UP (ceil) rounding_method
# Not floor or half up rounding.
sol_prod_deliver.product_uom.rounding *= 10
sol_prod_deliver.product_uom.flush(['rounding'])
expected_qty = 5.01
expected_qty = 5.2
qty_invoiced_field = sol_prod_deliver._fields.get('qty_invoiced')
sol_prod_deliver.env.add_to_compute(qty_invoiced_field, sol_prod_deliver)
self.assertEqual(sol_prod_deliver.qty_invoiced, expected_qty)
+5 -5
View File
@@ -1242,7 +1242,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# kit_uom_in_kit --|- component_uom_gm x3 Test-KG
# |- kit_uom_1 x2 Test-Dozen --|- component_uom_unit x2 Test-Dozen
# |- component_uom_dozen x1 Test-Dozen
# |- component_uom_kg x3 Test-G
# |- component_uom_kg x5 Test-G
kit_uom_1 = self._create_product('Sub Kit 1', self.uom_unit)
kit_uom_in_kit = self._create_product('Parent Kit', self.uom_unit)
@@ -1265,7 +1265,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
'bom_id': bom_kit_uom_1.id})
BomLine.create({
'product_id': component_uom_kg.id,
'product_qty': 3.0,
'product_qty': 5.0,
'product_uom_id': self.uom_gm.id,
'bom_id': bom_kit_uom_1.id})
@@ -1294,7 +1294,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
# Set enough quantities to make 1 kit_uom_in_kit in WH1
self.env['stock.quant']._update_available_quantity(component_uom_unit, warehouse_1.lot_stock_id, 576)
self.env['stock.quant']._update_available_quantity(component_uom_dozen, warehouse_1.lot_stock_id, 24)
self.env['stock.quant']._update_available_quantity(component_uom_kg, warehouse_1.lot_stock_id, 0.072)
self.env['stock.quant']._update_available_quantity(component_uom_kg, warehouse_1.lot_stock_id, 0.12)
self.env['stock.quant']._update_available_quantity(component_uom_gm, warehouse_1.lot_stock_id, 3000)
# Creation of a sale order for x5 kit_uom_in_kit
@@ -1323,7 +1323,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
qty_to_process = {
component_uom_unit: (1152, self.uom_unit),
component_uom_dozen: (48, self.uom_dozen),
component_uom_kg: (0.144, self.uom_kg),
component_uom_kg: (0.24, self.uom_kg),
component_uom_gm: (6000, self.uom_gm)
}
self._create_move_quantities(qty_to_process, components, warehouse_1)
@@ -1488,7 +1488,7 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon):
move_component_unit = order.picking_ids[0].move_lines.filtered(lambda m: m.product_id == component_unit)
move_component_kg = order.picking_ids[0].move_lines - move_component_unit
self.assertEqual(move_component_unit.product_uom_qty, 0.5)
self.assertEqual(move_component_kg.product_uom_qty, 0.583)
self.assertEqual(move_component_kg.product_uom_qty, 0.58)
def test_product_type_service_1(self):
route_manufacture = self.company_data['default_warehouse'].manufacture_pull_id.route_id.id
@@ -141,7 +141,7 @@ tour.register('sale_product_configurator_edition_tour', {
}, {
trigger: '.o_sale_product_configurator_edit',
}, {
trigger: 'td.o_data_cell:contains("2.000")',
trigger: 'td.o_data_cell:contains("2.00")',
run: function (){} // check quantity
}, {
trigger: 'td.o_product_configurator_cell',
@@ -101,7 +101,7 @@ tour.register('sale_matrix_tour', {
run: 'click' // apply the matrix
}, {
trigger: '.o_form_button_save:contains("Save")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("4.000")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("4.00")',
run: 'click' // SAVE Sales Order, after matrix has been applied (extra_trigger).
}, {
trigger: '.o_form_button_edit:contains("Edit")',
@@ -134,7 +134,7 @@ tour.register('sale_matrix_tour', {
run: 'click' // apply the matrix
}, {
trigger: '.o_form_button_save:contains("Save")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("8.200")',
extra_trigger: '.o_field_cell.o_data_cell.o_list_number:contains("8.20")',
run: 'click' // SAVE Sales Order, after matrix has been applied (extra_trigger).
},
]);
+2 -2
View File
@@ -275,10 +275,10 @@ class TestPacking(TestPackingCommon):
def test_move_picking_with_package(self):
"""
355.4 rounded with 0.001 precision is 355.40000000000003.
355.4 rounded with 0.01 precision is 355.40000000000003.
check that nonetheless, moving a picking is accepted
"""
self.assertEqual(self.productA.uom_id.rounding, 0.001)
self.assertEqual(self.productA.uom_id.rounding, 0.01)
self.assertEqual(
float_round(355.4, precision_rounding=self.productA.uom_id.rounding),
355.40000000000003,
+2
View File
@@ -9,6 +9,8 @@ from odoo import fields
class TestStockFlow(TestStockCommon):
def setUp(cls):
super(TestStockFlow, cls).setUp()
decimal_product_uom = cls.env.ref('product.decimal_product_uom')
decimal_product_uom.digits = 3
cls.partner_company2 = cls.env['res.partner'].create({
'name': 'My Company (Chicago)-demo',
'email': 'chicago@yourcompany.com',
-2
View File
@@ -27,7 +27,6 @@
<field name="name">Units</field>
<field name="factor" eval="1.0"/>
<field name="uom_type">reference</field>
<field name="rounding" eval="0.001"/>
</record>
<record id="product_uom_dozen" model="uom.uom">
<field name="category_id" ref="uom.product_uom_categ_unit"/>
@@ -41,7 +40,6 @@
<field name="name">kg</field>
<field name="factor" eval="1"/>
<field name="uom_type">reference</field>
<field name="rounding" eval="0.001"/>
</record>
<record id="product_uom_gram" model="uom.uom">
<field name="category_id" ref="product_uom_categ_kgm"/>
+1 -1
View File
@@ -35,7 +35,7 @@ class TestUom(TransactionCase):
# into Kilograms should work even if grams are rounded to 1.
self.uom_gram.write({'rounding': 1})
qty = self.uom_gram._compute_quantity(1234, self.uom_kgm)
self.assertEqual(qty, 1.234, "Converted quantity does not correspond.")
self.assertEqual(qty, 1.24, "Converted quantity does not correspond.")
def test_20_rounding(self):
product_uom = self.env['uom.uom'].create({