From 5642359c10758e309fc7013a4e502867e77eba5e Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Sun, 12 Jul 2026 15:23:17 +0530 Subject: [PATCH] fix: enforce read permission on ledger preview endpoints (#57039) Co-authored-by: Claude Opus 4.8 Co-authored-by: diptanilsaha --- erpnext/controllers/stock_controller.py | 2 + .../tests/test_stock_controller.py | 77 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 erpnext/controllers/tests/test_stock_controller.py diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index b81e63ad6e9..bd94076a2af 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -2060,6 +2060,7 @@ class StockController(AccountsController): def show_accounting_ledger_preview(company, doctype, docname): filters = frappe._dict(company=company, include_dimensions=1) doc = frappe.get_lazy_doc(doctype, docname) + doc.check_permission("read") doc.run_method("before_gl_preview") gl_columns, gl_data = get_accounting_ledger_preview(doc, filters) @@ -2073,6 +2074,7 @@ def show_accounting_ledger_preview(company, doctype, docname): def show_stock_ledger_preview(company, doctype, docname): filters = frappe._dict(company=company) doc = frappe.get_lazy_doc(doctype, docname) + doc.check_permission("read") doc.run_method("before_sl_preview") sl_columns, sl_data = get_stock_ledger_preview(doc, filters) diff --git a/erpnext/controllers/tests/test_stock_controller.py b/erpnext/controllers/tests/test_stock_controller.py new file mode 100644 index 00000000000..7720994419b --- /dev/null +++ b/erpnext/controllers/tests/test_stock_controller.py @@ -0,0 +1,77 @@ +# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import frappe + +from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry +from erpnext.controllers.stock_controller import ( + show_accounting_ledger_preview, + show_stock_ledger_preview, +) +from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt +from erpnext.tests.utils import ERPNextTestSuite + + +class TestLedgerPreviewPermission(ERPNextTestSuite): + def test_accounting_ledger_preview_requires_read_permission(self): + company = "_Test Company" + je = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, submit=True) + + email = "ledger_preview_no_role@example.com" + if not frappe.db.exists("User", email): + frappe.get_doc( + { + "doctype": "User", + "email": email, + "first_name": "No Role", + "user_type": "Website User", + "send_welcome_email": 0, + } + ).insert(ignore_permissions=True) + + try: + frappe.set_user(email) + self.assertRaises( + frappe.PermissionError, + show_accounting_ledger_preview, + company, + "Journal Entry", + je.name, + ) + finally: + frappe.set_user("Administrator") + + # a permitted user is still able to read the preview + accounting_ledger_result = show_accounting_ledger_preview(company, "Journal Entry", je.name) + self.assertTrue(accounting_ledger_result.get("gl_data")) + + def test_stock_ledger_preview_requires_read_permission(self): + company = "_Test Company" + pr = make_purchase_receipt() + + email = "ledger_preview_no_role@example.com" + if not frappe.db.exists("User", email): + frappe.get_doc( + { + "doctype": "User", + "email": email, + "first_name": "No Role", + "user_type": "Website User", + "send_welcome_email": 0, + } + ).insert(ignore_permissions=True) + + try: + frappe.set_user(email) + self.assertRaises( + frappe.PermissionError, + show_stock_ledger_preview, + company, + "Purchase Receipt", + pr.name, + ) + finally: + frappe.set_user("Administrator") + + stock_ledger_result = show_stock_ledger_preview(company, "Purchase Receipt", pr.name) + self.assertTrue(stock_ledger_result.get("sl_data"))