From 1da781f2aedd9d7fa1a33b82f90203ae9f4f5c0c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 10:42:01 +0530 Subject: [PATCH] fix(stock entry): calculate transferred quantity using transfer_qty (backport #51656) (#51675) * fix(stock entry): calculate transferred quantity using transfer_qty (cherry picked from commit 4e6d86d6f0bafc19c11e224e68c211a0db3371fa) # Conflicts: # erpnext/stock/doctype/stock_entry/stock_entry.py * test: allow from_warehouse while creating material request (cherry picked from commit 7e991483575c804b7cee1ae80a7e72c6679c1edb) * test: validate transferred quantity for material transfer entry (cherry picked from commit bf2ab32abf991b07ca6a45e1c9be840445181f7d) * chore: fix conflicts --------- Co-authored-by: Navin-S-R Co-authored-by: rohitwaghchaure --- .../material_request/test_material_request.py | 4 +- .../stock/doctype/stock_entry/stock_entry.py | 2 +- .../doctype/stock_entry/test_stock_entry.py | 60 +++++++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index ce5affdfdbe..fff0db2f93d 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -1004,7 +1004,8 @@ def make_material_request(**args): mr = frappe.new_doc("Material Request") mr.material_request_type = args.material_request_type or "Purchase" mr.company = args.company or "_Test Company" - mr.customer = args.customer or "_Test Customer" + if mr.material_request_type == "Customer Provided": + mr.customer = args.customer or "_Test Customer" mr.append( "items", { @@ -1013,6 +1014,7 @@ def make_material_request(**args): "uom": args.uom or "_Test UOM", "conversion_factor": args.conversion_factor or 1, "schedule_date": args.schedule_date or today(), + "from_warehouse": args.from_warehouse, "warehouse": args.warehouse or "_Test Warehouse - _TC", "cost_center": args.cost_center or "_Test Cost Center - _TC", }, diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index e06e3819e09..374fd8f98be 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -2807,7 +2807,7 @@ class StockEntry(StockController): stock_entries_child_list.append(d.ste_detail) transferred_qty = frappe.get_all( "Stock Entry Detail", - fields=["sum(qty) as qty"], + fields=["sum(transfer_qty) as qty"], filters={ "against_stock_entry": d.against_stock_entry, "ste_detail": d.ste_detail, diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index e12e816db7d..20fcc203645 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -14,6 +14,13 @@ from erpnext.stock.doctype.item.test_item import ( make_item_variant, set_item_variant_settings, ) +from erpnext.stock.doctype.material_request.material_request import ( + make_in_transit_stock_entry, +) +from erpnext.stock.doctype.material_request.test_material_request import ( + get_in_transit_warehouse, + make_material_request, +) from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import ( get_batch_from_bundle, get_serial_nos_from_bundle, @@ -2127,6 +2134,59 @@ class TestStockEntry(FrappeTestCase): self.assertEqual(se.purpose, "Repack") self.assertRaises(frappe.ValidationError, se.submit) + def test_transferred_qty_in_material_transfer(self): + item_code = "_Test Item" + source_warehouse = "_Test Warehouse - _TC" + target_warehouse = "_Test Warehouse 1 - _TC" + + if not frappe.db.get_value("UOM Conversion Detail", {"parent": item_code, "uom": "Box"}): + item_doc = frappe.get_doc("Item", item_code) + item_doc.append("uoms", {"uom": "Box", "conversion_factor": 12}) + item_doc.save(ignore_permissions=True) + + make_stock_entry(item_code=item_code, target=source_warehouse, qty=12, rate=100) + + # Create a Material Request for Material Transfer + material_request = make_material_request( + material_request_type="Material Transfer", + qty=1, + item_code=item_code, + uom="Box", + conversion_factor=12, + from_warehouse=source_warehouse, + warehouse=target_warehouse, + ) + in_transit_wh = get_in_transit_warehouse(material_request.company) + + # Create first Stock Entry (Source -> In-Transit) + stock_entry_1 = make_in_transit_stock_entry(material_request.name, in_transit_wh) + stock_entry_1.items[0].update( + { + "qty": 1, + "s_warehouse": source_warehouse, + } + ) + stock_entry_1.save().submit() + + # Validate transfer status after first transfer + material_request.reload() + self.assertEqual(material_request.transfer_status, "In Transit") + + # Create final Stock Entry (In-Transit -> Target) + end_transit_1 = make_stock_in_entry(stock_entry_1.name) + end_transit_1.save().submit() + end_transit_1.reload() + + # Validate quantities + stock_entry_1.reload() + self.assertEqual(stock_entry_1.items[0].qty, 1) + self.assertEqual(stock_entry_1.items[0].transfer_qty, 12) + self.assertEqual(stock_entry_1.items[0].transferred_qty, 12) + + # Validate transfer status after final transfer + material_request.reload() + self.assertEqual(material_request.transfer_status, "Completed") + def make_serialized_item(**args): args = frappe._dict(args)