mirror of
https://github.com/bringout/oca-ocb-mrp.git
synced 2026-04-27 14:32:01 +02:00
19.0 vanilla
This commit is contained in:
parent
accf5918df
commit
6e65e8c877
688 changed files with 225434 additions and 199401 deletions
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_mrp_repair_flow
|
||||
from . import test_tracability
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.fields import Command
|
||||
from odoo.tests import tagged
|
||||
from odoo.addons.mrp.tests.common import TestMrpCommon
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestMrpRepairFlow(TestMrpCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.ref('base.group_user').write({'implied_ids': [(4, cls.env.ref('stock.group_production_lot').id)]})
|
||||
|
||||
def test_repair_with_manufacture_mto_link(self):
|
||||
"""
|
||||
Test the integration between a repair order and a manufacturing order (MTO)
|
||||
for a product with 'Make to Order' (MTO) and 'Manufacture' routes.
|
||||
|
||||
Validates that a repair order triggers a manufacturing order with correct product
|
||||
and quantity, and ensures proper linking via the procurement group.
|
||||
"""
|
||||
mto_route = self.env.ref('stock.route_warehouse0_mto')
|
||||
mto_route.active = True
|
||||
manufacturing_route = self.env['stock.rule'].search([('action', '=', 'manufacture')]).route_id
|
||||
rule = mto_route.rule_ids.filtered(lambda r: r.picking_type_id.code == 'repair_operation')
|
||||
rule.procure_method = 'make_to_order'
|
||||
|
||||
product = self.product_2
|
||||
product.write({
|
||||
'route_ids': [Command.set([mto_route.id, manufacturing_route.id])],
|
||||
})
|
||||
|
||||
repair = self.env['repair.order'].create([
|
||||
{
|
||||
'move_ids': [
|
||||
Command.create({
|
||||
'repair_line_type': 'add',
|
||||
'product_id': product.id,
|
||||
'product_uom_qty': 1.0,
|
||||
})
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
repair.action_validate()
|
||||
|
||||
production = repair.reference_ids.production_ids
|
||||
self.assertEqual(production.product_id, product)
|
||||
self.assertEqual(production.product_qty, 1.0)
|
||||
self.assertEqual(production.move_dest_ids.repair_id, repair)
|
||||
self.assertEqual(production.repair_count, 1)
|
||||
self.assertEqual(repair.production_count, 1)
|
||||
|
||||
def test_adding_kit_parts_to_confirmed_repair(self):
|
||||
"""Test adding a kit product to a confirmed repair order.
|
||||
This ensures that:
|
||||
- Its moves are correctly exploded into their component parts.
|
||||
- The generated component moves are properly linked to the repair order.
|
||||
"""
|
||||
repair = self.env['repair.order'].create({
|
||||
'product_id': self.product.id,
|
||||
'picking_type_id': self.warehouse_1.repair_type_id.id,
|
||||
})
|
||||
repair.action_validate()
|
||||
self.assertEqual(repair.state, 'confirmed')
|
||||
self.assertEqual(len(repair.move_ids), 0)
|
||||
# Ensure the product is a kit
|
||||
self.assertTrue(self.product_5.is_kits)
|
||||
# Add the kit to the repair order
|
||||
self.env['stock.move'].create({
|
||||
'repair_id': repair.id,
|
||||
'product_id': self.product_5.id,
|
||||
'product_uom_qty': 1.0,
|
||||
'repair_line_type': 'add',
|
||||
})
|
||||
# Check that the kit has been exploded into its components
|
||||
self.assertEqual(len(repair.move_ids), 2)
|
||||
self.assertEqual(
|
||||
set(repair.move_ids.product_id.ids),
|
||||
set(self.product_5.bom_ids.bom_line_ids.product_id.ids)
|
||||
)
|
||||
|
|
@ -24,7 +24,6 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
ptrepair_lot = self.env['stock.lot'].create({
|
||||
'name': 'A1',
|
||||
'product_id': product_to_repair.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
product_to_remove = self.env['product.product'].create({
|
||||
'name': 'other first serial to remove with repair',
|
||||
|
|
@ -33,7 +32,6 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
ptremove_lot = self.env['stock.lot'].create({
|
||||
'name': 'B2',
|
||||
'product_id': product_to_remove.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
# Create a manufacturing order with product (with SN A1)
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
|
|
@ -44,21 +42,23 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
# Set serial to A1
|
||||
mo.lot_producing_id = ptrepair_lot
|
||||
mo.lot_producing_ids = ptrepair_lot
|
||||
# Set component serial to B2
|
||||
mo.move_raw_ids.move_line_ids.lot_id = ptremove_lot
|
||||
mo.move_raw_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
|
||||
with Form(self.env['repair.order']) as ro_form:
|
||||
ro_form.product_id = product_to_repair
|
||||
ro_form.lot_id = ptrepair_lot # Repair product Serial A1
|
||||
with ro_form.operations.new() as operation:
|
||||
operation.type = 'remove'
|
||||
with ro_form.move_ids.new() as operation:
|
||||
operation.repair_line_type = 'remove'
|
||||
operation.product_id = product_to_remove
|
||||
operation.lot_id = ptremove_lot # Remove product Serial B2 from the product
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = ptremove_lot # Remove product Serial B2 from the product.
|
||||
ro.action_repair_start()
|
||||
ro.move_ids.picked = True
|
||||
ro.action_repair_end()
|
||||
|
||||
# Create a manufacturing order with product (with SN A2)
|
||||
|
|
@ -70,13 +70,13 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
mo2 = mo2_form.save()
|
||||
mo2.action_confirm()
|
||||
# Set serial to A2
|
||||
mo2.lot_producing_id = self.env['stock.lot'].create({
|
||||
mo2.lot_producing_ids = self.env['stock.lot'].create({
|
||||
'name': 'A2',
|
||||
'product_id': product_to_repair.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
# Set component serial to B2 again, it is possible
|
||||
mo2.move_raw_ids.move_line_ids.lot_id = ptremove_lot
|
||||
mo2.move_raw_ids.picked = True
|
||||
# We are not forbidden to use that serial number, so nothing raised here
|
||||
mo2.button_mark_done()
|
||||
|
||||
|
|
@ -95,48 +95,39 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.action_assign()
|
||||
action = mo.button_mark_done()
|
||||
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
|
||||
wizard.process()
|
||||
mo.move_raw_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
return mo
|
||||
|
||||
picking_type = self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')])[0]
|
||||
picking_type.use_auto_consume_components_lots = True
|
||||
|
||||
stock_location = self.env.ref('stock.stock_location_stock')
|
||||
|
||||
finished, component = self.env['product.product'].create([{
|
||||
'name': 'Finished Product',
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
}, {
|
||||
'name': 'SN Componentt',
|
||||
'type': 'product',
|
||||
'name': 'SN Component',
|
||||
'is_storable': True,
|
||||
'tracking': 'serial',
|
||||
}])
|
||||
|
||||
sn_lot = self.env['stock.lot'].create({
|
||||
'product_id': component.id,
|
||||
'name': 'USN01',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
self.env['stock.quant']._update_available_quantity(component, stock_location, 1, lot_id=sn_lot)
|
||||
self.env['stock.quant']._update_available_quantity(component, self.stock_location, 1, lot_id=sn_lot)
|
||||
|
||||
mo = produce_one(finished, component)
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
|
||||
|
||||
ro_form = Form(self.env['repair.order'])
|
||||
ro_form.product_id = finished
|
||||
with ro_form.operations.new() as ro_line:
|
||||
ro_line.type = 'remove'
|
||||
with ro_form.move_ids.new() as ro_line:
|
||||
ro_line.repair_line_type = 'recycle'
|
||||
ro_line.product_id = component
|
||||
ro_line.lot_id = sn_lot
|
||||
ro_line.location_dest_id = stock_location
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = sn_lot
|
||||
ro.action_repair_start()
|
||||
ro.move_ids.picked = True
|
||||
ro.action_repair_end()
|
||||
|
||||
mo = produce_one(finished, component)
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
|
||||
|
|
@ -145,39 +136,39 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
# The user should be able to use the component in a new MO.
|
||||
ro_form = Form(self.env['repair.order'])
|
||||
ro_form.product_id = finished
|
||||
with ro_form.operations.new() as ro_line:
|
||||
ro_line.type = 'remove'
|
||||
with ro_form.move_ids.new() as ro_line:
|
||||
ro_line.repair_line_type = 'recycle'
|
||||
ro_line.product_id = component
|
||||
ro_line.lot_id = sn_lot
|
||||
ro_line.location_dest_id = stock_location
|
||||
ro_line.location_dest_id = self.stock_location
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = sn_lot
|
||||
ro.action_repair_start()
|
||||
ro.action_repair_end()
|
||||
self.assertEqual(ro.state, 'done')
|
||||
# Add the component into the product
|
||||
ro_form = Form(self.env['repair.order'])
|
||||
ro_form.product_id = finished
|
||||
with ro_form.operations.new() as ro_line:
|
||||
ro_line.type = 'add'
|
||||
with ro_form.move_ids.new() as ro_line:
|
||||
ro_line.repair_line_type = 'add'
|
||||
ro_line.product_id = component
|
||||
ro_line.lot_id = sn_lot
|
||||
ro_line.location_id = stock_location
|
||||
ro_line.location_id = self.stock_location
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = sn_lot
|
||||
ro.action_repair_start()
|
||||
ro.action_repair_end()
|
||||
self.assertEqual(ro.state, 'done')
|
||||
# Removing it a second time
|
||||
ro_form = Form(self.env['repair.order'])
|
||||
ro_form.product_id = finished
|
||||
with ro_form.operations.new() as ro_line:
|
||||
ro_line.type = 'remove'
|
||||
with ro_form.move_ids.new() as ro_line:
|
||||
ro_line.repair_line_type = 'recycle'
|
||||
ro_line.product_id = component
|
||||
ro_line.lot_id = sn_lot
|
||||
ro_line.location_dest_id = stock_location
|
||||
ro_line.location_dest_id = self.stock_location
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = sn_lot
|
||||
ro.action_repair_start()
|
||||
ro.action_repair_end()
|
||||
self.assertEqual(ro.state, 'done')
|
||||
|
|
@ -193,10 +184,10 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
"""
|
||||
finished, component = self.env['product.product'].create([{
|
||||
'name': 'Finished Product',
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
}, {
|
||||
'name': 'SN Componentt',
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
'tracking': 'serial',
|
||||
}])
|
||||
|
||||
|
|
@ -205,22 +196,22 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
'name': 'USN01',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
stock_location = self.env.ref('stock.stock_location_stock')
|
||||
self.env['stock.quant']._update_available_quantity(component, stock_location, 1, lot_id=sn_lot)
|
||||
self.assertEqual(component.qty_available, 1)
|
||||
|
||||
# create a repair order
|
||||
ro_form = Form(self.env['repair.order'])
|
||||
ro_form.product_id = self.product_1
|
||||
with ro_form.operations.new() as ro_line:
|
||||
ro_line.type = 'remove'
|
||||
with ro_form.move_ids.new() as ro_line:
|
||||
ro_line.repair_line_type = 'remove'
|
||||
ro_line.product_id = component
|
||||
ro_line.lot_id = sn_lot
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = sn_lot
|
||||
ro.action_repair_start()
|
||||
ro.action_repair_end()
|
||||
|
||||
self.env['stock.quant']._update_available_quantity(component, self.stock_location, 1, lot_id=sn_lot)
|
||||
self.assertEqual(component.qty_available, 1)
|
||||
|
||||
# create a manufacturing order
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
mo_form.product_id = finished
|
||||
|
|
@ -230,10 +221,9 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.action_assign()
|
||||
mo.move_raw_ids.move_line_ids.qty_done = 1
|
||||
action = mo.button_mark_done()
|
||||
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
|
||||
wizard.process()
|
||||
mo.move_raw_ids.move_line_ids.quantity = 1
|
||||
mo.move_raw_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
|
||||
# unbuild the mo
|
||||
|
|
@ -249,10 +239,9 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.action_assign()
|
||||
mo.move_raw_ids.move_line_ids.qty_done = 1
|
||||
action = mo.button_mark_done()
|
||||
wizard = Form(self.env[action['res_model']].with_context(action['context'])).save()
|
||||
wizard.process()
|
||||
mo.move_raw_ids.move_line_ids.quantity = 1
|
||||
mo.move_raw_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
|
||||
|
||||
|
|
@ -265,13 +254,12 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
Move the component back to the stock
|
||||
Use it in a MO
|
||||
"""
|
||||
stock_location = self.env.ref('stock.stock_location_stock')
|
||||
scrap_location = self.env['stock.location'].search([('company_id', '=', self.env.company.id), ('scrap_location', '=', True)], limit=1)
|
||||
scrap_location_id = self.env['stock.location'].search_read([('company_id', '=', self.env.company.id), ('usage', '=', 'inventory')], fields=['id'], limit=1)[0].get('id')
|
||||
|
||||
finished = self.bom_4.product_id
|
||||
component = self.bom_4.bom_line_ids.product_id
|
||||
component.write({
|
||||
'type': 'product',
|
||||
'is_storable': True,
|
||||
'tracking': 'serial',
|
||||
})
|
||||
|
||||
|
|
@ -280,25 +268,26 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
'name': 'SN01',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
self.env['stock.quant']._update_available_quantity(component, stock_location, 1, lot_id=sn_lot)
|
||||
self.env['stock.quant']._update_available_quantity(component, self.stock_location, 1, lot_id=sn_lot)
|
||||
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
mo_form.bom_id = self.bom_4
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.qty_producing = 1
|
||||
mo.move_raw_ids.move_line_ids.qty_done = 1
|
||||
mo.move_raw_ids.move_line_ids.quantity = 1
|
||||
mo.move_raw_ids.move_line_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
|
||||
ro = self.env['repair.order'].create({
|
||||
'product_id': finished.id,
|
||||
'operations': [
|
||||
'picking_type_id': self.warehouse_1.repair_type_id.id,
|
||||
'move_ids': [
|
||||
(0, 0, {
|
||||
'name': 'foo',
|
||||
'product_id': component.id,
|
||||
'lot_id': sn_lot.id,
|
||||
'type': 'remove',
|
||||
'location_dest_id': scrap_location.id,
|
||||
'lot_ids': [(4, sn_lot.id)],
|
||||
'repair_line_type': 'remove',
|
||||
'location_dest_id': scrap_location_id,
|
||||
'price_unit': 0,
|
||||
})
|
||||
],
|
||||
|
|
@ -308,17 +297,17 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
ro.action_repair_end()
|
||||
|
||||
sm = self.env['stock.move'].create({
|
||||
'name': component.name,
|
||||
'product_id': component.id,
|
||||
'product_uom_qty': 1,
|
||||
'product_uom': component.uom_id.id,
|
||||
'location_id': scrap_location.id,
|
||||
'location_dest_id': stock_location.id,
|
||||
'location_id': scrap_location_id,
|
||||
'location_dest_id': self.stock_location.id,
|
||||
})
|
||||
sm._action_confirm()
|
||||
sm.move_line_ids.write({
|
||||
'qty_done': 1.0,
|
||||
'quantity': 1.0,
|
||||
'lot_id': sn_lot.id,
|
||||
'picked': True,
|
||||
})
|
||||
sm._action_done()
|
||||
|
||||
|
|
@ -327,9 +316,25 @@ class TestRepairTraceability(TestMrpCommon):
|
|||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.qty_producing = 1
|
||||
mo.move_raw_ids.move_line_ids.qty_done = 1
|
||||
mo.move_raw_ids.move_line_ids.quantity = 1
|
||||
mo.move_raw_ids.move_line_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
|
||||
self.assertRecordValues(mo.move_raw_ids.move_line_ids, [
|
||||
{'product_id': component.id, 'lot_id': sn_lot.id, 'qty_done': 1.0, 'state': 'done'},
|
||||
{'product_id': component.id, 'lot_id': sn_lot.id, 'quantity': 1.0, 'state': 'done'},
|
||||
])
|
||||
|
||||
def test_repair_with_consumable_kit(self):
|
||||
"""Test that a consumable kit can be repaired."""
|
||||
self.assertEqual(self.bom_2.type, 'phantom')
|
||||
kit_product = self.bom_2.product_id
|
||||
kit_product.type = 'consu'
|
||||
self.assertEqual(kit_product.type, 'consu')
|
||||
ro = self.env['repair.order'].create({
|
||||
'product_id': kit_product.id,
|
||||
'picking_type_id': self.warehouse_1.repair_type_id.id,
|
||||
})
|
||||
ro.action_validate()
|
||||
ro.action_repair_start()
|
||||
ro.action_repair_end()
|
||||
self.assertEqual(ro.state, 'done')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue