[FIX] mrp: unlink temp stock move lots when updating quantity to done qty
You start with an MO with a quantity of 2 with routing and we produce just 1. At least one of the components is tracked by lots. When we update the MO to a quantity of 1 again, the temporary stock.move.lots continued to exist which led to processing a the consume d move of e.g. 1 piece with 2 pieces of the quants processed when posting inventory. A test is added in order to avoid this case opw-767526 and opw-772786
This commit is contained in:
committed by
Nicolas Martinelli
parent
0038bf43f2
commit
d62b307597
@@ -80,7 +80,6 @@ class TestWorkOrderProcess(common.TransactionCase):
|
||||
# --------------------------------------------------------------
|
||||
# Process cutting operation...
|
||||
# ---------------------------------------------------------
|
||||
|
||||
finished_lot =self.env['stock.production.lot'].create({'product_id': production_table.product_id.id})
|
||||
workorders[0].write({'final_lot_id': finished_lot.id})
|
||||
workorders[0].button_start()
|
||||
@@ -148,6 +147,119 @@ class TestWorkOrderProcess(common.TransactionCase):
|
||||
|
||||
self.assertEqual(finished_quant.consumed_quant_ids, consume_quants)
|
||||
|
||||
def test_00b_workorder_process(self):
|
||||
""" Testing consume quants and produced quants with workorder """
|
||||
dining_table = self.env.ref("mrp.product_product_computer_desk")
|
||||
product_table_sheet = self.env.ref('mrp.product_product_computer_desk_head')
|
||||
product_table_leg = self.env.ref('mrp.product_product_computer_desk_leg')
|
||||
product_bolt = self.env.ref('mrp.product_product_computer_desk_bolt')
|
||||
|
||||
production_table = self.env['mrp.production'].create({
|
||||
'product_id': dining_table.id,
|
||||
'product_qty': 2.0,
|
||||
'product_uom_id': dining_table.uom_id.id,
|
||||
'bom_id': self.ref("mrp.mrp_bom_desk")
|
||||
})
|
||||
|
||||
# Set tracking lot on finish and consume products.
|
||||
dining_table.tracking = 'lot'
|
||||
product_table_sheet.tracking = 'lot'
|
||||
product_table_leg.tracking = 'lot'
|
||||
product_bolt.tracking = "lot"
|
||||
|
||||
# Initial inventory of product sheet, lags and bolt
|
||||
lot_sheet = self.env['stock.production.lot'].create({'product_id': product_table_sheet.id})
|
||||
lot_leg = self.env['stock.production.lot'].create({'product_id': product_table_leg.id})
|
||||
lot_bolt = self.env['stock.production.lot'].create({'product_id': product_bolt.id})
|
||||
|
||||
# Initialize inventory
|
||||
# --------------------
|
||||
inventory = self.env['stock.inventory'].create({
|
||||
'name': 'Inventory Product Table',
|
||||
'filter': 'partial',
|
||||
'line_ids': [(0, 0, {
|
||||
'product_id': product_table_sheet.id,
|
||||
'product_uom_id': product_table_sheet.uom_id.id,
|
||||
'product_qty': 20,
|
||||
'prod_lot_id': lot_sheet.id,
|
||||
'location_id': self.source_location_id
|
||||
}), (0, 0, {
|
||||
'product_id': product_table_leg.id,
|
||||
'product_uom_id': product_table_leg.uom_id.id,
|
||||
'product_qty': 20,
|
||||
'prod_lot_id': lot_leg.id,
|
||||
'location_id': self.source_location_id
|
||||
}), (0, 0, {
|
||||
'product_id': product_bolt.id,
|
||||
'product_uom_id': product_bolt.uom_id.id,
|
||||
'product_qty': 20,
|
||||
'prod_lot_id': lot_bolt.id,
|
||||
'location_id': self.source_location_id
|
||||
})]
|
||||
})
|
||||
inventory.action_done()
|
||||
|
||||
# Create work order
|
||||
production_table.button_plan()
|
||||
# Check Work order created or not
|
||||
self.assertEqual(len(production_table.workorder_ids), 3)
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Process all workorder and check it state.
|
||||
# ----------------------------------------------------------
|
||||
|
||||
workorders = production_table.workorder_ids
|
||||
self.assertEqual(workorders[0].state, 'ready', "First workorder state should be ready.")
|
||||
self.assertEqual(workorders[1].state, 'pending')
|
||||
self.assertEqual(workorders[2].state, 'pending')
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Process cutting operation...
|
||||
# ---------------------------------------------------------
|
||||
finished_lot = self.env['stock.production.lot'].create({'product_id': production_table.product_id.id})
|
||||
workorders[0].write({'final_lot_id': finished_lot.id, 'qty_producing': 1.0})
|
||||
workorders[0].button_start()
|
||||
workorders[0].active_move_lot_ids[0].write({'lot_id': lot_sheet.id, 'quantity_done': 1})
|
||||
self.assertEqual(workorders[0].state, 'progress')
|
||||
workorders[0].record_production()
|
||||
|
||||
move_table_sheet = production_table.move_raw_ids.filtered(lambda x : x.product_id == product_table_sheet)
|
||||
self.assertEqual(move_table_sheet.quantity_done, 1)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Process drilling operation ...
|
||||
# ---------------------------------------------------------
|
||||
workorders[1].button_start()
|
||||
workorders[1].qty_producing = 1.0
|
||||
workorders[1].active_move_lot_ids[0].write({'lot_id': lot_leg.id, 'quantity_done': 4})
|
||||
workorders[1].record_production()
|
||||
move_leg = production_table.move_raw_ids.filtered(lambda x : x.product_id == product_table_leg)
|
||||
#self.assertEqual(workorders[1].state, 'done')
|
||||
self.assertEqual(move_leg.quantity_done, 4)
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Process fitting operation ...
|
||||
# ---------------------------------------------------------
|
||||
workorders[2].button_start()
|
||||
workorders[2].qty_producing = 1.0
|
||||
move_lot = workorders[2].active_move_lot_ids[0]
|
||||
move_lot.write({'lot_id': lot_bolt.id, 'quantity_done': 4})
|
||||
move_table_bolt = production_table.move_raw_ids.filtered(lambda x : x.product_id.id == product_bolt.id)
|
||||
workorders[2].record_production()
|
||||
self.assertEqual(move_table_bolt.quantity_done, 4)
|
||||
|
||||
# Change the quantity of the production order to 1
|
||||
wiz = self.env['change.production.qty'].create({'mo_id': production_table.id ,
|
||||
'product_qty': 1.0})
|
||||
wiz.change_prod_qty()
|
||||
# ---------------------------------------------------------------
|
||||
# Check consume quants and produce quants after posting inventory
|
||||
# ---------------------------------------------------------------
|
||||
production_table.post_inventory()
|
||||
self.assertEqual(sum(move_table_sheet.quant_ids.mapped('qty')), 1, "Wrong quantity of consumed product %s" % move_table_sheet.product_id.name)
|
||||
self.assertEqual(sum(move_leg.quant_ids.mapped('qty')), 4, "Wrong quantity of consumed product %s" % move_leg.product_id.name)
|
||||
self.assertEqual(sum(move_table_bolt.quant_ids.mapped('qty')), 4, "Wrong quantity of consumed product %s" % move_table_bolt.product_id.name)
|
||||
|
||||
def test_01_without_workorder(self):
|
||||
""" Testing consume quants and produced quants without workorder """
|
||||
unit = self.ref("product.product_uom_unit")
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import float_is_zero
|
||||
import math
|
||||
|
||||
class ChangeProductionQty(models.TransientModel):
|
||||
@@ -37,6 +38,7 @@ class ChangeProductionQty(models.TransientModel):
|
||||
|
||||
@api.multi
|
||||
def change_prod_qty(self):
|
||||
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||
for wizard in self:
|
||||
production = wizard.mo_id
|
||||
produced = sum(production.move_finished_ids.mapped('quantity_done'))
|
||||
@@ -64,11 +66,14 @@ class ChangeProductionQty(models.TransientModel):
|
||||
wo.duration_expected = (operation.workcenter_id.time_start +
|
||||
operation.workcenter_id.time_stop +
|
||||
cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
|
||||
quantity = wo.qty_production - wo.qty_produced
|
||||
if production.product_id.tracking == 'serial':
|
||||
quantity = 1.0
|
||||
quantity = 1.0 if float_is_zero(quantity, precision_digits=precision) else 0.0
|
||||
else:
|
||||
quantity = wo.qty_production - wo.qty_produced
|
||||
quantity = quantity if (quantity > 0) else 0
|
||||
if float_is_zero(quantity, precision_digits=precision):
|
||||
wo.final_lot_id = False
|
||||
wo.active_move_lot_ids.unlink()
|
||||
wo.qty_producing = quantity
|
||||
if wo.qty_produced < wo.qty_production and wo.state == 'done':
|
||||
wo.state = 'progress'
|
||||
@@ -81,6 +86,6 @@ class ChangeProductionQty(models.TransientModel):
|
||||
moves_finished = production.move_finished_ids.filtered(lambda move: move.operation_id == operation) #TODO: code does nothing, unless maybe by_products?
|
||||
moves_raw.mapped('move_lot_ids').write({'workorder_id': wo.id})
|
||||
(moves_finished + moves_raw).write({'workorder_id': wo.id})
|
||||
if wo.move_raw_ids.filtered(lambda x: x.product_id.tracking != 'none') and not wo.active_move_lot_ids:
|
||||
if quantity > 0 and wo.move_raw_ids.filtered(lambda x: x.product_id.tracking != 'none') and not wo.active_move_lot_ids:
|
||||
wo._generate_lot_ids()
|
||||
return {}
|
||||
|
||||
Reference in New Issue
Block a user