新增主生产计划模块
This commit is contained in:
517
mrp_mps/tests/test_mrp_mps.py
Normal file
517
mrp_mps/tests/test_mrp_mps.py
Normal file
@@ -0,0 +1,517 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import date
|
||||
from odoo.tests import common, Form
|
||||
|
||||
|
||||
class TestMpsMps(common.TransactionCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
""" Define a multi level BoM and generate a production schedule with
|
||||
default value for each of the products.
|
||||
BoM 1:
|
||||
Table
|
||||
|
|
||||
------------------------------------
|
||||
1 Drawer 2 Table Legs
|
||||
| |
|
||||
---------------- -------------------
|
||||
4 Screw 2 Table Legs 4 Screw 4 Bolt
|
||||
|
|
||||
-------------------
|
||||
4 Screw 4 Bolt
|
||||
|
||||
BoM 2 and 3:
|
||||
Wardrobe Chair
|
||||
| |
|
||||
3 Drawer 4 Table Legs
|
||||
"""
|
||||
super().setUpClass()
|
||||
|
||||
cls.table = cls.env['product.product'].create({
|
||||
'name': 'Table',
|
||||
'type': 'product',
|
||||
})
|
||||
cls.drawer = cls.env['product.product'].create({
|
||||
'name': 'Drawer',
|
||||
'type': 'product',
|
||||
})
|
||||
cls.table_leg = cls.env['product.product'].create({
|
||||
'name': 'Table Leg',
|
||||
'type': 'product',
|
||||
})
|
||||
cls.screw = cls.env['product.product'].create({
|
||||
'name': 'Screw',
|
||||
'type': 'product',
|
||||
})
|
||||
cls.bolt = cls.env['product.product'].create({
|
||||
'name': 'Bolt',
|
||||
'type': 'product',
|
||||
})
|
||||
bom_form_table = Form(cls.env['mrp.bom'])
|
||||
bom_form_table.product_tmpl_id = cls.table.product_tmpl_id
|
||||
bom_form_table.product_qty = 1
|
||||
cls.bom_table = bom_form_table.save()
|
||||
|
||||
with Form(cls.bom_table) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.drawer
|
||||
line.product_qty = 1
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.table_leg
|
||||
line.product_qty = 2
|
||||
|
||||
bom_form_drawer = Form(cls.env['mrp.bom'])
|
||||
bom_form_drawer.product_tmpl_id = cls.drawer.product_tmpl_id
|
||||
bom_form_drawer.product_qty = 1
|
||||
cls.bom_drawer = bom_form_drawer.save()
|
||||
|
||||
with Form(cls.bom_drawer) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.table_leg
|
||||
line.product_qty = 2
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.screw
|
||||
line.product_qty = 4
|
||||
|
||||
bom_form_table_leg = Form(cls.env['mrp.bom'])
|
||||
bom_form_table_leg.product_tmpl_id = cls.table_leg.product_tmpl_id
|
||||
bom_form_table_leg.product_qty = 1
|
||||
cls.bom_table_leg = bom_form_table_leg.save()
|
||||
|
||||
with Form(cls.bom_table_leg) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.bolt
|
||||
line.product_qty = 4
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.screw
|
||||
line.product_qty = 4
|
||||
|
||||
cls.wardrobe = cls.env['product.product'].create({
|
||||
'name': 'Wardrobe',
|
||||
'type': 'product',
|
||||
})
|
||||
|
||||
bom_form_wardrobe = Form(cls.env['mrp.bom'])
|
||||
bom_form_wardrobe.product_tmpl_id = cls.wardrobe.product_tmpl_id
|
||||
bom_form_wardrobe.product_qty = 1
|
||||
cls.bom_wardrobe = bom_form_wardrobe.save()
|
||||
|
||||
with Form(cls.bom_wardrobe) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.drawer
|
||||
# because pim-odoo said '3 drawers because 4 is too much'
|
||||
line.product_qty = 3
|
||||
|
||||
cls.chair = cls.env['product.product'].create({
|
||||
'name': 'Chair',
|
||||
'type': 'product',
|
||||
})
|
||||
|
||||
bom_form_chair = Form(cls.env['mrp.bom'])
|
||||
bom_form_chair.product_tmpl_id = cls.chair.product_tmpl_id
|
||||
bom_form_chair.product_qty = 1
|
||||
cls.bom_chair = bom_form_chair.save()
|
||||
|
||||
with Form(cls.bom_chair) as bom:
|
||||
with bom.bom_line_ids.new() as line:
|
||||
line.product_id = cls.table_leg
|
||||
line.product_qty = 4
|
||||
|
||||
cls.warehouse = cls.env['stock.warehouse'].search([], limit=1)
|
||||
cls.mps_table = cls.env['mrp.production.schedule'].create({
|
||||
'product_id': cls.table.id,
|
||||
'warehouse_id': cls.warehouse.id,
|
||||
})
|
||||
cls.mps_wardrobe = cls.env['mrp.production.schedule'].create({
|
||||
'product_id': cls.wardrobe.id,
|
||||
'warehouse_id': cls.warehouse.id,
|
||||
})
|
||||
cls.mps_chair = cls.env['mrp.production.schedule'].create({
|
||||
'product_id': cls.chair.id,
|
||||
'warehouse_id': cls.warehouse.id,
|
||||
})
|
||||
cls.mps_drawer = cls.env['mrp.production.schedule'].create({
|
||||
'product_id': cls.drawer.id,
|
||||
'warehouse_id': cls.warehouse.id,
|
||||
})
|
||||
cls.mps_table_leg = cls.env['mrp.production.schedule'].create({
|
||||
'product_id': cls.table_leg.id,
|
||||
'warehouse_id': cls.warehouse.id,
|
||||
})
|
||||
cls.mps_screw = cls.env['mrp.production.schedule'].create({
|
||||
'product_id': cls.screw.id,
|
||||
'warehouse_id': cls.warehouse.id,
|
||||
})
|
||||
cls.mps = cls.mps_table | cls.mps_wardrobe | cls.mps_chair |\
|
||||
cls.mps_drawer | cls.mps_table_leg | cls.mps_screw
|
||||
|
||||
def test_basic_state(self):
|
||||
""" Testing master product scheduling default values for client
|
||||
action rendering.
|
||||
"""
|
||||
mps_state = self.mps.get_mps_view_state()
|
||||
self.assertTrue(len(mps_state['manufacturing_period']), 12)
|
||||
|
||||
# Remove demo data
|
||||
production_schedule_ids = [s for s in mps_state['production_schedule_ids'] if s['id'] in self.mps.ids]
|
||||
# Check that 6 states are returned (one by production schedule)
|
||||
self.assertEqual(len(production_schedule_ids), 6)
|
||||
self.assertEqual(mps_state['company_id'], self.env.user.company_id.id)
|
||||
company_groups = mps_state['groups'][0]
|
||||
self.assertTrue(company_groups['mrp_mps_show_starting_inventory'])
|
||||
self.assertTrue(company_groups['mrp_mps_show_demand_forecast'])
|
||||
self.assertTrue(company_groups['mrp_mps_show_indirect_demand'])
|
||||
self.assertTrue(company_groups['mrp_mps_show_to_replenish'])
|
||||
self.assertTrue(company_groups['mrp_mps_show_safety_stock'])
|
||||
|
||||
self.assertFalse(company_groups['mrp_mps_show_actual_demand'])
|
||||
self.assertFalse(company_groups['mrp_mps_show_actual_replenishment'])
|
||||
self.assertFalse(company_groups['mrp_mps_show_available_to_promise'])
|
||||
|
||||
# Check that quantity on forecast are empty
|
||||
self.assertTrue(all([not forecast['starting_inventory_qty'] for forecast in production_schedule_ids[0]['forecast_ids']]))
|
||||
self.assertTrue(all([not forecast['forecast_qty'] for forecast in production_schedule_ids[0]['forecast_ids']]))
|
||||
self.assertTrue(all([not forecast['replenish_qty'] for forecast in production_schedule_ids[0]['forecast_ids']]))
|
||||
self.assertTrue(all([not forecast['safety_stock_qty'] for forecast in production_schedule_ids[0]['forecast_ids']]))
|
||||
self.assertTrue(all([not forecast['indirect_demand_qty'] for forecast in production_schedule_ids[0]['forecast_ids']]))
|
||||
# Check that there is 12 periods for each forecast
|
||||
self.assertTrue(all([len(production_schedule_id['forecast_ids']) == 12 for production_schedule_id in production_schedule_ids]))
|
||||
|
||||
def test_forecast_1(self):
|
||||
""" Testing master product scheduling """
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_screw.id,
|
||||
'date': date.today(),
|
||||
'forecast_qty': 100
|
||||
})
|
||||
screw_mps_state = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
forecast_at_first_period = screw_mps_state['forecast_ids'][0]
|
||||
self.assertEqual(forecast_at_first_period['forecast_qty'], 100)
|
||||
self.assertEqual(forecast_at_first_period['replenish_qty'], 100)
|
||||
self.assertEqual(forecast_at_first_period['safety_stock_qty'], 0)
|
||||
|
||||
self.env['stock.quant']._update_available_quantity(self.mps_screw.product_id, self.warehouse.lot_stock_id, 50)
|
||||
# Invalidate qty_available on product.product
|
||||
self.env.invalidate_all()
|
||||
screw_mps_state = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
forecast_at_first_period = screw_mps_state['forecast_ids'][0]
|
||||
self.assertEqual(forecast_at_first_period['forecast_qty'], 100)
|
||||
self.assertEqual(forecast_at_first_period['replenish_qty'], 50)
|
||||
self.assertEqual(forecast_at_first_period['safety_stock_qty'], 0)
|
||||
|
||||
self.mps_screw.max_to_replenish_qty = 20
|
||||
screw_mps_state = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
forecast_at_first_period = screw_mps_state['forecast_ids'][0]
|
||||
self.assertEqual(forecast_at_first_period['forecast_qty'], 100)
|
||||
self.assertEqual(forecast_at_first_period['replenish_qty'], 20)
|
||||
self.assertEqual(forecast_at_first_period['safety_stock_qty'], -30)
|
||||
forecast_at_second_period = screw_mps_state['forecast_ids'][1]
|
||||
self.assertEqual(forecast_at_second_period['forecast_qty'], 0)
|
||||
self.assertEqual(forecast_at_second_period['replenish_qty'], 20)
|
||||
self.assertEqual(forecast_at_second_period['safety_stock_qty'], -10)
|
||||
forecast_at_third_period = screw_mps_state['forecast_ids'][2]
|
||||
self.assertEqual(forecast_at_third_period['forecast_qty'], 0)
|
||||
self.assertEqual(forecast_at_third_period['replenish_qty'], 10)
|
||||
self.assertEqual(forecast_at_third_period['safety_stock_qty'], 0)
|
||||
|
||||
def test_replenish(self):
|
||||
""" Test to run procurement for forecasts. Check that replenish for
|
||||
different periods will not merger purchase order line and create
|
||||
multiple docurements. Also modify the existing quantity replenished on
|
||||
a forecast and run the replenishment again, ensure the purchase order
|
||||
line is updated.
|
||||
"""
|
||||
mps_dates = self.env.company._get_date_range()
|
||||
forecast_screw = self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_screw.id,
|
||||
'date': mps_dates[0][0],
|
||||
'forecast_qty': 100
|
||||
})
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_screw.id,
|
||||
'date': mps_dates[1][0],
|
||||
'forecast_qty': 100
|
||||
})
|
||||
|
||||
partner = self.env['res.partner'].create({
|
||||
'name': 'Jhon'
|
||||
})
|
||||
seller = self.env['product.supplierinfo'].create({
|
||||
'partner_id': partner.id,
|
||||
'price': 12.0,
|
||||
'delay': 0
|
||||
})
|
||||
self.screw.seller_ids = [(6, 0, [seller.id])]
|
||||
self.mps_screw.action_replenish()
|
||||
purchase_order_line = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)])
|
||||
self.assertTrue(purchase_order_line)
|
||||
|
||||
# It should not create a procurement since it exists already one for the
|
||||
# current period and the sum of lead time should be 0.
|
||||
self.mps_screw.action_replenish(based_on_lead_time=True)
|
||||
purchase_order_line = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)])
|
||||
self.assertEqual(len(purchase_order_line), 1)
|
||||
|
||||
self.mps_screw.action_replenish()
|
||||
purchase_order_lines = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)])
|
||||
self.assertEqual(len(purchase_order_lines), 2)
|
||||
self.assertEqual(len(purchase_order_lines.mapped('order_id')), 2)
|
||||
|
||||
# This replenish should be withtout effect since everything is already
|
||||
# plannified.
|
||||
self.mps_screw.action_replenish()
|
||||
purchase_order_lines = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)])
|
||||
self.assertEqual(len(purchase_order_lines), 2)
|
||||
|
||||
# Replenish an existing forecast with a procurement in progress
|
||||
forecast_screw.forecast_qty = 150
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
self.assertEqual(screw_forecast_1['state'], 'to_relaunch')
|
||||
self.assertTrue(screw_forecast_1['to_replenish'])
|
||||
self.assertTrue(screw_forecast_1['forced_replenish'])
|
||||
|
||||
self.mps_screw.action_replenish(based_on_lead_time=True)
|
||||
purchase_order_lines = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)])
|
||||
self.assertEqual(len(purchase_order_lines), 2)
|
||||
purchase_order_line = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)], order='date_planned', limit=1)
|
||||
self.assertEqual(purchase_order_line.product_qty, 150)
|
||||
|
||||
forecast_screw.forecast_qty = 50
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
self.assertEqual(screw_forecast_1['state'], 'to_correct')
|
||||
self.assertFalse(screw_forecast_1['to_replenish'])
|
||||
self.assertFalse(screw_forecast_1['forced_replenish'])
|
||||
|
||||
def test_lead_times(self):
|
||||
""" Manufacture, supplier and rules uses delay. The forecasts to
|
||||
replenish are impacted by those delay. Ensure that the MPS state and
|
||||
the period to replenish are correct.
|
||||
"""
|
||||
self.env.company.manufacturing_period = 'week'
|
||||
partner = self.env['res.partner'].create({
|
||||
'name': 'Jhon'
|
||||
})
|
||||
seller = self.env['product.supplierinfo'].create({
|
||||
'partner_id': partner.id,
|
||||
'price': 12.0,
|
||||
'delay': 7,
|
||||
})
|
||||
self.screw.seller_ids = [(6, 0, [seller.id])]
|
||||
|
||||
mps_dates = self.env.company._get_date_range()
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_screw.id,
|
||||
'date': mps_dates[0][0],
|
||||
'forecast_qty': 100
|
||||
})
|
||||
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
screw_forecast_2 = mps_screw['forecast_ids'][1]
|
||||
screw_forecast_3 = mps_screw['forecast_ids'][2]
|
||||
|
||||
# Check screw forecasts state
|
||||
self.assertEqual(screw_forecast_1['state'], 'to_launch')
|
||||
# launched because it's in lead time frame but it do not require a
|
||||
# replenishment. The state launched is used in order to render the cell
|
||||
# with a grey background.
|
||||
self.assertEqual(screw_forecast_2['state'], 'launched')
|
||||
self.assertEqual(screw_forecast_3['state'], 'to_launch')
|
||||
self.assertTrue(screw_forecast_1['to_replenish'])
|
||||
self.assertFalse(screw_forecast_2['to_replenish'])
|
||||
self.assertFalse(screw_forecast_3['to_replenish'])
|
||||
self.assertTrue(screw_forecast_1['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_2['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_3['forced_replenish'])
|
||||
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_screw.id,
|
||||
'date': mps_dates[1][0],
|
||||
'forecast_qty': 100
|
||||
})
|
||||
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
screw_forecast_2 = mps_screw['forecast_ids'][1]
|
||||
screw_forecast_3 = mps_screw['forecast_ids'][2]
|
||||
self.assertEqual(screw_forecast_1['state'], 'to_launch')
|
||||
self.assertEqual(screw_forecast_2['state'], 'to_launch')
|
||||
self.assertEqual(screw_forecast_3['state'], 'to_launch')
|
||||
self.assertTrue(screw_forecast_1['to_replenish'])
|
||||
self.assertTrue(screw_forecast_2['to_replenish'])
|
||||
self.assertFalse(screw_forecast_3['to_replenish'])
|
||||
self.assertTrue(screw_forecast_1['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_2['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_3['forced_replenish'])
|
||||
seller.delay = 14
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
screw_forecast_2 = mps_screw['forecast_ids'][1]
|
||||
screw_forecast_3 = mps_screw['forecast_ids'][2]
|
||||
self.assertEqual(screw_forecast_1['state'], 'to_launch')
|
||||
self.assertEqual(screw_forecast_2['state'], 'to_launch')
|
||||
self.assertEqual(screw_forecast_3['state'], 'launched')
|
||||
self.assertTrue(screw_forecast_1['to_replenish'])
|
||||
self.assertTrue(screw_forecast_2['to_replenish'])
|
||||
self.assertFalse(screw_forecast_3['to_replenish'])
|
||||
self.assertTrue(screw_forecast_1['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_2['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_3['forced_replenish'])
|
||||
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_screw.id,
|
||||
'date': mps_dates[2][0],
|
||||
'forecast_qty': 100
|
||||
})
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
screw_forecast_2 = mps_screw['forecast_ids'][1]
|
||||
screw_forecast_3 = mps_screw['forecast_ids'][2]
|
||||
self.assertEqual(screw_forecast_1['state'], 'to_launch')
|
||||
self.assertEqual(screw_forecast_2['state'], 'to_launch')
|
||||
self.assertEqual(screw_forecast_3['state'], 'to_launch')
|
||||
self.assertTrue(screw_forecast_1['to_replenish'])
|
||||
self.assertTrue(screw_forecast_2['to_replenish'])
|
||||
self.assertTrue(screw_forecast_3['to_replenish'])
|
||||
self.assertTrue(screw_forecast_1['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_2['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_3['forced_replenish'])
|
||||
|
||||
self.mps_screw.action_replenish(based_on_lead_time=True)
|
||||
purchase_order_line = self.env['purchase.order.line'].search([('product_id', '=', self.screw.id)])
|
||||
self.assertEqual(len(purchase_order_line.mapped('order_id')), 3)
|
||||
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
screw_forecast_2 = mps_screw['forecast_ids'][1]
|
||||
screw_forecast_3 = mps_screw['forecast_ids'][2]
|
||||
self.assertEqual(screw_forecast_1['state'], 'launched')
|
||||
self.assertEqual(screw_forecast_2['state'], 'launched')
|
||||
self.assertEqual(screw_forecast_3['state'], 'launched')
|
||||
self.assertFalse(screw_forecast_1['to_replenish'])
|
||||
self.assertFalse(screw_forecast_2['to_replenish'])
|
||||
self.assertFalse(screw_forecast_3['to_replenish'])
|
||||
self.assertFalse(screw_forecast_1['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_2['forced_replenish'])
|
||||
self.assertFalse(screw_forecast_3['forced_replenish'])
|
||||
|
||||
def test_indirect_demand(self):
|
||||
""" On a multiple BoM relation, ensure that the replenish quantity on
|
||||
a production schedule impact the indirect demand on other production
|
||||
that have a component as product.
|
||||
"""
|
||||
mps_dates = self.env.company._get_date_range()
|
||||
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_table.id,
|
||||
'date': mps_dates[0][0],
|
||||
'forecast_qty': 2
|
||||
})
|
||||
|
||||
# 2 drawer from table
|
||||
mps_drawer = self.mps_drawer.get_production_schedule_view_state()[0]
|
||||
drawer_forecast_1 = mps_drawer['forecast_ids'][0]
|
||||
self.assertEqual(drawer_forecast_1['indirect_demand_qty'], 2)
|
||||
# Screw for 2 tables:
|
||||
# 2 * 2 legs * 4 screw = 16
|
||||
# 1 drawer = 4 + 2 * legs * 4 = 12
|
||||
# 16 + 2 drawers = 16 + 24 = 40
|
||||
mps_screw = self.mps_screw.get_production_schedule_view_state()[0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
self.assertEqual(screw_forecast_1['indirect_demand_qty'], 40)
|
||||
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_wardrobe.id,
|
||||
'date': mps_dates[0][0],
|
||||
'forecast_qty': 3
|
||||
})
|
||||
|
||||
# 2 drawer from table + 9 from wardrobe (3 x 3)
|
||||
mps_drawer, mps_screw = (self.mps_drawer | self.mps_screw).get_production_schedule_view_state()
|
||||
drawer_forecast_1 = mps_drawer['forecast_ids'][0]
|
||||
self.assertEqual(drawer_forecast_1['indirect_demand_qty'], 11)
|
||||
# Screw for 2 tables + 3 wardrobe:
|
||||
# 11 drawer = 11 * 12 = 132
|
||||
# + 2 * 2 legs * 4 = 16
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
self.assertEqual(screw_forecast_1['indirect_demand_qty'], 148)
|
||||
|
||||
# Ensure that a forecast on another period will not impact the forecast
|
||||
# for current period.
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_table.id,
|
||||
'date': mps_dates[1][0],
|
||||
'forecast_qty': 2
|
||||
})
|
||||
mps_drawer, mps_screw = (self.mps_drawer | self.mps_screw).get_production_schedule_view_state()
|
||||
drawer_forecast_1 = mps_drawer['forecast_ids'][0]
|
||||
screw_forecast_1 = mps_screw['forecast_ids'][0]
|
||||
self.assertEqual(drawer_forecast_1['indirect_demand_qty'], 11)
|
||||
self.assertEqual(screw_forecast_1['indirect_demand_qty'], 148)
|
||||
|
||||
def test_impacted_schedule(self):
|
||||
impacted_schedules = self.mps_screw.get_impacted_schedule()
|
||||
self.assertEqual(sorted(impacted_schedules), sorted((self.mps - self.mps_screw).ids))
|
||||
|
||||
impacted_schedules = self.mps_drawer.get_impacted_schedule()
|
||||
self.assertEqual(sorted(impacted_schedules), sorted((self.mps_table |
|
||||
self.mps_wardrobe | self.mps_table_leg | self.mps_screw).ids))
|
||||
|
||||
def test_3_steps(self):
|
||||
self.warehouse.manufacture_steps = 'pbm_sam'
|
||||
self.table_leg.write({
|
||||
'route_ids': [(6, 0, [self.ref('mrp.route_warehouse0_manufacture')])]
|
||||
})
|
||||
|
||||
self.env['mrp.product.forecast'].create({
|
||||
'production_schedule_id': self.mps_table_leg.id,
|
||||
'date': date.today(),
|
||||
'forecast_qty': 25
|
||||
})
|
||||
|
||||
self.mps_table_leg.action_replenish()
|
||||
mps_table_leg = self.mps_table_leg.get_production_schedule_view_state()[0]
|
||||
self.assertEqual(mps_table_leg['forecast_ids'][0]['forecast_qty'], 25.0, "Wrong resulting value of to_supply")
|
||||
self.assertEqual(mps_table_leg['forecast_ids'][0]['incoming_qty'], 25.0, "Wrong resulting value of incoming quantity")
|
||||
|
||||
def test_interwh_delay(self):
|
||||
"""
|
||||
Suppose an interwarehouse configuration. The user adds some delays on
|
||||
each rule of the interwh route. Then, the user defines a replenishment
|
||||
qty on the MPS view and calls the replenishment action. This test
|
||||
ensures that the MPS view includes the delays for the incoming quantity
|
||||
"""
|
||||
main_warehouse = self.warehouse
|
||||
second_warehouse = self.env['stock.warehouse'].create({
|
||||
'name': 'Second Warehouse',
|
||||
'code': 'WH02',
|
||||
})
|
||||
main_warehouse.write({
|
||||
'resupply_wh_ids': [(6, 0, second_warehouse.ids)]
|
||||
})
|
||||
|
||||
interwh_route = self.env['stock.route'].search([('supplied_wh_id', '=', main_warehouse.id), ('supplier_wh_id', '=', second_warehouse.id)])
|
||||
interwh_route.rule_ids.delay = 1
|
||||
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'SuperProduct',
|
||||
'type': 'product',
|
||||
'route_ids': [(6, 0, interwh_route.ids)],
|
||||
})
|
||||
|
||||
mps = self.env['mrp.production.schedule'].create({
|
||||
'product_id': product.id,
|
||||
'warehouse_id': main_warehouse.id,
|
||||
})
|
||||
interval_index = 3
|
||||
mps.set_replenish_qty(interval_index, 1)
|
||||
mps.action_replenish()
|
||||
|
||||
state = mps.get_production_schedule_view_state()[0]
|
||||
for index, forecast in enumerate(state['forecast_ids']):
|
||||
self.assertEqual(forecast['incoming_qty'], 1 if index == interval_index else 0, 'Incoming qty is incorrect for index %s' % index)
|
||||
Reference in New Issue
Block a user