mirror of
https://github.com/frappe/erpnext.git
synced 2026-07-16 19:58:49 +00:00
Compare commits
1 Commits
v16.0.0-be
...
coderabbit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7ae191478 |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -6,7 +6,7 @@ Feature requests are also a great way to take the product forward. New ideas can
|
||||
|
||||
When you are raising an Issue, you should keep a few things in mind. Remember that the developer does not have access to your machine so you must give all the information you can while raising an Issue. If you are suggesting a feature, you should be very clear about what you want.
|
||||
|
||||
The Issue list is not the right place to ask a question or start a general discussion. If you want to do that , then the right place is the forum [https://discuss.frappe.io](https://discuss.frappe.io/c/erpnext/6).
|
||||
The Issue list is not the right place to ask a question or start a general discussion. If you want to do that , then the right place is the forum [https://discuss.erpnext.com](https://discuss.erpnext.com).
|
||||
|
||||
### Reply and Closing Policy
|
||||
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -9,7 +9,7 @@ body:
|
||||
Welcome to ERPNext issue tracker! Before creating an issue, please heed the following:
|
||||
|
||||
1. This tracker should only be used to report bugs and request features / enhancements to ERPNext
|
||||
- For questions and general support, checkout the [user manual](https://docs.erpnext.com/) or use [forum](https://discuss.frappe.io/c/erpnext/6)
|
||||
- For questions and general support, checkout the [user manual](https://docs.erpnext.com/) or use [forum](https://discuss.erpnext.com)
|
||||
- For documentation issues, propose edit on [documentation site](https://docs.erpnext.com/) directly.
|
||||
2. When making a bug report, make sure you provide all required information. The easier it is for
|
||||
maintainers to reproduce, the faster it'll be fixed.
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Community Forum
|
||||
url: https://discuss.frappe.io/c/erpnext/6
|
||||
url: https://discuss.erpnext.com/
|
||||
about: For general QnA, discussions and community help.
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -11,7 +11,7 @@ assignees: ''
|
||||
Welcome to ERPNext issue tracker! Before creating an issue, please heed the following:
|
||||
|
||||
1. This tracker should only be used to report bugs and request features / enhancements to ERPNext
|
||||
- For questions and general support, checkout the manual https://docs.erpnext.com or use https://discuss.frappe.io/c/erpnext/6
|
||||
- For questions and general support, checkout the manual https://erpnext.com/docs/user/manual/en or use https://discuss.erpnext.com
|
||||
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
|
||||
the original discussion.
|
||||
3. When making a feature request, make sure to be as verbose as possible. The better you convey your message, the greater the drive to make it happen.
|
||||
@@ -21,7 +21,7 @@ Please keep in mind that we get many many requests and we can't possibly work on
|
||||
|
||||
If you're in urgent need to a feature, please try the following channels to get paid developments done quickly:
|
||||
1. Certified ERPNext partners: https://erpnext.com/partners
|
||||
2. Developer community on ERPNext forums: https://discuss.frappe.io/c/framework/5
|
||||
2. Developer community on ERPNext forums: https://discuss.erpnext.com/c/developers/5
|
||||
3. Telegram group for ERPNext/Frappe development work: https://t.me/erpnext_opps
|
||||
|
||||
-->
|
||||
|
||||
@@ -133,7 +133,7 @@ To setup the repository locally follow the steps mentioned below:
|
||||
|
||||
1. [Frappe School](https://school.frappe.io) - Learn Frappe Framework and ERPNext from the various courses by the maintainers or from the community.
|
||||
2. [Official documentation](https://docs.erpnext.com/) - Extensive documentation for ERPNext.
|
||||
3. [Discussion Forum](https://discuss.frappe.io/c/erpnext/6) - Engage with community of ERPNext users and service providers.
|
||||
3. [Discussion Forum](https://discuss.erpnext.com/) - Engage with community of ERPNext users and service providers.
|
||||
4. [Telegram Group](https://erpnext_public.t.me) - Get instant help from huge community of users.
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
"account_currency",
|
||||
"column_break1",
|
||||
"parent_account",
|
||||
"account_category",
|
||||
"account_type",
|
||||
"tax_rate",
|
||||
"freeze_account",
|
||||
@@ -190,20 +189,13 @@
|
||||
"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-08-02 06:26:44.657146",
|
||||
"modified": "2025-01-22 10:40:35.766017",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
@@ -258,7 +250,6 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "account_number",
|
||||
"show_name_in_global_search": 1,
|
||||
"show_preview_popup": 1,
|
||||
@@ -266,4 +257,4 @@
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ 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
|
||||
@@ -109,7 +108,6 @@ class Account(NestedSet):
|
||||
self.validate_parent_child_account_type()
|
||||
self.validate_root_details()
|
||||
self.validate_account_number()
|
||||
self.validate_disabled()
|
||||
self.validate_group_or_ledger()
|
||||
self.set_root_and_report_type()
|
||||
self.validate_mandatory()
|
||||
@@ -254,14 +252,6 @@ class Account(NestedSet):
|
||||
|
||||
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
|
||||
|
||||
def validate_disabled(self):
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if not doc_before_save or cint(doc_before_save.disabled) == cint(self.disabled):
|
||||
return
|
||||
|
||||
if cint(self.disabled):
|
||||
self.validate_default_accounts_in_company()
|
||||
|
||||
def validate_group_or_ledger(self):
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if not doc_before_save or cint(doc_before_save.is_group) == cint(self.is_group):
|
||||
@@ -272,32 +262,9 @@ class Account(NestedSet):
|
||||
elif cint(self.is_group):
|
||||
if self.account_type and not self.flags.exclude_account_type_check:
|
||||
throw(_("Cannot covert to Group because Account Type is selected."))
|
||||
self.validate_default_accounts_in_company()
|
||||
elif self.check_if_child_exists():
|
||||
throw(_("Account with child nodes cannot be set as ledger"))
|
||||
|
||||
def validate_default_accounts_in_company(self):
|
||||
default_account_fields = get_company_default_account_fields()
|
||||
|
||||
company_default_accounts = frappe.db.get_value(
|
||||
"Company", self.company, list(default_account_fields.keys()), as_dict=1
|
||||
)
|
||||
|
||||
msg = _("Account {0} cannot be disabled as it is already set as {1} for {2}.")
|
||||
|
||||
if not self.disabled:
|
||||
msg = _("Account {0} cannot be converted to Group as it is already set as {1} for {2}.")
|
||||
|
||||
for d in default_account_fields:
|
||||
if company_default_accounts.get(d) == self.name:
|
||||
throw(
|
||||
msg.format(
|
||||
frappe.bold(self.name),
|
||||
frappe.bold(default_account_fields.get(d)),
|
||||
frappe.bold(self.company),
|
||||
)
|
||||
)
|
||||
|
||||
def validate_frozen_accounts_modifier(self):
|
||||
doc_before_save = self.get_doc_before_save()
|
||||
if not doc_before_save or doc_before_save.freeze_account == self.freeze_account:
|
||||
@@ -658,27 +625,3 @@ def _ensure_idle_system():
|
||||
).format(pretty_date(last_gl_update)),
|
||||
title=_("System In Use"),
|
||||
)
|
||||
|
||||
|
||||
def get_company_default_account_fields():
|
||||
return {
|
||||
"default_bank_account": "Default Bank Account",
|
||||
"default_cash_account": "Default Cash Account",
|
||||
"default_receivable_account": "Default Receivable Account",
|
||||
"default_payable_account": "Default Payable Account",
|
||||
"default_expense_account": "Default Expense Account",
|
||||
"default_income_account": "Default Income Account",
|
||||
"stock_received_but_not_billed": "Stock Received But Not Billed Account",
|
||||
"stock_adjustment_account": "Stock Adjustment Account",
|
||||
"write_off_account": "Write Off Account",
|
||||
"default_discount_account": "Default Payment Discount Account",
|
||||
"unrealized_profit_loss_account": "Unrealized Profit / Loss Account",
|
||||
"exchange_gain_loss_account": "Exchange Gain / Loss Account",
|
||||
"unrealized_exchange_gain_loss_account": "Unrealized Exchange Gain / Loss Account",
|
||||
"round_off_account": "Round Off Account",
|
||||
"default_deferred_revenue_account": "Default Deferred Revenue Account",
|
||||
"default_deferred_expense_account": "Default Deferred Expense Account",
|
||||
"accumulated_depreciation_account": "Accumulated Depreciation Account",
|
||||
"depreciation_expense_account": "Depreciation Expense Account",
|
||||
"disposal_account": "Gain/Loss Account on Asset Disposal",
|
||||
}
|
||||
|
||||
@@ -23,7 +23,15 @@ def create_charts(
|
||||
if root_account:
|
||||
root_type = child.get("root_type")
|
||||
|
||||
if account_name not in get_chart_metadata_fields():
|
||||
if account_name not in [
|
||||
"account_name",
|
||||
"account_number",
|
||||
"account_type",
|
||||
"root_type",
|
||||
"is_group",
|
||||
"tax_rate",
|
||||
"account_currency",
|
||||
]:
|
||||
account_number = cstr(child.get("account_number")).strip()
|
||||
account_name, account_name_in_db = add_suffix_if_duplicate(
|
||||
account_name, account_number, accounts
|
||||
@@ -47,7 +55,6 @@ 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"),
|
||||
@@ -90,7 +97,20 @@ 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(get_chart_metadata_fields())):
|
||||
elif len(
|
||||
set(child.keys())
|
||||
- set(
|
||||
[
|
||||
"account_name",
|
||||
"account_type",
|
||||
"root_type",
|
||||
"is_group",
|
||||
"tax_rate",
|
||||
"account_number",
|
||||
"account_currency",
|
||||
]
|
||||
)
|
||||
):
|
||||
is_group = 1
|
||||
else:
|
||||
is_group = 0
|
||||
@@ -233,7 +253,13 @@ 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 get_chart_metadata_fields():
|
||||
if account_name not in [
|
||||
"account_number",
|
||||
"account_type",
|
||||
"root_type",
|
||||
"is_group",
|
||||
"tax_rate",
|
||||
]:
|
||||
accounts.append(account_name)
|
||||
|
||||
_get_account_names(child)
|
||||
@@ -258,7 +284,15 @@ 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 get_chart_metadata_fields():
|
||||
if account_name in [
|
||||
"account_name",
|
||||
"account_number",
|
||||
"account_type",
|
||||
"root_type",
|
||||
"is_group",
|
||||
"tax_rate",
|
||||
"account_currency",
|
||||
]:
|
||||
continue
|
||||
|
||||
if from_coa_importer:
|
||||
@@ -276,16 +310,3 @@ 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,192 +9,103 @@ def get():
|
||||
return {
|
||||
_("Application of Funds (Assets)"): {
|
||||
_("Current Assets"): {
|
||||
_("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",
|
||||
},
|
||||
_("Accounts Receivable"): {_("Debtors"): {"account_type": "Receivable"}},
|
||||
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1},
|
||||
_("Cash In Hand"): {_("Cash"): {"account_type": "Cash"}, "account_type": "Cash"},
|
||||
_("Loans and Advances (Assets)"): {
|
||||
_("Employee Advances"): {
|
||||
"account_type": "Payable",
|
||||
"account_category": "Other Receivables",
|
||||
},
|
||||
_("Employee Advances"): {"account_type": "Payable"},
|
||||
},
|
||||
_("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"},
|
||||
_("Securities and Deposits"): {_("Earnest Money"): {}},
|
||||
_("Stock Assets"): {
|
||||
_("Stock In Hand"): {"account_type": "Stock", "account_category": "Stock Assets"},
|
||||
_("Stock In Hand"): {"account_type": "Stock"},
|
||||
"account_type": "Stock",
|
||||
"account_category": "Stock Assets",
|
||||
},
|
||||
_("Tax Assets"): {"is_group": 1, "account_category": "Other Current Assets"},
|
||||
_("Tax Assets"): {"is_group": 1},
|
||||
},
|
||||
_("Fixed Assets"): {
|
||||
_("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",
|
||||
},
|
||||
_("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"},
|
||||
_("CWIP Account"): {
|
||||
"account_type": "Capital Work in Progress",
|
||||
"account_category": "Tangible Assets",
|
||||
},
|
||||
},
|
||||
_("Investments"): {"is_group": 1, "account_category": "Long-term Investments"},
|
||||
_("Temporary Accounts"): {
|
||||
_("Temporary Opening"): {
|
||||
"account_type": "Temporary",
|
||||
"account_category": "Other Non-current Assets",
|
||||
}
|
||||
},
|
||||
_("Investments"): {"is_group": 1},
|
||||
_("Temporary Accounts"): {_("Temporary Opening"): {"account_type": "Temporary"}},
|
||||
"root_type": "Asset",
|
||||
},
|
||||
_("Expenses"): {
|
||||
_("Direct Expenses"): {
|
||||
_("Stock Expenses"): {
|
||||
_("Cost of Goods Sold"): {
|
||||
"account_type": "Cost of Goods Sold",
|
||||
"account_category": "Cost of Goods Sold",
|
||||
},
|
||||
_("Cost of Goods Sold"): {"account_type": "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",
|
||||
"account_type": "Expenses Included In Asset Valuation"
|
||||
},
|
||||
_("Expenses Included In Valuation"): {"account_type": "Expenses Included In Valuation"},
|
||||
_("Stock Adjustment"): {"account_type": "Stock Adjustment"},
|
||||
},
|
||||
},
|
||||
_("Indirect Expenses"): {
|
||||
_("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"},
|
||||
_("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"): {},
|
||||
},
|
||||
"root_type": "Expense",
|
||||
},
|
||||
_("Income"): {
|
||||
_("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,
|
||||
},
|
||||
_("Direct Income"): {_("Sales"): {}, _("Service"): {}},
|
||||
_("Indirect Income"): {"is_group": 1},
|
||||
"root_type": "Income",
|
||||
},
|
||||
_("Source of Funds (Liabilities)"): {
|
||||
_("Current Liabilities"): {
|
||||
_("Accounts Payable"): {
|
||||
_("Creditors"): {"account_type": "Payable", "account_category": "Trade Payables"},
|
||||
_("Payroll Payable"): {"account_category": "Other Payables"},
|
||||
_("Creditors"): {"account_type": "Payable"},
|
||||
_("Payroll Payable"): {},
|
||||
},
|
||||
_("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",
|
||||
"account_category": "Trade Payables",
|
||||
},
|
||||
_("Asset Received But Not Billed"): {
|
||||
"account_type": "Asset Received But Not Billed",
|
||||
"account_category": "Trade Payables",
|
||||
},
|
||||
_("Stock Received But Not Billed"): {"account_type": "Stock Received But Not Billed"},
|
||||
_("Asset Received But Not Billed"): {"account_type": "Asset Received But Not Billed"},
|
||||
},
|
||||
_("Duties and Taxes"): {
|
||||
"account_type": "Tax",
|
||||
"is_group": 1,
|
||||
"account_category": "Current Tax Liabilities",
|
||||
},
|
||||
_("Short-term Provisions"): {"account_category": "Short-term Provisions"},
|
||||
_("Duties and Taxes"): {"account_type": "Tax", "is_group": 1},
|
||||
_("Loans (Liabilities)"): {
|
||||
_("Secured Loans"): {"account_category": "Long-term Borrowings"},
|
||||
_("Unsecured Loans"): {"account_category": "Long-term Borrowings"},
|
||||
_("Bank Overdraft Account"): {"account_category": "Short-term Borrowings"},
|
||||
_("Secured Loans"): {},
|
||||
_("Unsecured Loans"): {},
|
||||
_("Bank Overdraft Account"): {},
|
||||
},
|
||||
},
|
||||
_("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", "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"},
|
||||
_("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"},
|
||||
"root_type": "Equity",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -10,128 +10,49 @@ def get():
|
||||
_("Application of Funds (Assets)"): {
|
||||
_("Current Assets"): {
|
||||
_("Accounts Receivable"): {
|
||||
_("Debtors"): {
|
||||
"account_type": "Receivable",
|
||||
"account_number": "1310",
|
||||
"account_category": "Trade Receivables",
|
||||
},
|
||||
_("Debtors"): {"account_type": "Receivable", "account_number": "1310"},
|
||||
"account_number": "1300",
|
||||
},
|
||||
_("Bank Accounts"): {
|
||||
"account_type": "Bank",
|
||||
"is_group": 1,
|
||||
"account_number": "1200",
|
||||
"account_category": "Cash and Cash Equivalents",
|
||||
},
|
||||
_("Bank Accounts"): {"account_type": "Bank", "is_group": 1, "account_number": "1200"},
|
||||
_("Cash In Hand"): {
|
||||
_("Cash"): {
|
||||
"account_type": "Cash",
|
||||
"account_number": "1110",
|
||||
"account_category": "Cash and Cash Equivalents",
|
||||
},
|
||||
_("Cash"): {"account_type": "Cash", "account_number": "1110"},
|
||||
"account_type": "Cash",
|
||||
"account_number": "1100",
|
||||
"account_category": "Cash and Cash Equivalents",
|
||||
},
|
||||
_("Loans and Advances (Assets)"): {
|
||||
_("Employee Advances"): {
|
||||
"account_number": "1610",
|
||||
"account_type": "Payable",
|
||||
"account_category": "Other Receivables",
|
||||
},
|
||||
_("Employee Advances"): {"account_number": "1610", "account_type": "Payable"},
|
||||
"account_number": "1600",
|
||||
},
|
||||
_("Securities and Deposits"): {
|
||||
_("Earnest Money"): {
|
||||
"account_number": "1651",
|
||||
"account_category": "Other Current Assets",
|
||||
},
|
||||
_("Earnest Money"): {"account_number": "1651"},
|
||||
"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",
|
||||
"account_category": "Stock Assets",
|
||||
},
|
||||
_("Stock In Hand"): {"account_type": "Stock", "account_number": "1410"},
|
||||
"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",
|
||||
"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",
|
||||
},
|
||||
_("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"},
|
||||
_("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",
|
||||
"account_category": "Long-term Investments",
|
||||
},
|
||||
_("Investments"): {"is_group": 1, "account_number": "1800"},
|
||||
_("Temporary Accounts"): {
|
||||
_("Temporary Opening"): {
|
||||
"account_type": "Temporary",
|
||||
"account_number": "1910",
|
||||
"account_category": "Other Non-current Assets",
|
||||
},
|
||||
_("Temporary Opening"): {"account_type": "Temporary", "account_number": "1910"},
|
||||
"account_number": "1900",
|
||||
},
|
||||
"root_type": "Asset",
|
||||
@@ -140,220 +61,97 @@ def get():
|
||||
_("Expenses"): {
|
||||
_("Direct Expenses"): {
|
||||
_("Stock Expenses"): {
|
||||
_("Cost of Goods Sold"): {
|
||||
"account_type": "Cost of Goods Sold",
|
||||
"account_number": "5111",
|
||||
"account_category": "Cost of Goods Sold",
|
||||
},
|
||||
_("Cost of Goods Sold"): {"account_type": "Cost of Goods Sold", "account_number": "5111"},
|
||||
_("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",
|
||||
"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"},
|
||||
_("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",
|
||||
},
|
||||
"root_type": "Expense",
|
||||
"account_number": "5000",
|
||||
},
|
||||
_("Income"): {
|
||||
_("Direct Income"): {
|
||||
_("Sales"): {"account_number": "4110", "account_category": "Revenue from Operations"},
|
||||
_("Service"): {"account_number": "4120", "account_category": "Revenue from Operations"},
|
||||
_("Sales"): {"account_number": "4110"},
|
||||
_("Service"): {"account_number": "4120"},
|
||||
"account_number": "4100",
|
||||
},
|
||||
_("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",
|
||||
},
|
||||
_("Indirect 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",
|
||||
"account_category": "Trade Payables",
|
||||
},
|
||||
_("Payroll Payable"): {"account_number": "2120", "account_category": "Other Payables"},
|
||||
_("Creditors"): {"account_type": "Payable", "account_number": "2110"},
|
||||
_("Payroll Payable"): {"account_number": "2120"},
|
||||
"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",
|
||||
"account_category": "Current Tax Liabilities",
|
||||
},
|
||||
_("TDS Payable"): {"account_number": "2310"},
|
||||
"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",
|
||||
"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",
|
||||
},
|
||||
_("Secured Loans"): {"account_number": "2410"},
|
||||
_("Unsecured Loans"): {"account_number": "2420"},
|
||||
_("Bank Overdraft Account"): {"account_number": "2430"},
|
||||
"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",
|
||||
"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",
|
||||
},
|
||||
_("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"},
|
||||
"root_type": "Equity",
|
||||
"account_number": "3000",
|
||||
},
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
// frappe.ui.form.on("Account Category", {
|
||||
// refresh(frm) {
|
||||
|
||||
// },
|
||||
// });
|
||||
@@ -1,71 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,20 +0,0 @@
|
||||
# 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
|
||||
@@ -309,8 +309,8 @@ def get_dimensions(with_cost_center_and_project=False):
|
||||
if with_cost_center_and_project:
|
||||
dimension_filters.extend(
|
||||
[
|
||||
frappe._dict({"fieldname": "cost_center", "document_type": "Cost Center"}),
|
||||
frappe._dict({"fieldname": "project", "document_type": "Project"}),
|
||||
{"fieldname": "cost_center", "document_type": "Cost Center"},
|
||||
{"fieldname": "project", "document_type": "Project"},
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
"period_closing_settings_section",
|
||||
"acc_frozen_upto",
|
||||
"ignore_account_closing_balance",
|
||||
"use_legacy_controller_for_pcv",
|
||||
"column_break_25",
|
||||
"frozen_accounts_modifier",
|
||||
"tab_break_dpet",
|
||||
@@ -652,12 +651,6 @@
|
||||
"fieldname": "use_legacy_budget_controller",
|
||||
"fieldtype": "Check",
|
||||
"label": "Use Legacy Budget Controller"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "use_legacy_controller_for_pcv",
|
||||
"fieldtype": "Check",
|
||||
"label": "Use Legacy Controller For Period Closing Voucher"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
@@ -666,7 +659,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2025-10-20 14:06:08.870427",
|
||||
"modified": "2025-09-24 16:08:08.515254",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Accounts Settings",
|
||||
|
||||
@@ -75,7 +75,6 @@ class AccountsSettings(Document):
|
||||
unlink_advance_payment_on_cancelation_of_order: DF.Check
|
||||
unlink_payment_on_cancellation_of_invoice: DF.Check
|
||||
use_legacy_budget_controller: DF.Check
|
||||
use_legacy_controller_for_pcv: DF.Check
|
||||
# end: auto-generated types
|
||||
|
||||
def validate(self):
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Advance Payment Ledger Entry", {
|
||||
refresh(frm) {
|
||||
frm.set_currency_labels(["amount"], frm.doc.currency);
|
||||
frm.set_currency_labels(["base_amount"], erpnext.get_currency(frm.doc.company));
|
||||
},
|
||||
});
|
||||
// frappe.ui.form.on("Advance Payment Ledger Entry", {
|
||||
// refresh(frm) {
|
||||
|
||||
// },
|
||||
// });
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
"voucher_no",
|
||||
"against_voucher_type",
|
||||
"against_voucher_no",
|
||||
"currency",
|
||||
"exchange_rate",
|
||||
"amount",
|
||||
"base_amount",
|
||||
"currency",
|
||||
"event",
|
||||
"delinked"
|
||||
],
|
||||
@@ -78,29 +76,13 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "DeLinked",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "base_amount",
|
||||
"fieldname": "base_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Amount (Company Currency)",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "exchange_rate",
|
||||
"fieldname": "exchange_rate",
|
||||
"fieldtype": "Float",
|
||||
"label": "Exchange Rate",
|
||||
"precision": "9",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"in_create": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-11-13 12:45:03.014555",
|
||||
"modified": "2025-10-13 15:11:58.300836",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Advance Payment Ledger Entry",
|
||||
|
||||
@@ -19,12 +19,10 @@ class AdvancePaymentLedgerEntry(Document):
|
||||
against_voucher_no: DF.DynamicLink | None
|
||||
against_voucher_type: DF.Link | None
|
||||
amount: DF.Currency
|
||||
base_amount: DF.Currency
|
||||
company: DF.Link | None
|
||||
currency: DF.Link | None
|
||||
delinked: DF.Check
|
||||
event: DF.Data | None
|
||||
exchange_rate: DF.Float
|
||||
voucher_no: DF.DynamicLink | None
|
||||
voucher_type: DF.Link | None
|
||||
# end: auto-generated types
|
||||
|
||||
@@ -9,6 +9,13 @@ cur_frm.add_fetch("bank", "swift_number", "swift_number");
|
||||
|
||||
frappe.ui.form.on("Bank Guarantee", {
|
||||
setup: function (frm) {
|
||||
frm.set_query("bank", function () {
|
||||
return {
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
},
|
||||
};
|
||||
});
|
||||
frm.set_query("bank_account", function () {
|
||||
return {
|
||||
filters: {
|
||||
|
||||
@@ -123,7 +123,8 @@
|
||||
"fieldname": "transaction_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Transaction ID",
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@@ -238,7 +239,7 @@
|
||||
"grid_page_length": 50,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-10-23 17:32:58.514807",
|
||||
"modified": "2025-09-26 17:06:29.207673",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Transaction",
|
||||
|
||||
@@ -272,19 +272,21 @@ def compare_expense_with_budget(args, budget_amount, action_for, action, budget_
|
||||
|
||||
if total_expense > budget_amount:
|
||||
if args.actual_expense > budget_amount:
|
||||
error_tense = _("is already")
|
||||
diff = args.actual_expense - budget_amount
|
||||
_msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It is already exceeded by {5}.")
|
||||
else:
|
||||
error_tense = _("will be")
|
||||
diff = total_expense - budget_amount
|
||||
_msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It will be exceeded by {5}.")
|
||||
|
||||
currency = frappe.get_cached_value("Company", args.company, "default_currency")
|
||||
msg = _msg.format(
|
||||
|
||||
msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It {5} exceed by {6}").format(
|
||||
_(action_for),
|
||||
frappe.bold(args.account),
|
||||
frappe.unscrub(args.budget_against_field),
|
||||
frappe.bold(budget_against),
|
||||
frappe.bold(fmt_money(budget_amount, currency=currency)),
|
||||
error_tense,
|
||||
frappe.bold(fmt_money(diff, currency=currency)),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
# 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
@@ -1,433 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
# 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
|
||||
@@ -1,545 +0,0 @@
|
||||
# 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
@@ -1,79 +0,0 @@
|
||||
# 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
|
||||
@@ -99,7 +99,7 @@ class FiscalYear(Document):
|
||||
)
|
||||
|
||||
overlap = False
|
||||
if not self.get("companies") and not company_for_existing:
|
||||
if not self.get("companies") or not company_for_existing:
|
||||
overlap = True
|
||||
|
||||
for d in self.get("companies"):
|
||||
|
||||
@@ -25,27 +25,6 @@ class TestFiscalYear(IntegrationTestCase):
|
||||
|
||||
self.assertRaises(frappe.exceptions.InvalidDates, fy.insert)
|
||||
|
||||
def test_company_fiscal_year_overlap(self):
|
||||
for name in ["_Test Global FY 2001", "_Test Company FY 2001"]:
|
||||
if frappe.db.exists("Fiscal Year", name):
|
||||
frappe.delete_doc("Fiscal Year", name)
|
||||
|
||||
global_fy = frappe.new_doc("Fiscal Year")
|
||||
global_fy.year = "_Test Global FY 2001"
|
||||
global_fy.year_start_date = "2001-04-01"
|
||||
global_fy.year_end_date = "2002-03-31"
|
||||
global_fy.insert()
|
||||
|
||||
company_fy = frappe.new_doc("Fiscal Year")
|
||||
company_fy.year = "_Test Company FY 2001"
|
||||
company_fy.year_start_date = "2001-01-01"
|
||||
company_fy.year_end_date = "2001-12-31"
|
||||
company_fy.append("companies", {"company": "_Test Company"})
|
||||
|
||||
company_fy.insert()
|
||||
self.assertTrue(frappe.db.exists("Fiscal Year", global_fy.name))
|
||||
self.assertTrue(frappe.db.exists("Fiscal Year", company_fy.name))
|
||||
|
||||
|
||||
def test_record_generator():
|
||||
test_records = [
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2025-07-17 12:24:05.609186",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"item_row",
|
||||
"tax_row",
|
||||
"rate",
|
||||
"amount",
|
||||
"taxable_amount"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "item_row",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Row",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tax_row",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Tax Row",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "rate",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Tax Rate"
|
||||
},
|
||||
{
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Tax Amount",
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"fieldname": "taxable_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Taxable Amount",
|
||||
"options": "Company:company:default_currency"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-09-26 15:54:19.750714",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Item Wise Tax Detail",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# 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 ItemWiseTaxDetail(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
|
||||
|
||||
amount: DF.Currency
|
||||
item_row: DF.Data
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
parenttype: DF.Data
|
||||
rate: DF.Float
|
||||
tax_row: DF.Data
|
||||
taxable_amount: DF.Currency
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
@@ -111,10 +111,6 @@ frappe.ui.form.on("Journal Entry", {
|
||||
}
|
||||
|
||||
erpnext.accounts.unreconcile_payment.add_unreconcile_btn(frm);
|
||||
|
||||
$.each(frm.doc.accounts || [], function (i, row) {
|
||||
erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
|
||||
});
|
||||
},
|
||||
before_save: function (frm) {
|
||||
if (frm.doc.docstatus == 0 && !frm.doc.is_system_generated) {
|
||||
|
||||
@@ -1774,7 +1774,7 @@ def get_exchange_rate(
|
||||
|
||||
# The date used to retreive the exchange rate here is the date passed
|
||||
# in as an argument to this function.
|
||||
elif (not flt(exchange_rate) or flt(exchange_rate) == 1) and account_currency and posting_date:
|
||||
elif (not exchange_rate or flt(exchange_rate) == 1) and account_currency and posting_date:
|
||||
exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
|
||||
else:
|
||||
exchange_rate = 1
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"fieldname": "account_currency",
|
||||
"fieldtype": "Link",
|
||||
"label": "Account Currency",
|
||||
"no_copy": 1,
|
||||
"options": "Currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
@@ -270,8 +271,7 @@
|
||||
"label": "Advance Voucher Type",
|
||||
"no_copy": 1,
|
||||
"options": "DocType",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "advance_voucher_no",
|
||||
@@ -279,14 +279,13 @@
|
||||
"label": "Advance Voucher No",
|
||||
"no_copy": 1,
|
||||
"options": "advance_voucher_type",
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-10-27 13:48:32.805100",
|
||||
"modified": "2025-09-29 13:01:48.916517",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Journal Entry Account",
|
||||
|
||||
@@ -577,8 +577,6 @@ frappe.ui.form.on("Payment Entry", {
|
||||
paid_from: function (frm) {
|
||||
if (frm.set_party_account_based_on_party) return;
|
||||
|
||||
frm.events.set_company_bank_account(frm);
|
||||
|
||||
frm.events.set_account_currency_and_balance(
|
||||
frm,
|
||||
frm.doc.paid_from,
|
||||
@@ -595,8 +593,6 @@ frappe.ui.form.on("Payment Entry", {
|
||||
paid_to: function (frm) {
|
||||
if (frm.set_party_account_based_on_party) return;
|
||||
|
||||
frm.events.set_company_bank_account(frm);
|
||||
|
||||
frm.events.set_account_currency_and_balance(
|
||||
frm,
|
||||
frm.doc.paid_to,
|
||||
@@ -1329,8 +1325,6 @@ frappe.ui.form.on("Payment Entry", {
|
||||
},
|
||||
|
||||
bank_account: function (frm) {
|
||||
if (frm.set_company_bank_account_based_on_coa) return;
|
||||
|
||||
const field = frm.doc.payment_type == "Pay" ? "paid_from" : "paid_to";
|
||||
if (frm.doc.bank_account && ["Pay", "Receive"].includes(frm.doc.payment_type)) {
|
||||
frappe.call({
|
||||
@@ -1369,34 +1363,6 @@ frappe.ui.form.on("Payment Entry", {
|
||||
}
|
||||
},
|
||||
|
||||
set_company_bank_account: function (frm) {
|
||||
if (!["Pay", "Receive"].includes(frm.doc.payment_type)) return;
|
||||
|
||||
const field = frm.doc.payment_type == "Pay" ? "paid_from" : "paid_to";
|
||||
|
||||
if (!frm.doc.company || !frm.doc[field]) return;
|
||||
|
||||
frm.set_company_bank_account_based_on_coa = true;
|
||||
|
||||
frappe.call({
|
||||
method: "frappe.client.get_value",
|
||||
args: {
|
||||
doctype: "Bank Account",
|
||||
filters: {
|
||||
company: frm.doc.company,
|
||||
account: frm.doc[field],
|
||||
disabled: 0,
|
||||
},
|
||||
fieldname: ["name"],
|
||||
},
|
||||
callback: async function (r) {
|
||||
if (r.message) await frm.set_value("bank_account", r.message.name);
|
||||
|
||||
frm.set_company_bank_account_based_on_coa = false;
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
sales_taxes_and_charges_template: function (frm) {
|
||||
frm.trigger("fetch_taxes_from_template");
|
||||
},
|
||||
@@ -1455,6 +1421,7 @@ frappe.ui.form.on("Payment Entry", {
|
||||
$.each(frm.doc["taxes"] || [], function (i, tax) {
|
||||
frm.events.validate_taxes_and_charges(tax);
|
||||
frm.events.validate_inclusive_tax(tax);
|
||||
tax.item_wise_tax_detail = {};
|
||||
let tax_fields = [
|
||||
"total",
|
||||
"tax_fraction_for_current_item",
|
||||
|
||||
@@ -1437,7 +1437,6 @@ class PaymentEntry(AccountsController):
|
||||
else allocated_amount_in_company_currency / self.transaction_exchange_rate,
|
||||
"advance_voucher_type": d.advance_voucher_type,
|
||||
"advance_voucher_no": d.advance_voucher_no,
|
||||
"transaction_exchange_rate": self.target_exchange_rate,
|
||||
},
|
||||
item=self,
|
||||
)
|
||||
|
||||
@@ -61,22 +61,6 @@ erpnext.accounts.PaymentReconciliationController = class PaymentReconciliationCo
|
||||
},
|
||||
};
|
||||
});
|
||||
this.frm.set_query("cost_center", "payments", () => {
|
||||
return {
|
||||
filters: {
|
||||
company: this.frm.doc.company,
|
||||
is_group: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
this.frm.set_query("cost_center", "allocation", () => {
|
||||
return {
|
||||
filters: {
|
||||
company: this.frm.doc.company,
|
||||
is_group: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
refresh() {
|
||||
@@ -401,16 +385,6 @@ frappe.ui.form.on("Payment Reconciliation Allocation", {
|
||||
// filter payment
|
||||
let payment = frm.doc.payments.filter((x) => x.reference_name == row.reference_name);
|
||||
|
||||
let amount = payment[0].amount;
|
||||
for (const d of frm.doc.allocation) {
|
||||
if (row.reference_name == d.reference_name && amount) {
|
||||
if (d.allocated_amount <= amount) {
|
||||
d.amount = amount;
|
||||
amount -= d.allocated_amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frm.call({
|
||||
doc: frm.doc,
|
||||
method: "calculate_difference_on_allocation_change",
|
||||
|
||||
@@ -72,7 +72,7 @@ class PaymentReconciliation(Document):
|
||||
self.common_filter_conditions = []
|
||||
self.accounting_dimension_filter_conditions = []
|
||||
self.ple_posting_date_filter = []
|
||||
self.dimensions = get_dimensions(with_cost_center_and_project=True)[0]
|
||||
self.dimensions = get_dimensions()[0]
|
||||
|
||||
def load_from_db(self):
|
||||
# 'modified' attribute is required for `run_doc_method` to work properly.
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
frappe.ui.form.on("Period Closing Voucher", {
|
||||
onload: function (frm) {
|
||||
if (!frm.doc.transaction_date) frm.doc.transaction_date = frappe.datetime.obj_to_str(new Date());
|
||||
|
||||
frm.ignore_doctypes_on_cancel_all = ["Process Period Closing Voucher"];
|
||||
},
|
||||
|
||||
setup: function (frm) {
|
||||
|
||||
@@ -132,11 +132,7 @@ class PeriodClosingVoucher(AccountsController):
|
||||
|
||||
def on_submit(self):
|
||||
self.db_set("gle_processing_status", "In Progress")
|
||||
if frappe.get_single_value("Accounts Settings", "use_legacy_controller_for_pcv"):
|
||||
self.make_gl_entries()
|
||||
else:
|
||||
ppcv = frappe.get_doc({"doctype": "Process Period Closing Voucher", "parent_pcv": self.name})
|
||||
ppcv.save().submit()
|
||||
self.make_gl_entries()
|
||||
|
||||
def on_cancel(self):
|
||||
self.ignore_linked_doctypes = (
|
||||
@@ -144,29 +140,11 @@ class PeriodClosingVoucher(AccountsController):
|
||||
"Stock Ledger Entry",
|
||||
"Payment Ledger Entry",
|
||||
"Account Closing Balance",
|
||||
"Process Period Closing Voucher",
|
||||
)
|
||||
self.block_if_future_closing_voucher_exists()
|
||||
|
||||
if not frappe.get_single_value("Accounts Settings", "use_legacy_controller_for_pcv"):
|
||||
self.cancel_process_pcv_docs()
|
||||
|
||||
self.db_set("gle_processing_status", "In Progress")
|
||||
self.cancel_gl_entries()
|
||||
|
||||
def cancel_process_pcv_docs(self):
|
||||
ppcvs = frappe.db.get_all("Process Period Closing Voucher", {"parent_pcv": self.name, "docstatus": 1})
|
||||
for x in ppcvs:
|
||||
frappe.get_doc("Process Period Closing Voucher", x.name).cancel()
|
||||
|
||||
def on_trash(self):
|
||||
super().on_trash()
|
||||
ppcvs = frappe.db.get_all(
|
||||
"Process Period Closing Voucher", {"parent_pcv": self.name, "docstatus": ["in", [1, 2]]}
|
||||
)
|
||||
for x in ppcvs:
|
||||
frappe.delete_doc("Process Period Closing Voucher", x.name, force=True, ignore_permissions=True)
|
||||
|
||||
def make_gl_entries(self):
|
||||
if frappe.db.estimate_count("GL Entry") > 100_000:
|
||||
frappe.enqueue(
|
||||
@@ -475,15 +453,8 @@ def process_gl_and_closing_entries(doc):
|
||||
frappe.db.set_value(doc.doctype, doc.name, "gle_processing_status", "Completed")
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(title=_("Period Closing Voucher {0} GL Entry Processing Failed").format(doc.name))
|
||||
frappe.db.set_value(
|
||||
doc.doctype,
|
||||
doc.name,
|
||||
{
|
||||
"error_message": str(e),
|
||||
"gle_processing_status": "Failed",
|
||||
},
|
||||
)
|
||||
frappe.log_error(e)
|
||||
frappe.db.set_value(doc.doctype, doc.name, "gle_processing_status", "Failed")
|
||||
|
||||
|
||||
def process_cancellation(voucher_type, voucher_no):
|
||||
@@ -495,17 +466,8 @@ def process_cancellation(voucher_type, voucher_no):
|
||||
frappe.db.set_value("Period Closing Voucher", voucher_no, "gle_processing_status", "Completed")
|
||||
except Exception as e:
|
||||
frappe.db.rollback()
|
||||
frappe.log_error(
|
||||
title=_("Period Closing Voucher {0} GL Entry Cancellation Failed").format(voucher_no)
|
||||
)
|
||||
frappe.db.set_value(
|
||||
voucher_type,
|
||||
voucher_no,
|
||||
{
|
||||
"error_message": str(e),
|
||||
"gle_processing_status": "Failed",
|
||||
},
|
||||
)
|
||||
frappe.log_error(e)
|
||||
frappe.db.set_value("Period Closing Voucher", voucher_no, "gle_processing_status", "Failed")
|
||||
|
||||
|
||||
def delete_closing_entries(voucher_no):
|
||||
|
||||
@@ -13,10 +13,6 @@ from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
|
||||
class TestPeriodClosingVoucher(IntegrationTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
frappe.db.set_single_value("Accounts Settings", "use_legacy_controller_for_pcv", 1)
|
||||
|
||||
def test_closing_entry(self):
|
||||
frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
|
||||
frappe.db.sql("delete from `tabPeriod Closing Voucher` where company='Test PCV Company'")
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
"taxes",
|
||||
"sec_tax_breakup",
|
||||
"other_charges_calculation",
|
||||
"item_wise_tax_details",
|
||||
"section_break_43",
|
||||
"base_total_taxes_and_charges",
|
||||
"column_break_47",
|
||||
@@ -1603,14 +1602,6 @@
|
||||
"fieldtype": "Data",
|
||||
"is_virtual": 1,
|
||||
"label": "Last Scanned Warehouse"
|
||||
},
|
||||
{
|
||||
"fieldname": "item_wise_tax_details",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Item Wise Tax Details",
|
||||
"no_copy": 1,
|
||||
"options": "Item Wise Tax Detail"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
|
||||
@@ -31,7 +31,6 @@ class POSInvoice(SalesInvoice):
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
from erpnext.accounts.doctype.item_wise_tax_detail.item_wise_tax_detail import ItemWiseTaxDetail
|
||||
from erpnext.accounts.doctype.payment_schedule.payment_schedule import PaymentSchedule
|
||||
from erpnext.accounts.doctype.pos_invoice_item.pos_invoice_item import POSInvoiceItem
|
||||
from erpnext.accounts.doctype.pricing_rule_detail.pricing_rule_detail import PricingRuleDetail
|
||||
@@ -100,7 +99,6 @@ class POSInvoice(SalesInvoice):
|
||||
is_opening: DF.Literal["No", "Yes"]
|
||||
is_pos: DF.Check
|
||||
is_return: DF.Check
|
||||
item_wise_tax_details: DF.Table[ItemWiseTaxDetail]
|
||||
items: DF.Table[POSInvoiceItem]
|
||||
language: DF.Data | None
|
||||
letter_head: DF.Link | None
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
"oldfieldname": "description",
|
||||
"oldfieldtype": "Text",
|
||||
"print_width": "200px",
|
||||
"reqd": 1,
|
||||
"width": "200px"
|
||||
},
|
||||
{
|
||||
@@ -857,15 +858,14 @@
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-11-12 18:11:11.818015",
|
||||
"modified": "2024-05-07 15:56:53.343317",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Invoice Item",
|
||||
"naming_rule": "Random",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class POSInvoiceItem(SalesInvoiceItem):
|
||||
delivered_by_supplier: DF.Check
|
||||
delivered_qty: DF.Float
|
||||
delivery_note: DF.Link | None
|
||||
description: DF.TextEditor | None
|
||||
description: DF.TextEditor
|
||||
discount_amount: DF.Currency
|
||||
discount_percentage: DF.Percent
|
||||
distributed_discount_amount: DF.Currency
|
||||
|
||||
@@ -17,6 +17,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_checks_for_pl_and_bs_accounts,
|
||||
)
|
||||
from erpnext.controllers.sales_and_purchase_return import get_sales_invoice_item_from_consolidated_invoice
|
||||
from erpnext.controllers.taxes_and_totals import ItemWiseTaxDetail
|
||||
|
||||
|
||||
class POSInvoiceMergeLog(Document):
|
||||
@@ -155,6 +156,7 @@ class POSInvoiceMergeLog(Document):
|
||||
|
||||
sales_invoice.save()
|
||||
sales_invoice.submit()
|
||||
|
||||
self.consolidated_invoice = sales_invoice.name
|
||||
|
||||
return sales_invoice
|
||||
@@ -205,7 +207,7 @@ class POSInvoiceMergeLog(Document):
|
||||
return return_invoices
|
||||
|
||||
def merge_pos_invoice_into(self, invoice, data):
|
||||
items, payments, taxes, item_tax_details = [], [], [], []
|
||||
items, payments, taxes = [], [], []
|
||||
|
||||
loyalty_amount_sum, loyalty_points_sum = 0, 0
|
||||
|
||||
@@ -215,8 +217,6 @@ class POSInvoiceMergeLog(Document):
|
||||
loyalty_amount_sum, loyalty_points_sum, idx = 0, 0, 1
|
||||
|
||||
for doc in data:
|
||||
old_new_item_map = frappe._dict()
|
||||
old_new_tax_map = frappe._dict()
|
||||
map_doc(doc, invoice, table_map={"doctype": invoice.doctype})
|
||||
|
||||
if doc.get("posting_date"):
|
||||
@@ -244,7 +244,6 @@ class POSInvoiceMergeLog(Document):
|
||||
if item.serial_and_batch_bundle:
|
||||
si_item.serial_and_batch_bundle = item.serial_and_batch_bundle
|
||||
items.append(si_item)
|
||||
old_new_item_map[item.name] = si_item
|
||||
|
||||
for tax in doc.get("taxes"):
|
||||
found = False
|
||||
@@ -254,7 +253,7 @@ class POSInvoiceMergeLog(Document):
|
||||
t.base_tax_amount = flt(t.base_tax_amount) + flt(
|
||||
tax.base_tax_amount_after_discount_amount
|
||||
)
|
||||
old_new_tax_map[tax.name] = t
|
||||
update_item_wise_tax_detail(t, tax)
|
||||
found = True
|
||||
if not found:
|
||||
tax.charge_type = "Actual"
|
||||
@@ -264,9 +263,8 @@ class POSInvoiceMergeLog(Document):
|
||||
tax.included_in_print_rate = 0
|
||||
tax.tax_amount = tax.tax_amount_after_discount_amount
|
||||
tax.base_tax_amount = tax.base_tax_amount_after_discount_amount
|
||||
tax.dont_recompute_tax = 1
|
||||
tax.item_wise_tax_detail = tax.item_wise_tax_detail
|
||||
taxes.append(tax)
|
||||
old_new_tax_map[tax.name] = tax
|
||||
|
||||
for payment in doc.get("payments"):
|
||||
found = False
|
||||
@@ -283,16 +281,6 @@ class POSInvoiceMergeLog(Document):
|
||||
base_rounding_adjustment += doc.base_rounding_adjustment
|
||||
base_rounded_total += doc.base_rounded_total
|
||||
|
||||
for d in doc.get("item_wise_tax_details"):
|
||||
row = frappe._dict(
|
||||
item=old_new_item_map[d.item_row],
|
||||
tax=old_new_tax_map[d.tax_row],
|
||||
amount=d.amount,
|
||||
rate=d.rate,
|
||||
taxable_amount=d.taxable_amount,
|
||||
)
|
||||
item_tax_details.append(row)
|
||||
|
||||
if loyalty_points_sum:
|
||||
invoice.redeem_loyalty_points = 1
|
||||
invoice.loyalty_points = loyalty_points_sum
|
||||
@@ -354,7 +342,6 @@ class POSInvoiceMergeLog(Document):
|
||||
invoice.set("sales_partner", None)
|
||||
invoice.set("commission_rate", 0)
|
||||
invoice.set("total_commission", 0)
|
||||
invoice._item_wise_tax_details = item_tax_details
|
||||
|
||||
return invoice
|
||||
|
||||
@@ -432,6 +419,24 @@ class POSInvoiceMergeLog(Document):
|
||||
si.cancel()
|
||||
|
||||
|
||||
def update_item_wise_tax_detail(consolidate_tax_row, tax_row):
|
||||
consolidated_tax_detail = json.loads(consolidate_tax_row.item_wise_tax_detail)
|
||||
tax_row_detail = json.loads(tax_row.item_wise_tax_detail)
|
||||
|
||||
if not consolidated_tax_detail:
|
||||
consolidated_tax_detail = {}
|
||||
|
||||
for item_code, tax_data in tax_row_detail.items():
|
||||
tax_data = ItemWiseTaxDetail(**tax_data)
|
||||
if consolidated_tax_detail.get(item_code):
|
||||
consolidated_tax_detail[item_code]["tax_amount"] += tax_data.tax_amount
|
||||
consolidated_tax_detail[item_code]["net_amount"] += tax_data.net_amount
|
||||
else:
|
||||
consolidated_tax_detail.update({item_code: tax_data})
|
||||
|
||||
consolidate_tax_row.item_wise_tax_detail = json.dumps(consolidated_tax_detail)
|
||||
|
||||
|
||||
def get_all_unconsolidated_invoices():
|
||||
filters = {
|
||||
"consolidated_invoice": ["in", ["", None]],
|
||||
|
||||
@@ -164,36 +164,20 @@ class TestPOSInvoiceMergeLog(IntegrationTestCase):
|
||||
inv.load_from_db()
|
||||
|
||||
consolidated_invoice = frappe.get_doc("Sales Invoice", inv.consolidated_invoice)
|
||||
|
||||
expected_item_wise_tax_details = [
|
||||
{
|
||||
"item_row": consolidated_invoice.items[0].name,
|
||||
"tax_row": consolidated_invoice.taxes[0].name,
|
||||
"rate": 9.0,
|
||||
"amount": 9.0,
|
||||
"taxable_amount": 100.0,
|
||||
item_wise_tax_detail = json.loads(consolidated_invoice.get("taxes")[0].item_wise_tax_detail)
|
||||
expected_item_wise_tax_detail = {
|
||||
"_Test Item": {
|
||||
"tax_rate": 9,
|
||||
"tax_amount": 9,
|
||||
"net_amount": 100,
|
||||
},
|
||||
{
|
||||
"item_row": consolidated_invoice.items[1].name,
|
||||
"tax_row": consolidated_invoice.taxes[0].name,
|
||||
"rate": 5.0,
|
||||
"amount": 5.0,
|
||||
"taxable_amount": 100.0,
|
||||
"_Test Item 2": {
|
||||
"tax_rate": 5,
|
||||
"tax_amount": 5,
|
||||
"net_amount": 100,
|
||||
},
|
||||
]
|
||||
|
||||
actual = [
|
||||
{
|
||||
"item_row": d.item_row,
|
||||
"tax_row": d.tax_row,
|
||||
"rate": d.rate,
|
||||
"amount": d.amount,
|
||||
"taxable_amount": d.taxable_amount,
|
||||
}
|
||||
for d in consolidated_invoice.get("item_wise_tax_details")
|
||||
]
|
||||
|
||||
self.assertEqual(actual, expected_item_wise_tax_details)
|
||||
}
|
||||
self.assertEqual(item_wise_tax_detail, expected_item_wise_tax_detail)
|
||||
|
||||
def test_consolidation_round_off_error_1(self):
|
||||
"""
|
||||
|
||||
@@ -43,19 +43,9 @@ class POSOpeningEntry(StatusUpdater):
|
||||
self.set_status()
|
||||
|
||||
def validate_pos_profile_and_cashier(self):
|
||||
if not frappe.db.exists("POS Profile", self.pos_profile):
|
||||
frappe.throw(_("POS Profile {} does not exist.").format(self.pos_profile))
|
||||
|
||||
pos_profile_company, pos_profile_disabled = frappe.db.get_value(
|
||||
"POS Profile", self.pos_profile, ["company", "disabled"]
|
||||
)
|
||||
|
||||
if pos_profile_disabled:
|
||||
frappe.throw(_("POS Profile {} is disabled.").format(frappe.bold(self.pos_profile)))
|
||||
|
||||
if self.company != pos_profile_company:
|
||||
if self.company != frappe.db.get_value("POS Profile", self.pos_profile, "company"):
|
||||
frappe.throw(
|
||||
_("POS Profile {} does not belong to company {}").format(self.pos_profile, self.company)
|
||||
_("POS Profile {} does not belongs to company {}").format(self.pos_profile, self.company)
|
||||
)
|
||||
|
||||
if not cint(frappe.db.get_value("User", self.user, "enabled")):
|
||||
|
||||
@@ -40,12 +40,6 @@ class TestPOSOpeningEntry(IntegrationTestCase):
|
||||
self.assertEqual(opening_entry.status, "Open")
|
||||
self.assertNotEqual(opening_entry.docstatus, 0)
|
||||
|
||||
def test_pos_opening_entry_on_disabled_pos(self):
|
||||
test_user, pos_profile = self.init_user_and_profile(disabled=1)
|
||||
|
||||
with self.assertRaises(frappe.ValidationError):
|
||||
create_opening_entry(pos_profile, test_user.name)
|
||||
|
||||
def test_multiple_pos_opening_entries_for_same_pos_profile(self):
|
||||
test_user, pos_profile = self.init_user_and_profile()
|
||||
opening_entry = create_opening_entry(pos_profile, test_user.name)
|
||||
|
||||
@@ -75,7 +75,6 @@ class POSProfile(Document):
|
||||
# end: auto-generated types
|
||||
|
||||
def validate(self):
|
||||
self.validate_disabled()
|
||||
self.validate_default_profile()
|
||||
self.validate_all_link_fields()
|
||||
self.validate_duplicate_groups()
|
||||
@@ -100,21 +99,6 @@ class POSProfile(Document):
|
||||
title=_("Mandatory Accounting Dimension"),
|
||||
)
|
||||
|
||||
def validate_disabled(self):
|
||||
old_doc = self.get_doc_before_save()
|
||||
|
||||
if (
|
||||
old_doc
|
||||
and self.disabled
|
||||
and old_doc.disabled != self.disabled
|
||||
and frappe.db.exists("POS Opening Entry", {"pos_profile": self.name, "status": "Open"})
|
||||
):
|
||||
frappe.throw(
|
||||
_("POS Profile {0} cannot be disabled as there are ongoing POS sessions.").format(
|
||||
frappe.bold(self.name)
|
||||
)
|
||||
)
|
||||
|
||||
def validate_default_profile(self):
|
||||
for row in self.applicable_for_users:
|
||||
res = frappe.db.sql(
|
||||
|
||||
@@ -4,7 +4,6 @@ import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.tests import IntegrationTestCase
|
||||
from frappe.utils import cint
|
||||
|
||||
from erpnext.accounts.doctype.pos_profile.pos_profile import (
|
||||
get_child_nodes,
|
||||
@@ -39,50 +38,6 @@ class TestPOSProfile(IntegrationTestCase):
|
||||
|
||||
frappe.db.sql("delete from `tabPOS Profile`")
|
||||
|
||||
def test_disabled_pos_profile_creation(self):
|
||||
make_pos_profile(name="_Test POS Profile 001", disabled=1)
|
||||
|
||||
pos_profile = frappe.get_doc("POS Profile", "_Test POS Profile 001")
|
||||
|
||||
if pos_profile:
|
||||
self.assertEqual(pos_profile.disabled, 1)
|
||||
|
||||
def test_disabled_pos_profile_after_opening(self):
|
||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||
from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry
|
||||
|
||||
test_user, pos_profile = init_user_and_profile()
|
||||
|
||||
if pos_profile:
|
||||
create_opening_entry(pos_profile, test_user.name)
|
||||
self.assertEqual(pos_profile.disabled, 0)
|
||||
|
||||
pos_profile.disabled = 1
|
||||
self.assertRaises(frappe.ValidationError, pos_profile.save)
|
||||
|
||||
def test_disabled_pos_profile_after_completing_session(self):
|
||||
from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import (
|
||||
make_closing_entry_from_opening,
|
||||
)
|
||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||
from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import (
|
||||
create_opening_entry,
|
||||
)
|
||||
|
||||
test_user, pos_profile = init_user_and_profile()
|
||||
|
||||
if pos_profile:
|
||||
opening_entry = create_opening_entry(pos_profile, test_user.name)
|
||||
|
||||
closing_entry = make_closing_entry_from_opening(opening_entry)
|
||||
closing_entry.submit()
|
||||
|
||||
pos_profile.disabled = 1
|
||||
pos_profile.save()
|
||||
pos_profile.reload()
|
||||
|
||||
self.assertEqual(pos_profile.disabled, 1)
|
||||
|
||||
|
||||
def get_customers_list(pos_profile=None):
|
||||
if pos_profile is None:
|
||||
@@ -162,7 +117,6 @@ def make_pos_profile(**args):
|
||||
"write_off_account": args.write_off_account or "_Test Write Off - _TC",
|
||||
"write_off_cost_center": args.write_off_cost_center or "_Test Write Off Cost Center - _TC",
|
||||
"location": "Block 1" if not args.do_not_set_accounting_dimension else None,
|
||||
"disabled": cint(args.disabled) or 0,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on("Process Period Closing Voucher", {
|
||||
refresh(frm) {
|
||||
if (frm.doc.docstatus == 1 && ["Queued"].find((x) => x == frm.doc.status)) {
|
||||
let execute_btn = __("Start");
|
||||
|
||||
frm.add_custom_button(execute_btn, () => {
|
||||
frm.call({
|
||||
method: "erpnext.accounts.doctype.process_period_closing_voucher.process_period_closing_voucher.start_pcv_processing",
|
||||
args: {
|
||||
docname: frm.doc.name,
|
||||
},
|
||||
}).then((r) => {
|
||||
if (!r.exc) {
|
||||
frappe.show_alert(__("Job Started"));
|
||||
frm.reload_doc();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus == 1 && ["Running"].find((x) => x == frm.doc.status)) {
|
||||
let execute_btn = __("Pause");
|
||||
|
||||
frm.add_custom_button(execute_btn, () => {
|
||||
frm.call({
|
||||
method: "erpnext.accounts.doctype.process_period_closing_voucher.process_period_closing_voucher.pause_pcv_processing",
|
||||
args: {
|
||||
docname: frm.doc.name,
|
||||
},
|
||||
}).then((r) => {
|
||||
if (!r.exc) {
|
||||
frappe.show_alert(__("PCV Paused"));
|
||||
frm.reload_doc();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (frm.doc.docstatus == 1 && ["Paused"].find((x) => x == frm.doc.status)) {
|
||||
let execute_btn = __("Resume");
|
||||
|
||||
frm.add_custom_button(execute_btn, () => {
|
||||
frm.call({
|
||||
method: "erpnext.accounts.doctype.process_period_closing_voucher.process_period_closing_voucher.resume_pcv_processing",
|
||||
args: {
|
||||
docname: frm.doc.name,
|
||||
},
|
||||
}).then((r) => {
|
||||
if (!r.exc) {
|
||||
frappe.show_alert(__("PCV Resumed"));
|
||||
frm.reload_doc();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// progress bar
|
||||
let progress = 0;
|
||||
|
||||
let normal_finished = frm.doc.normal_balances.filter((x) => x.status == "Completed").length;
|
||||
let opening_finished = frm.doc.z_opening_balances.filter((x) => x.status == "Completed").length;
|
||||
|
||||
progress =
|
||||
((normal_finished + opening_finished) /
|
||||
(frm.doc.normal_balances.length + frm.doc.z_opening_balances.length)) *
|
||||
100;
|
||||
frm.dashboard.add_progress("Books closure progress", progress, "");
|
||||
},
|
||||
});
|
||||
@@ -1,113 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format:Process-PCV-{###}",
|
||||
"creation": "2025-09-25 15:44:03.534699",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"parent_pcv",
|
||||
"status",
|
||||
"p_l_closing_balance",
|
||||
"normal_balances",
|
||||
"bs_closing_balance",
|
||||
"z_opening_balances",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "parent_pcv",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "PCV",
|
||||
"options": "Period Closing Voucher",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "Queued",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"no_copy": 1,
|
||||
"options": "Queued\nRunning\nPaused\nCompleted\nCancelled"
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Process Period Closing Voucher",
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "p_l_closing_balance",
|
||||
"fieldtype": "JSON",
|
||||
"label": "P&L Closing Balance",
|
||||
"no_copy": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "normal_balances",
|
||||
"fieldtype": "Table",
|
||||
"label": "Dates to Process",
|
||||
"no_copy": 1,
|
||||
"options": "Process Period Closing Voucher Detail"
|
||||
},
|
||||
{
|
||||
"fieldname": "z_opening_balances",
|
||||
"fieldtype": "Table",
|
||||
"label": "Opening Balances",
|
||||
"no_copy": 1,
|
||||
"options": "Process Period Closing Voucher Detail"
|
||||
},
|
||||
{
|
||||
"fieldname": "bs_closing_balance",
|
||||
"fieldtype": "JSON",
|
||||
"label": "Balance Sheet Closing Balance"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-11-05 11:40:24.996403",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Process Period Closing Voucher",
|
||||
"naming_rule": "Expression",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
@@ -1,559 +0,0 @@
|
||||
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import copy
|
||||
from datetime import timedelta
|
||||
|
||||
import frappe
|
||||
from frappe import qb
|
||||
from frappe.model.document import Document
|
||||
from frappe.query_builder.functions import Count, Max, Min, Sum
|
||||
from frappe.utils import add_days, flt, get_datetime
|
||||
from frappe.utils.scheduler import is_scheduler_inactive
|
||||
|
||||
from erpnext.accounts.doctype.account_closing_balance.account_closing_balance import (
|
||||
make_closing_entries,
|
||||
)
|
||||
|
||||
|
||||
class ProcessPeriodClosingVoucher(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.process_period_closing_voucher_detail.process_period_closing_voucher_detail import (
|
||||
ProcessPeriodClosingVoucherDetail,
|
||||
)
|
||||
|
||||
amended_from: DF.Link | None
|
||||
bs_closing_balance: DF.JSON | None
|
||||
normal_balances: DF.Table[ProcessPeriodClosingVoucherDetail]
|
||||
p_l_closing_balance: DF.JSON | None
|
||||
parent_pcv: DF.Link
|
||||
status: DF.Literal["Queued", "Running", "Paused", "Completed", "Cancelled"]
|
||||
z_opening_balances: DF.Table[ProcessPeriodClosingVoucherDetail]
|
||||
# end: auto-generated types
|
||||
|
||||
def validate(self):
|
||||
self.status = "Queued"
|
||||
self.populate_processing_tables()
|
||||
|
||||
def populate_processing_tables(self):
|
||||
self.generate_pcv_dates()
|
||||
self.generate_opening_balances_dates()
|
||||
|
||||
def get_dates(self, start, end):
|
||||
return [start + timedelta(days=x) for x in range((end - start).days + 1)]
|
||||
|
||||
def generate_pcv_dates(self):
|
||||
self.normal_balances = []
|
||||
pcv = frappe.get_doc("Period Closing Voucher", self.parent_pcv)
|
||||
|
||||
dates = self.get_dates(get_datetime(pcv.period_start_date), get_datetime(pcv.period_end_date))
|
||||
for x in dates:
|
||||
self.append(
|
||||
"normal_balances",
|
||||
{"processing_date": x, "status": "Queued", "report_type": "Profit and Loss"},
|
||||
)
|
||||
self.append(
|
||||
"normal_balances", {"processing_date": x, "status": "Queued", "report_type": "Balance Sheet"}
|
||||
)
|
||||
|
||||
def generate_opening_balances_dates(self):
|
||||
self.z_opening_balances = []
|
||||
|
||||
pcv = frappe.get_doc("Period Closing Voucher", self.parent_pcv)
|
||||
if pcv.is_first_period_closing_voucher():
|
||||
gl = qb.DocType("GL Entry")
|
||||
min = qb.from_(gl).select(Min(gl.posting_date)).where(gl.company.eq(pcv.company)).run()[0][0]
|
||||
max = qb.from_(gl).select(Max(gl.posting_date)).where(gl.company.eq(pcv.company)).run()[0][0]
|
||||
|
||||
dates = self.get_dates(get_datetime(min), get_datetime(max))
|
||||
for x in dates:
|
||||
self.append(
|
||||
"z_opening_balances",
|
||||
{"processing_date": x, "status": "Queued", "report_type": "Balance Sheet"},
|
||||
)
|
||||
|
||||
def on_submit(self):
|
||||
start_pcv_processing(self.name)
|
||||
|
||||
def on_cancel(self):
|
||||
cancel_pcv_processing(self.name)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def start_pcv_processing(docname: str):
|
||||
if frappe.db.get_value("Process Period Closing Voucher", docname, "status") in ["Queued", "Running"]:
|
||||
frappe.db.set_value("Process Period Closing Voucher", docname, "status", "Running")
|
||||
if normal_balances := frappe.db.get_all(
|
||||
"Process Period Closing Voucher Detail",
|
||||
filters={"parent": docname, "status": "Queued"},
|
||||
fields=["processing_date", "report_type", "parentfield"],
|
||||
order_by="parentfield, idx, processing_date",
|
||||
limit=4,
|
||||
):
|
||||
if not is_scheduler_inactive():
|
||||
for x in normal_balances:
|
||||
frappe.db.set_value(
|
||||
"Process Period Closing Voucher Detail",
|
||||
{
|
||||
"processing_date": x.processing_date,
|
||||
"parent": docname,
|
||||
"report_type": x.report_type,
|
||||
"parentfield": x.parentfield,
|
||||
},
|
||||
"status",
|
||||
"Running",
|
||||
)
|
||||
frappe.enqueue(
|
||||
method="erpnext.accounts.doctype.process_period_closing_voucher.process_period_closing_voucher.process_individual_date",
|
||||
queue="long",
|
||||
timeout="3600",
|
||||
is_async=True,
|
||||
enqueue_after_commit=True,
|
||||
docname=docname,
|
||||
date=x.processing_date,
|
||||
report_type=x.report_type,
|
||||
parentfield=x.parentfield,
|
||||
)
|
||||
else:
|
||||
frappe.db.set_value("Process Period Closing Voucher", docname, "status", "Completed")
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def pause_pcv_processing(docname: str):
|
||||
ppcv = qb.DocType("Process Period Closing Voucher")
|
||||
qb.update(ppcv).set(ppcv.status, "Paused").where(ppcv.name.eq(docname)).run()
|
||||
|
||||
if queued_dates := frappe.db.get_all(
|
||||
"Process Period Closing Voucher Detail",
|
||||
filters={"parent": docname, "status": "Queued"},
|
||||
pluck="name",
|
||||
):
|
||||
ppcvd = qb.DocType("Process Period Closing Voucher Detail")
|
||||
qb.update(ppcvd).set(ppcvd.status, "Paused").where(ppcvd.name.isin(queued_dates)).run()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def cancel_pcv_processing(docname: str):
|
||||
ppcv = qb.DocType("Process Period Closing Voucher")
|
||||
qb.update(ppcv).set(ppcv.status, "Cancelled").where(ppcv.name.eq(docname)).run()
|
||||
|
||||
if queued_dates := frappe.db.get_all(
|
||||
"Process Period Closing Voucher Detail",
|
||||
filters={"parent": docname, "status": "Queued"},
|
||||
pluck="name",
|
||||
):
|
||||
ppcvd = qb.DocType("Process Period Closing Voucher Detail")
|
||||
qb.update(ppcvd).set(ppcvd.status, "Cancelled").where(ppcvd.name.isin(queued_dates)).run()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def resume_pcv_processing(docname: str):
|
||||
ppcv = qb.DocType("Process Period Closing Voucher")
|
||||
qb.update(ppcv).set(ppcv.status, "Running").where(ppcv.name.eq(docname)).run()
|
||||
|
||||
if paused_dates := frappe.db.get_all(
|
||||
"Process Period Closing Voucher Detail",
|
||||
filters={"parent": docname, "status": "Paused"},
|
||||
pluck="name",
|
||||
):
|
||||
ppcvd = qb.DocType("Process Period Closing Voucher Detail")
|
||||
qb.update(ppcvd).set(ppcvd.status, "Queued").where(ppcvd.name.isin(paused_dates)).run()
|
||||
start_pcv_processing(docname)
|
||||
|
||||
|
||||
def update_default_dimensions(dimension_fields, gl_entry, dimension_values):
|
||||
for i, dimension in enumerate(dimension_fields):
|
||||
gl_entry[dimension] = dimension_values[i]
|
||||
|
||||
|
||||
def get_gle_for_pl_account(pcv, acc, balances, dimensions):
|
||||
balance_in_account_currency = flt(balances.debit_in_account_currency) - flt(
|
||||
balances.credit_in_account_currency
|
||||
)
|
||||
balance_in_company_currency = flt(balances.debit) - flt(balances.credit)
|
||||
gl_entry = frappe._dict(
|
||||
{
|
||||
"company": pcv.company,
|
||||
"posting_date": pcv.period_end_date,
|
||||
"account": acc,
|
||||
"account_currency": balances.account_currency,
|
||||
"debit_in_account_currency": abs(balance_in_account_currency)
|
||||
if balance_in_account_currency < 0
|
||||
else 0,
|
||||
"debit": abs(balance_in_company_currency) if balance_in_company_currency < 0 else 0,
|
||||
"credit_in_account_currency": abs(balance_in_account_currency)
|
||||
if balance_in_account_currency > 0
|
||||
else 0,
|
||||
"credit": abs(balance_in_company_currency) if balance_in_company_currency > 0 else 0,
|
||||
"is_period_closing_voucher_entry": 1,
|
||||
"voucher_type": "Period Closing Voucher",
|
||||
"voucher_no": pcv.name,
|
||||
"fiscal_year": pcv.fiscal_year,
|
||||
"remarks": pcv.remarks,
|
||||
"is_opening": "No",
|
||||
}
|
||||
)
|
||||
# update dimensions
|
||||
update_default_dimensions(get_dimensions(), gl_entry, dimensions)
|
||||
return gl_entry
|
||||
|
||||
|
||||
def get_gle_for_closing_account(pcv, dimension_balance, dimensions):
|
||||
balance_in_company_currency = flt(dimension_balance.balance_in_company_currency)
|
||||
debit = balance_in_company_currency if balance_in_company_currency > 0 else 0
|
||||
credit = abs(balance_in_company_currency) if balance_in_company_currency < 0 else 0
|
||||
|
||||
gl_entry = frappe._dict(
|
||||
{
|
||||
"company": pcv.company,
|
||||
"posting_date": pcv.period_end_date,
|
||||
"account": pcv.closing_account_head,
|
||||
"account_currency": frappe.db.get_value("Account", pcv.closing_account_head, "account_currency"),
|
||||
"debit_in_account_currency": debit,
|
||||
"debit": debit,
|
||||
"credit_in_account_currency": credit,
|
||||
"credit": credit,
|
||||
"is_period_closing_voucher_entry": 1,
|
||||
"voucher_type": "Period Closing Voucher",
|
||||
"voucher_no": pcv.name,
|
||||
"fiscal_year": pcv.fiscal_year,
|
||||
"remarks": pcv.remarks,
|
||||
"is_opening": "No",
|
||||
}
|
||||
)
|
||||
# update dimensions
|
||||
update_default_dimensions(get_dimensions(), gl_entry, dimensions)
|
||||
return gl_entry
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def schedule_next_date(docname: str):
|
||||
if to_process := frappe.db.get_all(
|
||||
"Process Period Closing Voucher Detail",
|
||||
filters={"parent": docname, "status": "Queued"},
|
||||
fields=["processing_date", "report_type", "parentfield"],
|
||||
order_by="parentfield, idx, processing_date",
|
||||
limit=1,
|
||||
):
|
||||
if not is_scheduler_inactive():
|
||||
frappe.db.set_value(
|
||||
"Process Period Closing Voucher Detail",
|
||||
{
|
||||
"processing_date": to_process[0].processing_date,
|
||||
"parent": docname,
|
||||
"report_type": to_process[0].report_type,
|
||||
"parentfield": to_process[0].parentfield,
|
||||
},
|
||||
"status",
|
||||
"Running",
|
||||
)
|
||||
frappe.enqueue(
|
||||
method="erpnext.accounts.doctype.process_period_closing_voucher.process_period_closing_voucher.process_individual_date",
|
||||
queue="long",
|
||||
timeout="3600",
|
||||
is_async=True,
|
||||
enqueue_after_commit=True,
|
||||
docname=docname,
|
||||
date=to_process[0].processing_date,
|
||||
report_type=to_process[0].report_type,
|
||||
parentfield=to_process[0].parentfield,
|
||||
)
|
||||
else:
|
||||
ppcvd = qb.DocType("Process Period Closing Voucher Detail")
|
||||
total_no_of_dates = (
|
||||
qb.from_(ppcvd).select(Count(ppcvd.star)).where(ppcvd.parent.eq(docname)).run()[0][0]
|
||||
)
|
||||
completed = (
|
||||
qb.from_(ppcvd)
|
||||
.select(Count(ppcvd.star))
|
||||
.where(ppcvd.parent.eq(docname) & ppcvd.status.eq("Completed"))
|
||||
.run()[0][0]
|
||||
)
|
||||
# Ensure both normal and opening balances are processed for all dates
|
||||
if total_no_of_dates == completed:
|
||||
summarize_and_post_ledger_entries(docname)
|
||||
|
||||
|
||||
def make_dict_json_compliant(dimension_wise_balance) -> dict:
|
||||
"""
|
||||
convert tuple -> str
|
||||
JSON doesn't support dictionary with tuple keys
|
||||
"""
|
||||
converted_dict = {}
|
||||
for k, v in dimension_wise_balance.items():
|
||||
str_key = [str(x) for x in k]
|
||||
str_key = ",".join(str_key)
|
||||
converted_dict[str_key] = v
|
||||
|
||||
return converted_dict
|
||||
|
||||
|
||||
def get_consolidated_gles(balances, report_type) -> list:
|
||||
gl_entries = []
|
||||
for x in balances:
|
||||
if x.report_type == report_type:
|
||||
closing_balances = [frappe._dict(gle) for gle in frappe.json.loads(x.closing_balance)]
|
||||
gl_entries.extend(closing_balances)
|
||||
return gl_entries
|
||||
|
||||
|
||||
def get_gl_entries(docname):
|
||||
"""
|
||||
Calculate total closing balance of all P&L accounts across PCV start and end date
|
||||
"""
|
||||
ppcv = frappe.get_doc("Process Period Closing Voucher", docname)
|
||||
|
||||
# calculate balance
|
||||
gl_entries = get_consolidated_gles(ppcv.normal_balances, "Profit and Loss")
|
||||
pl_dimension_wise_acc_balance = build_dimension_wise_balance_dict(gl_entries)
|
||||
|
||||
# save
|
||||
json_dict = make_dict_json_compliant(pl_dimension_wise_acc_balance)
|
||||
frappe.db.set_value(
|
||||
"Process Period Closing Voucher", docname, "p_l_closing_balance", frappe.json.dumps(json_dict)
|
||||
)
|
||||
|
||||
# build gl map
|
||||
pcv = frappe.get_doc("Period Closing Voucher", ppcv.parent_pcv)
|
||||
pl_accounts_reverse_gle = []
|
||||
closing_account_gle = []
|
||||
|
||||
for dimensions, account_balances in pl_dimension_wise_acc_balance.items():
|
||||
for acc, balances in account_balances.items():
|
||||
balance_in_company_currency = flt(balances.debit) - flt(balances.credit)
|
||||
if balance_in_company_currency:
|
||||
pl_accounts_reverse_gle.append(get_gle_for_pl_account(pcv, acc, balances, dimensions))
|
||||
|
||||
closing_account_gle.append(get_gle_for_closing_account(pcv, account_balances["balances"], dimensions))
|
||||
|
||||
return pl_accounts_reverse_gle, closing_account_gle
|
||||
|
||||
|
||||
def calculate_balance_sheet_balance(docname):
|
||||
"""
|
||||
Calculate total closing balance of all P&L accounts across PCV start and end date.
|
||||
If it is first PCV, opening entries are also considered
|
||||
"""
|
||||
ppcv = frappe.get_doc("Process Period Closing Voucher", docname)
|
||||
gl_entries = get_consolidated_gles(ppcv.normal_balances + ppcv.z_opening_balances, "Balance Sheet")
|
||||
|
||||
# build dimension wise dictionary from all GLE's
|
||||
bs_dimension_wise_acc_balance = build_dimension_wise_balance_dict(gl_entries)
|
||||
|
||||
# save
|
||||
json_dict = make_dict_json_compliant(bs_dimension_wise_acc_balance)
|
||||
frappe.db.set_value(
|
||||
"Process Period Closing Voucher", docname, "bs_closing_balance", frappe.json.dumps(json_dict)
|
||||
)
|
||||
return bs_dimension_wise_acc_balance
|
||||
|
||||
|
||||
def get_p_l_closing_entries(pl_gles, pcv):
|
||||
pl_closing_entries = copy.deepcopy(pl_gles)
|
||||
for d in pl_gles:
|
||||
# reverse debit and credit
|
||||
gle_copy = copy.deepcopy(d)
|
||||
gle_copy.debit = d.credit
|
||||
gle_copy.credit = d.debit
|
||||
gle_copy.debit_in_account_currency = d.credit_in_account_currency
|
||||
gle_copy.credit_in_account_currency = d.debit_in_account_currency
|
||||
gle_copy.is_period_closing_voucher_entry = 0
|
||||
gle_copy.period_closing_voucher = pcv.name
|
||||
pl_closing_entries.append(gle_copy)
|
||||
|
||||
return pl_closing_entries
|
||||
|
||||
|
||||
def get_bs_closing_entries(dimension_wise_balance, pcv):
|
||||
closing_entries = []
|
||||
for dimensions, account_balances in dimension_wise_balance.items():
|
||||
for acc, balances in account_balances.items():
|
||||
balance_in_company_currency = flt(balances.debit) - flt(balances.credit)
|
||||
if acc != "balances" and balance_in_company_currency:
|
||||
closing_entries.append(get_closing_entry(pcv, acc, balances, dimensions))
|
||||
|
||||
return closing_entries
|
||||
|
||||
|
||||
def get_closing_account_closing_entry(closing_account_gle, pcv):
|
||||
closing_entries_for_closing_account = copy.deepcopy(closing_account_gle)
|
||||
for d in closing_entries_for_closing_account:
|
||||
d.period_closing_voucher = pcv.name
|
||||
return closing_entries_for_closing_account
|
||||
|
||||
|
||||
def summarize_and_post_ledger_entries(docname):
|
||||
# P&L accounts
|
||||
pl_accounts_reverse_gle, closing_account_gle = get_gl_entries(docname)
|
||||
gl_entries = pl_accounts_reverse_gle + closing_account_gle
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
|
||||
if gl_entries:
|
||||
make_gl_entries(gl_entries, merge_entries=False)
|
||||
|
||||
pcv_name = frappe.db.get_value("Process Period Closing Voucher", docname, "parent_pcv")
|
||||
pcv = frappe.get_doc("Period Closing Voucher", pcv_name)
|
||||
|
||||
# Balance sheet accounts
|
||||
bs_dimension_wise_acc_balance = calculate_balance_sheet_balance(docname)
|
||||
|
||||
pl_closing_entries = get_p_l_closing_entries(pl_accounts_reverse_gle, pcv)
|
||||
bs_closing_entries = get_bs_closing_entries(bs_dimension_wise_acc_balance, pcv)
|
||||
closing_entries_for_closing_account = get_closing_account_closing_entry(closing_account_gle, pcv)
|
||||
closing_entries = pl_closing_entries + bs_closing_entries + closing_entries_for_closing_account
|
||||
|
||||
make_closing_entries(closing_entries, pcv.name, pcv.company, pcv.period_end_date)
|
||||
|
||||
frappe.db.set_value("Period Closing Voucher", pcv.name, "gle_processing_status", "Completed")
|
||||
frappe.db.set_value("Process Period Closing Voucher", docname, "status", "Completed")
|
||||
|
||||
|
||||
def get_closing_entry(pcv, account, balances, dimensions):
|
||||
closing_entry = frappe._dict(
|
||||
{
|
||||
"company": pcv.company,
|
||||
"closing_date": pcv.period_end_date,
|
||||
"period_closing_voucher": pcv.name,
|
||||
"account": account,
|
||||
"account_currency": balances.account_currency,
|
||||
"debit_in_account_currency": flt(balances.debit_in_account_currency),
|
||||
"debit": flt(balances.debit),
|
||||
"credit_in_account_currency": flt(balances.credit_in_account_currency),
|
||||
"credit": flt(balances.credit),
|
||||
"is_period_closing_voucher_entry": 0,
|
||||
}
|
||||
)
|
||||
# update dimensions
|
||||
update_default_dimensions(get_dimensions(), closing_entry, dimensions)
|
||||
return closing_entry
|
||||
|
||||
|
||||
def get_dimensions():
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
|
||||
get_accounting_dimensions,
|
||||
)
|
||||
|
||||
default_dimensions = ["cost_center", "finance_book", "project"]
|
||||
dimensions = default_dimensions + get_accounting_dimensions()
|
||||
return dimensions
|
||||
|
||||
|
||||
def get_dimension_key(res):
|
||||
return tuple([res.get(dimension) for dimension in get_dimensions()])
|
||||
|
||||
|
||||
def build_dimension_wise_balance_dict(gl_entries):
|
||||
dimension_balances = frappe._dict()
|
||||
for x in gl_entries:
|
||||
dimension_key = get_dimension_key(x)
|
||||
dimension_balances.setdefault(dimension_key, frappe._dict()).setdefault(
|
||||
x.account,
|
||||
frappe._dict(
|
||||
{
|
||||
"debit_in_account_currency": 0,
|
||||
"credit_in_account_currency": 0,
|
||||
"debit": 0,
|
||||
"credit": 0,
|
||||
"account_currency": x.account_currency,
|
||||
}
|
||||
),
|
||||
)
|
||||
dimension_balances[dimension_key][x.account].debit_in_account_currency += flt(
|
||||
x.debit_in_account_currency
|
||||
)
|
||||
dimension_balances[dimension_key][x.account].credit_in_account_currency += flt(
|
||||
x.credit_in_account_currency
|
||||
)
|
||||
dimension_balances[dimension_key][x.account].debit += flt(x.debit)
|
||||
dimension_balances[dimension_key][x.account].credit += flt(x.credit)
|
||||
|
||||
# dimension-wise total balances
|
||||
dimension_balances[dimension_key].setdefault(
|
||||
"balances",
|
||||
frappe._dict(
|
||||
{
|
||||
"balance_in_account_currency": 0,
|
||||
"balance_in_company_currency": 0,
|
||||
}
|
||||
),
|
||||
)
|
||||
balance_in_account_currency = flt(x.debit_in_account_currency) - flt(x.credit_in_account_currency)
|
||||
balance_in_company_currency = flt(x.debit) - flt(x.credit)
|
||||
dimension_balances[dimension_key][
|
||||
"balances"
|
||||
].balance_in_account_currency += balance_in_account_currency
|
||||
dimension_balances[dimension_key][
|
||||
"balances"
|
||||
].balance_in_company_currency += balance_in_company_currency
|
||||
|
||||
return dimension_balances
|
||||
|
||||
|
||||
def process_individual_date(docname: str, date, report_type, parentfield):
|
||||
current_date_status = frappe.db.get_value(
|
||||
"Process Period Closing Voucher Detail",
|
||||
{"processing_date": date, "report_type": report_type, "parentfield": parentfield},
|
||||
"status",
|
||||
)
|
||||
if current_date_status != "Running":
|
||||
return
|
||||
|
||||
pcv_name = frappe.db.get_value("Process Period Closing Voucher", docname, "parent_pcv")
|
||||
company = frappe.db.get_value("Period Closing Voucher", pcv_name, "company")
|
||||
|
||||
dimensions = get_dimensions()
|
||||
|
||||
accounts = frappe.db.get_all(
|
||||
"Account", filters={"company": company, "report_type": report_type}, pluck="name"
|
||||
)
|
||||
|
||||
# summarize
|
||||
gle = qb.DocType("GL Entry")
|
||||
query = qb.from_(gle).select(gle.account)
|
||||
for dim in dimensions:
|
||||
query = query.select(gle[dim])
|
||||
query = query.select(
|
||||
Sum(gle.debit).as_("debit"),
|
||||
Sum(gle.credit).as_("credit"),
|
||||
Sum(gle.debit_in_account_currency).as_("debit_in_account_currency"),
|
||||
Sum(gle.credit_in_account_currency).as_("credit_in_account_currency"),
|
||||
gle.account_currency,
|
||||
).where(
|
||||
(gle.company.eq(company))
|
||||
& (gle.is_cancelled.eq(0))
|
||||
& (gle.posting_date.eq(date))
|
||||
& (gle.account.isin(accounts))
|
||||
)
|
||||
|
||||
if parentfield == "z_opening_balances":
|
||||
query = query.where(gle.is_opening.eq("Yes"))
|
||||
|
||||
query = query.groupby(gle.account)
|
||||
for dim in dimensions:
|
||||
query = query.groupby(gle[dim])
|
||||
res = query.run(as_dict=True)
|
||||
|
||||
# save results
|
||||
frappe.db.set_value(
|
||||
"Process Period Closing Voucher Detail",
|
||||
{"processing_date": date, "parent": docname, "report_type": report_type, "parentfield": parentfield},
|
||||
"closing_balance",
|
||||
frappe.json.dumps(res),
|
||||
)
|
||||
|
||||
frappe.db.set_value(
|
||||
"Process Period Closing Voucher Detail",
|
||||
{"processing_date": date, "parent": docname, "report_type": report_type, "parentfield": parentfield},
|
||||
"status",
|
||||
"Completed",
|
||||
)
|
||||
|
||||
# chain call
|
||||
schedule_next_date(docname)
|
||||
@@ -1,20 +0,0 @@
|
||||
# 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 IntegrationTestProcessPeriodClosingVoucher(IntegrationTestCase):
|
||||
"""
|
||||
Integration tests for ProcessPeriodClosingVoucher.
|
||||
Use this class for testing interactions between multiple components.
|
||||
"""
|
||||
|
||||
pass
|
||||
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"creation": "2025-10-01 15:58:17.544153",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"processing_date",
|
||||
"report_type",
|
||||
"status",
|
||||
"closing_balance"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "processing_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Processing Date"
|
||||
},
|
||||
{
|
||||
"default": "Queued",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "Queued\nRunning\nPaused\nCompleted\nCancelled"
|
||||
},
|
||||
{
|
||||
"fieldname": "closing_balance",
|
||||
"fieldtype": "JSON",
|
||||
"in_list_view": 1,
|
||||
"label": "Closing Balance"
|
||||
},
|
||||
{
|
||||
"default": "Profit and Loss",
|
||||
"fieldname": "report_type",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Report Type",
|
||||
"options": "Profit and Loss\nBalance Sheet"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-10-20 12:03:59.106931",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Process Period Closing Voucher Detail",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"row_format": "Dynamic",
|
||||
"rows_threshold_for_grid_search": 20,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
# 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 ProcessPeriodClosingVoucherDetail(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
|
||||
|
||||
closing_balance: DF.JSON | None
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
parenttype: DF.Data
|
||||
processing_date: DF.Date | None
|
||||
report_type: DF.Literal["Profit and Loss", "Balance Sheet"]
|
||||
status: DF.Literal["Queued", "Running", "Paused", "Completed", "Cancelled"]
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
@@ -71,6 +71,14 @@ erpnext.accounts.PurchaseInvoice = class PurchaseInvoice extends erpnext.buying.
|
||||
if (this.frm.doc.supplier && this.frm.doc.__islocal) {
|
||||
this.frm.trigger("supplier");
|
||||
}
|
||||
|
||||
this.frm.set_query("supplier", function () {
|
||||
return {
|
||||
filters: {
|
||||
is_transporter: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
refresh(doc) {
|
||||
|
||||
@@ -112,7 +112,6 @@
|
||||
"tax_withheld_vouchers",
|
||||
"sec_tax_breakup",
|
||||
"other_charges_calculation",
|
||||
"item_wise_tax_details",
|
||||
"pricing_rule_details",
|
||||
"pricing_rules",
|
||||
"raw_materials_supplied",
|
||||
@@ -1671,14 +1670,6 @@
|
||||
"options": "Company:company:default_currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "item_wise_tax_details",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Item Wise Tax Details",
|
||||
"no_copy": 1,
|
||||
"options": "Item Wise Tax Detail"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
|
||||
@@ -40,6 +40,7 @@ from erpnext.assets.doctype.asset_category.asset_category import get_asset_categ
|
||||
from erpnext.buying.utils import check_on_hold_or_closed_status
|
||||
from erpnext.controllers.accounts_controller import validate_account_head
|
||||
from erpnext.controllers.buying_controller import BuyingController
|
||||
from erpnext.stock import get_warehouse_account_map
|
||||
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
|
||||
update_billed_amount_based_on_po,
|
||||
)
|
||||
@@ -62,7 +63,6 @@ class PurchaseInvoice(BuyingController):
|
||||
from frappe.types import DF
|
||||
|
||||
from erpnext.accounts.doctype.advance_tax.advance_tax import AdvanceTax
|
||||
from erpnext.accounts.doctype.item_wise_tax_detail.item_wise_tax_detail import ItemWiseTaxDetail
|
||||
from erpnext.accounts.doctype.payment_schedule.payment_schedule import PaymentSchedule
|
||||
from erpnext.accounts.doctype.pricing_rule_detail.pricing_rule_detail import PricingRuleDetail
|
||||
from erpnext.accounts.doctype.purchase_invoice_advance.purchase_invoice_advance import (
|
||||
@@ -137,7 +137,6 @@ class PurchaseInvoice(BuyingController):
|
||||
is_paid: DF.Check
|
||||
is_return: DF.Check
|
||||
is_subcontracted: DF.Check
|
||||
item_wise_tax_details: DF.Table[ItemWiseTaxDetail]
|
||||
items: DF.Table[PurchaseInvoiceItem]
|
||||
language: DF.Data | None
|
||||
letter_head: DF.Link | None
|
||||
@@ -461,12 +460,11 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
self.asset_received_but_not_billed = None
|
||||
|
||||
inventory_account_map = {}
|
||||
if self.update_stock:
|
||||
self.validate_item_code()
|
||||
self.validate_warehouse(for_validate)
|
||||
if auto_accounting_for_stock:
|
||||
inventory_account_map = self.get_inventory_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
for item in self.get("items"):
|
||||
# in case of auto inventory accounting,
|
||||
@@ -483,19 +481,21 @@ class PurchaseInvoice(BuyingController):
|
||||
)
|
||||
):
|
||||
if self.update_stock and item.warehouse and (not item.from_warehouse):
|
||||
_inv_dict = self.get_inventory_account_dict(item, inventory_account_map)
|
||||
|
||||
if for_validate and item.expense_account and item.expense_account != _inv_dict["account"]:
|
||||
if (
|
||||
for_validate
|
||||
and item.expense_account
|
||||
and item.expense_account != warehouse_account[item.warehouse]["account"]
|
||||
):
|
||||
msg = _(
|
||||
"Row {0}: Expense Head changed to {1} because account {2} is not linked to warehouse {3} or it is not the default inventory account"
|
||||
).format(
|
||||
item.idx,
|
||||
frappe.bold(_inv_dict["account"]),
|
||||
frappe.bold(warehouse_account[item.warehouse]["account"]),
|
||||
frappe.bold(item.expense_account),
|
||||
frappe.bold(item.warehouse),
|
||||
)
|
||||
frappe.msgprint(msg, title=_("Expense Head Changed"))
|
||||
item.expense_account = _inv_dict["account"]
|
||||
item.expense_account = warehouse_account[item.warehouse]["account"]
|
||||
else:
|
||||
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
|
||||
if item.purchase_receipt:
|
||||
@@ -857,7 +857,7 @@ class PurchaseInvoice(BuyingController):
|
||||
party=self.supplier,
|
||||
)
|
||||
|
||||
def get_gl_entries(self, inventory_account_map=None):
|
||||
def get_gl_entries(self, warehouse_account=None):
|
||||
self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
|
||||
|
||||
if self.auto_accounting_for_stock:
|
||||
@@ -947,7 +947,7 @@ class PurchaseInvoice(BuyingController):
|
||||
# item gl entries
|
||||
stock_items = self.get_stock_items()
|
||||
if self.update_stock and self.auto_accounting_for_stock:
|
||||
inventory_account_map = self.get_inventory_account_map()
|
||||
warehouse_account = get_warehouse_account_map(self.company)
|
||||
|
||||
landed_cost_entries = self.get_item_account_wise_lcv_entries()
|
||||
|
||||
@@ -997,24 +997,18 @@ class PurchaseInvoice(BuyingController):
|
||||
)
|
||||
|
||||
if item.from_warehouse:
|
||||
_inv_dict = self.get_inventory_account_dict(item, inventory_account_map)
|
||||
|
||||
_inv_dict_from_warehouse = self.get_inventory_account_dict(
|
||||
item, inventory_account_map, "from_warehouse"
|
||||
)
|
||||
|
||||
gl_entries.append(
|
||||
self.get_gl_dict(
|
||||
{
|
||||
"account": _inv_dict["account"],
|
||||
"against": _inv_dict_from_warehouse["account"],
|
||||
"account": warehouse_account[item.warehouse]["account"],
|
||||
"against": warehouse_account[item.from_warehouse]["account"],
|
||||
"cost_center": item.cost_center,
|
||||
"project": item.project or self.project,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"debit": warehouse_debit_amount,
|
||||
"debit_in_transaction_currency": item.net_amount,
|
||||
},
|
||||
_inv_dict["account_currency"],
|
||||
warehouse_account[item.warehouse]["account_currency"],
|
||||
item=item,
|
||||
)
|
||||
)
|
||||
@@ -1027,15 +1021,15 @@ class PurchaseInvoice(BuyingController):
|
||||
gl_entries.append(
|
||||
self.get_gl_dict(
|
||||
{
|
||||
"account": _inv_dict_from_warehouse["account"],
|
||||
"against": _inv_dict["account"],
|
||||
"account": warehouse_account[item.from_warehouse]["account"],
|
||||
"against": warehouse_account[item.warehouse]["account"],
|
||||
"cost_center": item.cost_center,
|
||||
"project": item.project or self.project,
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
|
||||
"debit": -1 * flt(credit_amount, item.precision("base_net_amount")),
|
||||
"debit_in_transaction_currency": item.net_amount,
|
||||
},
|
||||
_inv_dict_from_warehouse["account_currency"],
|
||||
warehouse_account[item.from_warehouse]["account_currency"],
|
||||
item=item,
|
||||
)
|
||||
)
|
||||
@@ -1103,19 +1097,15 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
# sub-contracting warehouse
|
||||
if flt(item.rm_supp_cost):
|
||||
supplier_wh_dict = self.get_inventory_account_dict(
|
||||
item, inventory_account_map, "supplier_warehouse"
|
||||
)
|
||||
|
||||
supplier_inventory_account = supplier_wh_dict["account"]
|
||||
if not supplier_inventory_account:
|
||||
supplier_warehouse_account = warehouse_account[self.supplier_warehouse]["account"]
|
||||
if not supplier_warehouse_account:
|
||||
frappe.throw(
|
||||
_("Please set account in Warehouse {0}").format(self.supplier_warehouse)
|
||||
)
|
||||
gl_entries.append(
|
||||
self.get_gl_dict(
|
||||
{
|
||||
"account": supplier_inventory_account,
|
||||
"account": supplier_warehouse_account,
|
||||
"against": item.expense_account,
|
||||
"cost_center": item.cost_center,
|
||||
"project": item.project or self.project,
|
||||
@@ -1123,7 +1113,7 @@ class PurchaseInvoice(BuyingController):
|
||||
"credit": flt(item.rm_supp_cost),
|
||||
"credit_in_transaction_currency": item.net_amount,
|
||||
},
|
||||
supplier_wh_dict["account_currency"],
|
||||
warehouse_account[self.supplier_warehouse]["account_currency"],
|
||||
item=item,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -912,8 +912,7 @@
|
||||
"label": "Rejected Serial and Batch Bundle",
|
||||
"no_copy": 1,
|
||||
"options": "Serial and Batch Bundle",
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "wip_composite_asset",
|
||||
@@ -985,7 +984,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-10-14 13:00:54.441511",
|
||||
"modified": "2025-03-07 10:21:59.960021",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
@@ -996,4 +995,4 @@
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,8 @@
|
||||
"base_net_amount",
|
||||
"base_tax_amount",
|
||||
"base_total",
|
||||
"base_tax_amount_after_discount_amount"
|
||||
"base_tax_amount_after_discount_amount",
|
||||
"item_wise_tax_detail"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -195,6 +196,16 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "item_wise_tax_detail",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"label": "Item Wise Tax Detail",
|
||||
"oldfieldname": "item_wise_tax_detail",
|
||||
"oldfieldtype": "Small Text",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -268,7 +279,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-07-24 15:08:44.433022",
|
||||
"modified": "2025-04-15 13:14:48.936047",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Taxes and Charges",
|
||||
|
||||
@@ -35,6 +35,7 @@ class PurchaseTaxesandCharges(Document):
|
||||
included_in_paid_amount: DF.Check
|
||||
included_in_print_rate: DF.Check
|
||||
is_tax_withholding_account: DF.Check
|
||||
item_wise_tax_detail: DF.Code | None
|
||||
net_amount: DF.Currency
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
|
||||
@@ -101,8 +101,8 @@ class RepostAccountingLedger(Document):
|
||||
if doc.doctype in ["Payment Entry", "Journal Entry"]:
|
||||
gle_map = doc.build_gl_map()
|
||||
elif doc.doctype == "Purchase Receipt":
|
||||
inventory_account_map = doc.get_inventory_account_map()
|
||||
gle_map = doc.get_gl_entries(inventory_account_map)
|
||||
warehouse_account_map = get_warehouse_account_map(doc.company)
|
||||
gle_map = doc.get_gl_entries(warehouse_account_map)
|
||||
else:
|
||||
gle_map = doc.get_gl_entries()
|
||||
|
||||
|
||||
@@ -256,18 +256,6 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
|
||||
|
||||
sales_order_btn() {
|
||||
var me = this;
|
||||
|
||||
let filters = {
|
||||
docstatus: 1,
|
||||
status: ["not in", ["Closed", "On Hold"]],
|
||||
per_billed: ["<", 99.99],
|
||||
company: me.frm.doc.company,
|
||||
};
|
||||
|
||||
if (me.frm.doc.has_subcontracted) {
|
||||
filters.is_subcontracted = 1;
|
||||
}
|
||||
|
||||
this.$sales_order_btn = this.frm.add_custom_button(
|
||||
__("Sales Order"),
|
||||
function () {
|
||||
@@ -278,7 +266,12 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
|
||||
setters: {
|
||||
customer: me.frm.doc.customer || undefined,
|
||||
},
|
||||
get_query_filters: filters,
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["not in", ["Closed", "On Hold"]],
|
||||
per_billed: ["<", 99.99],
|
||||
company: me.frm.doc.company,
|
||||
},
|
||||
allow_child_item_selection: true,
|
||||
child_fieldname: "items",
|
||||
child_columns: ["item_code", "item_name", "qty", "amount", "billed_amt"],
|
||||
@@ -805,15 +798,6 @@ frappe.ui.form.on("Sales Invoice", {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query("sales_person", "sales_team", function () {
|
||||
return {
|
||||
filters: {
|
||||
is_group: 0,
|
||||
enabled: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
onload: function (frm) {
|
||||
frm.redemption_conversion_factor = null;
|
||||
@@ -1110,9 +1094,6 @@ frappe.ui.form.on("Sales Invoice", {
|
||||
if (frm.doc.is_debit_note) {
|
||||
frm.set_df_property("return_against", "label", __("Adjustment Against"));
|
||||
}
|
||||
|
||||
frm.set_df_property("update_stock", "read_only", frm.doc.has_subcontracted);
|
||||
frm.toggle_display("update_stock", !frm.doc.has_subcontracted);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
"amended_from",
|
||||
"is_created_using_pos",
|
||||
"pos_closing_entry",
|
||||
"has_subcontracted",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break",
|
||||
@@ -101,7 +100,6 @@
|
||||
"discount_amount",
|
||||
"sec_tax_breakup",
|
||||
"other_charges_calculation",
|
||||
"item_wise_tax_details",
|
||||
"pricing_rule_details",
|
||||
"pricing_rules",
|
||||
"packing_list",
|
||||
@@ -2231,22 +2229,6 @@
|
||||
"fieldtype": "Data",
|
||||
"is_virtual": 1,
|
||||
"label": "Last Scanned Warehouse"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "has_subcontracted",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Has Subcontracted",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "item_wise_tax_details",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 1,
|
||||
"label": "Item Wise Tax Details",
|
||||
"no_copy": 1,
|
||||
"options": "Item Wise Tax Detail"
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
@@ -2260,7 +2242,7 @@
|
||||
"link_fieldname": "consolidated_invoice"
|
||||
}
|
||||
],
|
||||
"modified": "2025-10-09 14:48:59.472826",
|
||||
"modified": "2025-09-09 14:48:59.472826",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
||||
@@ -8,7 +8,6 @@ from frappe import _, msgprint, throw
|
||||
from frappe.contacts.doctype.address.address import get_address_display
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe.model.utils import get_fetch_values
|
||||
from frappe.query_builder import Case
|
||||
from frappe.utils import add_days, cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate
|
||||
from frappe.utils.data import comma_and
|
||||
|
||||
@@ -32,6 +31,7 @@ from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category
|
||||
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
|
||||
from erpnext.accounts.party import get_due_date, get_party_account, get_party_details
|
||||
from erpnext.accounts.utils import (
|
||||
cancel_exchange_gain_loss_journal,
|
||||
get_account_currency,
|
||||
update_voucher_outstanding,
|
||||
)
|
||||
@@ -65,7 +65,6 @@ class SalesInvoice(SellingController):
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
from erpnext.accounts.doctype.item_wise_tax_detail.item_wise_tax_detail import ItemWiseTaxDetail
|
||||
from erpnext.accounts.doctype.payment_schedule.payment_schedule import PaymentSchedule
|
||||
from erpnext.accounts.doctype.pricing_rule_detail.pricing_rule_detail import PricingRuleDetail
|
||||
from erpnext.accounts.doctype.sales_invoice_advance.sales_invoice_advance import SalesInvoiceAdvance
|
||||
@@ -132,7 +131,6 @@ class SalesInvoice(SellingController):
|
||||
from_date: DF.Date | None
|
||||
grand_total: DF.Currency
|
||||
group_same_items: DF.Check
|
||||
has_subcontracted: DF.Check
|
||||
ignore_default_payment_terms_template: DF.Check
|
||||
ignore_pricing_rule: DF.Check
|
||||
in_words: DF.SmallText | None
|
||||
@@ -147,7 +145,6 @@ class SalesInvoice(SellingController):
|
||||
is_opening: DF.Literal["No", "Yes"]
|
||||
is_pos: DF.Check
|
||||
is_return: DF.Check
|
||||
item_wise_tax_details: DF.Table[ItemWiseTaxDetail]
|
||||
items: DF.Table[SalesInvoiceItem]
|
||||
language: DF.Link | None
|
||||
letter_head: DF.Link | None
|
||||
@@ -339,8 +336,6 @@ class SalesInvoice(SellingController):
|
||||
self.validate_auto_set_posting_time()
|
||||
super().validate()
|
||||
|
||||
self.is_subcontracted()
|
||||
|
||||
if not (self.is_pos or self.is_debit_note):
|
||||
self.so_dn_required()
|
||||
|
||||
@@ -413,8 +408,6 @@ class SalesInvoice(SellingController):
|
||||
|
||||
self.allow_write_off_only_on_pos()
|
||||
self.reset_default_field_value("set_warehouse", "items", "warehouse")
|
||||
self.validate_subcontracted_sales_order()
|
||||
self.validate_scio_self_rm_qty()
|
||||
|
||||
def validate_accounts(self):
|
||||
self.validate_write_off_account()
|
||||
@@ -581,7 +574,6 @@ class SalesInvoice(SellingController):
|
||||
self.apply_loyalty_points()
|
||||
|
||||
self.process_common_party_accounting()
|
||||
self.update_billed_qty_in_scio()
|
||||
|
||||
def validate_pos_return(self):
|
||||
if self.is_consolidated:
|
||||
@@ -712,8 +704,6 @@ class SalesInvoice(SellingController):
|
||||
):
|
||||
self.cancel_pos_invoice_credit_note_generated_during_sales_invoice_mode()
|
||||
|
||||
self.update_billed_qty_in_scio()
|
||||
|
||||
def update_status_updater_args(self):
|
||||
if not cint(self.update_stock):
|
||||
return
|
||||
@@ -848,27 +838,6 @@ class SalesInvoice(SellingController):
|
||||
timesheet.set_status()
|
||||
timesheet.db_update_all()
|
||||
|
||||
def update_billed_qty_in_scio(self):
|
||||
if self.is_return:
|
||||
return
|
||||
|
||||
table = frappe.qb.DocType("Subcontracting Inward Order Received Item")
|
||||
data = frappe._dict(
|
||||
{
|
||||
item.scio_detail: item.stock_qty if self._action == "submit" else -item.stock_qty
|
||||
for item in self.items
|
||||
if item.scio_detail
|
||||
}
|
||||
)
|
||||
|
||||
if data:
|
||||
case_expr = Case()
|
||||
for name, qty in data.items():
|
||||
case_expr = case_expr.when(table.name == name, table.billed_qty + qty)
|
||||
frappe.qb.update(table).set(table.billed_qty, case_expr).where(
|
||||
(table.name.isin(list(data.keys()))) & (table.docstatus == 1)
|
||||
).run()
|
||||
|
||||
def update_time_sheet_detail(self, timesheet, args, sales_invoice):
|
||||
for data in timesheet.time_logs:
|
||||
if (
|
||||
@@ -1261,48 +1230,6 @@ class SalesInvoice(SellingController):
|
||||
if not self.is_pos and self.write_off_account:
|
||||
self.write_off_account = None
|
||||
|
||||
def validate_subcontracted_sales_order(self):
|
||||
if self.has_subcontracted:
|
||||
if [item for item in self.items if not item.sales_order and not item.scio_detail]:
|
||||
frappe.throw(
|
||||
_(
|
||||
"All items must be linked to a Sales Order or Subcontracting Inward Order for this Sales Invoice."
|
||||
)
|
||||
)
|
||||
if not all(
|
||||
frappe.get_all(
|
||||
"Sales Order",
|
||||
{"name": ["in", [item.sales_order for item in self.items if item.sales_order]]},
|
||||
pluck="is_subcontracted",
|
||||
)
|
||||
):
|
||||
frappe.throw(_("All linked Sales Orders must be subcontracted."))
|
||||
|
||||
def validate_scio_self_rm_qty(self):
|
||||
self_rms = [item for item in self.items if item.scio_detail]
|
||||
if self_rms:
|
||||
table = frappe.qb.DocType("Subcontracting Inward Order Received Item")
|
||||
query = (
|
||||
frappe.qb.from_(table)
|
||||
.select(table.required_qty, table.consumed_qty, table.billed_qty, table.name)
|
||||
.where((table.docstatus == 1) & (table.name.isin([item.scio_detail for item in self_rms])))
|
||||
)
|
||||
result = query.run(as_dict=True)
|
||||
data = {item.name: item for item in result}
|
||||
for item in self_rms:
|
||||
row = data.get(item.scio_detail)
|
||||
max_qty = max(row.required_qty, row.consumed_qty) - row.billed_qty
|
||||
if item.stock_qty > max_qty:
|
||||
frappe.throw(
|
||||
_("Row #{0}: Stock quantity {1} ({2}) for item {3} cannot exceed {4}").format(
|
||||
item.idx,
|
||||
item.stock_qty,
|
||||
item.stock_uom,
|
||||
get_link_to_form("Item", item.item_code),
|
||||
frappe.bold(max_qty),
|
||||
)
|
||||
)
|
||||
|
||||
def validate_write_off_account(self):
|
||||
if flt(self.write_off_amount) and not self.write_off_account:
|
||||
self.write_off_account = frappe.get_cached_value("Company", self.company, "write_off_account")
|
||||
@@ -1552,7 +1479,7 @@ class SalesInvoice(SellingController):
|
||||
elif self.docstatus == 2 and cint(self.update_stock) and cint(auto_accounting_for_stock):
|
||||
make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name)
|
||||
|
||||
def get_gl_entries(self, inventory_account_map=None):
|
||||
def get_gl_entries(self, warehouse_account=None):
|
||||
from erpnext.accounts.general_ledger import merge_similar_entries
|
||||
|
||||
gl_entries = []
|
||||
@@ -2224,23 +2151,6 @@ class SalesInvoice(SellingController):
|
||||
if update:
|
||||
self.db_set("status", self.status, update_modified=update_modified)
|
||||
|
||||
@frappe.whitelist()
|
||||
def is_subcontracted(self):
|
||||
if not self.has_subcontracted:
|
||||
self.has_subcontracted = bool(
|
||||
frappe.get_cached_value(
|
||||
"Sales Order",
|
||||
{
|
||||
"name": ["in", [item.sales_order for item in self.items if item.sales_order]],
|
||||
"is_subcontracted": 1,
|
||||
},
|
||||
"name",
|
||||
)
|
||||
)
|
||||
if self.has_subcontracted:
|
||||
self.update_stock = 0
|
||||
return self.has_subcontracted
|
||||
|
||||
|
||||
def get_total_in_party_account_currency(doc):
|
||||
total_fieldname = "grand_total" if doc.disable_rounded_total else "rounded_total"
|
||||
@@ -2442,7 +2352,7 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
"cost_center": "cost_center",
|
||||
},
|
||||
"postprocess": update_item,
|
||||
"condition": lambda doc: doc.delivered_by_supplier != 1 and not doc.scio_detail,
|
||||
"condition": lambda doc: doc.delivered_by_supplier != 1,
|
||||
},
|
||||
"Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True},
|
||||
"Sales Team": {
|
||||
@@ -2702,9 +2612,6 @@ def make_inter_company_transaction(doctype, source_name, target_doc=None):
|
||||
target.purchase_order = source.purchase_order
|
||||
target.po_detail = source.purchase_order_item
|
||||
|
||||
if (source.get("serial_no") or source.get("batch_no")) and not source.get("serial_and_batch_bundle"):
|
||||
target.use_serial_batch_fields = 1
|
||||
|
||||
item_field_map = {
|
||||
"doctype": target_doctype + " Item",
|
||||
"field_no_map": ["income_account", "expense_account", "cost_center", "warehouse"],
|
||||
|
||||
@@ -2077,12 +2077,12 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
{
|
||||
"item": "_Test Item",
|
||||
"taxable_amount": 10000.0,
|
||||
"Service Tax": {"tax_rate": 10.0, "tax_amount": 1000.0, "taxable_amount": 10000.0},
|
||||
"Service Tax": {"tax_rate": 10.0, "tax_amount": 1000.0, "net_amount": 10000.0},
|
||||
},
|
||||
{
|
||||
"item": "_Test Item 2",
|
||||
"taxable_amount": 5000.0,
|
||||
"Service Tax": {"tax_rate": 10.0, "tax_amount": 500.0, "taxable_amount": 5000.0},
|
||||
"Service Tax": {"tax_rate": 10.0, "tax_amount": 500.0, "net_amount": 5000.0},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -3980,29 +3980,29 @@ class TestSalesInvoice(ERPNextTestSuite):
|
||||
target_doc=si,
|
||||
args=json.dumps({"customer": dn1.customer, "merge_taxes": 1, "filtered_children": []}),
|
||||
)
|
||||
si.save()
|
||||
si.save().submit()
|
||||
|
||||
expected = [
|
||||
{
|
||||
"charge_type": "Actual",
|
||||
"account_head": "Freight and Forwarding Charges - _TC",
|
||||
"tax_amount": 120.0,
|
||||
"total": 1620.0,
|
||||
"base_total": 1620.0,
|
||||
"total": 1520.0,
|
||||
"base_total": 1520.0,
|
||||
},
|
||||
{
|
||||
"charge_type": "Actual",
|
||||
"account_head": "Marketing Expenses - _TC",
|
||||
"tax_amount": 150.0,
|
||||
"total": 1770.0,
|
||||
"base_total": 1770.0,
|
||||
"total": 1670.0,
|
||||
"base_total": 1670.0,
|
||||
},
|
||||
{
|
||||
"charge_type": "Actual",
|
||||
"account_head": "Miscellaneous Expenses - _TC",
|
||||
"tax_amount": 60.0,
|
||||
"total": 1830.0,
|
||||
"base_total": 1830.0,
|
||||
"total": 1610.0,
|
||||
"base_total": 1610.0,
|
||||
},
|
||||
]
|
||||
actual = [
|
||||
|
||||
@@ -109,7 +109,6 @@
|
||||
"column_break_vwhb",
|
||||
"pos_invoice",
|
||||
"pos_invoice_item",
|
||||
"scio_detail",
|
||||
"internal_transfer_section",
|
||||
"purchase_order",
|
||||
"column_break_92",
|
||||
@@ -979,20 +978,13 @@
|
||||
"options": "POS Invoice",
|
||||
"print_hide": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "scio_detail",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "SCIO Detail",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-09-04 11:08:25.583561",
|
||||
"modified": "2025-03-07 10:25:30.275246",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
@@ -1003,4 +995,4 @@
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,6 @@ class SalesInvoiceItem(Document):
|
||||
rate_with_margin: DF.Currency
|
||||
sales_invoice_item: DF.Data | None
|
||||
sales_order: DF.Link | None
|
||||
scio_detail: DF.Data | None
|
||||
serial_and_batch_bundle: DF.Link | None
|
||||
serial_no: DF.Text | None
|
||||
service_end_date: DF.Date | None
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"base_tax_amount",
|
||||
"base_total",
|
||||
"base_tax_amount_after_discount_amount",
|
||||
"item_wise_tax_detail",
|
||||
"dont_recompute_tax"
|
||||
],
|
||||
"fields": [
|
||||
@@ -173,6 +174,15 @@
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "item_wise_tax_detail",
|
||||
"fieldtype": "Code",
|
||||
"hidden": 1,
|
||||
"label": "Item Wise Tax Detail",
|
||||
"oldfieldname": "item_wise_tax_detail",
|
||||
"oldfieldtype": "Small Text",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -247,14 +257,13 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-07-24 15:08:34.381704",
|
||||
"modified": "2024-11-22 19:17:31.898467",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Taxes and Charges",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ class SalesTaxesandCharges(Document):
|
||||
dont_recompute_tax: DF.Check
|
||||
included_in_paid_amount: DF.Check
|
||||
included_in_print_rate: DF.Check
|
||||
item_wise_tax_detail: DF.Code | None
|
||||
net_amount: DF.Currency
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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
@@ -1,993 +0,0 @@
|
||||
{
|
||||
"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
@@ -1,824 +0,0 @@
|
||||
{
|
||||
"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)"
|
||||
}
|
||||
@@ -1,832 +0,0 @@
|
||||
{
|
||||
"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)"
|
||||
}
|
||||
@@ -1,418 +0,0 @@
|
||||
{
|
||||
"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)"
|
||||
}
|
||||
@@ -660,7 +660,6 @@ def make_reverse_gl_entries(
|
||||
adv_adj=False,
|
||||
update_outstanding="Yes",
|
||||
partial_cancel=False,
|
||||
posting_date=None,
|
||||
):
|
||||
"""
|
||||
Get original gl entries of the voucher
|
||||
@@ -758,8 +757,6 @@ def make_reverse_gl_entries(
|
||||
if immutable_ledger_enabled:
|
||||
new_gle["is_cancelled"] = 0
|
||||
new_gle["posting_date"] = frappe.form_dict.get("posting_date") or getdate()
|
||||
elif posting_date:
|
||||
new_gle["posting_date"] = posting_date
|
||||
|
||||
if new_gle["debit"] or new_gle["credit"]:
|
||||
make_entry(new_gle, adv_adj, "Yes")
|
||||
|
||||
@@ -39,16 +39,6 @@ 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",
|
||||
|
||||
@@ -26,13 +26,16 @@ frappe.query_reports["Accounts Payable"] = {
|
||||
{
|
||||
fieldname: "cost_center",
|
||||
label: __("Cost Center"),
|
||||
fieldtype: "MultiSelectList",
|
||||
get_data: function (txt) {
|
||||
return frappe.db.get_link_options("Cost Center", txt, {
|
||||
company: frappe.query_report.get_filter_value("company"),
|
||||
});
|
||||
},
|
||||
fieldtype: "Link",
|
||||
options: "Cost Center",
|
||||
get_query: () => {
|
||||
var company = frappe.query_report.get_filter_value("company");
|
||||
return {
|
||||
filters: {
|
||||
company: company,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldname: "party_account",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user