Merge pull request #58104 from frappe/mergify/bp/version-16-hotfix/pr-58078

fix: apply Sales Person user permissions in Accounts Receivable (backport #58078)
This commit is contained in:
Khushi Rawat
2026-08-13 12:28:49 +05:30
committed by GitHub

View File

@@ -7,6 +7,7 @@ from collections import OrderedDict
import frappe
from frappe import _, qb, query_builder, scrub
from frappe.database.schema import get_definition
from frappe.permissions import get_allowed_docs_for_doctype
from frappe.query_builder import Criterion
from frappe.query_builder.functions import Date, Substring, Sum
from frappe.utils import cint, cstr, flt, getdate, nowdate
@@ -52,6 +53,7 @@ class ReceivablePayableReport:
self.filters = frappe._dict(filters or {})
self.qb_selection_filter = []
self.ple = qb.DocType("Payment Ledger Entry")
self.sales_person_records = None
self.filters.report_date = getdate(self.filters.report_date or nowdate())
self.age_as_on = (
getdate(nowdate())
@@ -92,6 +94,7 @@ class ReceivablePayableReport:
self.party_type = get_party_types_from_account_type(self.account_type)
self.party_details = {}
self.invoices = set()
self.sales_person_records = None
self.skip_total_row = 0
self.advance_payment_doctypes = get_advance_payment_doctypes()
@@ -206,7 +209,7 @@ class ReceivablePayableReport:
def get_invoices(self, ple):
if ple.voucher_type in ("Sales Invoice", "Purchase Invoice"):
if self.filters.get("sales_person"):
if self.sales_person_records is not None:
if ple.voucher_no in self.sales_person_records.get(
"Sales Invoice", []
) or ple.party in self.sales_person_records.get("Customer", []):
@@ -237,7 +240,7 @@ class ReceivablePayableReport:
]
def get_voucher_balance(self, ple):
if self.filters.get("sales_person"):
if self.sales_person_records is not None:
if not (
ple.party in self.sales_person_records.get("Customer", [])
or ple.against_voucher_no in self.sales_person_records.get("Sales Invoice", [])
@@ -896,25 +899,54 @@ class ReceivablePayableReport:
self.ple_query = query
def get_permitted_sales_persons(self, parenttype):
if self.account_type != "Receivable":
return None
permissions = frappe.permissions.get_user_permissions(frappe.session.user).get("Sales Person", [])
if not permissions:
return None
return get_allowed_docs_for_doctype(permissions, parenttype)
def get_sales_invoices_or_customers_based_on_sales_person(self):
parenttypes = ["Customer", "Sales Invoice"]
permitted = {p: self.get_permitted_sales_persons(p) for p in parenttypes}
if not (self.filters.get("sales_person") or any(p is not None for p in permitted.values())):
return
steam = frappe.qb.DocType("Sales Team")
scope = []
for parenttype in parenttypes:
criterion = steam.parenttype == parenttype
if (allowed := permitted[parenttype]) is not None:
criterion &= steam.sales_person.isin(allowed or [""])
scope.append(criterion)
conditions = [Criterion.any(scope)]
if self.filters.get("sales_person"):
lft, rgt = frappe.db.get_value("Sales Person", self.filters.get("sales_person"), ["lft", "rgt"])
# nosemgrep
records = frappe.db.sql(
"""
select distinct parent, parenttype
from `tabSales Team` steam
where parenttype in ('Customer', 'Sales Invoice')
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person)
""",
(lft, rgt),
as_dict=1,
sp = frappe.qb.DocType("Sales Person")
conditions.append(
steam.sales_person.isin(
frappe.qb.from_(sp).select(sp.name).where((sp.lft >= lft) & (sp.rgt <= rgt))
)
)
self.sales_person_records = frappe._dict()
for d in records:
self.sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
records = (
frappe.qb.from_(steam)
.select(steam.parent, steam.parenttype)
.distinct()
.where(Criterion.all(conditions))
.run(as_dict=1)
)
self.sales_person_records = frappe._dict()
for d in records:
self.sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
def get_invoices_based_on_sales_partner(self):
if not self.filters.get("sales_partner"):