Merge pull request #36333 from GursheenK/AP-GL-not-matching

fix: AP report does not show expense claim payables
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 4996203..895c314 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -14,6 +14,7 @@
 from frappe.contacts.doctype.contact.contact import get_contact_details
 from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
 from frappe.model.utils import get_fetch_values
+from frappe.query_builder.functions import Date, Sum
 from frappe.utils import (
 	add_days,
 	add_months,
@@ -920,32 +921,35 @@
 
 
 def get_partywise_advanced_payment_amount(
-	party_type, posting_date=None, future_payment=0, company=None, party=None
+	party_type, posting_date=None, future_payment=0, company=None, party=None, account_type=None
 ):
-	cond = "1=1"
+	gle = frappe.qb.DocType("GL Entry")
+	query = (
+		frappe.qb.from_(gle)
+		.select(gle.party)
+		.where(
+			(gle.party_type.isin(party_type)) & (gle.against_voucher.isnull()) & (gle.is_cancelled == 0)
+		)
+		.groupby(gle.party)
+	)
+	if account_type == "Receivable":
+		query = query.select(Sum(gle.credit).as_("amount"))
+	else:
+		query = query.select(Sum(gle.debit).as_("amount"))
+
 	if posting_date:
 		if future_payment:
-			cond = "(posting_date <= '{0}' OR DATE(creation) <= '{0}')" "".format(posting_date)
+			query = query.where((gle.posting_date <= posting_date) | (Date(gle.creation) <= posting_date))
 		else:
-			cond = "posting_date <= '{0}'".format(posting_date)
+			query = query.where(gle.posting_date <= posting_date)
 
 	if company:
-		cond += "and company = {0}".format(frappe.db.escape(company))
+		query = query.where(gle.company == company)
 
 	if party:
-		cond += "and party = {0}".format(frappe.db.escape(party))
+		query = query.where(gle.party == party)
 
-	data = frappe.db.sql(
-		""" SELECT party, sum({0}) as amount
-		FROM `tabGL Entry`
-		WHERE
-			party_type = %s and against_voucher is null
-			and is_cancelled = 0
-			and {1} GROUP BY party""".format(
-			("credit") if party_type == "Customer" else "debit", cond
-		),
-		party_type,
-	)
+	data = query.run(as_dict=True)
 	if data:
 		return frappe._dict(data)
 
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.py b/erpnext/accounts/report/accounts_payable/accounts_payable.py
index 7b19994..8279afb 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.py
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.py
@@ -7,7 +7,7 @@
 
 def execute(filters=None):
 	args = {
-		"party_type": "Supplier",
+		"account_type": "Payable",
 		"naming_by": ["Buying Settings", "supp_master_name"],
 	}
 	return ReceivablePayableReport(filters).run(args)
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py
index 65fe1de..834c83c 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.py
@@ -9,7 +9,7 @@
 
 def execute(filters=None):
 	args = {
-		"party_type": "Supplier",
+		"account_type": "Payable",
 		"naming_by": ["Buying Settings", "supp_master_name"],
 	}
 	return AccountsReceivableSummary(filters).run(args)
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 30f7fb3..11bbb6f 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -7,7 +7,7 @@
 import frappe
 from frappe import _, qb, scrub
 from frappe.query_builder import Criterion
-from frappe.query_builder.functions import Date
+from frappe.query_builder.functions import Date, Sum
 from frappe.utils import cint, cstr, flt, getdate, nowdate
 
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
@@ -34,7 +34,7 @@
 
 def execute(filters=None):
 	args = {
-		"party_type": "Customer",
+		"account_type": "Receivable",
 		"naming_by": ["Selling Settings", "cust_master_name"],
 	}
 	return ReceivablePayableReport(filters).run(args)
@@ -70,8 +70,11 @@
 			"Company", self.filters.get("company"), "default_currency"
 		)
 		self.currency_precision = get_currency_precision() or 2
