feat: Add report summary in financial statements (#20876)

* feat: Add report summary API for Balance Sheet  and PL report

* fix: Add summary cards in Cash flow report

* feat: Add report summary in consolidated financial statements

* fix: Remove accumulated values filter from P&L and cashflow report

* fix: set company default currency in profit and loss statement if no data

Co-authored-by: Prssanna Desai <prssud@gmail.com>
This commit is contained in:
Deepesh Garg
2020-04-06 14:07:20 +05:30
committed by GitHub
parent c01ec7606d
commit 433e58d131
8 changed files with 131 additions and 44 deletions

View File

@@ -58,7 +58,10 @@ def execute(filters=None):
chart = get_chart_data(filters, columns, asset, liability, equity) chart = get_chart_data(filters, columns, asset, liability, equity)
return columns, data, message, chart report_summary = get_report_summary(period_list, asset, liability, equity, provisional_profit_loss,
total_credit, currency, filters)
return columns, data, message, chart, report_summary
def get_provisional_profit_loss(asset, liability, equity, period_list, company, currency=None, consolidated=False): def get_provisional_profit_loss(asset, liability, equity, period_list, company, currency=None, consolidated=False):
provisional_profit_loss = {} provisional_profit_loss = {}
@@ -120,6 +123,56 @@ def check_opening_balance(asset, liability, equity):
return _("Previous Financial Year is not closed"),opening_balance return _("Previous Financial Year is not closed"),opening_balance
return None,None return None,None
def get_report_summary(period_list, asset, liability, equity, provisional_profit_loss, total_credit, currency,
filters, consolidated=False):
net_asset, net_liability, net_equity, net_provisional_profit_loss = 0.0, 0.0, 0.0, 0.0
if filters.get('accumulated_values'):
period_list = [period_list[-1]]
for period in period_list:
key = period if consolidated else period.key
if asset:
net_asset += asset[-2].get(key)
if liability:
net_liability += liability[-2].get(key)
if equity:
net_equity += equity[-2].get(key)
if provisional_profit_loss:
net_provisional_profit_loss += provisional_profit_loss.get(key)
return [
{
"value": net_asset,
"label": "Total Asset",
"indicator": "Green",
"datatype": "Currency",
"currency": currency
},
{
"value": net_liability,
"label": "Total Liability",
"datatype": "Currency",
"indicator": "Red",
"currency": currency
},
{
"value": net_equity,
"label": "Total Equity",
"datatype": "Currency",
"indicator": "Blue",
"currency": currency
},
{
"value": net_provisional_profit_loss,
"label": "Provisional Profit / Loss (Credit)",
"indicator": "Green" if net_provisional_profit_loss > 0 else "Red",
"datatype": "Currency",
"currency": currency
}
]
def get_chart_data(filters, columns, asset, liability, equity): def get_chart_data(filters, columns, asset, liability, equity):
labels = [d.get("label") for d in columns[2:]] labels = [d.get("label") for d in columns[2:]]

View File

@@ -12,11 +12,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Cash Flow"]["filters"].splice(5, 1); frappe.query_reports["Cash Flow"]["filters"].splice(5, 1);
frappe.query_reports["Cash Flow"]["filters"].push( frappe.query_reports["Cash Flow"]["filters"].push(
{
"fieldname": "accumulated_values",
"label": __("Accumulated Values"),
"fieldtype": "Check"
},
{ {
"fieldname": "include_default_book_entries", "fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"), "label": __("Include Default Book Entries"),

View File

@@ -8,6 +8,7 @@ from frappe.utils import cint, cstr
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data) from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import get_net_profit_loss
from erpnext.accounts.utils import get_fiscal_year from erpnext.accounts.utils import get_fiscal_year
from six import iteritems
def execute(filters=None): def execute(filters=None):
@@ -29,6 +30,7 @@ def execute(filters=None):
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company) net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
data = [] data = []
summary_data = {}
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency") company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
for cash_flow_account in cash_flow_accounts: for cash_flow_account in cash_flow_accounts:
@@ -64,14 +66,16 @@ def execute(filters=None):
section_data.append(account_data) section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'], add_total_row_account(data, section_data, cash_flow_account['section_footer'],
period_list, company_currency) period_list, company_currency, summary_data)
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency) add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency, summary_data)
columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company) columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, filters.company)
chart = get_chart_data(columns, data) chart = get_chart_data(columns, data)
return columns, data, None, chart report_summary = get_report_summary(summary_data, company_currency)
return columns, data, None, chart, report_summary
def get_cash_flow_accounts(): def get_cash_flow_accounts():
operation_accounts = { operation_accounts = {
@@ -157,7 +161,7 @@ def get_start_date(period, accumulated_values, company):
return start_date return start_date
def add_total_row_account(out, data, label, period_list, currency, consolidated = False): def add_total_row_account(out, data, label, period_list, currency, summary_data, consolidated = False):
total_row = { total_row = {
"account_name": "'" + _("{0}").format(label) + "'", "account_name": "'" + _("{0}").format(label) + "'",
"account": "'" + _("{0}").format(label) + "'", "account": "'" + _("{0}").format(label) + "'",
@@ -176,6 +180,24 @@ def add_total_row_account(out, data, label, period_list, currency, consolidated
out.append(total_row) out.append(total_row)
out.append({}) out.append({})
summary_data[label] = total_row["total"]
def get_report_summary(summary_data, currency):
report_summary = []
for label, value in iteritems(summary_data):
report_summary.append(
{
"value": value,
"label": label,
"datatype": "Currency",
"currency": currency
}
)
return report_summary
def get_chart_data(columns, data): def get_chart_data(columns, data):
labels = [d.get("label") for d in columns[2:]] labels = [d.get("label") for d in columns[2:]]
datasets = [{'name':account.get('account').replace("'", ""), 'values': [account.get('total')]} for account in data if account.get('parent_account') == None and account.get('currency')] datasets = [{'name':account.get('account').replace("'", ""), 'values': [account.get('total')]} for account in data if account.get('parent_account') == None and account.get('currency')]

View File

@@ -61,5 +61,17 @@ frappe.query_reports["Consolidated Financial Statement"] = {
"fieldtype": "Check", "fieldtype": "Check",
"default": 1 "default": 1
} }
] ],
"formatter": function(value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data);
if (!data.parent_account) {
value = $(`<span>${value}</span>`);
var $value = $(value).css("font-weight", "bold");
value = $value.wrap("<p></p>").parent().html();
}
return value;
}
} }

