Merge pull request #4402 from nabinhait/allow_root_accounts
[feature] Allowed custom root accounts in Chart of Accounts
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 8544b17..5c6aecd 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -65,12 +65,19 @@
if self.root_type != db_value.root_type:
frappe.db.sql("update `tabAccount` set root_type=%s where lft > %s and rgt < %s",
(self.root_type, self.lft, self.rgt))
+
+ if self.root_type and not self.report_type:
+ self.report_type = "Balance Sheet" \
+ if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
def validate_root_details(self):
# does not exists parent
if frappe.db.exists("Account", self.name):
if not frappe.db.get_value("Account", self.name, "parent_account"):
throw(_("Root cannot be edited."), RootNotEditable)
+
+ if not self.parent_account and not self.is_group:
+ frappe.throw(_("Root Account must be a group"))
def validate_frozen_accounts_modifier(self):
old_value = frappe.db.get_value("Account", self.name, "freeze_account")
@@ -127,11 +134,11 @@
and docstatus != 2""", self.name)
def validate_mandatory(self):
- if not self.report_type:
- throw(_("Report Type is mandatory"))
-
if not self.root_type:
throw(_("Root Type is mandatory"))
+
+ if not self.report_type:
+ throw(_("Report Type is mandatory"))
def validate_warehouse_account(self):
if not cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js
index b172ae0..6a2a831 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.js
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js
@@ -117,7 +117,7 @@
}
},
{
- condition: function(node) { return !node.root && node.expandable; },
+ condition: function(node) { return node.expandable; },
label: __("Add Child"),
click: function() {
me.make_new()
@@ -208,6 +208,9 @@
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
+ {fieldtype:'Select', fieldname:'root_type', label:__('Root Type'),
+ options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'),
+ },
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
options: ['', 'Bank', 'Cash', 'Warehouse', 'Tax', 'Chargeable'].join('\n'),
description: __("Optional. This setting will be used to filter in various transactions.") },
@@ -237,6 +240,9 @@
$(fd.tax_rate.wrapper).toggle(fd.account_type.get_value()==='Tax');
$(fd.warehouse.wrapper).toggle(fd.account_type.get_value()==='Warehouse');
})
+
+ // root type if root
+ $(fd.root_type.wrapper).toggle(node.root);
// create
d.set_primary_action(__("Create New"), function() {
@@ -252,6 +258,14 @@
var node = me.tree.get_selected_node();
v.parent_account = node.label;
v.company = me.company;
+
+ if(node.root) {
+ v.is_root = true;
+ v.parent_account = null;
+ } else {
+ v.is_root = false;
+ v.root_type = null;
+ }
return frappe.call({
args: v,
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index be2e968..15e0553 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -80,8 +80,13 @@
return None
accounts, accounts_by_name = filter_accounts(accounts)
- gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
- accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
+
+ gl_entries_by_account = {}
+ for root in frappe.db.sql("""select lft, rgt from tabAccount
+ where root_type=%s and ifnull(parent_account, '') = ''""", root_type, as_dict=1):
+ set_gl_entries_by_account(company, period_list[0]["from_date"],
+ period_list[-1]["to_date"],root.lft, root.rgt, gl_entries_by_account,
+ ignore_closing_entries=ignore_closing_entries)
calculate_values(accounts_by_name, gl_entries_by_account, period_list)
accumulate_values_into_parents(accounts, accounts_by_name, period_list)
@@ -101,7 +106,6 @@
if entry.posting_date <= period.to_date:
d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit)
-
def accumulate_values_into_parents(accounts, accounts_by_name, period_list):
"""accumulate children's values in parent accounts"""
for d in reversed(accounts):
@@ -143,15 +147,20 @@
return out
def add_total_row(out, balance_must_be, period_list):
- row = {
+ total_row = {
"account_name": "'" + _("Total ({0})").format(balance_must_be) + "'",
"account": None
}
- for period in period_list:
- row[period.key] = out[0].get(period.key, 0.0)
- out[0][period.key] = ""
+
+ for row in out:
+ if not row.get("parent_account"):
+ for period in period_list:
+ total_row.setdefault(period.key, 0.0)
+ total_row[period.key] += row.get(period.key, 0.0)
- out.append(row)
+ row[period.key] = ""
+
+ out.append(total_row)
# blank row after Total
out.append({})
@@ -200,7 +209,8 @@
roots.sort(compare_roots)
-def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closing_entries=False):
+def set_gl_entries_by_account(company, from_date, to_date, root_lft, root_rgt, gl_entries_by_account,
+ ignore_closing_entries=False):
"""Returns a dict like { "account": [gl entries], ... }"""
additional_conditions = []
@@ -226,7 +236,6 @@
},
as_dict=True)
- gl_entries_by_account = {}
for entry in gl_entries:
gl_entries_by_account.setdefault(entry.account, []).append(entry)
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 05b771a..25ae482 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -134,6 +134,8 @@
ac.update(args)
ac.old_parent = ""
ac.freeze_account = "No"
+ if ac.get("is_root"):
+ ac.flags.ignore_mandatory = True
ac.insert()
return ac.name