diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 89c617e25d9..6f5459de03e 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -6,6 +6,7 @@ from collections import OrderedDict import frappe from frappe import _, qb, query_builder, scrub +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 @@ -51,6 +52,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()) @@ -91,6 +93,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() @@ -205,7 +208,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", []): @@ -236,7 +239,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", []) @@ -894,28 +897,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"]) - - steam = frappe.qb.DocType("Sales Team") sp = frappe.qb.DocType("Sales Person") - records = ( - frappe.qb.from_(steam) - .select(steam.parent, steam.parenttype) - .distinct() - .where( - steam.parenttype.isin(["Customer", "Sales Invoice"]) - & steam.sales_person.isin( - frappe.qb.from_(sp).select(sp.name).where((sp.lft >= lft) & (sp.rgt <= rgt)) - ) + conditions.append( + steam.sales_person.isin( + frappe.qb.from_(sp).select(sp.name).where((sp.lft >= lft) & (sp.rgt <= rgt)) ) - .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) + 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"):