-		self.dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
-		self.party_type = self.filters.party_type
+		self.dr_or_cr = "debit" if self.filters.account_type == "Receivable" else "credit"
+		self.account_type = self.filters.account_type
+		self.party_type = frappe.db.get_all(
+			"Party Type", {"account_type": self.account_type}, pluck="name"
+		)
 		self.party_details = {}
 		self.invoices = set()
 		self.skip_total_row = 0
@@ -197,6 +200,7 @@
 			# no invoice, this is an invoice / stand-alone payment / credit note
 			row = self.voucher_balance.get((ple.voucher_type, ple.voucher_no, ple.party))
 
+		row.party_type = ple.party_type
 		return row
 
 	def update_voucher_balance(self, ple):
@@ -207,8 +211,9 @@
 			return
 
 		# amount in "Party Currency", if its supplied. If not, amount in company currency
-		if self.filters.get(scrub(self.party_type)):
-			amount = ple.amount_in_account_currency
+		for party_type in self.party_type:
+			if self.filters.get(scrub(party_type)):
+				amount = ple.amount_in_account_currency
 		else:
 			amount = ple.amount
 		amount_in_account_currency = ple.amount_in_account_currency
@@ -362,7 +367,7 @@
 
 	def get_invoice_details(self):
 		self.invoice_details = frappe._dict()
-		if self.party_type == "Customer":
+		if self.account_type == "Receivable":
 			si_list = frappe.db.sql(
 				"""
 				select name, due_date, po_no
@@ -390,7 +395,7 @@
 						d.sales_person
 					)
 
-		if self.party_type == "Supplier":
+		if self.account_type == "Payable":
 			for pi in frappe.db.sql(
 				"""
 				select name, due_date, bill_no, bill_date
@@ -421,8 +426,10 @@
 		# customer / supplier name
 		party_details = self.get_party_details(row.party) or {}
 		row.update(party_details)
-		if self.filters.get(scrub(self.filters.party_type)):
-			row.currency = row.account_currency
+		for party_type in self.party_type:
+			if self.filters.get(scrub(party_type)):
+				row.currency = row.account_currency
+				break
 		else:
 			row.currency = self.company_currency
 
@@ -532,65 +539,67 @@
 						self.future_payments.setdefault((d.invoice_no, d.party), []).append(d)
 
 	def get_future_payments_from_payment_entry(self):
-		return frappe.db.sql(
-			"""
-			select
-				ref.reference_name as invoice_no,
-				payment_entry.party,
-				payment_entry.party_type,
-				payment_entry.posting_date as future_date,
-				ref.allocated_amount as future_amount,
-				payment_entry.reference_no as future_ref
-			from
-				`tabPayment Entry` as payment_entry inner join `tabPayment Entry Reference` as ref
-			on
-				(ref.parent = payment_entry.name)
-			where
-				payment_entry.docstatus < 2
-				and payment_entry.posting_date > %s
-				and payment_entry.party_type = %s
-			""",
-			(self.filters.report_date, self.party_type),
-			as_dict=1,
-		)
+		pe = frappe.qb.DocType("Payment Entry")
+		pe_ref = frappe.qb.DocType("Payment Entry Reference")
+		return (
+			frappe.qb.from_(pe)
+			.inner_join(pe_ref)
+			.on(pe_ref.parent == pe.name)
+			.select(
+				(pe_ref.reference_name).as_("invoice_no"),
+				pe.party,
+				pe.party_type,
+				(pe.posting_date).as_("future_date"),
+				(pe_ref.allocated_amount).as_("future_amount"),
+				(pe.reference_no).as_("future_ref"),
+			)
+			.where(
+				(pe.docstatus < 2)
+				& (pe.posting_date > self.filters.report_date)
+				& (pe.party_type.isin(self.party_type))
+			)
+		).run(as_dict=True)
 
 	def get_future_payments_from_journal_entry(self):
-		if self.filters.get("party"):
-			amount_field = (
-				"jea.debit_in_account_currency - jea.credit_in_account_currency"
-				if self.party_type == "Supplier"
-				else "jea.credit_in_account_currency - jea.debit_in_account_currency"
-			)
-		else:
-			amount_field = "jea.debit - " if self.party_type == "Supplier" else "jea.credit"
-
-		return frappe.db.sql(
-			"""
-			select
-				jea.reference_name as invoice_no,
+		je = frappe.qb.DocType("Journal Entry")
+		jea = frappe.qb.DocType("Journal Entry Account")
+		query = (
+			frappe.qb.from_(je)
+			.inner_join(jea)
+			.on(jea.parent == je.name)
+			.select(
+				jea.reference_name.as_("invoice_no"),
 				jea.party,
 				jea.party_type,
-				je.posting_date as future_date,
-				sum('{0}') as future_amount,
-				je.cheque_no as future_ref
-			from
-				`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
-			on
-				(jea.parent = je.name)
-			where
-				je.docstatus < 2
-				and je.posting_date > %s
-				and jea.party_type = %s
-				and jea.reference_name is not null and jea.reference_name != ''
-			group by je.name, jea.reference_name
-			having future_amount > 0
-			""".format(
-				amount_field
-			),
-			(self.filters.report_date, self.party_type),
-			as_dict=1,
+				je.posting_date.as_("future_date"),
+				je.cheque_no.as_("future_ref"),
+			)
+			.where(
+				(je.docstatus < 2)
+				& (je.posting_date > self.filters.report_date)
+				& (jea.party_type.isin(self.party_type))
+				& (jea.reference_name.isnotnull())
+				& (jea.reference_name != "")
+			)
 		)
 
