feat: Financial Ratio Report  (#36130)

* feat: Financial Ratio report added

* fix: Made columns dynamic

* fix: Changed fieldtype of year column

* fix: Added Financial Ratios for all Fiscal Years

* fix: Added Validation of only Parent Having account_type of Direct Income, Indirect Income, Current Asset and Current Liability

* fix: Added 4 more ratios

* fix: added a function for repeated code

* fix: added account_type in accounts utils and cleaned report code

* fix: created function for avg_ratio_values

* fix: cleaning code

* fix: basic ratios completed

* fix: cleaned the code

* chore: code cleanup

* chore: remove comments

* chore: code cleanup

* chore: cleanup account query

* chore: Remove unused variables

---------

Co-authored-by: Ritvik Sardana <ritviksardana@Ritviks-MacBook-Air.local>
Co-authored-by: Deepesh Garg <deepeshgarg6@gmail.com>
diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js
index f033b54..3c0eb85 100644
--- a/erpnext/accounts/doctype/account/account.js
+++ b/erpnext/accounts/doctype/account/account.js
@@ -1,67 +1,83 @@
 // Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-frappe.ui.form.on('Account', {
-	setup: function(frm) {
-		frm.add_fetch('parent_account', 'report_type', 'report_type');
-		frm.add_fetch('parent_account', 'root_type', 'root_type');
+frappe.ui.form.on("Account", {
+	setup: function (frm) {
+		frm.add_fetch("parent_account", "report_type", "report_type");
+		frm.add_fetch("parent_account", "root_type", "root_type");
 	},
-	onload: function(frm) {
-		frm.set_query('parent_account', function(doc) {
+	onload: function (frm) {
+		frm.set_query("parent_account", function (doc) {
 			return {
 				filters: {
-					"is_group": 1,
-					"company": doc.company
-				}
+					is_group: 1,
+					company: doc.company,
+				},
 			};
 		});
 	},
-	refresh: function(frm) {
-		frm.toggle_display('account_name', frm.is_new());
+	refresh: function (frm) {
+		frm.toggle_display("account_name", frm.is_new());
 
 		// hide fields if group
-		frm.toggle_display(['account_type', 'tax_rate'], cint(frm.doc.is_group) == 0);
+		frm.toggle_display(["tax_rate"], cint(frm.doc.is_group) == 0);
 
 		// disable fields
-		frm.toggle_enable(['is_group', 'company'], false);
+		frm.toggle_enable(["is_group", "company"], false);
 
 		if (cint(frm.doc.is_group) == 0) {
-			frm.toggle_display('freeze_account', frm.doc.__onload
-				&& frm.doc.__onload.can_freeze_account);
+			frm.toggle_display(
+				"freeze_account",
+				frm.doc.__onload && frm.doc.__onload.can_freeze_account
+			);
 		}
 
 		// read-only for root accounts
 		if (!frm.is_new()) {
 			if (!frm.doc.parent_account) {
 				frm.set_read_only();
-				frm.set_intro(__("This is a root account and cannot be edited."));
+				frm.set_intro(
+					__("This is a root account and cannot be edited.")
+				);
 			} else {
 				// credit days and type if customer or supplier
 				frm.set_intro(null);
-				frm.trigger('account_type');
+				frm.trigger("account_type");
 				// show / hide convert buttons
-				frm.trigger('add_toolbar_buttons');
+				frm.trigger("add_toolbar_buttons");
 			}
-			if (frm.has_perm('write')) {
-				frm.add_custom_button(__('Merge Account'), function () {
-					frm.trigger("merge_account");
-				}, __('Actions'));
-				frm.add_custom_button(__('Update Account Name / Number'), function () {
-					frm.trigger("update_account_number");
-				}, __('Actions'));
+			if (frm.has_perm("write")) {
+				frm.add_custom_button(
+					__("Merge Account"),
+					function () {
+						frm.trigger("merge_account");
+					},
+					__("Actions")
+				);
+				frm.add_custom_button(
+					__("Update Account Name / Number"),
+					function () {
+						frm.trigger("update_account_number");
+					},
+					__("Actions")
+				);
 			}
 		}
 	},
 	account_type: function (frm) {
 		if (frm.doc.is_group == 0) {
-			frm.toggle_display(['tax_rate'], frm.doc.account_type == 'Tax');
-			frm.toggle_display('warehouse', frm.doc.account_type == 'Stock');
+			frm.toggle_display(["tax_rate"], frm.doc.account_type == "Tax");
+			frm.toggle_display("warehouse", frm.doc.account_type == "Stock");
 		}
 	},
-	add_toolbar_buttons: function(frm) {
-		frm.add_custom_button(__('Chart of Accounts'), () => {
-			frappe.set_route("Tree", "Account");
-		}, __('View'));
+	add_toolbar_buttons: function (frm) {
+		frm.add_custom_button(
+			__("Chart of Accounts"),
+			() => {
+				frappe.set_route("Tree", "Account");
+			},
+			__("View")
+		);
 
 		if (frm.doc.is_group == 1) {
 			frm.add_custom_button(__('Convert to Non-Group'), function () {
@@ -86,31 +102,35 @@
 				frappe.set_route("query-report", "General Ledger");
 			}, __('View'));
 
-			frm.add_custom_button(__('Convert to Group'), function () {
-				return frappe.call({
-					doc: frm.doc,
-					method: 'convert_ledger_to_group',
-					callback: function() {
-						frm.refresh();
-					}
-				});
-			}, __('Actions'));
+			frm.add_custom_button(
+				__("Convert to Group"),
+				function () {
+					return frappe.call({
+						doc: frm.doc,
+						method: "convert_ledger_to_group",
+						callback: function () {
+							frm.refresh();
+						},
+					});
+				},
+				__("Actions")
+			);
 		}
 	},
 
-	merge_account: function(frm) {
+	merge_account: function (frm) {
 		var d = new frappe.ui.Dialog({
-			title: __('Merge with Existing Account'),
+			title: __("Merge with Existing Account"),
 			fields: [
 				{
-					"label" : "Name",
-					"fieldname": "name",
-					"fieldtype": "Data",
-					"reqd": 1,
-					"default": frm.doc.name
-				}
+					label: "Name",
+					fieldname: "name",
+					fieldtype: "Data",
+					reqd: 1,
+					default: frm.doc.name,
+				},
 			],
-			primary_action: function() {
+			primary_action: function () {
 				var data = d.get_values();
 				frappe.call({
 					method: "erpnext.accounts.doctype.account.account.merge_account",
@@ -119,44 +139,47 @@
 						new: data.name,
 						is_group: frm.doc.is_group,
 						root_type: frm.doc.root_type,
-						company: frm.doc.company
+						company: frm.doc.company,
 					},
-					callback: function(r) {
-						if(!r.exc) {
-							if(r.message) {
+					callback: function (r) {
+						if (!r.exc) {
+							if (r.message) {
 								frappe.set_route("Form", "Account", r.message);
 							}
 							d.hide();
 						}
-					}
+					},
 				});
 			},
-			primary_action_label: __('Merge')
+			primary_action_label: __("Merge"),
 		});
 		d.show();
 	},
 
-	update_account_number: function(frm) {
+	update_account_number: function (frm) {
 		var d = new frappe.ui.Dialog({
-			title: __('Update Account Number / Name'),
+			title: __("Update Account Number / Name"),
 			fields: [
 				{
-					"label": "Account Name",
-					"fieldname": "account_name",
-					"fieldtype": "Data",
-					"reqd": 1,
-					"default": frm.doc.account_name
+					label: "Account Name",
+					fieldname: "account_name",
+					fieldtype: "Data",
+					reqd: 1,
+					default: frm.doc.account_name,
 				},
 				{
-					"label": "Account Number",
-					"fieldname": "account_number",
-					"fieldtype": "Data",
-					"default": frm.doc.account_number
-				}
+					label: "Account Number",
+					fieldname: "account_number",
+					fieldtype: "Data",
+					default: frm.doc.account_number,
+				},
 			],
-			primary_action: function() {
+			primary_action: function () {
 				var data = d.get_values();
-				if(data.account_number === frm.doc.account_number && data.account_name === frm.doc.account_name) {
+				if (
+					data.account_number === frm.doc.account_number &&
+					data.account_name === frm.doc.account_name
+				) {
 					d.hide();
 					return;
 				}
@@ -166,23 +189,29 @@
 					args: {
 						account_number: data.account_number,
 						account_name: data.account_name,
-						name: frm.doc.name
+						name: frm.doc.name,
 					},
-					callback: function(r) {
-						if(!r.exc) {
-							if(r.message) {
+					callback: function (r) {
+						if (!r.exc) {
+							if (r.message) {
 								frappe.set_route("Form", "Account", r.message);
 							} else {
-								frm.set_value("account_number", data.account_number);
-								frm.set_value("account_name", data.account_name);
+								frm.set_value(
+									"account_number",
+									data.account_number
+								);
+								frm.set_value(
+									"account_name",
+									data.account_name
+								);
 							}
 							d.hide();
 						}
-					}
+					},
 				});
 			},
-			primary_action_label: __('Update')
+			primary_action_label: __("Update"),
 		});
 		d.show();
-	}
+	},
 });
diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json
index e79fb66..78f73ef 100644
--- a/erpnext/accounts/doctype/account/account.json
+++ b/erpnext/accounts/doctype/account/account.json
@@ -123,7 +123,7 @@
    "label": "Account Type",
    "oldfieldname": "account_type",
    "oldfieldtype": "Select",
-   "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nDepreciation\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary"
+   "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nCurrent Asset\nCurrent Liability\nDepreciation\nDirect Expense\nDirect Income\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nIndirect Expense\nIndirect Income\nLiability\nPayable\nReceivable\nRound Off\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary"
   },
   {
    "description": "Rate at which this tax is applied",
@@ -192,7 +192,7 @@
  "idx": 1,
  "is_tree": 1,
  "links": [],
- "modified": "2023-04-11 16:08:46.983677",
+ "modified": "2023-07-20 18:18:44.405723",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Account",
@@ -243,7 +243,6 @@
    "read": 1,
    "report": 1,
    "role": "Accounts Manager",
-   "set_user_permissions": 1,
    "share": 1,
    "write": 1
   }
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index e94b7cf..c1eca72 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -45,6 +45,7 @@
 		if frappe.local.flags.allow_unverified_charts:
 			return
 		self.validate_parent()
+		self.validate_parent_child_account_type()
 		self.validate_root_details()
 		validate_field_number("Account", self.name, self.account_number, self.company, "account_number")
 		self.validate_group_or_ledger()
@@ -55,6 +56,20 @@
 		self.validate_account_currency()
 		self.validate_root_company_and_sync_account_to_children()
 
+	def validate_parent_child_account_type(self):
+		if self.parent_account:
+			if self.account_type in [
+				"Direct Income",
+				"Indirect Income",
+				"Current Asset",
+				"Current Liability",
+				"Direct Expense",
+				"Indirect Expense",
+			]:
+				parent_account_type = frappe.db.get_value("Account", self.parent_account, ["account_type"])
+				if parent_account_type == self.account_type:
+					throw(_("Only Parent can be of type {0}").format(self.account_type))
+
 	def validate_parent(self):
 		"""Fetch Parent Details and validate parent account"""
 		if self.parent_account:
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.js b/erpnext/accounts/report/balance_sheet/balance_sheet.js
index 4a4ad4d..c65b9e8 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.js
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.js
@@ -1,22 +1,26 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-frappe.require("assets/erpnext/js/financial_statements.js", function() {
-	frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);
+frappe.require("assets/erpnext/js/financial_statements.js", function () {
+	frappe.query_reports["Balance Sheet"] = $.extend(
+		{},
+		erpnext.financial_statements
+	);
 
-	erpnext.utils.add_dimensions('Balance Sheet', 10);
+	erpnext.utils.add_dimensions("Balance Sheet", 10);
 
 	frappe.query_reports["Balance Sheet"]["filters"].push({
-		"fieldname": "accumulated_values",
-		"label": __("Accumulated Values"),
-		"fieldtype": "Check",
-		"default": 1
+		fieldname: "accumulated_values",
+		label: __("Accumulated Values"),
+		fieldtype: "Check",
+		default: 1,
 	});
+	console.log(frappe.query_reports["Balance Sheet"]["filters"]);
 
 	frappe.query_reports["Balance Sheet"]["filters"].push({
-		"fieldname": "include_default_book_entries",
-		"label": __("Include Default Book Entries"),
-		"fieldtype": "Check",
-		"default": 1
+		fieldname: "include_default_book_entries",
+		label: __("Include Default Book Entries"),
+		fieldtype: "Check",
+		default: 1,
 	});
 });
diff --git a/erpnext/accounts/report/financial_ratios/__init__.py b/erpnext/accounts/report/financial_ratios/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/report/financial_ratios/__init__.py
diff --git a/erpnext/accounts/report/financial_ratios/financial_ratios.js b/erpnext/accounts/report/financial_ratios/financial_ratios.js
new file mode 100644
index 0000000..643423d
--- /dev/null
+++ b/erpnext/accounts/report/financial_ratios/financial_ratios.js
@@ -0,0 +1,72 @@
+// Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Financial Ratios"] = {
+	filters: [
+		{
+			fieldname: "company",
+			label: __("Company"),
+			fieldtype: "Link",
+			options: "Company",
+			default: frappe.defaults.get_user_default("Company"),
+			reqd: 1,
+		},
+		{
+			fieldname: "from_fiscal_year",
+			label: __("Start Year"),
+			fieldtype: "Link",
+			options: "Fiscal Year",
+			default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
+			reqd: 1,
+		},
+		{
+			fieldname: "to_fiscal_year",
+			label: __("End Year"),
+			fieldtype: "Link",
+			options: "Fiscal Year",
+			default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today()),
+			reqd: 1,
+		},
+		{
+			fieldname: "periodicity",
+			label: __("Periodicity"),
+			fieldtype: "Data",
+			default: "Yearly",
+			reqd: 1,
+			hidden: 1,
+		},
+		{
+			fieldname: "period_start_date",
+			label: __("From Date"),
+			fieldtype: "Date",
+			default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1],
+			hidden: 1,
+		},
+		{
+			fieldname: "period_end_date",
+			label: __("To Date"),
+			fieldtype: "Date",
+			default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
+			hidden: 1,
+		},
+	],
+	"formatter": function(value, row, column, data, default_formatter) {
+
+		let heading_ratios = ["Liquidity Ratios", "Solvency Ratios","Turnover Ratios"]
+
+		if (heading_ratios.includes(value)) {
+			value = $(`<span>${value}</span>`);
+			let $value = $(value).css("font-weight", "bold");
+			value = $value.wrap("<p></p>").parent().html();
+		}
+
+		if (heading_ratios.includes(row[1].content) && column.fieldtype == "Float") {
+			column.fieldtype = "Data";
+		}
+
+		value = default_formatter(value, row, column, data);
+
+		return value;
+	},
+};
diff --git a/erpnext/accounts/report/financial_ratios/financial_ratios.json b/erpnext/accounts/report/financial_ratios/financial_ratios.json
new file mode 100644
index 0000000..1a2e56b
--- /dev/null
+++ b/erpnext/accounts/report/financial_ratios/financial_ratios.json
@@ -0,0 +1,37 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2023-07-13 16:11:11.925096",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2023-07-13 16:11:11.925096",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Financial Ratios",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Account",
+ "report_name": "Financial Ratios",
+ "report_type": "Script Report",
+ "roles": [
+  {
+   "role": "Accounts User"
+  },
+  {
+   "role": "Auditor"
+  },
+  {
+   "role": "Sales User"
+  },
+  {
+   "role": "Purchase User"
+  },
+  {
+   "role": "Accounts Manager"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/financial_ratios/financial_ratios.py b/erpnext/accounts/report/financial_ratios/financial_ratios.py
new file mode 100644
index 0000000..57421eb
--- /dev/null
+++ b/erpnext/accounts/report/financial_ratios/financial_ratios.py
@@ -0,0 +1,296 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.utils import add_days, flt
+
+from erpnext.accounts.report.financial_statements import get_data, get_period_list
+from erpnext.accounts.utils import get_balance_on, get_fiscal_year
+
+
+def execute(filters=None):
+	filters["filter_based_on"] = "Fiscal Year"
+	columns, data = [], []
+
+	setup_filters(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,
+	)
+
+	columns, years = get_columns(period_list)
+	data = get_ratios_data(filters, period_list, years)
+
+	return columns, data
+
+
+def setup_filters(filters):
+	if not filters.get("period_start_date"):
+		period_start_date = get_fiscal_year(fiscal_year=filters.from_fiscal_year)[1]
+		filters["period_start_date"] = period_start_date
+
+	if not filters.get("period_end_date"):
+		period_end_date = get_fiscal_year(fiscal_year=filters.to_fiscal_year)[2]
+		filters["period_end_date"] = period_end_date
+
+
+def get_columns(period_list):
+	years = []
+	columns = [
+		{
+			"label": _("Ratios"),
+			"fieldname": "ratio",
+			"fieldtype": "Data",
+			"width": 200,
+		},
+	]
+
+	for period in period_list:
+		columns.append(
+			{
+				"fieldname": period.key,
+				"label": period.label,
+				"fieldtype": "Float",
+				"width": 150,
+			}
+		)
+		years.append(period.key)
+
+	return columns, years
+
+
+def get_ratios_data(filters, period_list, years):
+
+	data = []
+	assets, liabilities, income, expense = get_gl_data(filters, period_list, years)
+
+	current_asset, total_asset = {}, {}
+	current_liability, total_liability = {}, {}
+	net_sales, total_income = {}, {}
+	cogs, total_expense = {}, {}
+	quick_asset = {}
+	direct_expense = {}
+
+	for year in years:
+		total_quick_asset = 0
+		total_net_sales = 0
+		total_cogs = 0
+
+		for d in [
+			[
+				current_asset,
+				total_asset,
+				"Current Asset",
+				year,
+				assets,
+				"Asset",
+				quick_asset,
+				total_quick_asset,
+			],
+			[
+				current_liability,
+				total_liability,
+				"Current Liability",
+				year,
+				liabilities,
+				"Liability",
+				{},
+				0,
+			],
+			[cogs, total_expense, "Cost of Goods Sold", year, expense, "Expense", {}, total_cogs],
+			[direct_expense, direct_expense, "Direct Expense", year, expense, "Expense", {}, 0],
+			[net_sales, total_income, "Direct Income", year, income, "Income", {}, total_net_sales],
+		]:
+			update_balances(d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7])
+	add_liquidity_ratios(data, years, current_asset, current_liability, quick_asset)
+	add_solvency_ratios(
+		data, years, total_asset, total_liability, net_sales, cogs, total_income, total_expense
+	)
+	add_turnover_ratios(
+		data, years, period_list, filters, total_asset, net_sales, cogs, direct_expense
+	)
+
+	return data
+
+
+def get_gl_data(filters, period_list, years):
+	data = {}
+
+	for d in [
+		["Asset", "Debit"],
+		["Liability", "Credit"],
+		["Income", "Credit"],
+		["Expense", "Debit"],
+	]:
+		data[frappe.scrub(d[0])] = get_data(
+			filters.company,
+			d[0],
+			d[1],
+			period_list,
+			only_current_fiscal_year=False,
+			filters=filters,
+		)
+
+	assets, liabilities, income, expense = (
+		data.get("asset"),
+		data.get("liability"),
+		data.get("income"),
+		data.get("expense"),
+	)
+
+	return assets, liabilities, income, expense
+
+
+def add_liquidity_ratios(data, years, current_asset, current_liability, quick_asset):
+	precision = frappe.db.get_single_value("System Settings", "float_precision")
+	data.append({"ratio": "Liquidity Ratios"})
+
+	ratio_data = [["Current Ratio", current_asset], ["Quick Ratio", quick_asset]]
+
+	for d in ratio_data:
+		row = {
+			"ratio": d[0],
+		}
+		for year in years:
+			row[year] = calculate_ratio(d[1].get(year, 0), current_liability.get(year, 0), precision)
+
+		data.append(row)
+
+
+def add_solvency_ratios(
+	data, years, total_asset, total_liability, net_sales, cogs, total_income, total_expense
+):
+	precision = frappe.db.get_single_value("System Settings", "float_precision")
+	data.append({"ratio": "Solvency Ratios"})
+
+	debt_equity_ratio = {"ratio": "Debt Equity Ratio"}
+	gross_profit_ratio = {"ratio": "Gross Profit Ratio"}
+	net_profit_ratio = {"ratio": "Net Profit Ratio"}
+	return_on_asset_ratio = {"ratio": "Return on Asset Ratio"}
+	return_on_equity_ratio = {"ratio": "Return on Equity Ratio"}
+
+	for year in years:
+		profit_after_tax = total_income[year] + total_expense[year]
+		share_holder_fund = total_asset[year] - total_liability[year]
+
+		debt_equity_ratio[year] = calculate_ratio(
+			total_liability.get(year), share_holder_fund, precision
+		)
+		return_on_equity_ratio[year] = calculate_ratio(profit_after_tax, share_holder_fund, precision)
+
+		net_profit_ratio[year] = calculate_ratio(profit_after_tax, net_sales.get(year), precision)
+		gross_profit_ratio[year] = calculate_ratio(
+			net_sales.get(year, 0) - cogs.get(year, 0), net_sales.get(year), precision
+		)
+		return_on_asset_ratio[year] = calculate_ratio(profit_after_tax, total_asset.get(year), precision)
+
+	data.append(debt_equity_ratio)
+	data.append(gross_profit_ratio)
+	data.append(net_profit_ratio)
+	data.append(return_on_asset_ratio)
+	data.append(return_on_equity_ratio)
+
+
+def add_turnover_ratios(
+	data, years, period_list, filters, total_asset, net_sales, cogs, direct_expense
+):
+	precision = frappe.db.get_single_value("System Settings", "float_precision")
+	data.append({"ratio": "Turnover Ratios"})
+
+	avg_data = {}
+	for d in ["Receivable", "Payable", "Stock"]:
+		avg_data[frappe.scrub(d)] = avg_ratio_balance("Receivable", period_list, precision, filters)
+
+	avg_debtors, avg_creditors, avg_stock = (
+		avg_data.get("receivable"),
+		avg_data.get("payable"),
+		avg_data.get("stock"),
+	)
+
+	ratio_data = [
+		["Fixed Asset Turnover Ratio", net_sales, total_asset],
+		["Debtor Turnover Ratio", net_sales, avg_debtors],
+		["Creditor Turnover Ratio", direct_expense, avg_creditors],
+		["Inventory Turnover Ratio", cogs, avg_stock],
+	]
+	for ratio in ratio_data:
+		row = {
+			"ratio": ratio[0],
+		}
+		for year in years:
+			row[year] = calculate_ratio(ratio[1].get(year, 0), ratio[2].get(year, 0), precision)
+
+		data.append(row)
+
+
+def update_balances(
+	ratio_dict,
+	total_dict,
+	account_type,
+	year,
+	root_type_data,
+	root_type,
+	net_dict=None,
+	total_net=0,
+):
+
+	for entry in root_type_data:
+		if not entry.get("parent_account") and entry.get("is_group"):
+			total_dict[year] = entry[year]
+			if account_type == "Direct Expense":
+				total_dict[year] = entry[year] * -1
+
+		if root_type in ("Asset", "Liability"):
+			if entry.get("account_type") == account_type and entry.get("is_group"):
+				ratio_dict[year] = entry.get(year)
+			if entry.get("account_type") in ["Bank", "Cash", "Receivable"] and not entry.get("is_group"):
+				total_net += entry.get(year)
+				net_dict[year] = total_net
+
+		elif root_type == "Income":
+			if entry.get("account_type") == account_type and entry.get("is_group"):
+				total_net += entry.get(year)
+				ratio_dict[year] = total_net
+		elif root_type == "Expense" and account_type == "Cost of Goods Sold":
+			if entry.get("account_type") == account_type:
+				total_net += entry.get(year)
+				ratio_dict[year] = total_net
+		else:
+			if entry.get("account_type") == account_type and entry.get("is_group"):
+				ratio_dict[year] = entry.get(year)
+
+
+def avg_ratio_balance(account_type, period_list, precision, filters):
+	avg_ratio = {}
+	for period in period_list:
+		opening_date = add_days(period["from_date"], -1)
+		closing_date = period["to_date"]
+
+		closing_balance = get_balance_on(
+			date=closing_date,
+			company=filters.company,
+			account_type=account_type,
+		)
+		opening_balance = get_balance_on(
+			date=opening_date,
+			company=filters.company,
+			account_type=account_type,
+		)
+		avg_ratio[period["key"]] = flt(
+			(flt(closing_balance) + flt(opening_balance)) / 2, precision=precision
+		)
+
+	return avg_ratio
+
+
+def calculate_ratio(value, denominator, precision):
+	if flt(denominator):
+		return flt(flt(value) / denominator, precision)
+	return 0
diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js
index e794f27..9fe93b9 100644
--- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js
+++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.js
@@ -1,19 +1,18 @@
 // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 // License: GNU General Public License v3. See license.txt
 
-
-frappe.require("assets/erpnext/js/financial_statements.js", function() {
-	frappe.query_reports["Profit and Loss Statement"] = $.extend({},
-		erpnext.financial_statements);
-
-	erpnext.utils.add_dimensions('Profit and Loss Statement', 10);
-
-	frappe.query_reports["Profit and Loss Statement"]["filters"].push(
-		{
-			"fieldname": "include_default_book_entries",
-			"label": __("Include Default Book Entries"),
-			"fieldtype": "Check",
-			"default": 1
-		}
+frappe.require("assets/erpnext/js/financial_statements.js", function () {
+	frappe.query_reports["Profit and Loss Statement"] = $.extend(
+		{},
+		erpnext.financial_statements
 	);
+
+	erpnext.utils.add_dimensions("Profit and Loss Statement", 10);
+
+	frappe.query_reports["Profit and Loss Statement"]["filters"].push({
+		fieldname: "accumulated_values",
+		label: __("Accumulated Values"),
+		fieldtype: "Check",
+		default: 1,
+	});
 });
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 961f41c..c24442e 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -179,6 +179,7 @@
 	in_account_currency=True,
 	cost_center=None,
 	ignore_account_permission=False,
+	account_type=None,
 ):
 	if not account and frappe.form_dict.get("account"):
 		account = frappe.form_dict.get("account")
@@ -254,6 +255,21 @@
 		else:
 			cond.append("""gle.account = %s """ % (frappe.db.escape(account, percent=False),))
 
+	if account_type:
+		accounts = frappe.db.get_all(
+			"Account",
+			filters={"company": company, "account_type": account_type, "is_group": 0},
+			pluck="name",
+			order_by="lft",
+		)
+
+		cond.append(
+			"""
+			gle.account in (%s)
+		"""
+			% (", ".join([frappe.db.escape(account) for account in accounts]))
+		)
+
 	if party_type and party:
 		cond.append(
 			"""gle.party_type = %s and gle.party = %s """
@@ -263,7 +279,8 @@
 	if company:
 		cond.append("""gle.company = %s """ % (frappe.db.escape(company, percent=False)))
 
-	if account or (party_type and party):
+	if account or (party_type and party) or account_type:
+
 		if in_account_currency:
 			select_field = "sum(debit_in_account_currency) - sum(credit_in_account_currency)"
 		else:
@@ -276,7 +293,6 @@
 				select_field, " and ".join(cond)
 			)
 		)[0][0]
-
 		# if bal is None, return 0
 		return flt(bal)