mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[12.0][FIX] mrp_multi_level: when grouping demand, if supply and
demand moves have the same date it can happen that the supply is effectively ignored if considered as staring move of the grouping and there are more groups to be done after it. A test case include in this fix depicts in detail the the problem and ensures no regression.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
# (http://www.eficent.com)
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from odoo.tests.common import SavepointCase
|
||||
|
||||
@@ -40,6 +40,7 @@ class TestMrpMultiLevelCommon(SavepointCase):
|
||||
cls.stock_location = cls.wh.lot_stock_id
|
||||
cls.customer_location = cls.env.ref(
|
||||
'stock.stock_location_customers')
|
||||
cls.supplier_location = cls.env.ref('stock.stock_location_suppliers')
|
||||
cls.calendar = cls.env.ref('resource.resource_calendar_std')
|
||||
# Add calendar to WH:
|
||||
cls.wh.calendar_id = cls.calendar
|
||||
@@ -68,6 +69,19 @@ class TestMrpMultiLevelCommon(SavepointCase):
|
||||
'warehouse_id': cls.wh.id,
|
||||
'location_id': cls.sec_loc.id,
|
||||
})
|
||||
# Create an area for design special cases and test them, different
|
||||
# cases will be expected to not share products, this way each case
|
||||
# can be isolated.
|
||||
cls.cases_loc = cls.loc_obj.create({
|
||||
'name': 'Special Cases location',
|
||||
'usage': 'internal',
|
||||
'location_id': cls.wh.view_location_id.id,
|
||||
})
|
||||
cls.cases_area = cls.mrp_area_obj.create({
|
||||
'name': 'Special Cases Tests',
|
||||
'warehouse_id': cls.wh.id,
|
||||
'location_id': cls.cases_loc.id,
|
||||
})
|
||||
|
||||
# Create products:
|
||||
route_buy = cls.env.ref('purchase_stock.route_warehouse0_buy').id
|
||||
@@ -132,6 +146,36 @@ class TestMrpMultiLevelCommon(SavepointCase):
|
||||
'mrp_maximum_order_qty': 500.0,
|
||||
'mrp_qty_multiple': 25.0,
|
||||
})
|
||||
# Create more products to test special corner case scenarios:
|
||||
cls.product_scenario_1 = cls.product_obj.create({
|
||||
'name': 'Product Special Scenario 1',
|
||||
'type': 'product',
|
||||
'list_price': 100.0,
|
||||
'route_ids': [(6, 0, [route_buy])],
|
||||
'seller_ids': [(0, 0, {'name': vendor1.id, 'price': 20.0})],
|
||||
})
|
||||
cls.product_mrp_area_obj.create({
|
||||
'product_id': cls.product_scenario_1.id,
|
||||
'mrp_area_id': cls.cases_area.id,
|
||||
'mrp_nbr_days': 7,
|
||||
'mrp_qty_multiple': 5.0,
|
||||
})
|
||||
|
||||
# Create pickings for Scenario 1:
|
||||
dt_base = cls.calendar.plan_days(3 + 1, datetime.today())
|
||||
cls._create_picking_in(
|
||||
cls.product_scenario_1, 87, dt_base, location=cls.cases_loc)
|
||||
dt_bit_later = dt_base + timedelta(hours=1)
|
||||
cls._create_picking_out(
|
||||
cls.product_scenario_1, 124, dt_bit_later, location=cls.cases_loc)
|
||||
dt_base_2 = cls.calendar.plan_days(3 + 1, datetime.today())
|
||||
cls._create_picking_out(
|
||||
cls.product_scenario_1, 90, dt_base_2, location=cls.cases_loc)
|
||||
|
||||
dt_next_group = cls.calendar.plan_days(10 + 1, datetime.today())
|
||||
cls._create_picking_out(
|
||||
cls.product_scenario_1, 18, dt_next_group, location=cls.cases_loc)
|
||||
|
||||
# Create test picking for FP-1 and FP-2:
|
||||
res = cls.calendar.plan_days(7 + 1, datetime.today().replace(hour=0))
|
||||
date_move = res.date()
|
||||
@@ -282,3 +326,49 @@ class TestMrpMultiLevelCommon(SavepointCase):
|
||||
'groups_id': [(6, 0, [group.id for group in groups])]
|
||||
})
|
||||
return user
|
||||
|
||||
@classmethod
|
||||
def _create_picking_in(cls, product, qty, date_move, location=None):
|
||||
if not location:
|
||||
location = cls.stock_location
|
||||
picking = cls.stock_picking_obj.create({
|
||||
'picking_type_id': cls.env.ref('stock.picking_type_in').id,
|
||||
'location_id': cls.supplier_location.id,
|
||||
'location_dest_id': location.id,
|
||||
'move_lines': [
|
||||
(0, 0, {
|
||||
'name': 'Test Move',
|
||||
'product_id': product.id,
|
||||
'date_expected': date_move,
|
||||
'date': date_move,
|
||||
'product_uom': product.uom_id.id,
|
||||
'product_uom_qty': qty,
|
||||
'location_id': cls.supplier_location.id,
|
||||
'location_dest_id': location.id,
|
||||
})],
|
||||
})
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
@classmethod
|
||||
def _create_picking_out(cls, product, qty, date_move, location=None):
|
||||
if not location:
|
||||
location = cls.stock_location
|
||||
picking = cls.stock_picking_obj.create({
|
||||
'picking_type_id': cls.env.ref('stock.picking_type_out').id,
|
||||
'location_id': location.id,
|
||||
'location_dest_id': cls.customer_location.id,
|
||||
'move_lines': [
|
||||
(0, 0, {
|
||||
'name': 'Test Move',
|
||||
'product_id': product.id,
|
||||
'date_expected': date_move,
|
||||
'date': date_move,
|
||||
'product_uom': product.uom_id.id,
|
||||
'product_uom_qty': qty,
|
||||
'location_id': location.id,
|
||||
'location_dest_id': cls.customer_location.id,
|
||||
})],
|
||||
})
|
||||
picking.action_confirm()
|
||||
return picking
|
||||
|
||||
@@ -250,3 +250,17 @@ class TestMrpMultiLevel(TestMrpMultiLevelCommon):
|
||||
prev = self.mrp_inventory_obj.search([
|
||||
('mrp_area_id', '!=', self.secondary_area.id)], limit=1)
|
||||
self.assertNotEqual(this.create_uid, prev.create_uid)
|
||||
|
||||
def test_11_special_scenario_1(self):
|
||||
"""When grouping demand supply and demand are in the same day but
|
||||
supply goes first."""
|
||||
moves = self.mrp_move_obj.search([
|
||||
('product_id', '=', self.product_scenario_1.id)])
|
||||
self.assertEqual(len(moves), 4)
|
||||
mrp_invs = self.mrp_inventory_obj.search([
|
||||
('product_id', '=', self.product_scenario_1.id)])
|
||||
self.assertEqual(len(mrp_invs), 2)
|
||||
# Net needs = 124 + 90 - 87 = 127 -> 130 (because of qty multiple)
|
||||
self.assertEqual(mrp_invs[0].to_procure, 130)
|
||||
# Net needs = 18, available on-hand = 3 -> 15
|
||||
self.assertEqual(mrp_invs[1].to_procure, 15)
|
||||
|
||||
@@ -488,7 +488,8 @@ class MultiLevelMrp(models.TransientModel):
|
||||
or (onhand + last_qty)
|
||||
< product_mrp_area.mrp_minimum_stock):
|
||||
name = 'Grouped Demand for %d Days' % grouping_delta
|
||||
qtytoorder = product_mrp_area.mrp_minimum_stock - last_qty
|
||||
qtytoorder = product_mrp_area.mrp_minimum_stock - \
|
||||
onhand - last_qty
|
||||
cm = self.create_action(
|
||||
product_mrp_area_id=product_mrp_area,
|
||||
mrp_date=last_date,
|
||||
|
||||
Reference in New Issue
Block a user