fix(stock): add warehouse filter to pick work order raw materials (backport #53748) (#53898)

Co-authored-by: Sudharsanan Ashok <135326972+Sudharsanan11@users.noreply.github.com>
fix(stock): add warehouse filter to pick work order raw materials (#53748)
This commit is contained in:
mergify[bot]
2026-03-30 08:12:48 +00:00
committed by GitHub
parent 319ba31b77
commit ad3c1e520e
2 changed files with 83 additions and 4 deletions

View File

@@ -523,8 +523,26 @@ class PickList(TransactionBase):
self.item_location_map = frappe._dict()
from_warehouses = [self.parent_warehouse] if self.parent_warehouse else []
if self.parent_warehouse:
from_warehouses.extend(get_descendants_of("Warehouse", self.parent_warehouse))
if self.work_order:
root_warehouse = frappe.db.get_value(
"Warehouse", {"company": self.company, "parent_warehouse": ["IS", "NOT SET"], "is_group": 1}
)
from_warehouses = [root_warehouse]
if from_warehouses:
from_warehouses.extend(get_descendants_of("Warehouse", from_warehouses[0]))
item_warehouse_dict = frappe._dict()
if self.work_order:
item_warehouse_list = frappe.get_all(
"Work Order Item",
filters={"parent": self.work_order},
fields=["item_code", "source_warehouse"],
)
if item_warehouse_list:
item_warehouse_dict = {item.item_code: item.source_warehouse for item in item_warehouse_list}
# Create replica before resetting, to handle empty table on update after submit.
locations_replica = self.get("locations")
@@ -542,6 +560,13 @@ class PickList(TransactionBase):
len_idx = len(self.get("locations")) or 0
for item_doc in items:
item_code = item_doc.item_code
priority_warehouses = []
if self.work_order and item_warehouse_dict.get(item_code):
source_warehouse = item_warehouse_dict.get(item_code)
priority_warehouses = [source_warehouse]
priority_warehouses.extend(get_descendants_of("Warehouse", source_warehouse))
from_warehouses = list(dict.fromkeys(priority_warehouses + from_warehouses))
self.item_location_map.setdefault(
item_code,
@@ -552,6 +577,7 @@ class PickList(TransactionBase):
self.company,
picked_item_details=picked_items_details.get(item_code),
consider_rejected_warehouses=self.consider_rejected_warehouses,
priority_warehouses=priority_warehouses,
),
)
@@ -969,6 +995,7 @@ def get_available_item_locations(
ignore_validation=False,
picked_item_details=None,
consider_rejected_warehouses=False,
priority_warehouses=None,
):
locations = []
@@ -1009,7 +1036,7 @@ def get_available_item_locations(
locations = filter_locations_by_picked_materials(locations, picked_item_details)
if locations:
locations = get_locations_based_on_required_qty(locations, required_qty)
locations = get_locations_based_on_required_qty(locations, required_qty, priority_warehouses)
if not ignore_validation:
validate_picked_materials(item_code, required_qty, locations, picked_item_details)
@@ -1017,9 +1044,14 @@ def get_available_item_locations(
return locations
def get_locations_based_on_required_qty(locations, required_qty):
def get_locations_based_on_required_qty(locations, required_qty, priority_warehouses):
filtered_locations = []
if priority_warehouses:
priority_locations = [loc for loc in locations if loc.warehouse in priority_warehouses]
fallback_locations = [loc for loc in locations if loc.warehouse not in priority_warehouses]
locations = priority_locations + fallback_locations
for location in locations:
if location.qty >= required_qty:
location.qty = required_qty

View File

@@ -1050,6 +1050,53 @@ class TestPickList(ERPNextTestSuite):
pl = create_pick_list(so.name)
self.assertFalse(pl.locations)
def test_pick_list_warehouse_for_work_order(self):
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
from erpnext.manufacturing.doctype.work_order.work_order import create_pick_list, make_work_order
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
# Create Warehouses for Work Order
source_warehouse = create_warehouse("_Test WO Warehouse")
wip_warehouse = create_warehouse("_Test WIP Warehouse", company="_Test Company")
fg_warehouse = create_warehouse("_Test Finished Goods Warehouse", company="_Test Company")
# Create Finished Good Item
fg_item = make_item("Test Work Order Finished Good Item", properties={"is_stock_item": 1}).name
# Create Raw Material Item
rm_item = make_item("Test Work Order Raw Material Item", properties={"is_stock_item": 1}).name
# Create BOM
bom = make_bom(item=fg_item, rate=100, raw_materials=[rm_item])
# Create Inward entry for Raw Material
make_stock_entry(item=rm_item, to_warehouse=wip_warehouse, qty=10)
make_stock_entry(item=rm_item, to_warehouse=source_warehouse, qty=10)
# Create Work Order
wo = make_work_order(item=fg_item, qty=5, bom_no=bom.name, company="_Test Company")
wo.required_items[0].source_warehouse = source_warehouse
wo.fg_warehouse = fg_warehouse
wo.skip_transfer = True
wo.submit()
# Create Pick List
pl = create_pick_list(wo.name, for_qty=wo.qty)
# System prioritises the Source Warehouse
self.assertEqual(pl.locations[0].warehouse, source_warehouse)
self.assertEqual(pl.locations[0].item_code, rm_item)
self.assertEqual(pl.locations[0].qty, 5)
# Create Outward Entry from Source Warehouse
make_stock_entry(item=rm_item, from_warehouse=source_warehouse, qty=10)
pl.set_item_locations()
# System should pick other available warehouses
self.assertEqual(pl.locations[0].warehouse, wip_warehouse)
self.assertEqual(pl.locations[0].item_code, rm_item)
self.assertEqual(pl.locations[0].qty, 5)
def test_pick_list_validation_for_serial_no(self):
warehouse = "_Test Warehouse - _TC"
item = make_item(