From 7b53402eae1e330f4f585002ee4a1bb828eaa701 Mon Sep 17 00:00:00 2001 From: Diptanil Saha Date: Sun, 6 Sep 2026 22:57:15 +0530 Subject: [PATCH] fix: add permission checks to whitelisted methods (#58787) --- .../chart_of_accounts/chart_of_accounts.py | 2 ++ .../doctype/loyalty_program/loyalty_program.py | 2 ++ .../unreconcile_payment/unreconcile_payment.py | 2 ++ erpnext/selling/page/sales_funnel/sales_funnel.py | 15 +++++++++------ erpnext/setup/doctype/company/company.json | 6 +++++- erpnext/templates/pages/order.py | 12 +++++------- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py index 89530b56e81..f11eb7855c2 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py +++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py @@ -102,6 +102,8 @@ def identify_is_group(child): def get_chart(chart_template: str | None, existing_company: str | None = None): chart = {} if existing_company: + frappe.has_permission("Company", doc=existing_company, throw=True) + return get_account_tree_from_existing_company(existing_company) elif chart_template == "Standard": diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/loyalty_program.py index 543feb89fa1..ef418c8ed1d 100644 --- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.py +++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.py @@ -97,6 +97,8 @@ def get_loyalty_program_details_with_points( include_expired_entry: bool = False, current_transaction_amount: int | float = 0, ): + frappe.has_permission("Customer", doc=customer, throw=True) + lp_details = get_loyalty_program_details(customer, loyalty_program, company=company, silent=silent) loyalty_program = frappe.get_doc("Loyalty Program", loyalty_program) loyalty_details = get_loyalty_details( diff --git a/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py index 97a17c21600..e367333e5b6 100644 --- a/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py +++ b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py @@ -106,6 +106,8 @@ def get_linked_payments_for_doc( company: str | None = None, doctype: str | None = None, docname: str | None = None ) -> list: if company and doctype and docname: + frappe.has_permission(doctype, doc=docname, throw=True) + _dt = doctype _dn = docname ple = qb.DocType("Payment Ledger Entry") diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.py b/erpnext/selling/page/sales_funnel/sales_funnel.py index e7c636ee385..76cb5aabaa3 100644 --- a/erpnext/selling/page/sales_funnel/sales_funnel.py +++ b/erpnext/selling/page/sales_funnel/sales_funnel.py @@ -21,6 +21,8 @@ def validate_filters(from_date, to_date, company): @frappe.whitelist() def get_funnel_data(from_date: str, to_date: str, company: str): + frappe.has_permission("Company", doc=company, throw=True) + validate_filters(from_date, to_date, company) lead = frappe.qb.DocType("Lead") @@ -76,23 +78,24 @@ def get_funnel_data(from_date: str, to_date: str, company: str): @frappe.whitelist() def get_opp_by_utm_source(from_date: str, to_date: str, company: str): - return get_opp_by("utm_source", from_date, to_date, company) + return get_opp_by("utm_source", from_date, to_date, company, ignore_permissions=False) @frappe.whitelist() def get_opp_by_utm_campaign(from_date: str, to_date: str, company: str): - return get_opp_by("utm_campaign", from_date, to_date, company) + return get_opp_by("utm_campaign", from_date, to_date, company, ignore_permissions=False) @frappe.whitelist() def get_opp_by_utm_medium(from_date: str, to_date: str, company: str): - return get_opp_by("utm_medium", from_date, to_date, company) + return get_opp_by("utm_medium", from_date, to_date, company, ignore_permissions=False) -def get_opp_by(by_field, from_date, to_date, company): +def get_opp_by(by_field, from_date, to_date, company, ignore_permissions=False): validate_filters(from_date, to_date, company) - opportunities = frappe.get_all( + get_opportunities = frappe.get_all if ignore_permissions else frappe.get_list + opportunities = get_opportunities( "Opportunity", filters=[ ["status", "in", ["Open", "Quotation", "Replied"]], @@ -147,7 +150,7 @@ def get_opp_by(by_field, from_date, to_date, company): def get_pipeline_data(from_date: str, to_date: str, company: str): validate_filters(from_date, to_date, company) - opportunities = frappe.get_all( + opportunities = frappe.get_list( "Opportunity", filters=[ ["status", "in", ["Open", "Quotation", "Replied"]], diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 84b4ba4b5f8..230b9a37350 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -1159,7 +1159,7 @@ "image_field": "company_logo", "is_tree": 1, "links": [], - "modified": "2026-08-21 23:11:40.429841", + "modified": "2026-09-06 12:00:00.000000", "modified_by": "Administrator", "module": "Setup", "name": "Company", @@ -1192,6 +1192,10 @@ "read": 1, "role": "Sales User" }, + { + "read": 1, + "role": "Sales Manager" + }, { "read": 1, "role": "Purchase User" diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py index dcf3b046722..76482f260eb 100644 --- a/erpnext/templates/pages/order.py +++ b/erpnext/templates/pages/order.py @@ -42,14 +42,12 @@ def get_context(context): customer_loyalty_program = frappe.db.get_value("Customer", context.doc.customer, "loyalty_program") if customer_loyalty_program: - from erpnext.accounts.doctype.loyalty_program.loyalty_program import ( - get_loyalty_program_details_with_points, - ) + from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_details - loyalty_program_details = get_loyalty_program_details_with_points( - context.doc.customer, customer_loyalty_program - ) - context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points")) + # website permission on the order is already checked above; this page only needs + # the customer's own point balance, so skip the desk-permission wrapper + loyalty_details = get_loyalty_details(context.doc.customer, customer_loyalty_program) + context.available_loyalty_points = int(loyalty_details.get("loyalty_points")) context.show_pay_button, context.pay_amount = get_payment_details(context.doc) context.show_make_pi_button = False