From 02d41b1dac4c338d514e5cde2767ddeeec550ab3 Mon Sep 17 00:00:00 2001 From: pandiyan Date: Tue, 16 Jun 2026 16:12:59 +0530 Subject: [PATCH 1/2] fix(stock): update transfer status for mixed transfer flows --- .../doctype/stock_entry/services/material_transfer.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/services/material_transfer.py b/erpnext/stock/doctype/stock_entry/services/material_transfer.py index c7d6ee05495..95429764917 100644 --- a/erpnext/stock/doctype/stock_entry/services/material_transfer.py +++ b/erpnext/stock/doctype/stock_entry/services/material_transfer.py @@ -429,9 +429,15 @@ def _resolve_transfer_qty(desire_to_transfer, pending_to_issue, can_transfer): def get_transferred_qty(material_request): + from pypika import Case + + se = frappe.qb.DocType("Stock Entry") sed = frappe.qb.DocType("Stock Entry Detail") + completed_qty = Case().when(se.add_to_transit == 1, sed.transferred_qty).else_(sed.transfer_qty) return ( frappe.qb.from_(sed) - .select(Sum(sed.transfer_qty).as_("transfer_qty"), Sum(sed.transferred_qty).as_("transferred_qty")) + .inner_join(se) + .on(se.name == sed.parent) + .select(Sum(sed.transfer_qty).as_("transfer_qty"), Sum(completed_qty).as_("transferred_qty")) .where((sed.material_request == material_request) & (sed.docstatus == 1)) ).run(as_dict=True)[0] From 1dbdf85ddcbd4ea2e40f6aef835f22f70c3e2659 Mon Sep 17 00:00:00 2001 From: pandiyan Date: Tue, 16 Jun 2026 17:06:26 +0530 Subject: [PATCH 2/2] test(stock): validate completed status for mixed transfer methods --- .../material_request/test_material_request.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 180ab3ae3bb..5406d722b3f 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -1145,6 +1145,52 @@ class TestMaterialRequest(ERPNextTestSuite): se.save() se.submit() + def test_mr_status_for_mixed_direct_and_transit_transfer(self): + material_request = make_material_request( + material_request_type="Material Transfer", + item_code="_Test Item Home Desktop 100", + qty=5, + ) + + in_transit_wh = get_in_transit_warehouse(material_request.company) + + # Make stock available + self._insert_stock_entry(20.0, 20.0) + + # Direct Transfer for 3 Qty + direct_transfer = make_stock_entry(material_request.name) + direct_transfer.items[0].update( + { + "qty": 3, + "transfer_qty": 3, + "s_warehouse": "_Test Warehouse 1 - _TC", + } + ) + direct_transfer.save() + direct_transfer.submit() + + # In Transit Transfer for remaining 2 Qty + transit_transfer = make_in_transit_stock_entry(material_request.name, in_transit_wh) + transit_transfer.items[0].update( + { + "qty": 2, + "s_warehouse": "_Test Warehouse 1 - _TC", + } + ) + transit_transfer.save() + transit_transfer.submit() + + # Complete End Transit + end_transit = make_stock_in_entry(transit_transfer.name) + end_transit.save() + end_transit.submit() + + material_request.reload() + + self.assertEqual(material_request.per_ordered, 100) + self.assertEqual(material_request.status, "Transferred") + self.assertEqual(material_request.transfer_status, "Completed") + def get_in_transit_warehouse(company): if not frappe.db.exists("Warehouse Type", "Transit"):