View File

@@ -8,11 +8,11 @@ from frappe.utils import flt, cint
from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency from erpnext.accounts.report.utils import get_currency, convert_to_presentation_currency
from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts from erpnext.accounts.report.financial_statements import get_fiscal_year_data, sort_accounts
from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss, from erpnext.accounts.report.balance_sheet.balance_sheet import (get_provisional_profit_loss,
check_opening_balance, get_chart_data) check_opening_balance, get_chart_data, get_report_summary as get_bs_summary)
from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (get_net_profit_loss, from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement import (get_net_profit_loss,
get_chart_data as get_pl_chart_data) get_chart_data as get_pl_chart_data, get_report_summary as get_pl_summary)
from erpnext.accounts.report.cash_flow.cash_flow import (get_cash_flow_accounts, get_account_type_based_gl_data, from erpnext.accounts.report.cash_flow.cash_flow import (get_cash_flow_accounts, get_account_type_based_gl_data,
add_total_row_account) add_total_row_account, get_report_summary as get_cash_flow_summary)
def execute(filters=None): def execute(filters=None):
columns, data, message, chart = [], [], [], [] columns, data, message, chart = [], [], [], []
@@ -25,17 +25,17 @@ def execute(filters=None):
columns = get_columns(companies_column) columns = get_columns(companies_column)
if filters.get('report') == "Balance Sheet": if filters.get('report') == "Balance Sheet":
data, message, chart = get_balance_sheet_data(fiscal_year, companies, columns, filters) data, message, chart, report_summary = get_balance_sheet_data(fiscal_year, companies, columns, filters)
elif filters.get('report') == "Profit and Loss Statement": elif filters.get('report') == "Profit and Loss Statement":
data, message, chart = get_profit_loss_data(fiscal_year, companies, columns, filters) data, message, chart, report_summary = get_profit_loss_data(fiscal_year, companies, columns, filters)
else: else:
if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')): if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')):
from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom
return execute_custom(filters=filters) return execute_custom(filters=filters)
data = get_cash_flow_data(fiscal_year, companies, filters) data, report_summary = get_cash_flow_data(fiscal_year, companies, filters)
return columns, data, message, chart return columns, data, message, chart, report_summary
def get_balance_sheet_data(fiscal_year, companies, columns, filters): def get_balance_sheet_data(fiscal_year, companies, columns, filters):
asset = get_data(companies, "Asset", "Debit", fiscal_year, filters=filters) asset = get_data(companies, "Asset", "Debit", fiscal_year, filters=filters)
@@ -75,9 +75,12 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
if total_credit: if total_credit:
data.append(total_credit) data.append(total_credit)
report_summary = get_bs_summary(companies, asset, liability, equity, provisional_profit_loss, total_credit,
company_currency, filters, True)
chart = get_chart_data(filters, columns, asset, liability, equity) chart = get_chart_data(filters, columns, asset, liability, equity)
return data, message, chart return data, message, chart, report_summary
def get_profit_loss_data(fiscal_year, companies, columns, filters): def get_profit_loss_data(fiscal_year, companies, columns, filters):
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
@@ -90,7 +93,9 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss) chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
return data, None, chart report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True)
return data, None, chart, report_summary
def get_income_expense_data(companies, fiscal_year, filters): def get_income_expense_data(companies, fiscal_year, filters):
company_currency = get_company_currency(filters) company_currency = get_company_currency(filters)
@@ -108,6 +113,7 @@ def get_cash_flow_data(fiscal_year, companies, filters):
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters) income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
data = [] data = []
summary_data = {}
company_currency = get_company_currency(filters) company_currency = get_company_currency(filters)
for cash_flow_account in cash_flow_accounts: for cash_flow_account in cash_flow_accounts:
@@ -142,11 +148,13 @@ def get_cash_flow_data(fiscal_year, companies, filters):
section_data.append(account_data) section_data.append(account_data)
add_total_row_account(data, section_data, cash_flow_account['section_footer'], add_total_row_account(data, section_data, cash_flow_account['section_footer'],
companies, company_currency, True) companies, company_currency, summary_data, True)
add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, True) add_total_row_account(data, data, _("Net Change in Cash"), companies, company_currency, summary_data, True)
return data report_summary = get_cash_flow_summary(summary_data, company_currency)
return data, report_summary
def get_account_type_based_data(account_type, companies, fiscal_year, filters): def get_account_type_based_data(account_type, companies, fiscal_year, filters):
data = {} data = {}

