this commit will allow users to setup replenish locations and replenish them directly if they have negative forecast instead of checking forecast qty per warehouse, this adds the abiltiy to replenish to any internal stock location, marked as replenish location, instead of just the warehouse location Task Id: 2796757 closes odoo/odoo#93633 Related: odoo/upgrade#3626 Signed-off-by: William Henrotin (whe) <whe@odoo.com>
552 lines
23 KiB
Python
552 lines
23 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import date, datetime, timedelta
|
|
|
|
from odoo.tests.common import Form, TransactionCase
|
|
from odoo.tools import mute_logger
|
|
|
|
|
|
class TestProcRule(TransactionCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
|
|
cls.uom_unit = cls.env.ref('uom.product_uom_unit')
|
|
cls.product = cls.env['product.product'].create({
|
|
'name': 'Desk Combination',
|
|
'type': 'consu',
|
|
})
|
|
cls.partner = cls.env['res.partner'].create({'name': 'Partner'})
|
|
|
|
def test_proc_rule(self):
|
|
# Create a product route containing a stock rule that will
|
|
# generate a move from Stock for every procurement created in Output
|
|
product_route = self.env['stock.route'].create({
|
|
'name': 'Stock -> output route',
|
|
'product_selectable': True,
|
|
'rule_ids': [(0, 0, {
|
|
'name': 'Stock -> output rule',
|
|
'action': 'pull',
|
|
'picking_type_id': self.ref('stock.picking_type_internal'),
|
|
'location_src_id': self.ref('stock.stock_location_stock'),
|
|
'location_dest_id': self.ref('stock.stock_location_output'),
|
|
})],
|
|
})
|
|
|
|
# Set this route on `product.product_product_3`
|
|
self.product.write({
|
|
'route_ids': [(4, product_route.id)]})
|
|
|
|
# Create Delivery Order of 10 `product.product_product_3` from Output -> Customer
|
|
product = self.product
|
|
vals = {
|
|
'name': 'Delivery order for procurement',
|
|
'partner_id': self.partner.id,
|
|
'picking_type_id': self.ref('stock.picking_type_out'),
|
|
'location_id': self.ref('stock.stock_location_output'),
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
'move_ids': [(0, 0, {
|
|
'name': '/',
|
|
'product_id': product.id,
|
|
'product_uom': product.uom_id.id,
|
|
'product_uom_qty': 10.00,
|
|
'procure_method': 'make_to_order',
|
|
'location_id': self.ref('stock.stock_location_output'),
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
})],
|
|
}
|
|
pick_output = self.env['stock.picking'].create(vals)
|
|
pick_output.move_ids._onchange_product_id()
|
|
|
|
# Confirm delivery order.
|
|
pick_output.action_confirm()
|
|
|
|
# I run the scheduler.
|
|
# Note: If purchase if already installed, the method _run_buy will be called due
|
|
# to the purchase demo data. As we update the stock module to run this test, the
|
|
# method won't be an attribute of stock.procurement at this moment. For that reason
|
|
# we mute the logger when running the scheduler.
|
|
with mute_logger('odoo.addons.stock.models.procurement'):
|
|
self.env['procurement.group'].run_scheduler()
|
|
|
|
# Check that a picking was created from stock to output.
|
|
moves = self.env['stock.move'].search([
|
|
('product_id', '=', self.product.id),
|
|
('location_id', '=', self.ref('stock.stock_location_stock')),
|
|
('location_dest_id', '=', self.ref('stock.stock_location_output')),
|
|
('move_dest_ids', 'in', [pick_output.move_ids[0].id])
|
|
])
|
|
self.assertEqual(len(moves.ids), 1, "It should have created a picking from Stock to Output with the original picking as destination")
|
|
|
|
def test_propagate_deadline_move(self):
|
|
deadline = datetime.now()
|
|
move_dest = self.env['stock.move'].create({
|
|
'name': 'move_dest',
|
|
'product_id': self.product.id,
|
|
'product_uom': self.uom_unit.id,
|
|
'date_deadline': deadline,
|
|
'location_id': self.ref('stock.stock_location_output'),
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
})
|
|
|
|
move_orig = self.env['stock.move'].create({
|
|
'name': 'move_orig',
|
|
'product_id': self.product.id,
|
|
'product_uom': self.uom_unit.id,
|
|
'date_deadline': deadline,
|
|
'move_dest_ids': [(4, move_dest.id)],
|
|
'location_id': self.ref('stock.stock_location_stock'),
|
|
'location_dest_id': self.ref('stock.stock_location_output'),
|
|
'quantity_done': 10,
|
|
})
|
|
new_deadline = move_orig.date_deadline - timedelta(days=6)
|
|
move_orig.date_deadline = new_deadline
|
|
self.assertEqual(move_dest.date_deadline, new_deadline, msg='deadline date should be propagated')
|
|
move_orig._action_done()
|
|
self.assertAlmostEqual(move_orig.date, datetime.now(), delta=timedelta(seconds=10), msg='date should be now')
|
|
self.assertEqual(move_orig.date_deadline, new_deadline, msg='deadline date should be unchanged')
|
|
self.assertEqual(move_dest.date_deadline, new_deadline, msg='deadline date should be unchanged')
|
|
|
|
def test_reordering_rule_1(self):
|
|
# Required for `location_id` to be visible in the view
|
|
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
|
warehouse = self.env['stock.warehouse'].search([], limit=1)
|
|
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
|
|
orderpoint_form.product_id = self.product
|
|
orderpoint_form.product_min_qty = 0.0
|
|
orderpoint_form.product_max_qty = 5.0
|
|
orderpoint = orderpoint_form.save()
|
|
|
|
# get auto-created pull rule from when warehouse is created
|
|
rule = self.env['stock.rule'].search([
|
|
('route_id', '=', warehouse.reception_route_id.id),
|
|
('location_dest_id', '=', warehouse.lot_stock_id.id),
|
|
('location_src_id', '=', self.env.ref('stock.stock_location_suppliers').id),
|
|
('action', '=', 'pull'),
|
|
('procure_method', '=', 'make_to_stock'),
|
|
('picking_type_id', '=', warehouse.in_type_id.id)])
|
|
|
|
# add a delay [i.e. lead days] so procurement will be triggered based on forecasted stock
|
|
rule.delay = 9.0
|
|
|
|
delivery_move = self.env['stock.move'].create({
|
|
'name': 'Delivery',
|
|
'date': datetime.today() + timedelta(days=5),
|
|
'product_id': self.product.id,
|
|
'product_uom': self.uom_unit.id,
|
|
'product_uom_qty': 12.0,
|
|
'location_id': warehouse.lot_stock_id.id,
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
})
|
|
delivery_move._action_confirm()
|
|
orderpoint._compute_qty()
|
|
self.env['procurement.group'].run_scheduler()
|
|
|
|
receipt_move = self.env['stock.move'].search([
|
|
('product_id', '=', self.product.id),
|
|
('location_id', '=', self.env.ref('stock.stock_location_suppliers').id)
|
|
])
|
|
self.assertTrue(receipt_move)
|
|
self.assertEqual(receipt_move.date.date(), date.today())
|
|
self.assertEqual(receipt_move.product_uom_qty, 17.0)
|
|
|
|
def test_reordering_rule_2(self):
|
|
"""Test when there is not enough product to assign a picking => automatically run
|
|
reordering rule (RR). Add extra product to already confirmed picking => automatically
|
|
run another RR
|
|
"""
|
|
# Required for `location_id` to be visible in the view
|
|
self.env.user.groups_id += self.env.ref('stock.group_stock_multi_locations')
|
|
|
|
self.productA = self.env['product.product'].create({
|
|
'name': 'Desk Combination',
|
|
'type': 'product',
|
|
})
|
|
|
|
self.productB = self.env['product.product'].create({
|
|
'name': 'Desk Decoration',
|
|
'type': 'product',
|
|
})
|
|
|
|
warehouse = self.env['stock.warehouse'].search([], limit=1)
|
|
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
|
|
orderpoint_form.product_id = self.productA
|
|
orderpoint_form.product_min_qty = 0.0
|
|
orderpoint_form.product_max_qty = 5.0
|
|
orderpoint = orderpoint_form.save()
|
|
|
|
self.env['stock.warehouse.orderpoint'].create({
|
|
'name': 'ProductB RR',
|
|
'product_id': self.productB.id,
|
|
'product_min_qty': 0,
|
|
'product_max_qty': 5,
|
|
})
|
|
|
|
self.env['stock.rule'].create({
|
|
'name': 'Rule Supplier',
|
|
'route_id': warehouse.reception_route_id.id,
|
|
'location_dest_id': warehouse.lot_stock_id.id,
|
|
'location_src_id': self.env.ref('stock.stock_location_suppliers').id,
|
|
'action': 'pull',
|
|
'delay': 9.0,
|
|
'procure_method': 'make_to_stock',
|
|
'picking_type_id': warehouse.in_type_id.id,
|
|
})
|
|
|
|
delivery_picking = self.env['stock.picking'].create({
|
|
'location_id': warehouse.lot_stock_id.id,
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
'picking_type_id': self.ref('stock.picking_type_out'),
|
|
})
|
|
delivery_move = self.env['stock.move'].create({
|
|
'name': 'Delivery',
|
|
'product_id': self.productA.id,
|
|
'product_uom': self.uom_unit.id,
|
|
'product_uom_qty': 12.0,
|
|
'location_id': warehouse.lot_stock_id.id,
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
'picking_id': delivery_picking.id,
|
|
})
|
|
delivery_picking.action_confirm()
|
|
delivery_picking.action_assign()
|
|
|
|
receipt_move = self.env['stock.move'].search([
|
|
('product_id', '=', self.productA.id),
|
|
('location_id', '=', self.env.ref('stock.stock_location_suppliers').id)
|
|
])
|
|
|
|
self.assertTrue(receipt_move)
|
|
self.assertEqual(receipt_move.date.date(), date.today())
|
|
self.assertEqual(receipt_move.product_uom_qty, 17.0)
|
|
|
|
delivery_picking.write({'move_ids': [(0, 0, {
|
|
'name': 'Extra Move',
|
|
'product_id': self.productB.id,
|
|
'product_uom': self.uom_unit.id,
|
|
'product_uom_qty': 5.0,
|
|
'location_id': warehouse.lot_stock_id.id,
|
|
'location_dest_id': self.ref('stock.stock_location_customers'),
|
|
'picking_id': delivery_picking.id,
|
|
'additional': True
|
|
})]})
|
|
|
|
receipt_move2 = self.env['stock.move'].search([
|
|
('product_id', '=', self.productB.id),
|
|
('location_id', '=', self.env.ref('stock.stock_location_suppliers').id)
|
|
])
|
|
|
|
self.assertTrue(receipt_move2)
|
|
self.assertEqual(receipt_move2.date.date(), date.today())
|
|
self.assertEqual(receipt_move2.product_uom_qty, 10.0)
|
|
|
|
def test_fixed_procurement_01(self):
|
|
""" Run a procurement for 5 products when there are only 4 in stock then
|
|
check that MTO is applied on the moves when the rule is set to 'mts_else_mto'
|
|
"""
|
|
self.partner = self.env['res.partner'].create({'name': 'Partner'})
|
|
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.user.id)], limit=1)
|
|
warehouse.delivery_steps = 'pick_ship'
|
|
final_location = self.partner.property_stock_customer
|
|
|
|
# Create a product and add 10 units in stock
|
|
product_a = self.env['product.product'].create({
|
|
'name': 'ProductA',
|
|
'type': 'product',
|
|
})
|
|
self.env['stock.quant']._update_available_quantity(product_a, warehouse.lot_stock_id, 10.0)
|
|
|
|
# Create a route which will allows 'wave picking'
|
|
wave_pg = self.env['procurement.group'].create({'name': 'Wave PG'})
|
|
wave_route = self.env['stock.route'].create({
|
|
'name': 'Wave for ProductA',
|
|
'product_selectable': True,
|
|
'sequence': 1,
|
|
'rule_ids': [(0, 0, {
|
|
'name': 'Stock -> output rule',
|
|
'action': 'pull',
|
|
'picking_type_id': self.ref('stock.picking_type_internal'),
|
|
'location_src_id': self.ref('stock.stock_location_stock'),
|
|
'location_dest_id': self.ref('stock.stock_location_output'),
|
|
'group_propagation_option': 'fixed',
|
|
'group_id': wave_pg.id,
|
|
})],
|
|
})
|
|
|
|
# Set this route on `product_a`
|
|
product_a.write({
|
|
'route_ids': [(4, wave_route.id)]
|
|
})
|
|
|
|
# Create a procurement for 2 units
|
|
pg = self.env['procurement.group'].create({'name': 'Wave 1'})
|
|
self.env['procurement.group'].run([
|
|
pg.Procurement(
|
|
product_a,
|
|
2.0,
|
|
product_a.uom_id,
|
|
final_location,
|
|
'wave_part_1',
|
|
'wave_part_1',
|
|
warehouse.company_id,
|
|
{
|
|
'warehouse_id': warehouse,
|
|
'group_id': pg
|
|
}
|
|
)
|
|
])
|
|
|
|
# 2 pickings should be created: 1 for pick, 1 for ship
|
|
picking_pick = self.env['stock.picking'].search([('group_id', '=', wave_pg.id)])
|
|
picking_ship = self.env['stock.picking'].search([('group_id', '=', pg.id)])
|
|
self.assertAlmostEqual(picking_pick.move_ids.product_uom_qty, 2.0)
|
|
self.assertAlmostEqual(picking_ship.move_ids.product_uom_qty, 2.0)
|
|
|
|
# Create a procurement for 3 units
|
|
pg = self.env['procurement.group'].create({'name': 'Wave 2'})
|
|
self.env['procurement.group'].run([
|
|
pg.Procurement(
|
|
product_a,
|
|
3.0,
|
|
product_a.uom_id,
|
|
final_location,
|
|
'wave_part_2',
|
|
'wave_part_2',
|
|
warehouse.company_id,
|
|
{
|
|
'warehouse_id': warehouse,
|
|
'group_id': pg
|
|
}
|
|
)
|
|
])
|
|
|
|
# The picking for the pick operation should be reused and the lines merged.
|
|
picking_ship = self.env['stock.picking'].search([('group_id', '=', pg.id)])
|
|
self.assertAlmostEqual(picking_pick.move_ids.product_uom_qty, 5.0)
|
|
self.assertAlmostEqual(picking_ship.move_ids.product_uom_qty, 3.0)
|
|
|
|
def test_orderpoint_replenishment_view_1(self):
|
|
""" Create two warehouses + two moves
|
|
verify that the replenishment view is consistent"""
|
|
warehouse_1 = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
|
|
warehouse_2, warehouse_3 = self.env['stock.warehouse'].create([{
|
|
'name': 'Warehouse Two',
|
|
'code': 'WH2',
|
|
'resupply_wh_ids': [warehouse_1.id],
|
|
}, {
|
|
'name': 'Warehouse Three',
|
|
'code': 'WH3',
|
|
'resupply_wh_ids': [warehouse_1.id],
|
|
}])
|
|
route_2 = self.env['stock.route'].search([
|
|
('supplied_wh_id', '=', warehouse_2.id),
|
|
('supplier_wh_id', '=', warehouse_1.id),
|
|
])
|
|
route_3 = self.env['stock.route'].search([
|
|
('supplied_wh_id', '=', warehouse_3.id),
|
|
('supplier_wh_id', '=', warehouse_1.id),
|
|
])
|
|
product = self.env['product.product'].create({
|
|
'name': 'Super Product',
|
|
'type': 'product',
|
|
'route_ids': [route_2.id, route_3.id]
|
|
})
|
|
moves = self.env['stock.move'].create([{
|
|
'name': 'Move WH2',
|
|
'location_id': warehouse_2.lot_stock_id.id,
|
|
'location_dest_id': self.partner.property_stock_customer.id,
|
|
'product_id': product.id,
|
|
'product_uom': product.uom_id.id,
|
|
'product_uom_qty': 1,
|
|
}, {
|
|
'name': 'Move WH3',
|
|
'location_id': warehouse_3.lot_stock_id.id,
|
|
'location_dest_id': self.partner.property_stock_customer.id,
|
|
'product_id': product.id,
|
|
'product_uom': product.uom_id.id,
|
|
'product_uom_qty': 1,
|
|
}])
|
|
moves._action_confirm()
|
|
# activate action of opening the replenishment view
|
|
self.env.flush_all()
|
|
self.env['stock.warehouse.orderpoint'].action_open_orderpoints()
|
|
replenishments = self.env['stock.warehouse.orderpoint'].search([
|
|
('product_id', '=', product.id),
|
|
])
|
|
# Verify that the location and the route make sense
|
|
self.assertRecordValues(replenishments, [
|
|
{'location_id': warehouse_2.lot_stock_id.id, 'route_id': route_2.id},
|
|
{'location_id': warehouse_3.lot_stock_id.id, 'route_id': route_3.id},
|
|
])
|
|
|
|
def test_orderpoint_replenishment_view_2(self):
|
|
""" Create a warehouse + location to replenish warehouse instead of main location
|
|
verify that the orderpoints created are for the replenish locations not the warehouse main location"""
|
|
warehouse_1 = self.env['stock.warehouse'].create({
|
|
'name': 'Warehouse 1',
|
|
'code': 'WH1',
|
|
})
|
|
warehouse_1.lot_stock_id.replenish_location = False
|
|
replenish_loc = self.env['stock.location'].create({
|
|
'name': 'Replenish Location',
|
|
'location_id': warehouse_1.lot_stock_id.id,
|
|
'replenish_location': True,
|
|
})
|
|
product = self.env['product.product'].create({
|
|
'name': 'Rep Product',
|
|
'type': 'product',
|
|
})
|
|
move = self.env['stock.move'].create({
|
|
'name': 'Move WH2',
|
|
'location_id': replenish_loc.id,
|
|
'location_dest_id': self.partner.property_stock_customer.id,
|
|
'product_id': product.id,
|
|
'product_uom': product.uom_id.id,
|
|
'product_uom_qty': 3,
|
|
})
|
|
move._action_confirm()
|
|
# activate action of opening the replenishment view
|
|
self.env.flush_all()
|
|
self.env['stock.warehouse.orderpoint'].action_open_orderpoints()
|
|
replenishments = self.env['stock.warehouse.orderpoint'].search([
|
|
('product_id', '=', product.id),
|
|
])
|
|
# Verify the location and the qty
|
|
self.assertRecordValues(replenishments, [
|
|
{'location_id': replenish_loc.id, 'qty_to_order': 3},
|
|
])
|
|
|
|
def test_orderpoint_compute_warehouse_location(self):
|
|
warehouse_a = self.env['stock.warehouse'].search([], limit=1)
|
|
warehouse_b = self.env['stock.warehouse'].create({
|
|
'name': 'Test Warehouse',
|
|
'code': 'TWH'
|
|
})
|
|
|
|
# No warehouse specified, no location specified
|
|
# Must choose default/first warehouse and the `lot_stock_id` of that warehouse
|
|
orderpoint = self.env['stock.warehouse.orderpoint'].create({
|
|
'product_id': self.product.id,
|
|
})
|
|
self.assertEqual(orderpoint.warehouse_id, warehouse_a)
|
|
self.assertEqual(orderpoint.location_id, warehouse_a.lot_stock_id)
|
|
orderpoint.unlink()
|
|
|
|
# Warehouse specified, must choose the `lot_stock_id` of that warehouse by default
|
|
orderpoint = self.env['stock.warehouse.orderpoint'].create({
|
|
'product_id': self.product.id,
|
|
'warehouse_id': warehouse_b.id,
|
|
})
|
|
self.assertEqual(orderpoint.warehouse_id, warehouse_b)
|
|
self.assertEqual(orderpoint.location_id, warehouse_b.lot_stock_id)
|
|
orderpoint.unlink()
|
|
|
|
# Location specified, must choose the warehouse of that location by default
|
|
orderpoint = self.env['stock.warehouse.orderpoint'].create({
|
|
'product_id': self.product.id,
|
|
'location_id': warehouse_b.lot_stock_id.id,
|
|
})
|
|
self.assertEqual(orderpoint.warehouse_id, warehouse_b)
|
|
self.assertEqual(orderpoint.location_id, warehouse_b.lot_stock_id)
|
|
orderpoint.unlink()
|
|
|
|
# Warehouse specified, location specified, must let them and not overwrite them with a default
|
|
location = warehouse_b.lot_stock_id.copy()
|
|
orderpoint = self.env['stock.warehouse.orderpoint'].create({
|
|
'product_id': self.product.id,
|
|
'warehouse_id': warehouse_b.id,
|
|
'location_id': location.id,
|
|
})
|
|
self.assertEqual(orderpoint.warehouse_id, warehouse_b)
|
|
self.assertEqual(orderpoint.location_id, location)
|
|
orderpoint.unlink()
|
|
|
|
|
|
class TestProcRuleLoad(TransactionCase):
|
|
def setUp(cls):
|
|
super(TestProcRuleLoad, cls).setUp()
|
|
cls.skipTest("Performance test, too heavy to run.")
|
|
|
|
def test_orderpoint_1(self):
|
|
""" Try 500 products with a 1000 RR(stock -> shelf1 and stock -> shelf2)
|
|
Also randomly include 4 miss configuration.
|
|
"""
|
|
warehouse = self.env['stock.warehouse'].create({
|
|
'name': 'Test Warehouse',
|
|
'code': 'TWH'
|
|
})
|
|
warehouse.reception_steps = 'three_steps'
|
|
supplier_loc = self.env.ref('stock.stock_location_suppliers')
|
|
stock_loc = warehouse.lot_stock_id
|
|
shelf1 = self.env['stock.location'].create({
|
|
'location_id': stock_loc.id,
|
|
'usage': 'internal',
|
|
'name': 'shelf1'
|
|
})
|
|
shelf2 = self.env['stock.location'].create({
|
|
'location_id': stock_loc.id,
|
|
'usage': 'internal',
|
|
'name': 'shelf2'
|
|
})
|
|
|
|
products = self.env['product.product'].create([{'name': i, 'type': 'product'} for i in range(500)])
|
|
self.env['stock.warehouse.orderpoint'].create([{
|
|
'product_id': products[i // 2].id,
|
|
'location_id': (i % 2 == 0) and shelf1.id or shelf2.id,
|
|
'warehouse_id': warehouse.id,
|
|
'product_min_qty': 5,
|
|
'product_max_qty': 10,
|
|
} for i in range(1000)])
|
|
|
|
self.env['stock.rule'].create({
|
|
'name': 'Rule Shelf1',
|
|
'route_id': warehouse.reception_route_id.id,
|
|
'location_dest_id': shelf1.id,
|
|
'location_src_id': stock_loc.id,
|
|
'action': 'pull',
|
|
'procure_method': 'make_to_order',
|
|
'picking_type_id': warehouse.int_type_id.id,
|
|
})
|
|
self.env['stock.rule'].create({
|
|
'name': 'Rule Shelf2',
|
|
'route_id': warehouse.reception_route_id.id,
|
|
'location_dest_id': shelf2.id,
|
|
'location_src_id': stock_loc.id,
|
|
'action': 'pull',
|
|
'procure_method': 'make_to_order',
|
|
'picking_type_id': warehouse.int_type_id.id,
|
|
})
|
|
self.env['stock.rule'].create({
|
|
'name': 'Rule Supplier',
|
|
'route_id': warehouse.reception_route_id.id,
|
|
'location_dest_id': warehouse.wh_input_stock_loc_id.id,
|
|
'location_src_id': supplier_loc.id,
|
|
'action': 'pull',
|
|
'procure_method': 'make_to_stock',
|
|
'picking_type_id': warehouse.in_type_id.id,
|
|
})
|
|
|
|
wrong_route = self.env['stock.route'].create({
|
|
'name': 'Wrong Route',
|
|
})
|
|
self.env['stock.rule'].create({
|
|
'name': 'Trap Rule',
|
|
'route_id': wrong_route.id,
|
|
'location_dest_id': warehouse.wh_input_stock_loc_id.id,
|
|
'location_src_id': supplier_loc.id,
|
|
'action': 'pull',
|
|
'procure_method': 'make_to_order',
|
|
'picking_type_id': warehouse.in_type_id.id,
|
|
})
|
|
(products[50] | products[99] | products[150] | products[199]).write({
|
|
'route_ids': [(4, wrong_route.id)]
|
|
})
|
|
self.env['procurement.group'].run_scheduler()
|
|
self.assertTrue(self.env['stock.move'].search([('product_id', 'in', products.ids)]))
|
|
for index in [50, 99, 150, 199]:
|
|
self.assertTrue(self.env['mail.activity'].search([
|
|
('res_id', '=', products[index].product_tmpl_id.id),
|
|
('res_model_id', '=', self.env.ref('product.model_product_template').id)
|
|
]))
|