Merge pull request #38969 from ruthra-kumar/bug_in_p_l_report

fix: incorrect net profit in Profit and Loss Statement
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 7355c4b..004a929 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -211,7 +211,13 @@
 		ignore_accumulated_values_for_fy,
 	)
 	accumulate_values_into_parents(accounts, accounts_by_name, period_list)
-	out = prepare_data(accounts, balance_must_be, period_list, company_currency)
+	out = prepare_data(
+		accounts,
+		balance_must_be,
+		period_list,
+		company_currency,
+		accumulated_values=filters.accumulated_values,
+	)
 	out = filter_out_zero_value_rows(out, parent_children_map)
 
 	if out and total:
@@ -270,7 +276,7 @@
 			) + d.get("opening_balance", 0.0)
 
 
-def prepare_data(accounts, balance_must_be, period_list, company_currency):
+def prepare_data(accounts, balance_must_be, period_list, company_currency, accumulated_values):
 	data = []
 	year_start_date = period_list[0]["year_start_date"].strftime("%Y-%m-%d")
 	year_end_date = period_list[-1]["year_end_date"].strftime("%Y-%m-%d")
@@ -310,8 +316,14 @@
 				has_value = True
 				total += flt(row[period.key])
 
-		row["has_value"] = has_value
-		row["total"] = total
+		if accumulated_values:
+			# when 'accumulated_values' is enabled, periods have running balance.
+			# so, last period will have the net amount.
+			row["has_value"] = has_value
+			row["total"] = flt(d.get(period_list[-1].key, 0.0), 3)
+		else:
+			row["has_value"] = has_value
+			row["total"] = total
 		data.append(row)
 
 	return data
diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
index 002c05c..12a8554 100644
--- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
+++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py
@@ -82,14 +82,25 @@
 	if filters.get("accumulated_in_group_company"):
 		period_list = get_filtered_list_for_consolidated_report(filters, period_list)
 
-	for period in period_list:
-		key = period if consolidated else period.key
+	if filters.accumulated_values:
+		# when 'accumulated_values' is enabled, periods have running balance.
+		# so, last period will have the net amount.
+		key = period_list[-1].key
 		if income:
-			net_income += income[-2].get(key)
+			net_income = income[-2].get(key)
 		if expense:
-			net_expense += expense[-2].get(key)
+			net_expense = expense[-2].get(key)
 		if net_profit_loss:
-			net_profit += net_profit_loss.get(key)
+			net_profit = net_profit_loss.get(key)
+	else:
+		for period in period_list:
+			key = period if consolidated else period.key
+			if income:
+				net_income += income[-2].get(key)
+			if expense:
+				net_expense += expense[-2].get(key)
+			if net_profit_loss:
+				net_profit += net_profit_loss.get(key)
 
 	if len(period_list) == 1 and periodicity == "Yearly":
 		profit_label = _("Profit This Year")
diff --git a/erpnext/accounts/report/profit_and_loss_statement/test_profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/test_profit_and_loss_statement.py
new file mode 100644
index 0000000..b4423ab
--- /dev/null
+++ b/erpnext/accounts/report/profit_and_loss_statement/test_profit_and_loss_statement.py
@@ -0,0 +1,94 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+import frappe
+from frappe.tests.utils import FrappeTestCase
+from frappe.utils import add_days, getdate, today
+
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.report.financial_statements import get_period_list
+from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import execute
+from erpnext.accounts.test.accounts_mixin import AccountsTestMixin
+
+
+class TestProfitAndLossStatement(AccountsTestMixin, FrappeTestCase):
+	def setUp(self):
+		self.create_company()
+		self.create_customer()
+		self.create_item()
+
+	def tearDown(self):
+		frappe.db.rollback()
+
+	def create_sales_invoice(self, qty=1, rate=150, no_payment_schedule=False, do_not_submit=False):
+		frappe.set_user("Administrator")
+		si = create_sales_invoice(
+			item=self.item,
+			company=self.company,
+			customer=self.customer,
+			debit_to=self.debit_to,
+			posting_date=today(),
+			parent_cost_center=self.cost_center,
+			cost_center=self.cost_center,
+			rate=rate,
+			price_list_rate=rate,
+			qty=qty,
+			do_not_save=1,
+		)
+		si = si.save()
+		if not do_not_submit:
+			si = si.submit()
+		return si
+
+	def get_fiscal_year(self):
+		active_fy = frappe.db.get_all(
+			"Fiscal Year",
+			filters={"disabled": 0, "year_start_date": ("<=", today()), "year_end_date": (">=", today())},
+		)[0]
+		return frappe.get_doc("Fiscal Year", active_fy.name)
+
+	def get_report_filters(self):
+		fy = self.get_fiscal_year()
+		return frappe._dict(
+			company=self.company,
+			from_fiscal_year=fy.name,
+			to_fiscal_year=fy.name,
+			period_start_date=fy.year_start_date,
+			period_end_date=fy.year_end_date,
+			filter_based_on="Fiscal Year",
+			periodicity="Monthly",
+			accumulated_vallues=True,
+		)
+
+	def test_profit_and_loss_output_and_summary(self):
+		si = self.create_sales_invoice(qty=1, rate=150)
+
+		filters = self.get_report_filters()
+		period_list = get_period_list(
+			filters.from_fiscal_year,
+			filters.to_fiscal_year,
+			filters.period_start_date,
+			filters.period_end_date,
+			filters.filter_based_on,
+			filters.periodicity,
+			company=filters.company,
+		)
+
+		result = execute(filters)[1]
+		current_period = [x for x in period_list if x.from_date <= getdate() and x.to_date >= getdate()][
+			0
+		]
+		current_period_key = current_period.key
+		without_current_period = [x for x in period_list if x.key != current_period.key]
+		# all period except current period(whence invoice was posted), should be '0'
+		for acc in result:
+			if acc:
+				with self.subTest(acc=acc):
+					for period in without_current_period:
+						self.assertEqual(acc[period.key], 0)
+
+		for acc in result:
+			if acc:
+				with self.subTest(current_period_key=current_period_key):
+					self.assertEqual(acc[current_period_key], 150)
+					self.assertEqual(acc["total"], 150)