[FIX] mrp: handle unbuild/scrap/unscrap and production with same serial
When a product has been unbuilt and also (mistakenly) scrapped, it's impossible to reuse the serial number in production again, even if the product is unscrapped. This fixes the sanity check in a similar way to the _check_sn_uniqueness function, not just checking for removed stock move lines, but also unremoved stock move lines. A test case is also added to check this scenario. This is a similar fix to a previous commit we did (4f07b260807053586ac6c01cf92ac3d5e37b1041) where we bumped into a problem with the duplicate serial sanity check. closes odoo/odoo#142574 X-original-commit: 1761b95d9fda5d5355f35effd1f345a25ded1197 Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
committed by
William Henrotin
parent
29a6abfba1
commit
d00d6bcb08
@@ -2560,10 +2560,17 @@ class MrpProduction(models.Model):
|
||||
removed = self.env['stock.move.line'].search_count([
|
||||
('lot_id', '=', lot.id),
|
||||
('state', '=', 'done'),
|
||||
('location_dest_id.scrap_location', '=', True)
|
||||
('location_id.scrap_location', '=', False),
|
||||
('location_dest_id.scrap_location', '=', True),
|
||||
])
|
||||
unremoved = self.env['stock.move.line'].search_count([
|
||||
('lot_id', '=', lot.id),
|
||||
('state', '=', 'done'),
|
||||
('location_id.scrap_location', '=', True),
|
||||
('location_dest_id.scrap_location', '=', False),
|
||||
])
|
||||
# Either removed or unbuild
|
||||
if not ((duplicates_unbuild or removed) and duplicates - duplicates_unbuild - removed == 0):
|
||||
if not ((duplicates_unbuild or removed) and duplicates - duplicates_unbuild - removed + unremoved == 0):
|
||||
return True
|
||||
# Check presence of same sn in current production
|
||||
duplicates = co_prod_move_lines.filtered(lambda ml: ml.quantity and ml.lot_id == lot)
|
||||
|
||||
@@ -1391,6 +1391,79 @@ class TestMrpOrder(TestMrpCommon):
|
||||
subassembly_mo2.lot_producing_id = subassembly_sn
|
||||
subassembly_mo2.button_mark_done()
|
||||
|
||||
def test_product_produce_duplicate_6(self):
|
||||
"""Produce a product for the second time with the same serial
|
||||
after having unbuilt, scrapped and unscrapped the product"""
|
||||
product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product",
|
||||
"type": "product",
|
||||
"tracking": "serial",
|
||||
}
|
||||
)
|
||||
|
||||
sn = self.env["stock.lot"].create(
|
||||
{
|
||||
"name": "SN",
|
||||
"product_id": product.id,
|
||||
"company_id": self.env.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
mo1_form = Form(self.env["mrp.production"])
|
||||
mo1_form.product_id = product
|
||||
mo1 = mo1_form.save()
|
||||
mo1.action_confirm()
|
||||
with Form(mo1) as mo:
|
||||
mo.qty_producing = 1
|
||||
mo1.lot_producing_id = sn
|
||||
mo1.button_mark_done()
|
||||
|
||||
ub_form = Form(self.env["mrp.unbuild"])
|
||||
ub_form.mo_id = mo1
|
||||
ub = ub_form.save()
|
||||
ub.action_unbuild()
|
||||
|
||||
scrap = self.env['stock.scrap'].create({
|
||||
'product_id': product.id,
|
||||
'product_uom_id': product.uom_id.id,
|
||||
'lot_id': sn.id,
|
||||
})
|
||||
scrap.do_scrap()
|
||||
|
||||
unscrap_picking = self.env['stock.picking'].create({
|
||||
'picking_type_id': self.env.ref('stock.picking_type_internal').id,
|
||||
'location_id': scrap.scrap_location_id.id,
|
||||
'location_dest_id': scrap.location_id.id,
|
||||
})
|
||||
unscrap_move = self.env['stock.move'].create({
|
||||
'name': 'unscrap',
|
||||
'location_id': scrap.scrap_location_id.id,
|
||||
'location_dest_id': scrap.location_id.id,
|
||||
'product_id': product.id,
|
||||
'product_uom': product.uom_id.id,
|
||||
'picking_id': unscrap_picking.id,
|
||||
})
|
||||
unscrap_picking.action_confirm()
|
||||
self.env['stock.move.line'].create({
|
||||
'move_id': unscrap_move.id,
|
||||
'product_id': unscrap_move.product_id.id,
|
||||
'lot_id': sn.id,
|
||||
'quantity': 1,
|
||||
'product_uom_id': unscrap_move.product_uom.id,
|
||||
'picking_id': unscrap_move.picking_id.id,
|
||||
})
|
||||
unscrap_picking.button_validate()
|
||||
|
||||
mo2_form = Form(self.env["mrp.production"])
|
||||
mo2_form.product_id = product
|
||||
mo2 = mo2_form.save()
|
||||
mo2.action_confirm()
|
||||
with Form(mo2) as mo:
|
||||
mo.qty_producing = 1
|
||||
mo2.lot_producing_id = sn
|
||||
mo2.button_mark_done()
|
||||
|
||||
def test_product_produce_12(self):
|
||||
""" Checks that, the production is robust against deletion of finished move."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user