+		if self.filters.get("party"):
+			if self.account_type == "Payable":
+				query = query.select(
+					Sum(jea.debit_in_account_currency - jea.credit_in_account_currency).as_("future_amount")
+				)
+			else:
+				query = query.select(
+					Sum(jea.credit_in_account_currency - jea.debit_in_account_currency).as_("future_amount")
+				)
+		else:
+			query = query.select(
+				Sum(jea.debit if self.account_type == "Payable" else jea.credit).as_("future_amount")
+			)
+
+		query = query.having(qb.Field("future_amount") > 0)
+		return query.run(as_dict=True)
+
 	def allocate_future_payments(self, row):
 		# future payments are captured in additional columns
 		# this method allocates pending future payments against a voucher to
@@ -619,13 +628,17 @@
 			row.future_ref = ", ".join(row.future_ref)
 
 	def get_return_entries(self):
-		doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
+		doctype = "Sales Invoice" if self.account_type == "Receivable" else "Purchase Invoice"
 		filters = {"is_return": 1, "docstatus": 1, "company": self.filters.company}
-		party_field = scrub(self.filters.party_type)
-		if self.filters.get(party_field):
-			filters.update({party_field: self.filters.get(party_field)})
+		or_filters = {}
+		for party_type in self.party_type:
+			party_field = scrub(party_type)
+			if self.filters.get(party_field):
+				or_filters.update({party_field: self.filters.get(party_field)})
 		self.return_entries = frappe._dict(
-			frappe.get_all(doctype, filters, ["name", "return_against"], as_list=1)
+			frappe.get_all(
+				doctype, filters=filters, or_filters=or_filters, fields=["name", "return_against"], as_list=1
+			)
 		)
 
 	def set_ageing(self, row):
@@ -716,6 +729,7 @@
 			)
 			.where(ple.delinked == 0)
 			.where(Criterion.all(self.qb_selection_filter))
+			.where(Criterion.any(self.or_filters))
 		)
 
 		if self.filters.get("group_by_party"):
@@ -746,16 +760,18 @@
 
 	def prepare_conditions(self):
 		self.qb_selection_filter = []
-		party_type_field = scrub(self.party_type)
-		self.qb_selection_filter.append(self.ple.party_type == self.party_type)
+		self.or_filters = []
+		for party_type in self.party_type:
+			party_type_field = scrub(party_type)
+			self.or_filters.append(self.ple.party_type == party_type)
 
-		self.add_common_filters(party_type_field=party_type_field)
+			self.add_common_filters(party_type_field=party_type_field)
 