View File

@@ -151,7 +151,7 @@ def get_data(
calculate_values( calculate_values(
accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy) accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy)
accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values) 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)
out = filter_out_zero_value_rows(out, parent_children_map) out = filter_out_zero_value_rows(out, parent_children_map)
@@ -191,7 +191,7 @@ def calculate_values(
d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit)
def accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values): def accumulate_values_into_parents(accounts, accounts_by_name, period_list):
"""accumulate children's values in parent accounts""" """accumulate children's values in parent accounts"""
for d in reversed(accounts): for d in reversed(accounts):
if d.parent_account: if d.parent_account:

View File

@@ -15,11 +15,6 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
return frappe.db.get_link_options('Project', txt); return frappe.db.get_link_options('Project', txt);
} }
}, },
{
"fieldname": "accumulated_values",
"label": __("Accumulated Values"),
"fieldtype": "Check"
},
{ {
"fieldname": "include_default_book_entries", "fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"), "label": __("Include Default Book Entries"),

View File

@@ -31,20 +31,22 @@ def execute(filters=None):
chart = get_chart_data(filters, columns, income, expense, net_profit_loss) chart = get_chart_data(filters, columns, income, expense, net_profit_loss)
report_summary = get_report_summary(columns, income, expense, net_profit_loss, filters.periodicity, period_list) default_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
report_summary = get_report_summary(period_list, filters.periodicity, income, expense, net_profit_loss, default_currency)
return columns, data, None, chart, report_summary return columns, data, None, chart, report_summary
def get_report_summary(columns, income, expense, net_profit_loss, period_list, periodicity): def get_report_summary(period_list, periodicity, income, expense, net_profit_loss, default_currency, consolidated=False):
income_data, expense_data, net_profit = [], [], [] net_income, net_expense, net_profit = 0.0, 0.0, 0.0
for p in columns[2:]: for period in period_list:
key = period if consolidated else period.key
if income: if income:
income_data.append(income[-2].get(p.get("fieldname"))) net_income += income[-2].get(key)
if expense: if expense:
expense_data.append(expense[-2].get(p.get("fieldname"))) net_expense += expense[-2].get(key)
if net_profit_loss: if net_profit_loss:
net_profit.append(net_profit_loss.get(p.get("fieldname"))) net_profit += net_profit_loss.get(key)
if (len(period_list) == 1 and periodicity== 'Yearly'): if (len(period_list) == 1 and periodicity== 'Yearly'):
profit_label = _("Profit This Year") profit_label = _("Profit This Year")
@@ -57,23 +59,23 @@ def get_report_summary(columns, income, expense, net_profit_loss, period_list, p
return [ return [
{ {
"value": net_profit[-1], "value": net_profit,
"indicator": "Green" if net_profit[-1] > 0 else "Red", "indicator": "Green" if net_profit > 0 else "Red",
"label": profit_label, "label": profit_label,
"datatype": "Currency", "datatype": "Currency",
"currency": net_profit_loss.get("currency") "currency": net_profit_loss.get("currency") if net_profit_loss else default_currency
}, },
{ {
"value": income_data[-1], "value": net_income,
"label": income_label, "label": income_label,
"datatype": "Currency", "datatype": "Currency",
"currency": income[-1].get('currency') "currency": income[-1].get('currency') if income else default_currency
}, },
{ {
"value": expense_data[-1], "value": net_expense,
"label": expense_label, "label": expense_label,
"datatype": "Currency", "datatype": "Currency",
"currency": expense[-1].get('currency') "currency": expense[-1].get('currency') if expense else default_currency
} }
] ]