feat: support custom financial statements (#49098)

Co-authored-by: Abdeali Chharchhoda <abdealiking786@gmail.com>
This commit is contained in:
Smit Vora
2025-11-15 09:59:01 +05:30
committed by GitHub
parent b98f4611e6
commit 68cdadf11a
50 changed files with 11340 additions and 189 deletions

View File

@@ -21,6 +21,7 @@
"account_currency",
"column_break1",
"parent_account",
"account_category",
"account_type",
"tax_rate",
"freeze_account",
@@ -189,13 +190,20 @@
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disable"
},
{
"description": "Used with Financial Report Template",
"fieldname": "account_category",
"fieldtype": "Link",
"label": "Account Category",
"options": "Account Category"
}
],
"icon": "fa fa-money",
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2025-01-22 10:40:35.766017",
"modified": "2025-08-02 06:26:44.657146",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
@@ -250,6 +258,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"search_fields": "account_number",
"show_name_in_global_search": 1,
"show_preview_popup": 1,
@@ -257,4 +266,4 @@
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
}

View File

@@ -31,6 +31,7 @@ class Account(NestedSet):
if TYPE_CHECKING:
from frappe.types import DF
account_category: DF.Link | None
account_currency: DF.Link | None
account_name: DF.Data
account_number: DF.Data | None

View File

