fix: Handling payments against credit/debit notes and party currency (#19154)

diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 8cbf845..bcbd427 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -59,7 +59,6 @@
 		self.invoices = set()
 
 	def get_data(self):
-		t1 = now()
 		self.get_gl_entries()
 		self.voucher_balance = OrderedDict()
 		self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
@@ -73,6 +72,9 @@
 		# fetch future payments against invoices
 		self.get_future_payments()
 
+		# Get return entries
+		self.get_return_entries()
+
 		self.data = []
 		for gle in self.gl_entries:
 			self.update_voucher_balance(gle)
@@ -91,6 +93,7 @@
 					party = gle.party,
 					posting_date = gle.posting_date,
 					remarks = gle.remarks,
+					account_currency = gle.account_currency,
 					invoiced = 0.0,
 					paid = 0.0,
 					credit_note = 0.0,
@@ -106,7 +109,6 @@
 		# get the row where this balance needs to be updated
 		# if its a payment, it will return the linked invoice or will be considered as advance
 		row = self.get_voucher_balance(gle)
-
 		# gle_balance will be the total "debit - credit" for receivable type reports and
 		# and vice-versa for payable type reports
 		gle_balance = self.get_gle_balance(gle)
@@ -131,7 +133,18 @@
 
 		if gle.against_voucher:
 			# find invoice
-			voucher_balance = self.voucher_balance.get((gle.against_voucher_type, gle.against_voucher, gle.party))
+			against_voucher = gle.against_voucher
+
+			# If payment is made against credit note
+			# and credit note is made against a Sales Invoice
+			# then consider the payment against original sales invoice.
+			if gle.against_voucher_type in ('Sales Invoice', 'Purchase Invoice'):
+				if gle.against_voucher in self.return_entries:
+					return_against = self.return_entries.get(gle.against_voucher)
+					if return_against:
+						against_voucher = return_against
+
+			voucher_balance = self.voucher_balance.get((gle.against_voucher_type, against_voucher, gle.party))
 
 		if not voucher_balance:
 			# no invoice, this is an invoice / stand-alone payment / credit note
@@ -258,7 +271,6 @@
 		# customer / supplier name
 		party_details = self.get_party_details(row.party)
 		row.update(party_details)
-
 		if self.filters.get(scrub(self.filters.party_type)):
 			row.currency = row.account_currency
 		else:
@@ -423,6 +435,19 @@
 		if row.future_ref:
 			row.future_ref = ', '.join(row.future_ref)
 
+	def get_return_entries(self):
+		doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
+		filters={
+			'is_return': 1,
+			'docstatus': 1
+		}
+		party_field = scrub(self.filters.party_type)
+		if self.filters.get(party_field):
+			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)
+		)
+
 	def set_ageing(self, row):
 		if self.filters.ageing_based_on == "Due Date":
 			entry_date = row.due_date
@@ -689,11 +714,11 @@
 	def get_chart_data(self):
 		rows = []
 		for row in self.data:
-			rows.append(
-				{
-					'values': [row.range1, row.range2, row.range3, row.range4, row.range5]
-				}
-			)
+			values = [row.range1, row.range2, row.range3, row.range4, row.range5]
+			precision = cint(frappe.db.get_default("float_precision")) or 2
+			rows.append({
+				'values': [flt(val, precision) for val in values]
+			})
 
 		self.chart = {
 			"data": {