Merge pull request #57031 from mihir-kandoi/fix-job-card-pick-list-transfer

fix(stock): link job card in stock entry created from pick list
This commit is contained in:
Mihir Kandoi
2026-07-10 16:54:31 +05:30
committed by GitHub
2 changed files with 99 additions and 2 deletions

View File

@@ -665,6 +665,48 @@ class TestJobCard(ERPNextTestSuite):
self.assertEqual(ste.from_bom, 1.0)
self.assertEqual(ste.bom_no, work_order.bom_no)
def test_job_card_material_transfer_via_pick_list(self):
from erpnext.stock.doctype.material_request.mapper import create_pick_list
from erpnext.stock.doctype.pick_list.mapper import (
create_stock_entry as create_stock_entry_from_pick_list,
)
create_bom_with_multiple_operations()
work_order = make_wo_with_transfer_against_jc()
for item in work_order.required_items:
make_stock_entry(
item_code=item.item_code,
target=item.source_warehouse,
qty=item.required_qty * 2,
basic_rate=100,
)
job_card_name = frappe.db.get_value("Job Card", {"work_order": work_order.name}, "name")
job_card = frappe.get_doc("Job Card", job_card_name)
mr = make_material_request(job_card_name)
mr.schedule_date = today()
mr.submit()
pick_list = create_pick_list(mr.name)
pick_list.submit()
ste = frappe.get_doc(create_stock_entry_from_pick_list(pick_list.as_dict()))
self.assertEqual(ste.purpose, "Material Transfer for Manufacture")
self.assertEqual(ste.job_card, job_card_name)
self.assertEqual(ste.work_order, work_order.name)
self.assertEqual(ste.fg_completed_qty, job_card.for_quantity)
for row in ste.items:
self.assertEqual(row.t_warehouse, job_card.wip_warehouse)
self.assertTrue(row.job_card_item)
ste.insert()
ste.submit()
job_card.reload()
self.assertEqual(job_card.transferred_qty, job_card.for_quantity)
def test_job_card_proccess_qty_and_completed_qty(self):
from erpnext.manufacturing.doctype.routing.test_routing import (
create_routing,

View File

@@ -289,15 +289,22 @@ def create_stock_entry(pick_list: str | dict):
stock_entry.pick_list = pick_list.get("name")
stock_entry.purpose = pick_list.get("purpose")
stock_entry.company = pick_list.get("company")
stock_entry.set_stock_entry_type()
if pick_list.get("work_order"):
job_card = pick_list.get("material_request") and frappe.db.get_value(
"Material Request", pick_list.get("material_request"), "job_card"
)
if job_card:
stock_entry = update_stock_entry_based_on_job_card(pick_list, stock_entry, job_card)
elif pick_list.get("work_order"):
stock_entry = update_stock_entry_based_on_work_order(pick_list, stock_entry)
elif pick_list.get("material_request"):
stock_entry = update_stock_entry_based_on_material_request(pick_list, stock_entry)
else:
stock_entry = update_stock_entry_items_with_no_reference(pick_list, stock_entry)
stock_entry.set_stock_entry_type()
if not stock_entry.get("items"):
return frappe.msgprint(_("All picked items have already been transferred against this Pick List"))
@@ -344,9 +351,57 @@ def stock_entry_exists(pick_list_name):
return frappe.db.exists("Stock Entry", {"pick_list": pick_list_name})
def update_stock_entry_based_on_job_card(pick_list, stock_entry, job_card):
job_card = frappe.db.get_value(
"Job Card",
job_card,
["name", "work_order", "bom_no", "semi_fg_bom", "for_quantity", "transferred_qty", "wip_warehouse"],
as_dict=True,
)
stock_entry.purpose = "Material Transfer for Manufacture"
stock_entry.job_card = job_card.name
stock_entry.work_order = job_card.work_order
stock_entry.from_bom = 1
stock_entry.bom_no = job_card.semi_fg_bom or job_card.bom_no
stock_entry.fg_completed_qty = max(flt(job_card.for_quantity) - flt(job_card.transferred_qty), 0)
stock_entry.to_warehouse = job_card.wip_warehouse
job_card_items = get_job_card_items_by_material_request_item(pick_list)
for location in pick_list.locations:
if get_pending_transfer_stock_qty(location) <= 0:
continue
item = frappe._dict()
update_common_item_properties(item, location)
item.t_warehouse = job_card.wip_warehouse
item.job_card_item = job_card_items.get(location.material_request_item)
stock_entry.append("items", item)
return stock_entry
def get_job_card_items_by_material_request_item(pick_list):
material_request_items = [
location.material_request_item for location in pick_list.locations if location.material_request_item
]
if not material_request_items:
return {}
return dict(
frappe.get_all(
"Material Request Item",
filters={"name": ["in", material_request_items]},
fields=["name", "job_card_item"],
as_list=True,
)
)
def update_stock_entry_based_on_work_order(pick_list, stock_entry):
work_order = frappe.get_doc("Work Order", pick_list.get("work_order"))
stock_entry.purpose = "Material Transfer for Manufacture"
stock_entry.work_order = work_order.name
stock_entry.company = work_order.company
stock_entry.from_bom = 1