@@ -23,15 +23,7 @@ def create_charts(
if root_account:
root_type = child.get("root_type")
if account_name not in [
"account_name",
"account_number",
"account_type",
"root_type",
"is_group",
"tax_rate",
"account_currency",
]:
if account_name not in get_chart_metadata_fields():
account_number = cstr(child.get("account_number")).strip()
account_name, account_name_in_db = add_suffix_if_duplicate(
account_name, account_number, accounts
@@ -55,6 +47,7 @@ def create_charts(
"report_type": report_type,
"account_number": account_number,
"account_type": child.get("account_type"),
"account_category": child.get("account_category"),
"account_currency": child.get("account_currency")
if custom_chart
else frappe.get_cached_value("Company", company, "default_currency"),
@@ -97,20 +90,7 @@ def add_suffix_if_duplicate(account_name, account_number, accounts):
def identify_is_group(child):
if child.get("is_group"):
is_group = child.get("is_group")
elif len(
set(child.keys())
- set(
[
"account_name",
"account_type",
"root_type",
"is_group",
"tax_rate",
"account_number",
"account_currency",
]
)
):
elif len(set(child.keys()) - set(get_chart_metadata_fields())):
is_group = 1
else:
is_group = 0
@@ -253,13 +233,7 @@ def validate_bank_account(coa, bank_account):
def _get_account_names(account_master):
for account_name, child in account_master.items():
if account_name not in [
"account_number",
"account_type",
"root_type",
"is_group",
"tax_rate",
]:
if account_name not in get_chart_metadata_fields():
accounts.append(account_name)
_get_account_names(child)
@@ -284,15 +258,7 @@ def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=Fals
"""recursively called to form a parent-child based list of dict from chart template"""
for account_name, child in children.items():
account = {}
if account_name in [
"account_name",
"account_number",
"account_type",
"root_type",
"is_group",
"tax_rate",
"account_currency",
]:
if account_name in get_chart_metadata_fields():
continue
if from_coa_importer:
@@ -310,3 +276,16 @@ def build_tree_from_json(chart_template, chart_data=None, from_coa_importer=Fals
_import_accounts(chart, None)
return accounts
def get_chart_metadata_fields():
return [
"account_name",
"account_number",
"account_type",
"account_category",
"root_type",
"is_group",
"tax_rate",
"account_currency",
]

View File

@@ -9,103 +9,192 @@ def get():
return {
_("Application of Funds (Assets)"): {
_("Current Assets"): {
_("Accounts Receivable"): {_("Debtors"): {"account_type": "Receivable"}},
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1},
_("Cash In Hand"): {_("Cash"): {"account_type": "Cash"}, "account_type": "Cash"},
_("Accounts Receivable"): {
_("Debtors"): {"account_type": "Receivable", "account_category": "Trade Receivables"}
},
_("Bank Accounts"): {
"account_type": "Bank",
"is_group": 1,
"account_category": "Cash and Cash Equivalents",
},
_("Cash In Hand"): {
_("Cash"): {"account_type": "Cash", "account_category": "Cash and Cash Equivalents"},
"account_type": "Cash",
"account_category": "Cash and Cash Equivalents",
},
_("Loans and Advances (Assets)"): {
_("Employee Advances"): {"account_type": "Payable"},
_("Employee Advances"): {
"account_type": "Payable",
"account_category": "Other Receivables",
},
},
_("Securities and Deposits"): {_("Earnest Money"): {}},
_("Securities and Deposits"): {
_("Earnest Money"): {"account_category": "Other Current Assets"}
},
_("Prepaid Expenses"): {"account_category": "Other Current Assets"},
_("Short-term Investments"): {"account_category": "Short-term Investments"},
_("Stock Assets"): {
_("Stock In Hand"): {"account_type": "Stock"},
_("Stock In Hand"): {"account_type": "Stock", "account_category": "Stock Assets"},
"account_type": "Stock",
"account_category": "Stock Assets",
},
_("Tax Assets"): {"is_group": 1},
_("Tax Assets"): {"is_group": 1, "account_category": "Other Current Assets"},
},
_("Fixed Assets"): {
_("Capital Equipment"): {"account_type": "Fixed Asset"},
_("Electronic Equipment"): {"account_type": "Fixed Asset"},
_("Furniture and Fixtures"): {"account_type": "Fixed Asset"},
_("Office Equipment"): {"account_type": "Fixed Asset"},
_("Plants and Machineries"): {"account_type": "Fixed Asset"},
_("Buildings"): {"account_type": "Fixed Asset"},
_("Software"): {"account_type": "Fixed Asset"},
_("Accumulated Depreciation"): {"account_type": "Accumulated Depreciation"},
_("Capital Equipment"): {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets",
},
_("Electronic Equipment"): {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets",
},
_("Furniture and Fixtures"): {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets",
},
_("Office Equipment"): {"account_type": "Fixed Asset", "account_category": "Tangible Assets"},
_("Plants and Machineries"): {
"account_type": "Fixed Asset",
"account_category": "Tangible Assets",
},
_("Buildings"): {"account_type": "Fixed Asset", "account_category": "Tangible Assets"},
_("Software"): {"account_type": "Fixed Asset", "account_category": "Intangible Assets"},
_("Accumulated Depreciation"): {
"account_type": "Accumulated Depreciation",
"account_category": "Tangible Assets",
},
_("CWIP Account"): {
"account_type": "Capital Work in Progress",
"account_category": "Tangible Assets",
},
},
_("Investments"): {"is_group": 1},
_("Temporary Accounts"): {_("Temporary Opening"): {"account_type": "Temporary"}},
_("Investments"): {"is_group": 1, "account_category": "Long-term Investments"},
_("Temporary Accounts"): {
_("Temporary Opening"): {
"account_type": "Temporary",
"account_category": "Other Non-current Assets",
}
},
"root_type": "Asset",
},
_("Expenses"): {
_("Direct Expenses"): {
_("Stock Expenses"): {
_("Cost of Goods Sold"): {"account_type": "Cost of Goods Sold"},
_("Expenses Included In Asset Valuation"): {
"account_type": "Expenses Included In Asset Valuation"
_("Cost of Goods Sold"): {
"account_type": "Cost of Goods Sold",
"account_category": "Cost of Goods Sold",
},
_("Expenses Included In Asset Valuation"): {
"account_type": "Expenses Included In Asset Valuation",
"account_category": "Other Direct Costs",
},
_("Expenses Included In Valuation"): {
"account_type": "Expenses Included In Valuation",
"account_category": "Other Direct Costs",
},
_("Stock Adjustment"): {
"account_type": "Stock Adjustment",
"account_category": "Other Direct Costs",
},
_("Expenses Included In Valuation"): {"account_type": "Expenses Included In Valuation"},
_("Stock Adjustment"): {"account_type": "Stock Adjustment"},
},
},
_("Indirect Expenses"): {
_("Administrative Expenses"): {},
_("Commission on Sales"): {},
_("Depreciation"): {"account_type": "Depreciation"},
_("Entertainment Expenses"): {},
_("Freight and Forwarding Charges"): {"account_type": "Chargeable"},
_("Legal Expenses"): {},
_("Marketing Expenses"): {"account_type": "Chargeable"},
_("Miscellaneous Expenses"): {"account_type": "Chargeable"},
_("Office Maintenance Expenses"): {},
_("Office Rent"): {},
_("Postal Expenses"): {},
_("Print and Stationery"): {},
_("Round Off"): {"account_type": "Round Off"},
_("Salary"): {},
_("Sales Expenses"): {},
_("Telephone Expenses"): {},
_("Travel Expenses"): {},
_("Utility Expenses"): {},
_("Write Off"): {},
_("Exchange Gain/Loss"): {},
_("Gain/Loss on Asset Disposal"): {},
_("Impairment"): {},
_("Administrative Expenses"): {"account_category": "Operating Expenses"},
_("Commission on Sales"): {"account_category": "Operating Expenses"},
_("Depreciation"): {"account_type": "Depreciation", "account_category": "Operating Expenses"},
_("Entertainment Expenses"): {"account_category": "Operating Expenses"},
_("Freight and Forwarding Charges"): {
"account_type": "Chargeable",
"account_category": "Operating Expenses",
},
_("Legal Expenses"): {"account_category": "Operating Expenses"},
_("Marketing Expenses"): {
"account_type": "Chargeable",
"account_category": "Operating Expenses",
},
_("Miscellaneous Expenses"): {
"account_type": "Chargeable",
"account_category": "Operating Expenses",
},
_("Office Maintenance Expenses"): {"account_category": "Operating Expenses"},
_("Office Rent"): {"account_category": "Operating Expenses"},
_("Postal Expenses"): {"account_category": "Operating Expenses"},
_("Print and Stationery"): {"account_category": "Operating Expenses"},
_("Round Off"): {"account_type": "Round Off", "account_category": "Operating Expenses"},
_("Salary"): {"account_category": "Operating Expenses"},
_("Sales Expenses"): {"account_category": "Operating Expenses"},
_("Telephone Expenses"): {"account_category": "Operating Expenses"},
_("Travel Expenses"): {"account_category": "Operating Expenses"},
_("Utility Expenses"): {"account_category": "Operating Expenses"},
_("Write Off"): {"account_category": "Operating Expenses"},
_("Exchange Gain/Loss"): {"account_category": "Operating Expenses"},
_("Interest Expense"): {"account_category": "Finance Costs"},
_("Bank Charges"): {"account_category": "Finance Costs"},
_("Gain/Loss on Asset Disposal"): {"account_category": "Other Operating Income"},
_("Impairment"): {"account_category": "Operating Expenses"},
_("Tax Expense"): {"account_category": "Tax Expense"},
},
"root_type": "Expense",
},
_("Income"): {
_("Direct Income"): {_("Sales"): {}, _("Service"): {}},
_("Indirect Income"): {"is_group": 1},
_("Direct Income"): {
_("Sales"): {"account_category": "Revenue from Operations"},
_("Service"): {"account_category": "Revenue from Operations"},
},
_("Indirect Income"): {
_("Interest Income"): {"account_category": "Investment Income"},
_("Interest on Fixed Deposits"): {"account_category": "Investment Income"},
"is_group": 1,
},
"root_type": "Income",
},
_("Source of Funds (Liabilities)"): {
_("Current Liabilities"): {
_("Accounts Payable"): {
_("Creditors"): {"account_type": "Payable"},
_("Payroll Payable"): {},
_("Creditors"): {"account_type": "Payable", "account_category": "Trade Payables"},
_("Payroll Payable"): {"account_category": "Other Payables"},
},
_("Accrued Expenses"): {"account_category": "Other Current Liabilities"},
_("Customer Advances"): {"account_category": "Other Current Liabilities"},
_("Stock Liabilities"): {
_("Stock Received But Not Billed"): {"account_type": "Stock Received But Not Billed"},
_("Asset Received But Not Billed"): {"account_type": "Asset Received But Not Billed"},
_("Stock Received But Not Billed"): {
"account_type": "Stock Received But Not Billed",
"account_category": "Trade Payables",
},
_("Asset Received But Not Billed"): {
"account_type": "Asset Received But Not Billed",
"account_category": "Trade Payables",
},
},
_("Duties and Taxes"): {"account_type": "Tax", "is_group": 1},
_("Duties and Taxes"): {
"account_type": "Tax",
"is_group": 1,
"account_category": "Current Tax Liabilities",
},
_("Short-term Provisions"): {"account_category": "Short-term Provisions"},
_("Loans (Liabilities)"): {
_("Secured Loans"): {},
_("Unsecured Loans"): {},
_("Bank Overdraft Account"): {},
_("Secured Loans"): {"account_category": "Long-term Borrowings"},
_("Unsecured Loans"): {"account_category": "Long-term Borrowings"},
_("Bank Overdraft Account"): {"account_category": "Short-term Borrowings"},
},
},
_("Non-Current Liabilities"): {
_("Long-term Provisions"): {"account_category": "Long-term Provisions"},
_("Employee Benefits Obligation"): {"account_category": "Other Non-current Liabilities"},
"is_group": 1,
},
"root_type": "Liability",
},
_("Equity"): {
_("Capital Stock"): {"account_type": "Equity"},
_("Dividends Paid"): {"account_type": "Equity"},
_("Opening Balance Equity"): {"account_type": "Equity"},
_("Retained Earnings"): {"account_type": "Equity"},
_("Revaluation Surplus"): {"account_type": "Equity"},
_("Capital Stock"): {"account_type": "Equity", "account_category": "Share Capital"},
_("Dividends Paid"): {"account_type": "Equity", "account_category": "Reserves and Surplus"},
_("Opening Balance Equity"): {
"account_type": "Equity",
"account_category": "Reserves and Surplus",
},
_("Retained Earnings"): {"account_type": "Equity", "account_category": "Reserves and Surplus"},
_("Revaluation Surplus"): {"account_type": "Equity", "account_category": "Reserves and Surplus"},
"root_type": "Equity",
},
}

View File

@@ -10,49 +10,128 @@ def get():
_("Application of Funds (Assets)"): {
_("Current Assets"): {
_("Accounts Receivable"): {
_("Debtors"): {"account_type": "Receivable", "account_number": "1310"},
_("Debtors"): {
"account_type": "Receivable",
"account_number": "1310",
"account_category": "Trade Receivables",
},
"account_number": "1300",
},
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1, "account_number": "1200"},
_("Bank Accounts"): {
"account_type": "Bank",
"is_group": 1,
"account_number": "1200",
"account_category": "Cash and Cash Equivalents",
},
_("Cash In Hand"): {
_("Cash"): {"account_type": "Cash", "account_number": "1110"},
_("Cash"): {
"account_type": "Cash",
"account_number": "1110",
"account_category": "Cash and Cash Equivalents",
},
"account_type": "Cash",
"account_number": "1100",
"account_category": "Cash and Cash Equivalents",
},
_("Loans and Advances (Assets)"): {
_("Employee Advances"): {"account_number": "1610", "account_type": "Payable"},
_("Employee Advances"): {
"account_number": "1610",
"account_type": "Payable",
"account_category": "Other Receivables",
},
"account_number": "1600",
},
_("Securities and Deposits"): {
_("Earnest Money"): {"account_number": "1651"},
_("Earnest Money"): {
"account_number": "1651",
"account_category": "Other Current Assets",
},
"account_number": "1650",
},
_("Prepaid Expenses"): {
"account_number": "1660",
"account_category": "Other Current Assets",
},
_("Short-term Investments"): {
"account_number": "1670",
"account_category": "Short-term Investments",
},
_("Stock Assets"): {
_("Stock In Hand"): {"account_type": "Stock", "account_number": "1410"},
_("Stock In Hand"): {
"account_type": "Stock",
"account_number": "1410",
"account_category": "Stock Assets",
},
"account_type": "Stock",
"account_number": "1400",
"account_category": "Stock Assets",
},
_("Tax Assets"): {
"is_group": 1,
"account_number": "1500",
"account_category": "Other Current Assets",
},
_("Tax Assets"): {"is_group": 1, "account_number": "1500"},
"account_number": "1100-1600",
},
_("Fixed Assets"): {
_("Capital Equipment"): {"account_type": "Fixed Asset", "account_number": "1710"},
_("Electronic Equipment"): {"account_type": "Fixed Asset", "account_number": "1720"},
_("Furniture and Fixtures"): {"account_type": "Fixed Asset", "account_number": "1730"},
_("Office Equipment"): {"account_type": "Fixed Asset", "account_number": "1740"},
_("Plants and Machineries"): {"account_type": "Fixed Asset", "account_number": "1750"},
_("Buildings"): {"account_type": "Fixed Asset", "account_number": "1760"},
_("Software"): {"account_type": "Fixed Asset", "account_number": "1770"},
_("Capital Equipment"): {
"account_type": "Fixed Asset",
"account_number": "1710",
"account_category": "Tangible Assets",
},
_("Electronic Equipment"): {
"account_type": "Fixed Asset",
"account_number": "1720",
"account_category": "Tangible Assets",
},
_("Furniture and Fixtures"): {
"account_type": "Fixed Asset",
"account_number": "1730",
"account_category": "Tangible Assets",
},
_("Office Equipment"): {
"account_type": "Fixed Asset",
"account_number": "1740",
"account_category": "Tangible Assets",
},
_("Plants and Machineries"): {
"account_type": "Fixed Asset",
"account_number": "1750",
"account_category": "Tangible Assets",
},
_("Buildings"): {
"account_type": "Fixed Asset",
"account_number": "1760",
"account_category": "Tangible Assets",
},
_("Software"): {
"account_type": "Fixed Asset",
"account_number": "1770",
"account_category": "Intangible Assets",
},
_("Accumulated Depreciation"): {
"account_type": "Accumulated Depreciation",
"account_number": "1780",
"account_category": "Tangible Assets",
},
_("CWIP Account"): {
"account_type": "Capital Work in Progress",
"account_number": "1790",
"account_category": "Tangible Assets",
},
_("CWIP Account"): {"account_type": "Capital Work in Progress", "account_number": "1790"},
"account_number": "1700",
},
_("Investments"): {"is_group": 1, "account_number": "1800"},
_("Investments"): {
"is_group": 1,
"account_number": "1800",
"account_category": "Long-term Investments",
},
_("Temporary Accounts"): {
_("Temporary Opening"): {"account_type": "Temporary", "account_number": "1910"},
_("Temporary Opening"): {
"account_type": "Temporary",
"account_number": "1910",
"account_category": "Other Non-current Assets",
},
"account_number": "1900",
},
"root_type": "Asset",
@@ -61,97 +140,220 @@ def get():
_("Expenses"): {
_("Direct Expenses"): {
_("Stock Expenses"): {
_("Cost of Goods Sold"): {"account_type": "Cost of Goods Sold", "account_number": "5111"},
_("Cost of Goods Sold"): {
"account_type": "Cost of Goods Sold",
"account_number": "5111",
"account_category": "Cost of Goods Sold",
},
_("Expenses Included In Asset Valuation"): {
"account_type": "Expenses Included In Asset Valuation",
"account_number": "5112",
"account_category": "Other Direct Costs",
},
_("Expenses Included In Valuation"): {
"account_type": "Expenses Included In Valuation",
"account_number": "5118",
"account_category": "Other Direct Costs",
},
_("Stock Adjustment"): {
"account_type": "Stock Adjustment",
"account_number": "5119",
"account_category": "Other Direct Costs",
},
_("Stock Adjustment"): {"account_type": "Stock Adjustment", "account_number": "5119"},
"account_number": "5110",
},
"account_number": "5100",
},
_("Indirect Expenses"): {
_("Administrative Expenses"): {"account_number": "5201"},
_("Commission on Sales"): {"account_number": "5202"},
_("Depreciation"): {"account_type": "Depreciation", "account_number": "5203"},
_("Entertainment Expenses"): {"account_number": "5204"},
_("Freight and Forwarding Charges"): {"account_type": "Chargeable", "account_number": "5205"},
_("Legal Expenses"): {"account_number": "5206"},
_("Marketing Expenses"): {"account_type": "Chargeable", "account_number": "5207"},
_("Office Maintenance Expenses"): {"account_number": "5208"},
_("Office Rent"): {"account_number": "5209"},
_("Postal Expenses"): {"account_number": "5210"},
_("Print and Stationery"): {"account_number": "5211"},
_("Round Off"): {"account_type": "Round Off", "account_number": "5212"},
_("Salary"): {"account_number": "5213"},
_("Sales Expenses"): {"account_number": "5214"},
_("Telephone Expenses"): {"account_number": "5215"},
_("Travel Expenses"): {"account_number": "5216"},
_("Utility Expenses"): {"account_number": "5217"},
_("Write Off"): {"account_number": "5218"},
_("Exchange Gain/Loss"): {"account_number": "5219"},
_("Gain/Loss on Asset Disposal"): {"account_number": "5220"},
_("Miscellaneous Expenses"): {"account_type": "Chargeable", "account_number": "5221"},
"account_number": "5200",
_("Administrative Expenses"): {
"account_number": "5201",
"account_category": "Operating Expenses",
},
_("Commission on Sales"): {
"account_number": "5202",
"account_category": "Operating Expenses",
},
_("Depreciation"): {
"account_type": "Depreciation",
"account_number": "5203",
"account_category": "Operating Expenses",
},
_("Entertainment Expenses"): {
"account_number": "5204",
"account_category": "Operating Expenses",
},
_("Freight and Forwarding Charges"): {
"account_type": "Chargeable",
"account_number": "5205",
"account_category": "Operating Expenses",
},
_("Legal Expenses"): {"account_number": "5206", "account_category": "Operating Expenses"},
_("Marketing Expenses"): {
"account_type": "Chargeable",
"account_number": "5207",
"account_category": "Operating Expenses",
},
_("Office Maintenance Expenses"): {
"account_number": "5208",
"account_category": "Operating Expenses",
},
_("Office Rent"): {"account_number": "5209", "account_category": "Operating Expenses"},
_("Postal Expenses"): {"account_number": "5210", "account_category": "Operating Expenses"},
_("Print and Stationery"): {
"account_number": "5211",
"account_category": "Operating Expenses",
},
_("Round Off"): {
"account_type": "Round Off",
"account_number": "5212",
"account_category": "Operating Expenses",
},
_("Salary"): {"account_number": "5213", "account_category": "Operating Expenses"},
_("Sales Expenses"): {"account_number": "5214", "account_category": "Operating Expenses"},
_("Telephone Expenses"): {"account_number": "5215", "account_category": "Operating Expenses"},
_("Travel Expenses"): {"account_number": "5216", "account_category": "Operating Expenses"},
_("Utility Expenses"): {"account_number": "5217", "account_category": "Operating Expenses"},
_("Write Off"): {"account_number": "5218", "account_category": "Operating Expenses"},
_("Exchange Gain/Loss"): {"account_number": "5219", "account_category": "Operating Expenses"},
_("Interest Expense"): {"account_number": "5220", "account_category": "Finance Costs"},
_("Bank Charges"): {"account_number": "5221", "account_category": "Finance Costs"},
_("Gain/Loss on Asset Disposal"): {
"account_number": "5222",
"account_category": "Other Operating Income",
},
_("Miscellaneous Expenses"): {
"account_type": "Chargeable",
"account_number": "5223",
"account_category": "Operating Expenses",
},
_("Impairment"): {"account_number": "5224", "account_category": "Operating Expenses"},
_("Tax Expense"): {"account_number": "5225", "account_category": "Tax Expense"},
},
"root_type": "Expense",
"account_number": "5000",
},
_("Income"): {
_("Direct Income"): {
_("Sales"): {"account_number": "4110"},
_("Service"): {"account_number": "4120"},
_("Sales"): {"account_number": "4110", "account_category": "Revenue from Operations"},
_("Service"): {"account_number": "4120", "account_category": "Revenue from Operations"},
"account_number": "4100",
},
_("Indirect Income"): {"is_group": 1, "account_number": "4200"},
_("Indirect Income"): {
_("Interest Income"): {"account_number": "4210", "account_category": "Investment Income"},
_("Interest on Fixed Deposits"): {
"account_number": "4220",
"account_category": "Investment Income",
},
"is_group": 1,
"account_number": "4200",
},
"root_type": "Income",
"account_number": "4000",
},
_("Source of Funds (Liabilities)"): {
_("Current Liabilities"): {
_("Accounts Payable"): {
_("Creditors"): {"account_type": "Payable", "account_number": "2110"},
_("Payroll Payable"): {"account_number": "2120"},
_("Creditors"): {
"account_type": "Payable",
"account_number": "2110",
"account_category": "Trade Payables",
},
_("Payroll Payable"): {"account_number": "2120", "account_category": "Other Payables"},
"account_number": "2100",
},
_("Accrued Expenses"): {
"account_number": "2150",
"account_category": "Other Current Liabilities",
},
_("Customer Advances"): {
"account_number": "2160",
"account_category": "Other Current Liabilities",
},
_("Stock Liabilities"): {
_("Stock Received But Not Billed"): {
"account_type": "Stock Received But Not Billed",
"account_number": "2210",
"account_category": "Trade Payables",
},
_("Asset Received But Not Billed"): {
"account_type": "Asset Received But Not Billed",
"account_number": "2211",
"account_category": "Trade Payables",
},
"account_number": "2200",
},
_("Duties and Taxes"): {
_("TDS Payable"): {"account_number": "2310"},
_("TDS Payable"): {
"account_number": "2310",
"account_category": "Current Tax Liabilities",
},
"account_type": "Tax",
"is_group": 1,
"account_number": "2300",
"account_category": "Current Tax Liabilities",
},
_("Short-term Provisions"): {
"account_number": "2350",
"account_category": "Short-term Provisions",
},
_("Loans (Liabilities)"): {
_("Secured Loans"): {"account_number": "2410"},
_("Unsecured Loans"): {"account_number": "2420"},
_("Bank Overdraft Account"): {"account_number": "2430"},
_("Secured Loans"): {
"account_number": "2410",
"account_category": "Long-term Borrowings",
},
_("Unsecured Loans"): {
"account_number": "2420",
"account_category": "Long-term Borrowings",
},
_("Bank Overdraft Account"): {
"account_number": "2430",
"account_category": "Short-term Borrowings",
},
"account_number": "2400",
},
"account_number": "2100-2400",
},
_("Non-Current Liabilities"): {
_("Long-term Provisions"): {
"account_number": "2510",
"account_category": "Long-term Provisions",
},
_("Employee Benefits Obligation"): {
"account_number": "2520",
"account_category": "Other Non-current Liabilities",
},
"is_group": 1,
"account_number": "2500",
},
"root_type": "Liability",
"account_number": "2000",
},
_("Equity"): {
_("Capital Stock"): {"account_type": "Equity", "account_number": "3100"},
_("Dividends Paid"): {"account_type": "Equity", "account_number": "3200"},
_("Opening Balance Equity"): {"account_type": "Equity", "account_number": "3300"},
_("Retained Earnings"): {"account_type": "Equity", "account_number": "3400"},
_("Capital Stock"): {
"account_type": "Equity",
"account_number": "3100",
"account_category": "Share Capital",
},
_("Dividends Paid"): {
"account_type": "Equity",
"account_number": "3200",
"account_category": "Reserves and Surplus",
},
_("Opening Balance Equity"): {
"account_type": "Equity",
"account_number": "3300",
"account_category": "Reserves and Surplus",
},
_("Retained Earnings"): {
"account_type": "Equity",
"account_number": "3400",
"account_category": "Reserves and Surplus",
},
_("Revaluation Surplus"): {
"account_type": "Equity",
"account_number": "3500",
"account_category": "Reserves and Surplus",
},
"root_type": "Equity",
"account_number": "3000",
},

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("Account Category", {
// refresh(frm) {
// },
// });

View File

@@ -0,0 +1,71 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:account_category_name",
"creation": "2025-08-02 06:22:31.835063",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"account_category_name",
"description"
],
"fields": [
{
"fieldname": "account_category_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Account Category Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "description",
"fieldtype": "Small Text",
"label": "Description"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-10-15 03:19:47.171349",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account Category",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"read": 1,
"role": "Auditor"
}
],
"row_format": "Dynamic",
"search_fields": "account_category_name, description",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,94 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import json
import os
import frappe
from frappe import _
from frappe.model.document import Document, bulk_insert
DOCTYPE = "Account Category"
class AccountCategory(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
account_category_name: DF.Data
description: DF.SmallText | None
# end: auto-generated types
def after_rename(self, old_name, new_name, merge):
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
FormulaFieldUpdater,
)
# get all template rows with this account category being used
row = frappe.qb.DocType("Financial Report Row")
rows = frappe._dict(
frappe.qb.from_(row)
.select(row.name, row.calculation_formula)
.where(row.calculation_formula.like(f"%{old_name}%"))
.run()
)
if not rows:
return
# Update formulas with new name
updater = FormulaFieldUpdater(
field_name="account_category",
value_mapping={old_name: new_name},
exclude_operators=["like", "not like"],
)
updated_formulas = updater.update_in_rows(rows)
if updated_formulas:
frappe.msgprint(
_("Updated {0} Financial Report Row(s) with new category name").format(len(updated_formulas))
)
def import_account_categories(template_path: str):
categories_file = os.path.join(template_path, "account_categories.json")
if not os.path.exists(categories_file):
return
with open(categories_file) as f:
categories = json.load(f, object_hook=frappe._dict)
create_account_categories(categories)
def create_account_categories(categories: list[dict]):
if not categories:
return
existing_categories = set(frappe.get_all(DOCTYPE, pluck="name"))
new_categories = []
for category_data in categories:
category_name = category_data.get("account_category_name")
if not category_name or category_name in existing_categories:
continue
doc = frappe.get_doc(
{
**category_data,
"doctype": DOCTYPE,
"name": category_name,
}
)
new_categories.append(doc)
existing_categories.add(category_name)
if new_categories:
bulk_insert(DOCTYPE, new_categories)

View File

@@ -0,0 +1,20 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class IntegrationTestAccountCategory(IntegrationTestCase):
"""
Integration tests for AccountCategory.
Use this class for testing interactions between multiple components.
"""
pass

View File

@@ -0,0 +1,187 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-09-06 09:39:46.503678",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"reference_code",
"display_name",
"indentation_level",
"data_source",
"balance_type",
"column_break_hxqu",
"fieldtype",
"color",
"bold_text",
"italic_text",
"hidden_calculation",
"hide_when_empty",
"reverse_sign",
"include_in_charts",
"section_break_ornw",
"column_break_asfe",
"advanced_filtering",
"filters_editor",
"calculation_formula",
"section_break_pvro",
"formula_description"
],
"fields": [
{
"columns": 1,
"description": "Code to reference this line in formulas (e.g., REV100, EXP200, ASSET100)",
"fieldname": "reference_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Line Reference"
},
{
"description": "Text displayed on the financial statement (e.g., 'Total Revenue', 'Cash and Cash Equivalents')",
"fieldname": "display_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Display Name"
},
{
"columns": 1,
"description": "Indentation level: 0 = Main heading, 1 = Sub-category, 2 = Individual accounts, etc.",
"fieldname": "indentation_level",
"fieldtype": "Int",
"in_list_view": 1,
"label": "Indent Level"
},
{
"description": "How this line gets its data",
"fieldname": "data_source",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Data Source",
"options": "\nAccount Data\nCalculated Amount\nCustom API\nBlank Line\nColumn Break\nSection Break"
},
{
"depends_on": "eval:doc.data_source == 'Account Data'",
"description": "Opening Balance = Start of period, Closing Balance = End of period, Period Movement = Net change during period",
"fieldname": "balance_type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Balance Type",
"mandatory_depends_on": "eval:doc.data_source == 'Account Data'",
"options": "\nOpening Balance\nClosing Balance\nPeriod Movement (Debits - Credits)"
},
{
"fieldname": "column_break_hxqu",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Bold text for emphasis (totals, major headings)",
"fieldname": "bold_text",
"fieldtype": "Check",
"label": "Bold Text"
},
{
"default": "0",
"description": "Italic text for subtotals or notes",
"fieldname": "italic_text",
"fieldtype": "Check",
"label": "Italic Text"
},
{
"default": "0",
"description": "Calculate but don't show on final report",
"fieldname": "hidden_calculation",
"fieldtype": "Check",
"label": "Hidden Line (Internal Use Only)"
},
{
"default": "0",
"description": "Hide this line if amount is zero",
"fieldname": "hide_when_empty",
"fieldtype": "Check",
"label": "Hide If Zero"
},
{
"columns": 1,
"default": "0",
"description": "Show negative values as positive (for expenses in P&L)",
"fieldname": "reverse_sign",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Reverse Sign"
},
{
"fieldname": "section_break_ornw",
"fieldtype": "Section Break"
},
{
"depends_on": "eval: (doc.data_source === \"Account Data\" && doc.advanced_filtering) || [\"Calculated Amount\", \"Custom API\"].includes(doc.data_source);\n",
"fieldname": "calculation_formula",
"fieldtype": "Code",
"label": "Formula or Account Filter",
"mandatory_depends_on": "eval:doc.data_source != 'Blank Line' && doc.data_source != 'Column Break' && doc.data_source != 'Section Break'"
},
{
"fieldname": "formula_description",
"fieldtype": "HTML"
},
{
"default": "0",
"description": "If enabled, this row's values will be displayed on financial charts",
"fieldname": "include_in_charts",
"fieldtype": "Check",
"label": "Include in Charts"
},
{
"description": "Color to highlight values (e.g., red for exceptions)",
"fieldname": "color",
"fieldtype": "Color",
"label": "Color"
},
{
"description": "How to format and present values in the financial report (only if different from column fieldtype)",
"fieldname": "fieldtype",
"fieldtype": "Select",
"label": "Value Type",
"options": "\nCurrency\nFloat\nInt\nPercent"
},
{
"depends_on": "eval: doc.data_source === \"Account Data\" && !doc.advanced_filtering",
"fieldname": "filters_editor",
"fieldtype": "HTML"
},
{
"depends_on": "eval: ![\"Blank Line\", \"Column Break\", \"Section Break\"].includes(doc.data_source);",
"fieldname": "column_break_asfe",
"fieldtype": "Column Break"
},
{
"default": "0",
"depends_on": "eval: doc.data_source === \"Account Data\"",
"description": "Use <strong>Python</strong> filters to get Accounts",
"fieldname": "advanced_filtering",
"fieldtype": "Check",
"label": "Advanced Filtering",
"print_hide": 1
},
{
"fieldname": "section_break_pvro",
"fieldtype": "Section Break"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-10-14 09:23:27.208072",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Financial Report Row",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,47 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class FinancialReportRow(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
advanced_filtering: DF.Check
balance_type: DF.Literal[
"", "Opening Balance", "Closing Balance", "Period Movement (Debits - Credits)"
]
bold_text: DF.Check
calculation_formula: DF.Code | None
color: DF.Color | None
data_source: DF.Literal[
"",
"Account Data",
"Calculated Amount",
"Custom API",
"Blank Line",
"Column Break",
"Section Break",
]
display_name: DF.Data | None
fieldtype: DF.Literal["", "Currency", "Float", "Int", "Percent"]
hidden_calculation: DF.Check
hide_when_empty: DF.Check
include_in_charts: DF.Check
indentation_level: DF.Int
italic_text: DF.Check
parent: DF.Data
parentfield: DF.Data
parenttype: DF.Data
reference_code: DF.Data | None
reverse_sign: DF.Check
# end: auto-generated types
pass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,433 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("Financial Report Template", {
refresh(frm) {
// add custom button to view missed accounts
frm.add_custom_button(__("View Account Coverage"), function () {
let selected_rows = frm.get_field("rows").grid.get_selected_children();
const has_selection = selected_rows.length > 0;
if (selected_rows.length === 0) selected_rows = frm.doc.rows;
show_accounts_tree(selected_rows, has_selection);
});
// add custom button to open the financial report
frm.add_custom_button(__("View Report"), function () {
frappe.set_route("query-report", frm.doc.report_type, {
report_template: frm.doc.name,
});
});
},
validate(frm) {
if (!frm.doc.rows || frm.doc.rows.length === 0) {
frappe.msgprint(__("At least one row is required for a financial report template"));
}
},
});
frappe.ui.form.on("Financial Report Row", {
data_source(frm, cdt, cdn) {
const row = locals[cdt][cdn];
update_formula_label(frm, row.data_source);
update_formula_description(frm, row.data_source);
if (row.data_source !== "Account Data") {
frappe.model.set_value(cdt, cdn, "balance_type", "");
}
if (["Blank Line", "Column Break", "Section Break"].includes(row.data_source)) {
frappe.model.set_value(cdt, cdn, "calculation_formula", "");
}
set_up_filters_editor(frm, cdt, cdn);
},
form_render(frm, cdt, cdn) {
const row = locals[cdt][cdn];
update_formula_label(frm, row.data_source);
update_advanced_formula_property(frm, cdt, cdn);
set_up_filters_editor(frm, cdt, cdn);
update_formula_description(frm, row.data_source);
},
calculation_formula(frm, cdt, cdn) {
update_advanced_formula_property(frm, cdt, cdn);
},
advanced_filtering(frm, cdt, cdn) {
set_up_filters_editor(frm, cdt, cdn);
},
});
// FILTERS EDITOR
function set_up_filters_editor(frm, cdt, cdn) {
const row = locals[cdt][cdn];
if (row.data_source !== "Account Data" || row.advanced_filtering) return;
const grid_row = frm.fields_dict["rows"].grid.get_row(cdn);
const wrapper = grid_row.get_field("filters_editor").$wrapper;
wrapper.empty();
const ACCOUNT = "Account";
const FIELD_IDX = 1;
const OPERATOR_IDX = 2;
const VALUE_IDX = 3;
// Parse saved filters
let saved_filters = [];
if (row.calculation_formula) {
try {
const parsed = JSON.parse(row.calculation_formula);
if (Array.isArray(parsed)) saved_filters = [parsed];
else if (parsed.and) saved_filters = parsed.and;
} catch (e) {
frappe.show_alert({
message: __("Invalid filter formula. Please check the syntax."),
indicator: "red",
});
}
}
if (saved_filters.length)
// Ensure every filter starts with "Account"
saved_filters = saved_filters.map((f) => [ACCOUNT, ...f]);
frappe.model.with_doctype(ACCOUNT, () => {
const filter_group = new frappe.ui.FilterGroup({
parent: wrapper,
doctype: ACCOUNT,
on_change: () => {
// only need [[field, operator, value]]
const filters = filter_group
.get_filters()
.map((f) => [f[FIELD_IDX], f[OPERATOR_IDX], f[VALUE_IDX]]);
const current = filters.length > 1 ? { and: filters } : filters[0];
frappe.model.set_value(cdt, cdn, "calculation_formula", JSON.stringify(current));
},
});
filter_group.add_filters_to_filter_group(saved_filters);
});
}
function update_advanced_formula_property(frm, cdt, cdn) {
const row = locals[cdt][cdn];
const is_advanced = is_advanced_formula(row);
frm.set_df_property("rows", "read_only", is_advanced, frm.doc.name, "advanced_filtering", cdn);
if (is_advanced && !row.advanced_filtering) {
row.advanced_filtering = 1;
frm.refresh_field("rows");
}
}
function is_advanced_formula(row) {
if (!row || row.data_source !== "Account Data") return false;
let parsed = null;
if (row.calculation_formula) {
try {
parsed = JSON.parse(row.calculation_formula);
} catch (e) {
console.warn("Invalid JSON in calculation_formula:", e);
return false;
}
}
if (Array.isArray(parsed)) return false;
if (parsed?.or) return true;
if (parsed?.and) return parsed.and.some((cond) => !Array.isArray(cond));
return false;
}
// ACCOUNTS TREE VIEW
function show_accounts_tree(template_rows, has_selection) {
// filtered rows
const account_rows = template_rows.filter((row) => row.data_source === "Account Data");
if (account_rows.length === 0) {
frappe.show_alert(__("No <strong>Account Data</strong> row found"));
return;
}
const dialog = new frappe.ui.Dialog({
title: __("Accounts Missing from Report"),
fields: [
{
fieldname: "company",
fieldtype: "Link",
options: "Company",
label: "Company",
reqd: 1,
default: frappe.defaults.get_user_default("Company"),
onchange: () => {
const company_field = dialog.get_field("company");
if (!company_field.value || company_field.value === company_field.last_value) return;
refresh_tree_view(dialog, account_rows);
},
},
{
fieldname: "view_type",
fieldtype: "Select",
options: ["Missing Accounts", "Filtered Accounts"],
label: "View",
default: has_selection ? "Filtered Accounts" : "Missing Accounts",
reqd: 1,
onchange: () => {
dialog.set_title(
dialog.get_value("view_type") === "Missing Accounts"
? __("Accounts Missing from Report")
: __("Accounts Included in Report")
);
refresh_tree_view(dialog, account_rows);
},
},
{
fieldname: "tip",
fieldtype: "HTML",
label: "Tip",
options: `
<div class="alert alert-success" role="alert">
Tip: Select report lines to view their accounts
</div>
`,
depends_on: has_selection ? "eval: false" : "eval: true",
},
{
fieldname: "tree_area",
fieldtype: "HTML",
label: "Chart of Accounts",
read_only: 1,
depends_on: "eval: doc.company",
},
],
primary_action_label: __("Done"),
primary_action() {
dialog.hide();
},
});
dialog.show();
refresh_tree_view(dialog, account_rows);
}
async function refresh_tree_view(dialog, account_rows) {
const missed = dialog.get_value("view_type") === "Missing Accounts";
const company = dialog.get_value("company");
const wrapper = dialog.get_field("tree_area").$wrapper;
wrapper.empty();
// get filtered accounts
const { message: filtered_accounts } = await frappe.call({
method: "erpnext.accounts.doctype.financial_report_template.financial_report_engine.get_filtered_accounts",
args: { company: company, account_rows: account_rows },
});
// render tree
const tree = new FilteredTree({
parent: wrapper,
label: company,
root_value: company,
method: "erpnext.accounts.doctype.financial_report_template.financial_report_engine.get_children_accounts",
args: { doctype: "Account", company: company, filtered_accounts: filtered_accounts, missed: missed },
toolbar: [],
});
tree.load_children(tree.root_node, true);
}
class FilteredTree extends frappe.ui.Tree {
render_children_of_all_nodes(data_list) {
data_list = this.get_filtered_data_list(data_list);
super.render_children_of_all_nodes(data_list);
}
get_filtered_data_list(data_list) {
let removed_nodes = new Set();
// Filter nodes with no data
data_list = data_list.filter((d) => {
if (d.data.length === 0) {
removed_nodes.add(d.parent);
return false;
}
return true;
});
// Remove references to removed nodes and iteratively remove empty parents
while (removed_nodes.size > 0) {
const current_removed = [...removed_nodes];
removed_nodes.clear();
data_list = data_list.filter((d) => {
d.data = d.data.filter((a) => !current_removed.includes(a.value));
if (d.data.length === 0) {
removed_nodes.add(d.parent);
return false;
}
return true;
});
}
return data_list;
}
}
function update_formula_label(frm, data_source) {
const grid = frm.fields_dict.rows.grid;
const field = grid.fields_map.calculation_formula;
if (!field) return;
const labels = {
"Account Data": "Account Filter",
"Custom API": "API Method Path",
};
grid.update_docfield_property(
"calculation_formula",
"label",
labels[data_source] || "Calculation Formula"
);
}
// FORMULA DESCRIPTION
function update_formula_description(frm, data_source) {
if (!data_source) return;
let grid = frm.fields_dict.rows.grid;
let field = grid.fields_map.formula_description;
if (!field) return;
// Common CSS styles and elements
const container_style = `style="padding: var(--padding-md); border: 1px solid var(--border-color); border-radius: var(--border-radius); margin-top: var(--margin-sm);"`;
const title_style = `style="margin-top: 0; color: var(--text-color);"`;
const subtitle_style = `style="color: var(--text-color); margin-bottom: var(--margin-xs);"`;
const text_style = `style="margin-bottom: var(--margin-sm); color: var(--text-muted);"`;
const list_style = `style="margin-bottom: var(--margin-sm); color: var(--text-muted); font-size: 0.9em;"`;
const note_style = `style="margin-bottom: 0; color: var(--text-muted); font-size: 0.9em;"`;
const tip_style = `style="margin-bottom: 0; color: var(--text-color); font-size: 0.85em;"`;
let description_html = "";
if (data_source === "Account Data") {
description_html = `
<div ${container_style}>
<h5 ${title_style}>Account Filter Guide</h5>
<p ${text_style}>Specify which accounts to include in this line.</p>
<h6 ${subtitle_style}>Basic Examples:</h6>
<ul ${list_style}>
<li><code>["account_type", "=", "Cash"]</code> - All Cash accounts</li>
<li><code>["root_type", "in", ["Asset", "Liability"]]</code> - All Asset and Liability accounts</li>
<li><code>["account_category", "like", "Revenue"]</code> - Revenue accounts</li>
</ul>
<h6 ${subtitle_style}>Multiple Conditions (AND/OR):</h6>
<ul ${list_style}>
<li><code>{"and": [["root_type", "=", "Asset"], ["account_type", "=", "Cash"]]}</code></li>
<li><code>{"or": [["account_category", "like", "Revenue"], ["account_category", "like", "Income"]]}</code></li>
</ul>
<p ${note_style}><strong>Available operators:</strong> <code>=, !=, in, not in, like, not like, is</code></p>
<p ${tip_style}><strong>Multi-Company Tip:</strong> Use fields like <code>account_type</code>, <code>root_type</code>, and <code>account_category</code> for templates that work across multiple companies.</p>
</div>`;
} else if (data_source === "Calculated Amount") {
description_html = `
<div ${container_style}>
<h5 ${title_style}>Formula Guide</h5>
<p ${text_style}>Create calculations using reference codes from other lines.</p>
<h6 ${subtitle_style}>Basic Examples:</h6>
<ul ${list_style}>
<li><code>REV100 + REV200</code> - Add two revenue lines</li>
<li><code>ASSETS - LIABILITIES</code> - Calculate equity</li>
<li><code>REVENUE * 0.1</code> - 10% of revenue</li>
</ul>
<h6 ${subtitle_style}>Common Functions:</h6>
<ul ${list_style}>
<li><code>abs(value)</code> - Remove negative sign</li>
<li><code>round(value)</code> - Round to whole number</li>
<li><code>max(val1, val2)</code> - Larger of two values</li>
<li><code>min(val1, val2)</code> - Smaller of two values</li>
</ul>
<p ${note_style}><strong>Required:</strong> Use "Reference Code" from other rows in your formulas.</p>
</div>`;
} else if (data_source === "Custom API") {
description_html = `
<div ${container_style}>
<h5 ${title_style}>Custom API Setup</h5>
<p ${text_style}>Path to your custom method that returns financial data.</p>
<h6 ${subtitle_style}>Format:</h6>
<ul ${list_style}>
<li><code>erpnext.custom.financial_apis.get_custom_revenue</code></li>
<li><code>my_app.financial_reports.get_kpi_data</code></li>
</ul>
<h6 ${subtitle_style}>Return Format:</h6>
<p ${text_style}>Numbers for each period: <code>[1000.0, 1200.0, 1150.0]</code></p>
</div>`;
} else if (data_source === "Blank Line") {
description_html = `
<div ${container_style}>
<h5 ${title_style}>Blank Line</h5>
<p ${text_style}>Adds empty space for better visual separation.</p>
<h6 ${subtitle_style}>Use For:</h6>
<ul ${list_style}>
<li>Separating major sections</li>
<li>Adding space before totals</li>
</ul>
<p ${note_style}><strong>Note:</strong> No formula needed - creates visual spacing only.</p>
</div>`;
} else if (data_source === "Column Break") {
description_html = `
<div ${container_style}>
<h5 ${title_style}>Column Break</h5>
<p ${text_style}>Creates a visual break for side-by-side layout.</p>
<h6 ${subtitle_style}>Use For:</h6>
<ul ${list_style}>
<li>Horizontal P&L statements</li>
<li>Side-by-side Balance Sheet sections</li>
</ul>
<p ${note_style}><strong>Note:</strong> No formula needed - this is for formatting only.</p>
</div>`;
} else if (data_source === "Section Break") {
description_html = `
<div ${container_style}>
<h5 ${title_style}>Section Break</h5>
<p ${text_style}>Creates a visual break for separating different sections.</p>
<h6 ${subtitle_style}>Use For:</h6>
<ul ${list_style}>
<li>Separating major sections in a report - say trading & profit and loss</li>
<li>Improving readability by adding space</li>
</ul>
<p ${note_style}><strong>Note:</strong> No formula needed - this is for formatting only.</p>
</div>`;
}
grid.update_docfield_property("formula_description", "options", description_html);
}

View File

@@ -0,0 +1,102 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:template_name",
"creation": "2025-08-02 04:44:15.184541",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"template_name",
"report_type",
"module",
"column_break_lvnq",
"disabled",
"section_break_fvlw",
"rows"
],
"fields": [
{
"description": "Descriptive name for your template (e.g., 'Standard P&L', 'Detailed Balance Sheet')",
"fieldname": "template_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Template Name",
"reqd": 1,
"unique": 1
},
{
"description": "Type of financial statement this template generates",
"fieldname": "report_type",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Report Type",
"options": "\nProfit and Loss Statement\nBalance Sheet\nCash Flow\nCustom Financial Statement"
},
{
"depends_on": "eval:frappe.boot.developer_mode",
"fieldname": "module",
"fieldtype": "Link",
"label": "Module (for Export)",
"options": "Module Def"
},
{
"fieldname": "column_break_lvnq",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_fvlw",
"fieldtype": "Section Break"
},
{
"allow_bulk_edit": 1,
"fieldname": "rows",
"fieldtype": "Table",
"label": "Report Line Items",
"options": "Financial Report Row"
},
{
"default": "0",
"description": "Disable template to prevent use in reports",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-11-14 00:11:03.508139",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Financial Report Template",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
{
"read": 1,
"role": "Accounts User"
},
{
"read": 1,
"role": "Auditor"
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "template_name"
}

View File

@@ -0,0 +1,179 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import os
import shutil
import frappe
from frappe import _
from frappe.model.document import Document
from erpnext.accounts.doctype.account_category.account_category import import_account_categories
from erpnext.accounts.doctype.financial_report_template.financial_report_validation import TemplateValidator
class FinancialReportTemplate(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
from erpnext.accounts.doctype.financial_report_row.financial_report_row import FinancialReportRow
disabled: DF.Check
module: DF.Link | None
report_type: DF.Literal[
"", "Profit and Loss Statement", "Balance Sheet", "Cash Flow", "Custom Financial Statement"
]
rows: DF.Table[FinancialReportRow]
template_name: DF.Data
# end: auto-generated types
def validate(self):
validator = TemplateValidator(self)
result = validator.validate()
result.notify_user()
def on_update(self):
self._export_template()
def on_trash(self):
self._delete_template()
def _export_template(self):
from frappe.modules.utils import export_module_json
if not self.module:
return
export_module_json(self, True, self.module)
self._export_account_categories()
def _delete_template(self):
if not self.module or not frappe.conf.developer_mode:
return
module_path = frappe.get_module_path(self.module)
dir_path = os.path.join(module_path, "financial_report_template", frappe.scrub(self.name))
shutil.rmtree(dir_path, ignore_errors=True)
def _export_account_categories(self):
import json
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
FormulaFieldExtractor,
)
if not self.module or not frappe.conf.developer_mode or frappe.flags.in_import:
return
# Extract category from rows
extractor = FormulaFieldExtractor(
field_name="account_category", exclude_operators=["like", "not like"]
)
account_data_rows = [row for row in self.rows if row.data_source == "Account Data"]
category_names = extractor.extract_from_rows(account_data_rows)
if not category_names:
return
# Get path
module_path = frappe.get_module_path(self.module)
categories_file = os.path.join(module_path, "financial_report_template", "account_categories.json")
# Load existing categories
existing_categories = {}
if os.path.exists(categories_file):
try:
with open(categories_file) as f:
existing_data = json.load(f)
existing_categories = {cat["account_category_name"]: cat for cat in existing_data}
except (json.JSONDecodeError, KeyError):
pass # Create new file
# Fetch categories from database
if category_names:
db_categories = frappe.get_all(
"Account Category",
filters={"account_category_name": ["in", list(category_names)]},
fields=["account_category_name", "description"],
)
for cat in db_categories:
existing_categories[cat["account_category_name"]] = cat
# Sort by category name
sorted_categories = sorted(existing_categories.values(), key=lambda x: x["account_category_name"])
# Write to file
os.makedirs(os.path.dirname(categories_file), exist_ok=True)
with open(categories_file, "w") as f:
json.dump(sorted_categories, f, indent=2)
def sync_financial_report_templates(chart_of_accounts=None, existing_company=None):
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import get_chart
# If COA is being created for an existing company,
# skip syncing templates as they are likely already present
if existing_company:
return
# Allow regional templates to completely override ERPNext
# templates based on the chart of accounts selected
disable_default_financial_report_template = False
if chart_of_accounts:
coa = get_chart(chart_of_accounts)
if coa.get("disable_default_financial_report_template", False):
disable_default_financial_report_template = True
installed_apps = frappe.get_installed_apps()
for app in installed_apps:
if disable_default_financial_report_template and app == "erpnext":
continue
_sync_templates_for(app)
def _sync_templates_for(app_name):
templates = []
for module_name in frappe.local.app_modules.get(app_name) or []:
module_path = frappe.get_module_path(module_name)
template_path = os.path.join(module_path, "financial_report_template")
if not os.path.isdir(template_path):
continue
import_account_categories(template_path)
for template_dir in os.listdir(template_path):
json_file = os.path.join(template_path, template_dir, f"{template_dir}.json")
if os.path.isfile(json_file):
templates.append(json_file)
if not templates:
return
# ensure files are not exported
frappe.flags.in_import = True
for template_path in templates:
with open(template_path) as f:
template_data = frappe._dict(frappe.parse_json(f.read()))
template_name = template_data.get("name")
if not frappe.db.exists("Financial Report Template", template_name):
doc = frappe.get_doc(template_data)
doc.flags.ignore_mandatory = True
doc.flags.ignore_permissions = True
doc.flags.ignore_validate = True
doc.insert()
frappe.flags.in_import = False

View File

@@ -0,0 +1,545 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import ast
import json
import re
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, ClassVar
import frappe
from frappe import _
from frappe.database.operator_map import OPERATOR_MAP
from frappe.database.query import SQLFunctionParser
@dataclass
class ValidationIssue:
"""Represents a single validation issue"""
message: str
row_idx: int | None = None
field: str | None = None
details: dict[str, Any] = None
def __post_init__(self):
if self.details is None:
self.details = {}
def __str__(self) -> str:
prefix = f"Row {self.row_idx}: " if self.row_idx else ""
field_info = f"[{self.field}] " if self.field else ""
message = f"{prefix}{field_info}{self.message}"
return _(message)
@dataclass
class ValidationResult:
issues: list[ValidationIssue] = field(default_factory=list)
warnings: list[ValidationIssue] = field(default_factory=list)
@property
def is_valid(self) -> bool:
return len(self.issues) == 0
@property
def has_warnings(self) -> bool:
return len(self.warnings) > 0
@property
def error_count(self) -> int:
return len(self.issues)
@property
def warning_count(self) -> int:
return len(self.warnings)
def merge(self, other: "ValidationResult") -> "ValidationResult":
self.issues.extend(other.issues)
self.warnings.extend(other.warnings)
return self
def add_error(self, issue: ValidationIssue) -> None:
"""Add a critical error that prevents functionality"""
self.issues.append(issue)
def add_warning(self, issue: ValidationIssue) -> None:
"""Add a warning for recommendatory validation"""
self.warnings.append(issue)
def notify_user(self) -> None:
warnings = "<br><br>".join(str(w) for w in self.warnings)
errors = "<br><br>".join(str(e) for e in self.issues)
if warnings:
frappe.msgprint(warnings, title=_("Warnings"), indicator="orange")
if errors:
frappe.throw(errors, title=_("Errors"))
class TemplateValidator:
"""Main validator that orchestrates all validations"""
def __init__(self, template):
self.template = template
self.validators = [
TemplateStructureValidator(),
DependencyValidator(template),
]
self.formula_validator = FormulaValidator(template)
def validate(self) -> ValidationResult:
result = ValidationResult([])
# Run template-level validators
for validator in self.validators:
result.merge(validator.validate(self.template))
# Run row-level validations
account_fields = {field.fieldname for field in frappe.get_meta("Account").fields}
for row in self.template.rows:
result.merge(self.formula_validator.validate(row, account_fields))
return result
class Validator(ABC):
@abstractmethod
def validate(self, context: Any) -> ValidationResult:
pass
class TemplateStructureValidator(Validator):
def validate(self, template) -> ValidationResult:
result = ValidationResult()
result.merge(self._validate_reference_codes(template))
result.merge(self._validate_required_fields(template))
return result
def _validate_reference_codes(self, template) -> ValidationResult:
result = ValidationResult()
used_codes = set()
for row in template.rows:
if not row.reference_code:
continue
ref_code = row.reference_code.strip()
# Check format
if not re.match(r"^[A-Za-z][A-Za-z0-9_-]*$", ref_code):
result.add_error(
ValidationIssue(
message=f"Invalid line reference format: '{ref_code}'. Must start with letter and contain only letters, numbers, underscores, and hyphens",
row_idx=row.idx,
)
)
# Check uniqueness
if ref_code in used_codes:
result.add_error(
ValidationIssue(
message=f"Duplicate line reference: '{ref_code}'",
row_idx=row.idx,
)
)
used_codes.add(ref_code)
return result
def _validate_required_fields(self, template) -> ValidationResult:
result = ValidationResult()
for row in template.rows:
# Balance type required
if row.data_source == "Account Data" and not row.balance_type:
result.add_error(
ValidationIssue(
message="Balance Type is required for Account Data",
row_idx=row.idx,
)
)
# Calculation formula required
if row.data_source in ["Account Data", "Calculated Amount", "Custom API"]:
if not row.calculation_formula:
result.add_error(
ValidationIssue(
message=f"Formula is required for {row.data_source}",
row_idx=row.idx,
)
)
return result
class DependencyValidator(Validator):
def __init__(self, template):
self.template = template
self.dependencies = self._build_dependency_graph()
def validate(self, context=None) -> ValidationResult:
result = ValidationResult()
result.merge(self._validate_circular_dependencies())
result.merge(self._validate_missing_dependencies())
return result
def _build_dependency_graph(self) -> dict[str, list[str]]:
graph = {}
available_codes = {row.reference_code for row in self.template.rows if row.reference_code}
for row in self.template.rows:
if row.reference_code and row.data_source == "Calculated Amount" and row.calculation_formula:
deps = extract_reference_codes_from_formula(row.calculation_formula, list(available_codes))
if deps:
graph[row.reference_code] = deps
return graph
def _validate_circular_dependencies(self) -> ValidationResult:
"""
Efficient cycle detection using DFS (Depth-First Search) with three-color algorithm:
- WHITE (0): unvisited node
- GRAY (1): currently being processed (on recursion stack)
- BLACK (2): fully processed
Example cycle detection:
A → B → C → A (cycle detected when A is GRAY and visited again)
"""
result = ValidationResult()
WHITE, GRAY, BLACK = 0, 1, 2
colors = {node: WHITE for node in self.dependencies}
def dfs(node, path):
if node not in colors:
return # External dependency
if colors[node] == GRAY:
# Found cycle
cycle_start = path.index(node)
cycle = [*path[cycle_start:], node]
result.add_error(
ValidationIssue(
message=f"Circular dependency detected: {''.join(cycle)}",
)
)
return
if colors[node] == BLACK:
return # Already processed
colors[node] = GRAY
path.append(node)
for neighbor in self.dependencies.get(node, []):
dfs(neighbor, path.copy())
colors[node] = BLACK
for node in self.dependencies:
if colors[node] == WHITE:
dfs(node, [])
return result
def _validate_missing_dependencies(self) -> ValidationResult:
available = {row.reference_code for row in self.template.rows if row.reference_code}
result = ValidationResult()
for ref_code, deps in self.dependencies.items():
undefined = [d for d in deps if d not in available]
if undefined:
row_idx = self._get_row_idx(ref_code)
result.add_error(
ValidationIssue(
message=f"Line References undefined in Formula: {', '.join(undefined)}",
row_idx=row_idx,
)
)
return result
def _get_row_idx(self, reference_code: str) -> int | None:
for row in self.template.rows:
if row.reference_code == reference_code:
return row.idx
return None
class CalculationFormulaValidator(Validator):
"""Validates calculation formulas used in Calculated Amount rows"""
def __init__(self, reference_codes: set[str]):
self.reference_codes = reference_codes
def validate(self, row) -> ValidationResult:
"""Validate calculation formula for a single row"""
result = ValidationResult()
if row.data_source != "Calculated Amount":
return result
if not row.calculation_formula:
result.add_error(
ValidationIssue(
message="Formula is required for Calculated Amount",
row_idx=row.idx,
field="Formula",
)
)
return result
formula = self._preprocess_formula(row.calculation_formula)
row.calculation_formula = formula
# Check parentheses
if not self._are_parentheses_balanced(formula):
result.add_error(
ValidationIssue(
message="Formula has unbalanced parentheses",
row_idx=row.idx,
)
)
return result
# Check self-reference
available_codes = list(self.reference_codes)
refs = extract_reference_codes_from_formula(formula, available_codes)
if row.reference_code and row.reference_code in refs:
result.add_error(
ValidationIssue(
message=f"Formula references itself ('{row.reference_code}')",
row_idx=row.idx,
)
)
# Check undefined references
undefined = set(refs) - set(available_codes)
if undefined:
result.add_error(
ValidationIssue(
message=f"Formula references undefined codes: {', '.join(undefined)}",
row_idx=row.idx,
)
)
# Try to evaluate with dummy values
eval_error = self._test_formula_evaluation(formula, available_codes)
if eval_error:
result.add_error(
ValidationIssue(
message=f"Formula evaluation error: {eval_error}",
row_idx=row.idx,
)
)
return result
def _preprocess_formula(self, formula: str) -> str:
if not formula or not isinstance(formula, str):
return ""
return formula.strip()
@staticmethod
def _are_parentheses_balanced(formula: str) -> bool:
return formula.count("(") == formula.count(")")
def _test_formula_evaluation(self, formula: str, available_codes: list[str]) -> str | None:
try:
context = {code: 1.0 for code in available_codes}
context.update(
{
"abs": abs,
"round": round,
"min": min,
"max": max,
"sum": sum,
"sqrt": lambda x: x**0.5,
"pow": pow,
"ceil": lambda x: int(x) + (1 if x % 1 else 0),
"floor": lambda x: int(x),
}
)
result = frappe.safe_eval(formula, eval_globals=None, eval_locals=context)
if not isinstance(result, (int, float)): # noqa: UP038
return f"Formula must return a numeric value, got {type(result).__name__}"
return None
except Exception as e:
return str(e)
class AccountFilterValidator(Validator):
"""Validates account filter expressions used in Account Data rows"""
def __init__(self, account_fields: set | None = None):
self.account_fields = account_fields or set(frappe.get_meta("Account")._valid_columns)
def validate(self, row) -> ValidationResult:
result = ValidationResult()
if row.data_source != "Account Data":
return result
if not row.calculation_formula:
result.add_error(
ValidationIssue(
message="Account filter is required for Account Data",
row_idx=row.idx,
field="Formula",
)
)
return result
try:
filter_config = json.loads(row.calculation_formula)
error = self._validate_filter_structure(filter_config, self.account_fields)
if error:
result.add_error(
ValidationIssue(
message=error,
row_idx=row.idx,
field="Account Filter",
)
)
except json.JSONDecodeError as e:
result.add_error(
ValidationIssue(
message=f"Invalid JSON format: {e!s}",
row_idx=row.idx,
field="Account Filter",
)
)
return result
def _validate_filter_structure(self, filter_config, account_fields: set) -> str | None:
# simple condition: [field, operator, value]
if isinstance(filter_config, list):
if len(filter_config) != 3:
return "Filter must be [field, operator, value]"
field, operator, value = filter_config
if not isinstance(field, str) or not isinstance(operator, str):
return "Field and operator must be strings"
if field not in account_fields:
return f"Field '{field}' is not a valid account field"
if operator.casefold() not in OPERATOR_MAP:
return f"Invalid operator '{operator}'"
if operator in ["in", "not in"] and not isinstance(value, list):
return f"Operator '{operator}' requires a list value"
# logical condition: {"and": [condition1, condition2]}
elif isinstance(filter_config, dict):
if len(filter_config) != 1:
return "Logical condition must have exactly one operator"
op = next(iter(filter_config.keys())).lower()
if op not in ["and", "or"]:
return "Logical operators must be 'and' or 'or'"
conditions = filter_config[next(iter(filter_config.keys()))]
if not isinstance(conditions, list) or len(conditions) < 1:
return "Logical conditions need at least 1 sub-condition"
# recursive
for condition in conditions:
error = self._validate_filter_structure(condition, account_fields)
if error:
return error
else:
return "Filter must be a list or dict"
return None
class FormulaValidator(Validator):
def __init__(self, template):
self.template = template
reference_codes = {row.reference_code for row in template.rows if row.reference_code}
self.calculation_validator = CalculationFormulaValidator(reference_codes)
self.account_filter_validator = AccountFilterValidator()
def validate(self, row, account_fields: set) -> ValidationResult:
result = ValidationResult()
if not row.calculation_formula:
return result
if row.data_source == "Calculated Amount":
return self.calculation_validator.validate(row)
elif row.data_source == "Account Data":
# Update account fields if provided
if account_fields:
self.account_filter_validator.account_fields = account_fields
return self.account_filter_validator.validate(row)
elif row.data_source == "Custom API":
result.merge(self._validate_custom_api(row))
return result
def _validate_custom_api(self, row) -> ValidationResult:
result = ValidationResult()
api_path = row.calculation_formula
if "." not in api_path:
result.add_error(
ValidationIssue(
message="Custom API path should be in format: app.module.method",
row_idx=row.idx,
field="Formula",
)
)
return result
# Method exists?
try:
module_path, method_name = api_path.rsplit(".", 1)
module = frappe.get_module(module_path)
if not hasattr(module, method_name):
result.add_error(
ValidationIssue(
message=f"Method '{method_name}' not found in module '{module_path}' (might be environment-specific)",
row_idx=row.idx,
field="Formula",
)
)
except Exception as e:
result.add_error(
ValidationIssue(
message=f"Could not validate API path: {e!s}",
row_idx=row.idx,
field="Formula",
)
)
return result
def extract_reference_codes_from_formula(formula: str, available_codes: list[str]) -> list[str]:
found_codes = []
for code in available_codes:
# Match complete words only to avoid partial matches
pattern = r"\b" + re.escape(code) + r"\b"
if re.search(pattern, formula):
found_codes.append(code)
return found_codes

View File

@@ -0,0 +1,79 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe.tests import IntegrationTestCase
from frappe.tests.utils import make_test_records
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class TestFinancialReportTemplate(IntegrationTestCase):
pass
class FinancialReportTemplateTestCase(IntegrationTestCase):
"""Utility class with common setup and helper methods for all test classes"""
@classmethod
def setUpClass(cls):
"""Set up test data"""
make_test_records("Company")
make_test_records("Fiscal Year")
cls.create_test_template()
@classmethod
def create_test_template(cls):
"""Create a test financial report template"""
if not frappe.db.exists("Financial Report Template", "Test P&L Template"):
template = frappe.get_doc(
{
"doctype": "Financial Report Template",
"template_name": "Test P&L Template",
"report_type": "Profit and Loss Statement",
"rows": [
{
"reference_code": "INC001",
"display_name": "Income",
"indentation_level": 0,
"data_source": "Account Data",
"balance_type": "Closing Balance",
"bold_text": 1,
"calculation_formula": '["root_type", "=", "Income"]',
},
{
"reference_code": "EXP001",
"display_name": "Expenses",
"indentation_level": 0,
"data_source": "Account Data",
"balance_type": "Closing Balance",
"bold_text": 1,
"calculation_formula": '["root_type", "=", "Expense"]',
},
{
"reference_code": "NET001",
"display_name": "Net Profit/Loss",
"indentation_level": 0,
"data_source": "Calculated Amount",
"bold_text": 1,
"calculation_formula": "INC001 - EXP001",
},
],
}
)
template.insert()
cls.test_template = frappe.get_doc("Financial Report Template", "Test P&L Template")
@staticmethod
def create_test_template_with_rows(rows_data):
"""Helper method to create test template with specific rows"""
template_name = f"Test Template {frappe.generate_hash()[:8]}"
template = frappe.get_doc(
{"doctype": "Financial Report Template", "template_name": template_name, "rows": rows_data}
)
return template

View File

@@ -0,0 +1,118 @@
[
{
"account_category_name": "Cash and Cash Equivalents",
"description": "Cash on hand, demand deposits, and short-term highly liquid investments readily convertible to cash with original maturities of three months or less. Examples: Cash in hand, bank current accounts, money market funds, treasury bills \u22643 months."
},
{
"account_category_name": "Cost of Goods Sold",
"description": "Direct costs attributable to cost of goods sold. Examples: Raw materials, stock in trade."
},
{
"account_category_name": "Current Tax Liabilities",
"description": "Income tax obligations for current and prior periods. Examples: Provision for income tax, advance tax paid, tax deducted at source."
},
{
"account_category_name": "Finance Costs",
"description": "Interest and financing-related expenses. Examples: Interest on borrowings, bank charges, lease interest, foreign exchange losses."
},
{
"account_category_name": "Intangible Assets",
"description": "Identifiable non-monetary assets without physical substance. Examples: Software, patents, trademarks, licenses, development costs."
},
{
"account_category_name": "Investment Income",
"description": "Returns generated from financial investments and cash management. Examples: Interest income, dividend income, rental income, fair value gains."
},
{
"account_category_name": "Long-term Borrowings",
"description": "Interest-bearing debt obligations with maturity beyond one year. Examples: Term loans, bonds, debentures, mortgages."
},
{
"account_category_name": "Long-term Investments",
"description": "Investments held for strategic purposes or extended periods. Examples: Equity investments, bonds, associates, joint ventures, deposits."
},
{
"account_category_name": "Long-term Provisions",
"description": "Present obligations beyond one year with uncertain timing/amount. Examples: Asset retirement obligations, environmental remediation, legal settlements."
},
{
"account_category_name": "Operating Expenses",
"description": "Costs incurred in ordinary business operations excluding direct costs. Examples: Selling expenses, administrative costs, marketing, utilities, rent."
},
{
"account_category_name": "Other Current Assets",
"description": "Current assets not classified elsewhere including prepaid expenses and advances. Examples: Prepaid insurance, prepaid rent, advance to suppliers, security deposits recoverable within one year."
},
{
"account_category_name": "Other Current Liabilities",
"description": "Short-term obligations not classified elsewhere. Examples: Accrued expenses, statutory liabilities, employee payables."
},
{
"account_category_name": "Other Direct Costs",
"description": "Direct costs excluding cost of goods sold. Examples: Direct labor, manufacturing overhead, freight inward."
},
{
"account_category_name": "Other Non-current Assets",
"description": "Long-term assets not classified elsewhere. Examples: Security deposits, long-term prepayments, advances for capital goods."
},
{
"account_category_name": "Other Non-current Liabilities",
"description": "Long-term obligations not classified elsewhere. Examples: Long-term deposits, deferred income, government grants."
},
{
"account_category_name": "Other Operating Income",
"description": "Incidental income related to business operations but not core revenue. Examples: Scrap sales, government grants, insurance claims, foreign exchange gains."
},
{
"account_category_name": "Other Payables",
"description": "Non-trade payables and obligations to parties other than suppliers. Examples: Employee payables, accrued expenses, customer advances, security deposits received."
},
{
"account_category_name": "Other Receivables",
"description": "Non-trade amounts due to the entity excluding financing arrangements. Examples: Employee advances, insurance claims, tax refunds, deposits recoverable."
},
{
"account_category_name": "Reserves and Surplus",
"description": "Accumulated profits and other reserves created from profits or share premium. Examples: General reserves, retained earnings, statutory reserves, share premium."
},
{
"account_category_name": "Revenue from Operations",
"description": "Income from primary business activities in ordinary course. Examples: Sales of goods, service revenue, commission income, royalty income."
},
{
"account_category_name": "Share Capital",
"description": "Nominal value of issued and paid-up equity shares. Examples: Common stock, ordinary shares, preference shares."
},
{
"account_category_name": "Short-term Borrowings",
"description": "Interest-bearing debt obligations due within one year. Examples: Bank overdrafts, short-term loans, current portion of long-term debt."
},
{
"account_category_name": "Short-term Investments",
"description": "Financial instruments held for short-term investment purposes, readily convertible to cash. Examples: Marketable securities, fixed deposits >3 months, mutual funds."
},
{
"account_category_name": "Short-term Provisions",
"description": "Present obligations due within one year with uncertain timing or amount. Examples: Warranty provisions, legal claims, restructuring costs."
},
{
"account_category_name": "Stock Assets",
"description": "Inventory and stock-related assets including raw materials, work in progress, finished goods, and stock in trade. Examples: Raw materials, finished goods, trading merchandise, consumables."
},
{
"account_category_name": "Tangible Assets",
"description": "Physical assets used in business operations including property, plant, and equipment. Examples: Land, buildings, machinery, equipment, vehicles, furniture, capital work in progress."
},
{
"account_category_name": "Tax Expense",
"description": "Current and deferred income tax obligations. Examples: Current tax provision, deferred tax expense, withholding taxes."
},
{
"account_category_name": "Trade Payables",
"description": "Amounts owed to suppliers. Examples: Supplier invoices, accrued purchases, bills payable."
},
{
"account_category_name": "Trade Receivables",
"description": "Amounts due from customers for goods sold or services provided in ordinary course of business. Examples: Accounts receivable, notes receivable from customers, unbilled revenue."
}
]

View File

@@ -0,0 +1,993 @@
{
"creation": "2025-09-07 07:24:40.762641",
"disabled": 0,
"docstatus": 0,
"doctype": "Financial Report Template",
"idx": 0,
"modified": "2025-10-15 03:12:19.165699",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Horizontal Balance Sheet (Columnar)",
"owner": "Administrator",
"report_type": "Balance Sheet",
"rows": [
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Section Break",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Column Break",
"display_name": "Equity & Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "Capital & Reserves",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CAPITAL_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Share Capital\"]",
"data_source": "Account Data",
"display_name": "Share Capital",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_SHARE_CAPITAL",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "{\"and\":[[\"account_category\",\"=\",\"Reserves and Surplus\"],[\"account_name\",\"not like\",\"%Retained Earnings%\"]]}",
"data_source": "Account Data",
"display_name": "Reserves & Surplus",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_RESERVES",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "{\"and\":[[\"account_name\",\"like\",\"%Retained Earnings%\"],[\"account_category\",\"=\",\"Reserves and Surplus\"]]}",
"data_source": "Account Data",
"display_name": "Retained Earnings",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_RETAINED_EARNINGS",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "L_SHARE_CAPITAL + L_RESERVES + L_RETAINED_EARNINGS",
"data_source": "Calculated Amount",
"display_name": "Total Capital & Reserves",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "L_TOTAL_EQUITY",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "Non-Current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "NCL_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Long-term Borrowings\"], [\"account_name\", \"not like\", \"Unsecured\"]]}",
"data_source": "Account Data",
"display_name": "Secured Loans",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_SECURED_LOANS",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Long-term Borrowings\"], [\"account_name\", \"like\", \"Unsecured\"]]}",
"data_source": "Account Data",
"display_name": "Unsecured Loans",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_UNSECURED_LOANS",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Long-term Provisions\"]",
"data_source": "Account Data",
"display_name": "Long-term Provisions",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_LT_PROVISIONS",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Non-current Liabilities\"]",
"data_source": "Account Data",
"display_name": "Other Non-current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_OTHER_NCL",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "L_SECURED_LOANS + L_UNSECURED_LOANS + L_LT_PROVISIONS + L_OTHER_NCL",
"data_source": "Calculated Amount",
"display_name": "Total Non-current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "L_TOTAL_NCL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "Current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CL_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Short-term Borrowings\"]",
"data_source": "Account Data",
"display_name": "Short-term Borrowings",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_ST_BORROWINGS",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Trade Payables\"]",
"data_source": "Account Data",
"display_name": "Trade Payables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_TRADE_PAYABLES",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Payables\"]",
"data_source": "Account Data",
"display_name": "Other Payables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_OTHER_PAYABLES",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Current Tax Liabilities\"]",
"data_source": "Account Data",
"display_name": "Current Tax Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_TAX_LIABILITIES",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Short-term Provisions\"]",
"data_source": "Account Data",
"display_name": "Short-term Provisions",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_PROVISIONS",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Current Liabilities\"]",
"data_source": "Account Data",
"display_name": "Other Current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_OTHER_CL",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "L_ST_BORROWINGS + L_TRADE_PAYABLES + L_OTHER_PAYABLES + L_TAX_LIABILITIES + L_PROVISIONS + L_OTHER_CL",
"data_source": "Calculated Amount",
"display_name": "Total Current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "L_TOTAL_CL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "Current Year Earnings",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "PL_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 1,
"calculation_formula": "[\"root_type\", \"in\", [\"Income\", \"Expense\"]]",
"color": "#28a745",
"data_source": "Account Data",
"display_name": "Net Profit/(Loss) for the Year",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "L_CURRENT_PL",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Column Break",
"display_name": "Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "Non-Current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "NCA_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Tangible Assets\"], [\"account_type\", \"!=\", \"Accumulated Depreciation\"]]}",
"data_source": "Account Data",
"display_name": "Property, Plant & Equipment",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_TANGIBLE",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_type\", \"like\", \"Accumulated Depreciation\"]",
"data_source": "Account Data",
"display_name": "Less: Accumulated Depreciation",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 2,
"italic_text": 1,
"reference_code": "A_ACC_DEPRECIATION",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "A_TANGIBLE - A_ACC_DEPRECIATION",
"data_source": "Calculated Amount",
"display_name": "Net Tangible Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_NET_TANGIBLE",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Intangible Assets\"]",
"data_source": "Account Data",
"display_name": "Intangible Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_INTANGIBLE",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Long-term Investments\"]",
"data_source": "Account Data",
"display_name": "Long-term Investments",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_LT_INVESTMENTS",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Non-current Assets\"]",
"data_source": "Account Data",
"display_name": "Other Non-current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_OTHER_NCA",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "(A_NET_TANGIBLE if A_ACC_DEPRECIATION else A_TANGIBLE) + A_INTANGIBLE + A_LT_INVESTMENTS + A_OTHER_NCA",
"data_source": "Calculated Amount",
"display_name": "Total Non-current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "A_TOTAL_NCA",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "Current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CA_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Stock Assets\"]",
"data_source": "Account Data",
"display_name": "Inventories",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_STOCK",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Trade Receivables\"]",
"data_source": "Account Data",
"display_name": "Trade Receivables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_TRADE_RECEIVABLES",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Receivables\"]",
"data_source": "Account Data",
"display_name": "Other Receivables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_OTHER_RECEIVABLES",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Short-term Investments\"]",
"data_source": "Account Data",
"display_name": "Short-term Investments",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_ST_INVESTMENTS",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Cash and Cash Equivalents\"]",
"data_source": "Account Data",
"display_name": "Cash & Bank Balances",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_CASH_BANK",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Current Assets\"]",
"data_source": "Account Data",
"display_name": "Other Current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "A_OTHER_CA",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "A_STOCK + A_TRADE_RECEIVABLES + A_OTHER_RECEIVABLES + A_ST_INVESTMENTS + A_CASH_BANK + A_OTHER_CA",
"data_source": "Calculated Amount",
"display_name": "Total Current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "A_TOTAL_CA",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Section Break",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "L_TOTAL_EQUITY + L_TOTAL_NCL + L_TOTAL_CL + L_CURRENT_PL",
"data_source": "Calculated Amount",
"display_name": "TOTAL",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "L_GRAND_TOTAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Column Break",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "A_TOTAL_NCA + A_TOTAL_CA",
"data_source": "Calculated Amount",
"display_name": "TOTAL",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "A_GRAND_TOTAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Section Break",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "L_GRAND_TOTAL - A_GRAND_TOTAL",
"color": "#EC864B",
"data_source": "Calculated Amount",
"display_name": "Balance Check (should be zero)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 1,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "BALANCE_CHECK",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "A_TOTAL_NCA + A_TOTAL_CA",
"data_source": "Calculated Amount",
"display_name": "Total Assets",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TOTAL_ASSETS",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "L_TOTAL_NCL + L_TOTAL_CL",
"data_source": "Calculated Amount",
"display_name": "Total Liabilities",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TOTAL_LIABILITIES",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "L_TOTAL_EQUITY + L_CURRENT_PL",
"data_source": "Calculated Amount",
"display_name": "Total Equity",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TOTAL_EQUITY",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "KEY FINANCIAL RATIOS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "METRICS_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(A_TOTAL_CA / L_TOTAL_CL) if L_TOTAL_CL != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Current Ratio",
"fieldtype": "Float",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "CURRENT_RATIO",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "((A_TRADE_RECEIVABLES + A_ST_INVESTMENTS + A_CASH_BANK) / L_TOTAL_CL) if L_TOTAL_CL != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Quick Ratio (Acid Test)",
"fieldtype": "Float",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "QUICK_RATIO",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "((L_SECURED_LOANS + L_UNSECURED_LOANS + L_ST_BORROWINGS) / TOTAL_EQUITY) if TOTAL_EQUITY != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Debt to Equity Ratio",
"fieldtype": "Float",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "DEBT_EQUITY_RATIO",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "A_TOTAL_CA - L_TOTAL_CL",
"data_source": "Calculated Amount",
"display_name": "Net Working Capital",
"fieldtype": "Currency",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "WORKING_CAPITAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(TOTAL_EQUITY / TOTAL_ASSETS * 100) if TOTAL_ASSETS != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Equity Ratio %",
"fieldtype": "Percent",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "EQUITY_RATIO",
"reverse_sign": 0
}
],
"template_name": "Horizontal Balance Sheet (Columnar)"
}

View File

@@ -0,0 +1,824 @@
{
"creation": "2025-09-06 21:47:56.970556",
"disabled": 0,
"docstatus": 0,
"doctype": "Financial Report Template",
"idx": 0,
"modified": "2025-10-15 03:13:38.485684",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Standard Balance Sheet (IFRS)",
"owner": "Administrator",
"report_type": "Balance Sheet",
"rows": [
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "ASSETS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "ASSETS_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "CURRENT ASSETS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CA_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Cash and Cash Equivalents\"]",
"data_source": "Account Data",
"display_name": "Cash and Cash Equivalents",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CA100",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Trade Receivables\"]",
"data_source": "Account Data",
"display_name": "Trade Receivables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CA200",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Receivables\"]",
"data_source": "Account Data",
"display_name": "Other Receivables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CA300",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Stock Assets\"]",
"data_source": "Account Data",
"display_name": "Inventories",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CA400",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Short-term Investments\"]",
"data_source": "Account Data",
"display_name": "Short-term Investments",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CA500",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Current Assets\"]",
"data_source": "Account Data",
"display_name": "Other Current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CA600",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CA100 + CA200 + CA300 + CA400 + CA500 + CA600",
"data_source": "Calculated Amount",
"display_name": "Total Current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "CA_TOTAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "NON-CURRENT ASSETS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "NCA_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Tangible Assets\"]",
"data_source": "Account Data",
"display_name": "Property, Plant and Equipment",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCA100",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Intangible Assets\"]",
"data_source": "Account Data",
"display_name": "Intangible Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCA200",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Long-term Investments\"]",
"data_source": "Account Data",
"display_name": "Long-term Investments",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCA300",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Non-current Assets\"]",
"data_source": "Account Data",
"display_name": "Other Non-current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCA400",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "NCA100 + NCA200 + NCA300 + NCA400",
"data_source": "Calculated Amount",
"display_name": "Total Non-current Assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "NCA_TOTAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CA_TOTAL + NCA_TOTAL",
"data_source": "Calculated Amount",
"display_name": "TOTAL ASSETS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TOTAL_ASSETS",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "LIABILITIES AND EQUITY",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "LIAB_EQUITY_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "CURRENT LIABILITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CL_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Trade Payables\"]",
"data_source": "Account Data",
"display_name": "Trade Payables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CL100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Payables\"]",
"data_source": "Account Data",
"display_name": "Other Payables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CL200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Short-term Borrowings\"]",
"data_source": "Account Data",
"display_name": "Short-term Borrowings",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CL300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Current Tax Liabilities\"]",
"data_source": "Account Data",
"display_name": "Current Tax Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CL400",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Short-term Provisions\"]",
"data_source": "Account Data",
"display_name": "Short-term Provisions",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CL500",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Current Liabilities\"]",
"data_source": "Account Data",
"display_name": "Other Current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CL600",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CL100 + CL200 + CL300 + CL400 + CL500 + CL600",
"data_source": "Calculated Amount",
"display_name": "Total Current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "CL_TOTAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "NON-CURRENT LIABILITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "NCL_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Long-term Borrowings\"]",
"data_source": "Account Data",
"display_name": "Long-term Borrowings",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCL100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Long-term Provisions\"]",
"data_source": "Account Data",
"display_name": "Long-term Provisions",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCL200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Non-current Liabilities\"]",
"data_source": "Account Data",
"display_name": "Other Non-current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "NCL300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "NCL100 + NCL200 + NCL300",
"data_source": "Calculated Amount",
"display_name": "Total Non-current Liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "NCL_TOTAL",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CL_TOTAL + NCL_TOTAL",
"data_source": "Calculated Amount",
"display_name": "TOTAL LIABILITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TOTAL_LIABILITIES",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"data_source": "Blank Line",
"display_name": "EQUITY",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "EQ_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Share Capital\"]",
"data_source": "Account Data",
"display_name": "Share Capital",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "EQ100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Reserves and Surplus\"]",
"data_source": "Account Data",
"display_name": "Reserves and Surplus",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "EQ200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 0,
"calculation_formula": "[\"root_type\", \"in\", [\"Income\", \"Expense\"]]",
"data_source": "Account Data",
"display_name": "Provisional Profit and Loss",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 1,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "EQ300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "EQ100 + EQ200 + EQ300",
"data_source": "Calculated Amount",
"display_name": "Total Equity",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "TOTAL_EQUITY",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "TOTAL_EQUITY",
"data_source": "Calculated Amount",
"display_name": "TOTAL EQUITY",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "TOTAL_LIABILITIES + TOTAL_EQUITY",
"data_source": "Calculated Amount",
"display_name": "TOTAL LIABILITIES AND EQUITY",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TOTAL_LIAB_EQUITY",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "TOTAL_ASSETS - TOTAL_LIAB_EQUITY",
"color": "#CB2929",
"data_source": "Calculated Amount",
"display_name": "Balance Check (should be zero)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 1,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "BALANCE_CHECK",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "CA_TOTAL / CL_TOTAL if CL_TOTAL != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Current Ratio",
"fieldtype": "Float",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CURRENT_RATIO",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(CL300 + NCL100) / TOTAL_EQUITY if TOTAL_EQUITY != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Debt to Equity Ratio",
"fieldtype": "Float",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "DEBT_EQUITY_RATIO",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "CA_TOTAL - CL_TOTAL",
"data_source": "Calculated Amount",
"display_name": "Working Capital",
"fieldtype": "Currency",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "WORKING_CAPITAL",
"reverse_sign": 0
}
],
"template_name": "Standard Balance Sheet (IFRS)"
}

View File

@@ -0,0 +1,832 @@
{
"creation": "2025-09-07 22:45:05.754628",
"disabled": 0,
"docstatus": 0,
"doctype": "Financial Report Template",
"idx": 0,
"modified": "2025-10-27 08:25:12.870928",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Standard Cash Flow Statement (IFRS)",
"owner": "Administrator",
"report_type": "Cash Flow",
"rows": [
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "CASH FLOWS FROM OPERATING ACTIVITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_OP_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"root_type\", \"in\", [\"Income\", \"Expense\"]], [\"account_category\", \"!=\", \"Tax Expense\"]]}",
"color": "",
"data_source": "Account Data",
"display_name": "Profit before tax",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_OP100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "Adjustments for:",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CF_ADJ_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_type\", \"=\", \"Depreciation\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Depreciation and amortization",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_ADJ100",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Finance Costs\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Finance costs",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_ADJ200",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Investment Income\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Investment income",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_ADJ300",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_OP100 + CF_ADJ100 + CF_ADJ200 + CF_ADJ300",
"color": "",
"data_source": "Calculated Amount",
"display_name": "Operating profit before working capital changes",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CF_OP_BEFORE_WC",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "Working capital changes:",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CF_WC_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Trade Receivables\"]",
"color": "",
"data_source": "Account Data",
"display_name": "(Increase)/decrease in trade receivables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_WC100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Stock Assets\"]",
"color": "",
"data_source": "Account Data",
"display_name": "(Increase)/decrease in inventories",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_WC200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"in\", [\"Other Receivables\", \"Other Current Assets\"]]",
"color": "",
"data_source": "Account Data",
"display_name": "(Increase)/decrease in other current assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_WC300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Trade Payables\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Increase/(decrease) in trade payables",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_WC400",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"in\", [\"Other Payables\", \"Current Tax Liabilities\", \"Short-term Borrowings\", \"Short-term Provisions\", \"Other Current Liabilities\"]]",
"color": "",
"data_source": "Account Data",
"display_name": "Increase/(decrease) in other current liabilities",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 0,
"reference_code": "CF_WC500",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_OP_BEFORE_WC + CF_WC100 + CF_WC200 + CF_WC300 + CF_WC400 + CF_WC500",
"color": "",
"data_source": "Calculated Amount",
"display_name": "Cash generated from operations",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_CASH_GEN",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Finance Costs\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Interest paid",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_OP200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Tax Expense\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Income taxes paid",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_OP300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_CASH_GEN + CF_OP200 + CF_OP300",
"color": "",
"data_source": "Calculated Amount",
"display_name": "NET CASH FROM OPERATING ACTIVITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_OP_NET",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "CASH FLOWS FROM INVESTING ACTIVITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Tangible Assets\"], [\"account_type\", \"!=\", \"Accumulated Depreciation\"]]}",
"color": "",
"data_source": "Account Data",
"display_name": "Purchase / Sale of property, plant and equipment",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_type\", \"=\", \"Accumulated Depreciation\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Accumulated Depreciation",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV101",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "max(0, CF_ADJ100 - CF_INV101)",
"color": "",
"data_source": "Calculated Amount",
"display_name": "Depreciation and amortization",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 1,
"include_in_charts": 0,
"indentation_level": 1,
"italic_text": 1,
"reference_code": "CF_INV102",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Intangible Assets\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Purchase of intangible assets",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"in\", [\"Long-term Investments\", \"Short-term Investments\"]]",
"color": "",
"data_source": "Account Data",
"display_name": "Purchase of investments",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Investment Income\"], [\"account_name\", \"not like\", \"dividend\"]]}",
"color": "",
"data_source": "Account Data",
"display_name": "Interest received",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV400",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Investment Income\"], [\"account_name\", \"like\", \"dividend\"]]}",
"color": "",
"data_source": "Account Data",
"display_name": "Dividends received",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV500",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_INV100 + CF_INV102 + CF_INV200 + CF_INV300 + CF_INV400 + CF_INV500",
"color": "",
"data_source": "Calculated Amount",
"display_name": "NET CASH FROM INVESTING ACTIVITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_INV_NET",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "CASH FLOWS FROM FINANCING ACTIVITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_FIN_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"in\", [\"Share Capital\", \"Reserves and Surplus\"]], [\"account_name\", \"not like\", \"Dividends Paid\"]]}",
"color": "",
"data_source": "Account Data",
"display_name": "Proceeds from issue of share capital",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_FIN100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"in\", [\"Long-term Borrowings\", \"Short-term Borrowings\"]]",
"color": "",
"data_source": "Account Data",
"display_name": "Proceeds from / Repayment of borrowings",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_FIN200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"in\", [\"Share Capital\", \"Reserves and Surplus\"]], [\"account_name\", \"like\", \"Dividends Paid\"]]}",
"color": "",
"data_source": "Account Data",
"display_name": "Dividends paid",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_FIN300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_FIN100 + CF_FIN200 + CF_FIN300",
"color": "",
"data_source": "Calculated Amount",
"display_name": "NET CASH FROM FINANCING ACTIVITIES",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_FIN_NET",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_OP_NET + CF_INV_NET + CF_FIN_NET",
"color": "",
"data_source": "Calculated Amount",
"display_name": "NET INCREASE/(DECREASE) IN CASH AND CASH EQUIVALENTS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_NET_INCREASE",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Opening Balance",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Cash and Cash Equivalents\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Cash and cash equivalents at beginning of period",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_CASH_BEGIN",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_type\", \"like\", \"Exchange\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Effect of exchange rate changes",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_FX_EFFECT",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Closing Balance",
"bold_text": 1,
"calculation_formula": "[\"account_category\", \"=\", \"Cash and Cash Equivalents\"]",
"color": "",
"data_source": "Account Data",
"display_name": "Cash and cash equivalents at end of period",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_CASH_END",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "CF_CASH_END - (CF_CASH_BEGIN + CF_NET_INCREASE + CF_FX_EFFECT)",
"color": "#CB2929",
"data_source": "Calculated Amount",
"display_name": "Validation Check (should be zero)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 1,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "CF_VALIDATION",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "",
"color": "",
"data_source": "Blank Line",
"display_name": "CASH FLOW METRICS",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CF_METRICS_HEADER",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "CF_OP_NET + CF_INV100",
"color": "",
"data_source": "Calculated Amount",
"display_name": "Free Cash Flow",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CF_FREE_CASH",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(CF_OP_NET / (CF_FIN300 + CF_OP200)) if (CF_FIN300 + CF_OP200) != 0 else 0",
"color": "",
"data_source": "Calculated Amount",
"display_name": "Cash Flow Coverage Ratio",
"fieldtype": "Float",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "CF_COVERAGE",
"reverse_sign": 0
}
],
"template_name": "Standard Cash Flow Statement (IFRS)"
}

View File

@@ -0,0 +1,418 @@
{
"creation": "2025-09-06 10:23:05.259864",
"disabled": 0,
"docstatus": 0,
"doctype": "Financial Report Template",
"idx": 0,
"modified": "2025-09-15 15:02:15.911105",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Standard Profit and Loss (IFRS)",
"owner": "Administrator",
"report_type": "Profit and Loss Statement",
"rows": [
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\":[[\"account_category\",\"=\",\"Revenue from Operations\"]]}",
"data_source": "Account Data",
"display_name": "Sales Revenue",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "REV100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Cost of Goods Sold\"]",
"data_source": "Account Data",
"display_name": "Cost of Goods Sold",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "COGS100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Direct Costs\"]",
"data_source": "Account Data",
"display_name": "Other Direct Costs",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "COGS200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "REV100 + COGS100 + COGS200",
"data_source": "Calculated Amount",
"display_name": "GROSS PROFIT (GP)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "GROSS_PROFIT",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Other Operating Income\"]",
"data_source": "Account Data",
"display_name": "Other Operating Income",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "OPIN100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Operating Expenses\"], [\"account_name\", \"like\", \"Sales\"]]}",
"data_source": "Account Data",
"display_name": "Selling & Distribution Expenses",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "OPEX100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Operating Expenses\"], [\"account_name\", \"like\", \"Administrative\"]]}",
"data_source": "Account Data",
"display_name": "Administrative Expenses",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "OPEX200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "{\"and\": [[\"account_category\", \"=\", \"Operating Expenses\"], [\"account_name\", \"not like\", \"Sales\"], [\"account_name\", \"not like\", \"Administrative\"]]}",
"data_source": "Account Data",
"display_name": "Other Operating Expenses",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "OPEX300",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "GROSS_PROFIT + OPIN100 + OPEX100 + OPEX200 + OPEX300",
"data_source": "Calculated Amount",
"display_name": "OPERATING PROFIT (EBIT)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "EBIT",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Investment Income\"]",
"data_source": "Account Data",
"display_name": "Investment Income",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "FIN100",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Finance Costs\"]",
"data_source": "Account Data",
"display_name": "Finance Costs",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "FIN200",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "EBIT + FIN100 + FIN200",
"data_source": "Calculated Amount",
"display_name": "PROFIT BEFORE TAX (EBT)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "PBT",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"account_category\", \"=\", \"Tax Expense\"]",
"data_source": "Account Data",
"display_name": "Tax Expense",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "TAX",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "PBT + TAX",
"data_source": "Calculated Amount",
"display_name": "NET PROFIT (NP)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "NET_PROFIT",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "NET_PROFIT - ACT_NET_PROFIT",
"color": "#CB2929",
"data_source": "Calculated Amount",
"display_name": "VARIANCE (Calculated vs Actual)",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 1,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "VAL_DIFF",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"data_source": "Blank Line",
"fieldtype": "",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 0,
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(GROSS_PROFIT / REV100) * 100 if REV100 != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Gross Profit Margin %",
"fieldtype": "Percent",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "GP_MARGIN",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(EBIT / REV100) * 100 if REV100 != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Operating Profit Margin %",
"fieldtype": "Percent",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "OP_MARGIN",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 0,
"calculation_formula": "(NET_PROFIT / REV100) * 100 if REV100 != 0 else 0",
"data_source": "Calculated Amount",
"display_name": "Net Profit Margin %",
"fieldtype": "Percent",
"hidden_calculation": 0,
"hide_when_empty": 0,
"include_in_charts": 0,
"indentation_level": 0,
"italic_text": 1,
"reference_code": "NP_MARGIN",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"root_type\", \"=\", \"Income\"]",
"data_source": "Account Data",
"display_name": "Total Income",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "ACT_TOTAL_INCOME",
"reverse_sign": 1
},
{
"advanced_filtering": 0,
"balance_type": "Period Movement (Debits - Credits)",
"bold_text": 0,
"calculation_formula": "[\"root_type\", \"=\", \"Expense\"]",
"data_source": "Account Data",
"display_name": "Total Expenses",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "ACT_TOTAL_EXPENSES",
"reverse_sign": 0
},
{
"advanced_filtering": 0,
"balance_type": "",
"bold_text": 1,
"calculation_formula": "ACT_TOTAL_INCOME - ACT_TOTAL_EXPENSES",
"data_source": "Calculated Amount",
"display_name": "Net Profit",
"fieldtype": "",
"hidden_calculation": 1,
"hide_when_empty": 0,
"include_in_charts": 1,
"indentation_level": 0,
"italic_text": 0,
"reference_code": "ACT_NET_PROFIT",
"reverse_sign": 0
}
],
"template_name": "Standard Profit and Loss (IFRS)"
}

View File

@@ -39,6 +39,16 @@ class TestAccountBalance(IntegrationTestCase):
"currency": "EUR",
"balance": 0.0,
},
{
"account": "Interest Income - _TC2",
"currency": "EUR",
"balance": 0.0,
},
{
"account": "Interest on Fixed Deposits - _TC2",
"currency": "EUR",
"balance": 0.0,
},
{
"account": "Sales - _TC2",
"currency": "EUR",

View File

@@ -1,11 +1,28 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);
const BS_REPORT_NAME = "Balance Sheet";
erpnext.utils.add_dimensions("Balance Sheet", 10);
frappe.query_reports[BS_REPORT_NAME] = $.extend({}, erpnext.financial_statements);
frappe.query_reports["Balance Sheet"]["filters"].push(
erpnext.utils.add_dimensions(BS_REPORT_NAME, 10);
frappe.query_reports[BS_REPORT_NAME]["filters"].push(
{
fieldname: "report_template",
label: __("Report Template"),
fieldtype: "Link",
options: "Financial Report Template",
get_query: { filters: { report_type: BS_REPORT_NAME, disabled: 0 } },
},
{
fieldname: "show_account_details",
label: __("Account Detail Level"),
fieldtype: "Select",
options: ["Summary", "Account Breakdown"],
default: "Summary",
depends_on: "eval:doc.report_template",
},
{
fieldname: "selected_view",
label: __("Select View"),
@@ -33,7 +50,8 @@ frappe.query_reports["Balance Sheet"]["filters"].push(
fieldname: "show_zero_values",
label: __("Show zero values"),
fieldtype: "Check",
depends_on: "eval:!doc.report_template",
}
);
frappe.query_reports["Balance Sheet"]["export_hidden_cols"] = true;
frappe.query_reports[BS_REPORT_NAME]["export_hidden_cols"] = true;

View File

@@ -6,6 +6,9 @@ import frappe
from frappe import _
from frappe.utils import cint, flt
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
FinancialReportEngine,
)
from erpnext.accounts.report.financial_statements import (
compute_growth_view_data,
get_columns,
@@ -16,6 +19,9 @@ from erpnext.accounts.report.financial_statements import (
def execute(filters=None):
if filters and filters.report_template:
return FinancialReportEngine().execute(filters)
period_list = get_period_list(
filters.from_fiscal_year,
filters.to_fiscal_year,

View File

@@ -1,20 +1,37 @@
// Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.query_reports["Cash Flow"] = $.extend(erpnext.financial_statements, {
const CF_REPORT_NAME = "Cash Flow";
frappe.query_reports[CF_REPORT_NAME] = $.extend(erpnext.financial_statements, {
name_field: "section",
parent_field: "parent_section",
});
erpnext.utils.add_dimensions("Cash Flow", 10);
erpnext.utils.add_dimensions(CF_REPORT_NAME, 10);
// The last item in the array is the definition for Presentation Currency
// filter. It won't be used in cash flow for now so we pop it. Please take
// of this if you are working here.
frappe.query_reports["Cash Flow"]["filters"].splice(8, 1);
frappe.query_reports[CF_REPORT_NAME]["filters"].splice(8, 1);
frappe.query_reports["Cash Flow"]["filters"].push(
frappe.query_reports[CF_REPORT_NAME]["filters"].push(
{
fieldname: "report_template",
label: __("Report Template"),
fieldtype: "Link",
options: "Financial Report Template",
get_query: { filters: { report_type: CF_REPORT_NAME, disabled: 0 } },
},
{
fieldname: "show_account_details",
label: __("Account Detail Level"),
fieldtype: "Select",
options: ["Summary", "Account Breakdown"],
default: "Summary",
depends_on: "eval:doc.report_template",
},
{
fieldname: "include_default_book_entries",
label: __("Include Default FB Entries"),

View File

@@ -10,6 +10,9 @@ from frappe.query_builder import DocType
from frappe.utils import cstr, flt
from pypika import Order
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
FinancialReportEngine,
)
from erpnext.accounts.report.financial_statements import (
get_columns,
get_cost_centers_with_children,
@@ -25,6 +28,9 @@ from erpnext.accounts.utils import get_fiscal_year
def execute(filters=None):
if filters and filters.report_template:
return FinancialReportEngine().execute(filters)
period_list = get_period_list(
filters.from_fiscal_year,
filters.to_fiscal_year,

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
const CFS_REPORT_NAME = "Custom Financial Statement";
frappe.query_reports[CFS_REPORT_NAME] = $.extend({}, erpnext.financial_statements);
erpnext.utils.add_dimensions(CFS_REPORT_NAME, 10);
frappe.query_reports[CFS_REPORT_NAME]["filters"].push(
{
fieldname: "report_template",
label: __("Report Template"),
fieldtype: "Link",
options: "Financial Report Template",
get_query: { filters: { disabled: 0 } },
reqd: 1,
},
{
fieldname: "show_account_details",
label: __("Account Detail Level"),
fieldtype: "Select",
options: ["Summary", "Account Breakdown"],
default: "Summary",
depends_on: "eval:doc.report_template",
},
{
fieldname: "include_default_book_entries",
label: __("Include Default FB Entries"),
fieldtype: "Check",
default: 1,
}
);
frappe.query_reports[CFS_REPORT_NAME]["export_hidden_cols"] = true;

View File

@@ -0,0 +1,34 @@
{
"add_total_row": 0,
"add_translate_data": 0,
"columns": [],
"creation": "2025-10-03 01:21:24.043064",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letterhead": null,
"modified": "2025-10-03 01:21:24.043064",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Custom Financial Statement",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "GL Entry",
"report_name": "Custom Financial Statement",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts User"
},
{
"role": "Accounts Manager"
},
{
"role": "Auditor"
}
],
"timeout": 0
}

View File

@@ -0,0 +1,11 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
FinancialReportEngine,
)
def execute(filters: dict | None = None):
if filters and filters.report_template:
return FinancialReportEngine().execute(filters)

View File

@@ -1,11 +1,28 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Profit and Loss Statement"] = $.extend({}, erpnext.financial_statements);
const PL_REPORT_NAME = "Profit and Loss Statement";
erpnext.utils.add_dimensions("Profit and Loss Statement", 10);
frappe.query_reports[PL_REPORT_NAME] = $.extend({}, erpnext.financial_statements);
frappe.query_reports["Profit and Loss Statement"]["filters"].push(
erpnext.utils.add_dimensions(PL_REPORT_NAME, 10);
frappe.query_reports[PL_REPORT_NAME]["filters"].push(
{
fieldname: "report_template",
label: __("Report Template"),
fieldtype: "Link",
options: "Financial Report Template",
get_query: { filters: { report_type: PL_REPORT_NAME, disabled: 0 } },
},
{
fieldname: "show_account_details",
label: __("Account Detail Level"),
fieldtype: "Select",
options: ["Summary", "Account Breakdown"],
default: "Summary",
depends_on: "eval:doc.report_template",
},
{
fieldname: "selected_view",
label: __("Select View"),
@@ -34,7 +51,8 @@ frappe.query_reports["Profit and Loss Statement"]["filters"].push(
fieldname: "show_zero_values",
label: __("Show zero values"),
fieldtype: "Check",
depends_on: "eval:!doc.report_template",
}
);
frappe.query_reports["Profit and Loss Statement"]["export_hidden_cols"] = true;
frappe.query_reports[PL_REPORT_NAME]["export_hidden_cols"] = true;

View File

@@ -6,6 +6,9 @@ import frappe
from frappe import _
from frappe.utils import flt
from erpnext.accounts.doctype.financial_report_template.financial_report_engine import (
FinancialReportEngine,
)
from erpnext.accounts.report.financial_statements import (
compute_growth_view_data,
compute_margin_view_data,
@@ -17,6 +20,9 @@ from erpnext.accounts.report.financial_statements import (
def execute(filters=None):
if filters and filters.report_template:
return FinancialReportEngine().execute(filters)
period_list = get_period_list(
filters.from_fiscal_year,
filters.to_fiscal_year,

View File

@@ -440,6 +440,7 @@ erpnext.patches.v16_0.make_workstation_operating_components #1
erpnext.patches.v16_0.set_reporting_currency
erpnext.patches.v16_0.set_posting_datetime_for_sabb_and_drop_indexes
erpnext.patches.v16_0.update_serial_no_reference_name
erpnext.patches.v16_0.update_account_categories_for_existing_accounts
erpnext.patches.v16_0.rename_subcontracted_quantity
erpnext.patches.v16_0.add_new_stock_entry_types
erpnext.patches.v15_0.set_asset_status_if_not_already_set

View File

@@ -0,0 +1,69 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import get_chart_metadata_fields
from erpnext.accounts.doctype.account.chart_of_accounts.verified import standard_chart_of_accounts
from erpnext.accounts.doctype.financial_report_template.financial_report_template import (
sync_financial_report_templates,
)
def execute():
"""
Patch to create default account categories and update existing accounts
with appropriate account categories based on standard chart of accounts mapping
"""
sync_financial_report_templates()
update_account_categories()
def update_account_categories():
account_mapping = get_standard_account_category_mapping()
companies = frappe.get_all("Company", pluck="name")
mapped_account_categories = {}
for company in companies:
map_account_categories_for_company(company, account_mapping, mapped_account_categories)
if not mapped_account_categories:
return
frappe.db.bulk_update("Account", mapped_account_categories)
def get_standard_account_category_mapping():
account_mapping = {}
def _extract_account_mapping(chart_data, prefix=""):
for account_name, account_details in chart_data.items():
if account_name in get_chart_metadata_fields():
continue
if isinstance(account_details, dict) and account_details.get("account_category"):
account_mapping[account_name] = account_details["account_category"]
if isinstance(account_details, dict):
_extract_account_mapping(account_details, prefix)
standard_chart = standard_chart_of_accounts.get()
_extract_account_mapping(standard_chart)
return account_mapping
def map_account_categories_for_company(company, account_mapping, mapped_account_categories):
accounts = frappe.get_all(
"Account",
filters={"company": company, "account_category": ["is", "not set"]},
fields=["name", "account_name"],
)
for account in accounts:
account_category = account_mapping.get(account.account_name)
if account_category:
mapped_account_categories[account.name] = {"account_category": account_category}

View File

@@ -4,45 +4,160 @@ erpnext.financial_statements = {
filters: get_filters(),
baseData: null,
formatter: function (value, row, column, data, default_formatter, filter) {
if (
frappe.query_report.get_filter_value("selected_view") == "Growth" &&
data &&
column.colIndex >= 3
) {
const growthPercent = data[column.fieldname];
// Growth/Margin
if (this._is_special_view(column, data))
return this._format_special_view(value, row, column, data, default_formatter);
if (growthPercent == undefined) return "NA"; //making this not applicable for undefined/null values
if (frappe.query_report.get_filter_value("report_template"))
return this._format_custom_report(value, row, column, data, default_formatter, filter);
else return this._format_standard_report(value, row, column, data, default_formatter, filter);
},
_is_special_view: function (column, data) {
if (!data) return false;
const view = frappe.query_report.get_filter_value("selected_view");
return (view === "Growth" && column.colIndex >= 3) || (view === "Margin" && column.colIndex >= 2);
},
_format_custom_report: function (value, row, column, data, default_formatter, filter) {
const columnInfo = this._parse_column_info(column.fieldname, data);
const formatting = this._get_formatting_for_column(data, columnInfo);
if (columnInfo.isAccount) {
return this._format_custom_account_column(
value,
data,
formatting,
column,
default_formatter,
row
);
} else {
return this._format_custom_value_column(value, data, formatting, column, default_formatter, row);
}
},
_parse_column_info: function (fieldname, data) {
const valueMatch = fieldname.match(/^(?:seg_(\d+)_)?(.+)$/);
const periodKeys = data._segment_info?.period_keys || [];
const baseName = valueMatch ? valueMatch[2] : fieldname;
const isPeriodColumn = periodKeys.includes(baseName);
return {
isAccount: baseName === "account",
isPeriod: isPeriodColumn,
segmentIndex: valueMatch && valueMatch[1] ? parseInt(valueMatch[1]) : null,
fieldname: baseName,
};
},
_get_formatting_for_column: function (data, columnInfo) {
let formatting = {};
if (columnInfo.segmentIndex !== null && data.segment_values)
formatting = data.segment_values[`seg_${columnInfo.segmentIndex}`] || {};
else formatting = data;
return formatting;
},
_format_custom_account_column: function (value, data, formatting, column, default_formatter, row) {
if (!value) return "";
// Link to open ledger
const should_link_to_ledger =
formatting.is_detail || (formatting.account_filters && formatting.child_accounts);
if (should_link_to_ledger) {
const glData = {
account: formatting.account_name || formatting.child_accounts || value,
from_date: formatting.from_date || formatting.period_start_date,
to_date: formatting.to_date || formatting.period_end_date,
account_type: formatting.account_type,
company: frappe.query_report.get_filter_value("company"),
};
column.link_onclick =
"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(glData) + ")";
value = default_formatter(value, row, column, data);
}
let formattedValue = String(value);
// Prefix
if (formatting.is_detail || formatting.prefix)
formattedValue = (formatting.prefix || "• ") + formattedValue;
// Indent
if (data._segment_info && data._segment_info.total_segments === 1) {
column.is_tree = true;
} else if (formatting.indent && formatting.indent > 0) {
const indent = "&nbsp;".repeat(formatting.indent * 4);
formattedValue = indent + formattedValue;
}
// Style
return this._style_custom_value(formattedValue, formatting, null);
},
_format_custom_value_column: function (value, data, formatting, column, default_formatter, row) {
if (formatting.is_blank_line) return "";
const col = { ...column };
col.fieldtype = formatting.fieldtype || col.fieldtype;
// Avoid formatting as currency
if (col.fieldtype === "Float") col.options = null;
let formattedValue = default_formatter(value, row, col, data);
return this._style_custom_value(formattedValue, formatting, value);
},
_style_custom_value(formattedValue, formatting, value) {
let $element = $(`<span>${formattedValue}</span>`);
if (formatting.bold) $element.css("font-weight", "bold");
if (formatting.italic) $element.css("font-style", "italic");
if (formatting.warn_if_negative && typeof value === "number" && value < 0)
$element.addClass("text-danger");
if (formatting.color) $element.css("color", formatting.color);
return $element.wrap("<p></p>").parent().html();
},
_format_special_view: function (value, row, column, data, default_formatter) {
const selectedView = frappe.query_report.get_filter_value("selected_view");
if (selectedView === "Growth") {
const growthPercent = data[column.fieldname];
if (growthPercent === undefined) return "NA";
if (growthPercent === "") return "";
if (column.fieldname === "total") {
value = $(`<span>${growthPercent}</span>`);
} else {
value = $(`<span>${(growthPercent >= 0 ? "+" : "") + growthPercent + "%"}</span>`);
if (growthPercent < 0) {
value = $(value).addClass("text-danger");
} else {
value = $(value).addClass("text-success");
}
}
value = $(value).wrap("<p></p>").parent().html();
return $(value).wrap("<p></p>").parent().html();
} else {
const marginPercent = data[column.fieldname];
if (marginPercent === undefined) return "NA";
return value;
} else if (frappe.query_report.get_filter_value("selected_view") == "Margin" && data) {
if (column.colIndex >= 2) {
const marginPercent = data[column.fieldname];
if (marginPercent == undefined) return "NA"; //making this not applicable for undefined/null values
value = $(`<span>${marginPercent + "%"}</span>`);
if (marginPercent < 0) value = $(value).addClass("text-danger");
else value = $(value).addClass("text-success");
value = $(value).wrap("<p></p>").parent().html();
return value;
}
value = $(`<span>${marginPercent + "%"}</span>`);
if (marginPercent < 0) value = $(value).addClass("text-danger");
else value = $(value).addClass("text-success");
return $(value).wrap("<p></p>").parent().html();
}
},
_format_standard_report: function (value, row, column, data, default_formatter, filter) {
if (data && column.fieldname == this.name_field) {
// first column
value = data.section_name || data.account_name || value;
if (filter && filter?.text && filter?.type == "contains") {

View File

@@ -15,6 +15,9 @@ from frappe.utils import add_months, cint, formatdate, get_first_day, get_link_t
from frappe.utils.nestedset import NestedSet, rebuild_tree
from erpnext.accounts.doctype.account.account import get_account_currency
from erpnext.accounts.doctype.financial_report_template.financial_report_template import (
sync_financial_report_templates,
)
from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges
@@ -294,6 +297,7 @@ class Company(NestedSet):
):
if not frappe.local.flags.ignore_chart_of_accounts:
frappe.flags.country_change = True
sync_financial_report_templates(self.chart_of_accounts, self.existing_company)
self.create_default_accounts()
self.create_default_warehouses()