From a0d156120b2ebb9d22ab1556104b38b8faa85126 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2026 22:04:42 +0530 Subject: [PATCH] fix: field validation and perm checks on `get_stock_reservation_entries_for_voucher` (backport #57968) (#57986) Co-authored-by: Diptanil Saha --- .../stock_reservation_entry.py | 27 ++++++++++++++----- .../test_stock_reservation_entry.py | 16 +++++------ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py index ca31f33bf76..32b42d85cdc 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/stock_reservation_entry.py @@ -882,7 +882,7 @@ def get_ssb_bundle_for_voucher(sre: dict) -> object: def has_reserved_stock(voucher_type: str, voucher_no: str, voucher_detail_no: str | None = None) -> bool: """Returns True if there is any Stock Reservation Entry for the given voucher.""" - if get_stock_reservation_entries_for_voucher( + if _get_stock_reservation_entries_for_voucher( voucher_type, voucher_no, voucher_detail_no, fields=["name"], ignore_status=True ): return True @@ -1113,7 +1113,7 @@ def cancel_stock_reservation_entries( sre_list = {} if voucher_type and voucher_no: - sre_list = get_stock_reservation_entries_for_voucher( + sre_list = _get_stock_reservation_entries_for_voucher( voucher_type, voucher_no, voucher_detail_no, fields=["name"] ) elif from_voucher_type and from_voucher_no: @@ -1156,6 +1156,24 @@ def get_stock_reservation_entries_for_voucher( ) -> list[dict]: """Returns list of Stock Reservation Entries against a Voucher.""" + return _get_stock_reservation_entries_for_voucher( + voucher_type, voucher_no, voucher_detail_no, fields, ignore_status, ignore_permissions=False + ) + + +def _get_stock_reservation_entries_for_voucher( + voucher_type: str, + voucher_no: str, + voucher_detail_no: str | None = None, + fields: list[str] | None = None, + ignore_status: bool = False, + ignore_permissions: bool = True, +) -> list[dict]: + """Returns list of Stock Reservation Entries against a Voucher.""" + + if not ignore_permissions: + frappe.has_permission(voucher_type, doc=voucher_no, throw=True) + if not fields or not isinstance(fields, list): fields = [ "name", @@ -1169,14 +1187,11 @@ def get_stock_reservation_entries_for_voucher( sre = frappe.qb.DocType("Stock Reservation Entry") query = ( - frappe.qb.from_(sre) + frappe.get_query(sre, fields=fields) .where((sre.docstatus == 1) & (sre.voucher_type == voucher_type) & (sre.voucher_no == voucher_no)) .orderby(sre.creation) ) - for field in fields: - query = query.select(sre[field]) - if voucher_detail_no: query = query.where(sre.voucher_detail_no == voucher_detail_no) diff --git a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py index 942c7f482ae..deba0d967c8 100644 --- a/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py +++ b/erpnext/stock/doctype/stock_reservation_entry/test_stock_reservation_entry.py @@ -13,9 +13,9 @@ from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry import StockEntry from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( + _get_stock_reservation_entries_for_voucher, cancel_stock_reservation_entries, get_sre_reserved_qty_details_for_voucher, - get_stock_reservation_entries_for_voucher, has_reserved_stock, ) from erpnext.stock.utils import get_stock_balance @@ -278,7 +278,7 @@ class TestStockReservationEntry(FrappeTestCase): self.assertTrue(has_reserved_stock("Sales Order", so.name)) for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, fields=["reserved_qty", "status"] )[0] self.assertEqual(item.stock_reserved_qty, sre_details.reserved_qty) @@ -335,7 +335,7 @@ class TestStockReservationEntry(FrappeTestCase): dn1.submit() for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, fields=["delivered_qty", "status"] )[0] self.assertGreater(sre_details.delivered_qty, 0) @@ -352,7 +352,7 @@ class TestStockReservationEntry(FrappeTestCase): dn2.submit() for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, @@ -396,7 +396,7 @@ class TestStockReservationEntry(FrappeTestCase): so.load_from_db() for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, fields=["status", "reserved_qty"] )[0] @@ -411,7 +411,7 @@ class TestStockReservationEntry(FrappeTestCase): dn.submit() for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, fields=["status", "delivered_qty", "reserved_qty"] )[0] @@ -459,7 +459,7 @@ class TestStockReservationEntry(FrappeTestCase): so.load_from_db() for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, @@ -520,7 +520,7 @@ class TestStockReservationEntry(FrappeTestCase): so.load_from_db() for item in so.items: - sre_details = get_stock_reservation_entries_for_voucher( + sre_details = _get_stock_reservation_entries_for_voucher( "Sales Order", so.name, item.name, fields=["reserved_qty"] )[0]