diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index ab2f45d4f8b..fc19c40f8f9 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -7,6 +7,7 @@ from frappe import _ from frappe.utils import cint, flt from erpnext.accounts.report.financial_statements import ( + compute_growth_view_data, get_columns, get_data, get_filtered_list_for_consolidated_report, @@ -101,6 +102,9 @@ def execute(filters=None): period_list, asset, liability, equity, provisional_profit_loss, currency, filters ) + if filters.get("selected_view") == "Growth": + compute_growth_view_data(data, period_list) + return columns, data, message, chart, report_summary, primitive_summary diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 44b74463336..73e49983fb2 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -2,6 +2,7 @@ # License: GNU General Public License v3. See license.txt +import copy import functools import math import re @@ -668,3 +669,67 @@ def get_filtered_list_for_consolidated_report(filters, period_list): filtered_summary_list.append(period) return filtered_summary_list + + +def compute_growth_view_data(data, columns): + data_copy = copy.deepcopy(data) + + for row_idx in range(len(data_copy)): + for column_idx in range(1, len(columns)): + previous_period_key = columns[column_idx - 1].get("key") + current_period_key = columns[column_idx].get("key") + current_period_value = data_copy[row_idx].get(current_period_key) + previous_period_value = data_copy[row_idx].get(previous_period_key) + annual_growth = 0 + + if current_period_value is None: + data[row_idx][current_period_key] = None + continue + + if previous_period_value == 0 and current_period_value > 0: + annual_growth = 1 + + elif previous_period_value > 0: + annual_growth = (current_period_value - previous_period_value) / previous_period_value + + growth_percent = round(annual_growth * 100, 2) + + data[row_idx][current_period_key] = growth_percent + + +def compute_margin_view_data(data, columns, accumulated_values): + if not columns: + return + + if not accumulated_values: + columns.append({"key": "total"}) + + data_copy = copy.deepcopy(data) + + base_row = None + for row in data_copy: + if row.get("account_name") == _("Income"): + base_row = row + break + + if not base_row: + return + + for row_idx in range(len(data_copy)): + # Taking the total income from each column (for all the financial years) as the base (100%) + row = data_copy[row_idx] + if not row: + continue + + for column in columns: + curr_period = column.get("key") + base_value = base_row[curr_period] + curr_value = row[curr_period] + + if curr_value is None or base_value <= 0: + data[row_idx][curr_period] = None + continue + + margin_percent = round((curr_value / base_value) * 100, 2) + + data[row_idx][curr_period] = margin_percent 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 35453f2ec44..2b6280c74b5 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 @@ -7,6 +7,8 @@ from frappe import _ from frappe.utils import flt from erpnext.accounts.report.financial_statements import ( + compute_growth_view_data, + compute_margin_view_data, get_columns, get_data, get_filtered_list_for_consolidated_report, @@ -68,6 +70,12 @@ def execute(filters=None): period_list, filters.periodicity, income, expense, net_profit_loss, currency, filters ) + if filters.get("selected_view") == "Growth": + compute_growth_view_data(data, period_list) + + if filters.get("selected_view") == "Margin": + compute_margin_view_data(data, period_list, filters.accumulated_values) + return columns, data, None, chart, report_summary, primitive_summary diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index 1d323ccd46e..73ac9111303 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -9,40 +9,29 @@ erpnext.financial_statements = { data && column.colIndex >= 3 ) { - //Assuming that the first three columns are s.no, account name and the very first year of the accounting values, to calculate the relative percentage values of the successive columns. - const lastAnnualValue = row[column.colIndex - 1].content; - const currentAnnualvalue = data[column.fieldname]; - if (currentAnnualvalue == undefined) return "NA"; //making this not applicable for undefined/null values - let annualGrowth = 0; - if (lastAnnualValue == 0 && currentAnnualvalue > 0) { - //If the previous year value is 0 and the current value is greater than 0 - annualGrowth = 1; - } else if (lastAnnualValue > 0) { - annualGrowth = (currentAnnualvalue - lastAnnualValue) / lastAnnualValue; - } + const growthPercent = data[column.fieldname]; - const growthPercent = Math.round(annualGrowth * 10000) / 100; //calculating the rounded off percentage + if (growthPercent == undefined) return "NA"; //making this not applicable for undefined/null values - value = $(`${(growthPercent >= 0 ? "+" : "") + growthPercent + "%"}`); - if (growthPercent < 0) { - value = $(value).addClass("text-danger"); + if (column.fieldname === "total") { + value = $(`${growthPercent}`); } else { - value = $(value).addClass("text-success"); + value = $(`${(growthPercent >= 0 ? "+" : "") + growthPercent + "%"}`); + + if (growthPercent < 0) { + value = $(value).addClass("text-danger"); + } else { + value = $(value).addClass("text-success"); + } } value = $(value).wrap("

").parent().html(); return value; } else if (frappe.query_report.get_filter_value("selected_view") == "Margin" && data) { - if (column.fieldname == "account" && data.account_name == __("Income")) { - //Taking the total income from each column (for all the financial years) as the base (100%) - this.baseData = row; - } if (column.colIndex >= 2) { - //Assuming that the first two columns are s.no and account name, to calculate the relative percentage values of the successive columns. - const currentAnnualvalue = data[column.fieldname]; - const baseValue = this.baseData[column.colIndex].content; - if (currentAnnualvalue == undefined || baseValue <= 0) return "NA"; - const marginPercent = Math.round((currentAnnualvalue / baseValue) * 10000) / 100; + const marginPercent = data[column.fieldname]; + + if (marginPercent == undefined) return "NA"; //making this not applicable for undefined/null values value = $(`${marginPercent + "%"}`); if (marginPercent < 0) value = $(value).addClass("text-danger");