mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-16 08:05:00 +00:00
feat: support custom financial statements (#49098)
Co-authored-by: Abdeali Chharchhoda <abdealiking786@gmail.com>
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
// },
|
||||
// });
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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": []
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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."
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)"
|
||||
}
|
||||
@@ -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)"
|
||||
}
|
||||
@@ -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)"
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
@@ -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 = " ".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") {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user