mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-13 01:34:10 +00:00
fix: add validation for transferred qty and handle MR transfer status for in-transit entry. (backport #50683) (#51134)
fix: add validation for transferred qty and handle MR transfer status for in-transit entry. (#50683)
* fix: add validation for transferred qty
* fix: modify if statement
* test: add unit test for mr transfer status in-transit entry
(cherry picked from commit 890316a793)
Co-authored-by: Logesh Periyasamy <logeshperiyasamy24@gmail.com>
This commit is contained in:
@@ -19,6 +19,7 @@ from erpnext.stock.doctype.material_request.material_request import (
|
|||||||
make_supplier_quotation,
|
make_supplier_quotation,
|
||||||
raise_work_orders,
|
raise_work_orders,
|
||||||
)
|
)
|
||||||
|
from erpnext.stock.doctype.stock_entry.stock_entry import make_stock_in_entry
|
||||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
|
|
||||||
|
|
||||||
@@ -926,6 +927,49 @@ class TestMaterialRequest(FrappeTestCase):
|
|||||||
pl_for_pending = create_pick_list(mr.name)
|
pl_for_pending = create_pick_list(mr.name)
|
||||||
self.assertEqual(pl_for_pending.locations[0].qty, 5)
|
self.assertEqual(pl_for_pending.locations[0].qty, 5)
|
||||||
|
|
||||||
|
def test_mr_status_with_partial_and_excess_end_transit(self):
|
||||||
|
material_request = make_material_request(
|
||||||
|
material_request_type="Material Transfer",
|
||||||
|
item_code="_Test Item Home Desktop 100",
|
||||||
|
)
|
||||||
|
|
||||||
|
in_transit_wh = get_in_transit_warehouse(material_request.company)
|
||||||
|
|
||||||
|
# Make sure stock is available in source warehouse
|
||||||
|
self._insert_stock_entry(20.0, 20.0)
|
||||||
|
|
||||||
|
# Stock Entry (Transfer to In-Transit)
|
||||||
|
stock_entry_1 = make_in_transit_stock_entry(material_request.name, in_transit_wh)
|
||||||
|
stock_entry_1.items[0].update(
|
||||||
|
{
|
||||||
|
"qty": 5,
|
||||||
|
"s_warehouse": "_Test Warehouse 1 - _TC",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
stock_entry_1.save().submit()
|
||||||
|
|
||||||
|
stock_entry_2 = make_in_transit_stock_entry(material_request.name, in_transit_wh)
|
||||||
|
stock_entry_2.items[0].update(
|
||||||
|
{
|
||||||
|
"qty": 5,
|
||||||
|
"s_warehouse": "_Test Warehouse 1 - _TC",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
stock_entry_2.save().submit()
|
||||||
|
|
||||||
|
end_transit_1 = make_stock_in_entry(stock_entry_1.name)
|
||||||
|
end_transit_1.save().submit()
|
||||||
|
|
||||||
|
# Material Request Transfer Status should still be In Transit
|
||||||
|
material_request.load_from_db()
|
||||||
|
self.assertEqual(material_request.transfer_status, "In Transit")
|
||||||
|
|
||||||
|
end_transit_2 = make_stock_in_entry(stock_entry_2.name)
|
||||||
|
end_transit_2.items[0].update({"qty": 6}) # More than transferred
|
||||||
|
end_transit_2.save()
|
||||||
|
|
||||||
|
self.assertRaises(frappe.ValidationError, end_transit_2.submit)
|
||||||
|
|
||||||
|
|
||||||
def get_in_transit_warehouse(company):
|
def get_in_transit_warehouse(company):
|
||||||
if not frappe.db.exists("Warehouse Type", "Transit"):
|
if not frappe.db.exists("Warehouse Type", "Transit"):
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from collections import defaultdict
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _, bold
|
from frappe import _, bold
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
|
from frappe.query_builder import DocType
|
||||||
from frappe.query_builder.functions import Sum
|
from frappe.query_builder.functions import Sum
|
||||||
from frappe.utils import (
|
from frappe.utils import (
|
||||||
cint,
|
cint,
|
||||||
@@ -2815,6 +2816,17 @@ class StockEntry(StockController):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if d.docstatus == 1:
|
||||||
|
transfer_qty = frappe.get_value("Stock Entry Detail", d.ste_detail, "transfer_qty")
|
||||||
|
|
||||||
|
if transferred_qty and transferred_qty[0]:
|
||||||
|
if transferred_qty[0].qty > transfer_qty:
|
||||||
|
frappe.throw(
|
||||||
|
_(
|
||||||
|
"Row {0}: Transferred quantity cannot be greater than the requested quantity."
|
||||||
|
).format(d.idx)
|
||||||
|
)
|
||||||
|
|
||||||
stock_entries[(d.against_stock_entry, d.ste_detail)] = (
|
stock_entries[(d.against_stock_entry, d.ste_detail)] = (
|
||||||
transferred_qty[0].qty if transferred_qty and transferred_qty[0] else 0.0
|
transferred_qty[0].qty if transferred_qty and transferred_qty[0] else 0.0
|
||||||
) or 0.0
|
) or 0.0
|
||||||
@@ -2878,7 +2890,7 @@ class StockEntry(StockController):
|
|||||||
parent_se = frappe.get_value("Stock Entry", self.outgoing_stock_entry, "add_to_transit")
|
parent_se = frappe.get_value("Stock Entry", self.outgoing_stock_entry, "add_to_transit")
|
||||||
|
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
material_request = item.material_request or None
|
material_request = item.get("material_request")
|
||||||
if self.purpose == "Material Transfer" and material_request not in material_requests:
|
if self.purpose == "Material Transfer" and material_request not in material_requests:
|
||||||
if self.outgoing_stock_entry and parent_se:
|
if self.outgoing_stock_entry and parent_se:
|
||||||
material_request = frappe.get_value(
|
material_request = frappe.get_value(
|
||||||
@@ -2887,6 +2899,11 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
if material_request and material_request not in material_requests:
|
if material_request and material_request not in material_requests:
|
||||||
material_requests.append(material_request)
|
material_requests.append(material_request)
|
||||||
|
if status == "Completed":
|
||||||
|
qty = get_transferred_qty(material_request)
|
||||||
|
if qty.get("transfer_qty") > qty.get("transferred_qty"):
|
||||||
|
status = "In Transit"
|
||||||
|
|
||||||
frappe.db.set_value("Material Request", material_request, "transfer_status", status)
|
frappe.db.set_value("Material Request", material_request, "transfer_status", status)
|
||||||
|
|
||||||
def set_serial_no_batch_for_finished_good(self):
|
def set_serial_no_batch_for_finished_good(self):
|
||||||
@@ -3545,3 +3562,18 @@ def get_batchwise_serial_nos(item_code, row):
|
|||||||
batchwise_serial_nos[batch_no] = sorted([serial_no.name for serial_no in serial_nos])
|
batchwise_serial_nos[batch_no] = sorted([serial_no.name for serial_no in serial_nos])
|
||||||
|
|
||||||
return batchwise_serial_nos
|
return batchwise_serial_nos
|
||||||
|
|
||||||
|
|
||||||
|
def get_transferred_qty(material_request):
|
||||||
|
sed = DocType("Stock Entry Detail")
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(sed)
|
||||||
|
.select(
|
||||||
|
Sum(sed.transfer_qty).as_("transfer_qty"),
|
||||||
|
Sum(sed.transferred_qty).as_("transferred_qty"),
|
||||||
|
)
|
||||||
|
.where((sed.material_request == material_request) & (sed.docstatus == 1))
|
||||||
|
).run(as_dict=True)
|
||||||
|
|
||||||
|
return query[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user