fix(accounts): run snapshot reports on live data for users with permission restrictions

This commit is contained in:
Nabin Hait
2026-10-21 12:07:38 +05:30
parent d77dc849fb
commit 8fede9db09
6 changed files with 58 additions and 2 deletions
@@ -22,6 +22,7 @@ from erpnext.accounts.report.financial_statements import (
get_period_list,
prepare_data,
)
from erpnext.accounts.report.utils import has_gl_entry_restrictions
def execute(filters=None):
@@ -271,6 +272,9 @@ def get_chart_data(filters, chart_columns, asset, liability, equity, currency):
def execute_snapshot_report(filters):
if has_gl_entry_restrictions():
return execute(filters)
from frappe.database.duckdb.database import get_latest_sync
if not (conn := get_latest_sync("GL Entry")):
@@ -16,7 +16,11 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
get_dimension_with_children,
)
from erpnext.accounts.report.financial_statements import get_cost_centers_with_children
from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency
from erpnext.accounts.report.utils import (
convert_to_presentation_currency,
get_currency,
has_gl_entry_restrictions,
)
from erpnext.accounts.utils import get_account_currency
@@ -795,6 +799,9 @@ def get_columns(filters):
def execute_snapshot_report(filters):
if has_gl_entry_restrictions():
return execute(filters)
from frappe.database.duckdb.database import get_latest_sync
if conn := get_latest_sync("GL Entry"):
@@ -12,6 +12,33 @@ from erpnext.controllers.sales_and_purchase_return import make_return_doc
class TestGeneralLedger(FrappeTestCase):
def test_snapshot_reports_use_live_data_for_restricted_users(self):
from importlib import import_module
from unittest.mock import patch
from erpnext.tests.permission_test_utils import as_user, make_fenced_user
restricted = make_fenced_user(
"gl-snapshot-fenced@example.com", ["Accounts User"], [("Company", "_Test Company")]
)
unrestricted = make_fenced_user("gl-snapshot-open@example.com", ["Accounts User"])
for report in ("general_ledger", "balance_sheet", "profit_and_loss_statement", "trial_balance"):
module = import_module(f"erpnext.accounts.report.{report}.{report}")
for user, expect_live in ((restricted, True), (unrestricted, False)):
with (
as_user(user),
patch.object(module, "execute", return_value="live") as live,
patch(
"frappe.database.duckdb.database.get_latest_sync", side_effect=frappe.ValidationError
),
):
try:
result = module.execute_snapshot_report(frappe._dict(company="_Test Company"))
except frappe.ValidationError:
result = "snapshot"
self.assertEqual(result, "live" if expect_live else "snapshot", f"{report} as {user}")
self.assertEqual(live.called, expect_live)
def setUp(self):
self.company = "_Test Company"
self.clear_old_entries()
@@ -22,6 +22,7 @@ from erpnext.accounts.report.financial_statements import (
get_period_list,
prepare_data,
)
from erpnext.accounts.report.utils import has_gl_entry_restrictions
def execute(filters=None):
@@ -204,6 +205,9 @@ def get_chart_data(filters, chart_columns, income, expense, net_profit_loss, cur
def execute_snapshot_report(filters):
if has_gl_entry_restrictions():
return execute(filters)
from frappe.database.duckdb.database import get_latest_sync
if not (conn := get_latest_sync("GL Entry")):
@@ -18,7 +18,11 @@ from erpnext.accounts.report.financial_statements import (
get_cost_centers_with_children,
set_gl_entries_by_account,
)
from erpnext.accounts.report.utils import convert_to_presentation_currency, get_currency
from erpnext.accounts.report.utils import (
convert_to_presentation_currency,
get_currency,
has_gl_entry_restrictions,
)
from erpnext.accounts.utils import get_zero_cutoff
value_fields = (
@@ -513,6 +517,9 @@ def hide_group_accounts(data):
def execute_snapshot_report(filters):
if has_gl_entry_restrictions():
return execute(filters)
from frappe.database.duckdb.database import get_latest_sync
if conn := get_latest_sync("GL Entry"):
+7
View File
@@ -436,3 +436,10 @@ def get_opening_row(party_type, party, from_date, company):
& (gle.is_cancelled == 0)
)
).run(as_dict=True)
def has_gl_entry_restrictions() -> bool:
"""Snapshot reports read a DuckDB copy that cannot apply the user's GL Entry permission conditions."""
from frappe.desk.reportview import build_match_conditions
return bool(build_match_conditions("GL Entry"))