-		if party_type_field == "customer":
-			self.add_customer_filters()
+			if party_type_field == "customer":
+				self.add_customer_filters()
 
-		elif party_type_field == "supplier":
-			self.add_supplier_filters()
+			elif party_type_field == "supplier":
+				self.add_supplier_filters()
 
 		if self.filters.cost_center:
 			self.get_cost_center_conditions()
@@ -784,11 +800,10 @@
 			self.qb_selection_filter.append(self.ple.account == self.filters.party_account)
 		else:
 			# get GL with "receivable" or "payable" account_type
-			account_type = "Receivable" if self.party_type == "Customer" else "Payable"
 			accounts = [
 				d.name
 				for d in frappe.get_all(
-					"Account", filters={"account_type": account_type, "company": self.filters.company}
+					"Account", filters={"account_type": self.account_type, "company": self.filters.company}
 				)
 			]
 
@@ -878,7 +893,7 @@
 
 	def get_party_details(self, party):
 		if not party in self.party_details:
-			if self.party_type == "Customer":
+			if self.account_type == "Receivable":
 				fields = ["customer_name", "territory", "customer_group", "customer_primary_contact"]
 
 				if self.filters.get("sales_partner"):
@@ -901,14 +916,20 @@
 		self.columns = []
 		self.add_column("Posting Date", fieldtype="Date")
 		self.add_column(
-			label=_(self.party_type),
+			label="Party Type",
+			fieldname="party_type",
+			fieldtype="Data",
+			width=100,
+		)
+		self.add_column(
+			label="Party",
 			fieldname="party",
-			fieldtype="Link",
-			options=self.party_type,
+			fieldtype="Dynamic Link",
+			options="party_type",
 			width=180,
 		)
 		self.add_column(
-			label="Receivable Account" if self.party_type == "Customer" else "Payable Account",
+			label=self.account_type + " Account",
 			fieldname="party_account",
 			fieldtype="Link",
 			options="Account",
@@ -916,13 +937,19 @@
 		)
 
 		if self.party_naming_by == "Naming Series":
+			if self.account_type == "Payable":
+				label = "Supplier Name"
+				fieldname = "supplier_name"
+			else:
+				label = "Customer Name"
+				fieldname = "customer_name"
 			self.add_column(
-				_("{0} Name").format(self.party_type),
-				fieldname=scrub(self.party_type) + "_name",
+				label=label,
+				fieldname=fieldname,
 				fieldtype="Data",
 			)
 
