[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:
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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'), '&', ('state', '=', 'done'), ('is_locked', '=', True)]}"/>
|
||||
<field name="qty_producing" class="text-left" attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&', ('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)
|
||||
|
||||
@@ -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).
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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).
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user