-		if self.party_type == "Customer":
+		if self.account_type == "Receivable":
 			self.add_column(
 				_("Customer Contact"),
 				fieldname="customer_primary_contact",
@@ -942,7 +969,7 @@
 
 		self.add_column(label="Due Date", fieldtype="Date")
 
-		if self.party_type == "Supplier":
+		if self.account_type == "Payable":
 			self.add_column(label=_("Bill No"), fieldname="bill_no", fieldtype="Data")
 			self.add_column(label=_("Bill Date"), fieldname="bill_date", fieldtype="Date")
 
@@ -952,7 +979,7 @@
 
 		self.add_column(_("Invoiced Amount"), fieldname="invoiced")
 		self.add_column(_("Paid Amount"), fieldname="paid")
-		if self.party_type == "Customer":
+		if self.account_type == "Receivable":
 			self.add_column(_("Credit Note"), fieldname="credit_note")
 		else:
 			# note: fieldname is still `credit_note`
@@ -970,7 +997,7 @@
 			self.add_column(label=_("Future Payment Amount"), fieldname="future_amount")
 			self.add_column(label=_("Remaining Balance"), fieldname="remaining_balance")
 
-		if self.filters.party_type == "Customer":
+		if self.filters.account_type == "Receivable":
 			self.add_column(label=_("Customer LPO"), fieldname="po_no", fieldtype="Data")
 
 			# comma separated list of linked delivery notes
@@ -991,7 +1018,7 @@
 			if self.filters.sales_partner:
 				self.add_column(label=_("Sales Partner"), fieldname="default_sales_partner", fieldtype="Data")
 
-		if self.filters.party_type == "Supplier":
+		if self.filters.account_type == "Payable":
 			self.add_column(
 				label=_("Supplier Group"),
 				fieldname="supplier_group",
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index 9c01b1a..3aa1ae7 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -12,7 +12,7 @@
 
 def execute(filters=None):
 	args = {
-		"party_type": "Customer",
+		"account_type": "Receivable",
 		"naming_by": ["Selling Settings", "cust_master_name"],
 	}
 
@@ -21,7 +21,10 @@
 
 class AccountsReceivableSummary(ReceivablePayableReport):
 	def run(self, args):
-		self.party_type = args.get("party_type")
+		self.account_type = args.get("account_type")
+		self.party_type = frappe.db.get_all(
+			"Party Type", {"account_type": self.account_type}, pluck="name"
+		)
 		self.party_naming_by = frappe.db.get_value(
 			args.get("naming_by")[0], None, args.get("naming_by")[1]
 		)
@@ -35,13 +38,19 @@
 
 		self.get_party_total(args)
 
+		party = None
+		for party_type in self.party_type:
+			if self.filters.get(scrub(party_type)):
+				party = self.filters.get(scrub(party_type))
+
 		party_advance_amount = (
 			get_partywise_advanced_payment_amount(
 				self.party_type,
 				self.filters.report_date,
 				self.filters.show_future_payments,
 				self.filters.company,
-				party=self.filters.get(scrub(self.party_type)),
+				party=party,
+				account_type=self.account_type,
 			)
 			or {}
 		)
@@ -57,9 +66,13 @@
 
 			row.party = party
 			if self.party_naming_by == "Naming Series":
-				row.party_name = frappe.get_cached_value(
-					self.party_type, party, scrub(self.party_type) + "_name"
-				)
+				if self.account_type == "Payable":
+					doctype = "Supplier"
+					fieldname = "supplier_name"
+				else:
+					doctype = "Customer"
+					fieldname = "customer_name"
+				row.party_name = frappe.get_cached_value(doctype, party, fieldname)
 
 			row.update(party_dict)
 
@@ -93,6 +106,7 @@
 
 			# set territory, customer_group, sales person etc
 			self.set_party_details(d)
+			self.party_total[d.party].update({"party_type": d.party_type})
 
 	def init_party_total(self, row):
 		self.party_total.setdefault(
@@ -131,17 +145,27 @@
 	def get_columns(self):
 		self.columns = []
 		self.add_column(
-			label=_(self.party_type),
+			label="Party Type",
+			fieldname="party_type",
+			fieldtype="Data",
+			width=100,
+		)
+		self.add_column(
+			label="Party",
 			fieldname="party",
-			fieldtype="Link",
-			options=self.party_type,
+			fieldtype="Dynamic Link",
+			options="party_type",
 			width=180,
 		)
 
 		if self.party_naming_by == "Naming Series":
-			self.add_column(_("{0} Name").format(self.party_type), fieldname="party_name", fieldtype="Data")
+			self.add_column(
+				label="Supplier Name" if self.account_type == "Payable" else "Customer Name",
+				fieldname="party_name",
+				fieldtype="Data",
+			)
 
-		credit_debit_label = "Credit Note" if self.party_type == "Customer" else "Debit Note"
+		credit_debit_label = "Credit Note" if self.account_type == "Receivable" else "Debit Note"
 
 		self.add_column(_("Advance Amount"), fieldname="advance")
 		self.add_column(_("Invoiced Amount"), fieldname="invoiced")
@@ -159,7 +183,7 @@
 			self.add_column(label=_("Future Payment Amount"), fieldname="future_amount")
 			self.add_column(label=_("Remaining Balance"), fieldname="remaining_balance")
 
-		if self.party_type == "Customer":
+		if self.account_type == "Receivable":
 			self.add_column(
 				label=_("Territory"), fieldname="territory", fieldtype="Link", options="Territory"
 			)