Create Chart of Accounts based on existing company
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
index 7894e77..e26e354 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
@@ -6,9 +6,8 @@
from frappe.utils import cstr
from unidecode import unidecode
-def create_charts(chart_name, company):
- chart = get_chart(chart_name)
-
+def create_charts(company, chart_template=None, existing_company=None):
+ chart = get_chart(chart_template, existing_company)
if chart:
accounts = []
@@ -17,7 +16,7 @@
if root_account:
root_type = child.get("root_type")
- if account_name not in ["account_type", "root_type", "is_group"]:
+ if account_name not in ["account_type", "root_type", "is_group", "tax_rate"]:
account_name_in_db = unidecode(account_name.strip().lower())
if account_name_in_db in accounts:
@@ -57,21 +56,21 @@
def identify_is_group(child):
if child.get("is_group"):
is_group = child.get("is_group")
- elif len(set(child.keys()) - set(["account_type", "root_type", "is_group"])):
+ elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate"])):
is_group = 1
else:
is_group = 0
return is_group
-def get_chart(chart_name):
+def get_chart(chart_template, existing_company=None):
chart = {}
- if chart_name == "Standard Template":
+ if existing_company:
+ return get_account_tree_from_existing_company(existing_company)
+
+ elif chart_template == "Standard":
from erpnext.accounts.doctype.account.chart_of_accounts.verified import standard_chart_of_accounts
return standard_chart_of_accounts.get()
-
-
-
else:
folders = ("verified",)
if frappe.local.flags.allow_unverified_charts:
@@ -82,7 +81,7 @@
if fname.endswith(".json"):
with open(os.path.join(path, fname), "r") as f:
chart = f.read()
- if chart and json.loads(chart).get("name") == chart_name:
+ if chart and json.loads(chart).get("name") == chart_template:
return json.loads(chart).get("tree")
@frappe.whitelist()
@@ -114,3 +113,47 @@
charts.append("Standard")
return charts
+
+
+def get_account_tree_from_existing_company(existing_company):
+ all_accounts = frappe.get_all('Account',
+ filters={'company': existing_company},
+ fields = ["name", "account_name", "parent_account", "account_type",
+ "is_group", "root_type", "tax_rate"],
+ order_by="lft, rgt")
+
+ account_tree = {}
+
+ # fill in tree starting with root accounts (those with no parent)
+ build_account_tree(account_tree, None, all_accounts)
+
+ return account_tree
+
+def build_account_tree(tree, parent, all_accounts):
+ # find children
+ parent_account = parent.name if parent else None
+ children = [acc for acc in all_accounts if acc.parent_account == parent_account]
+
+ # if no children, but a group account
+ if not children and parent.is_group:
+ tree["is_group"] = 1
+
+ # build a subtree for each child
+ for child in children:
+ if child.account_type == "Stock" and not child.is_group:
+ tree["is_group"] = 1
+ continue
+
+ # start new subtree
+ tree[child.account_name] = {}
+
+ # assign account_type and root_type
+ if child.account_type:
+ tree[child.account_name]["account_type"] = child.account_type
+ if child.tax_rate:
+ tree[child.account_name]["tax_rate"] = child.tax_rate
+ if not parent:
+ tree[child.account_name]["root_type"] = child.root_type
+
+ # call recursively to build a subtree for current account
+ build_account_tree(tree[child.account_name], child, all_accounts)
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index 3dedd53..338d10a 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -299,6 +299,34 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "default_currency",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Default Currency",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Currency",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
@@ -354,61 +382,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "default_currency",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_14",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "create_chart_of_accounts_based_on",
"fieldtype": "Select",
"hidden": 0,
@@ -449,7 +422,7 @@
"in_standard_filter": 0,
"label": "Chart Of Accounts Template",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"options": "",
"permlevel": 0,
"precision": "",
@@ -479,7 +452,7 @@
"in_standard_filter": 0,
"label": "Existing Company ",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"options": "Company",
"permlevel": 0,
"precision": "",
@@ -1633,7 +1606,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2016-11-22 04:14:51.319655",
+ "modified": "2016-11-23 16:32:04.893315",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 00538cd..7f506d5 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -30,6 +30,7 @@
self.validate_abbr()
self.validate_default_accounts()
self.validate_currency()
+ self.validate_coa_input()
def validate_abbr(self):
if not self.abbr:
@@ -113,16 +114,25 @@
warehouse.insert()
def create_default_accounts(self):
- if not self.chart_of_accounts:
- self.chart_of_accounts = "Standard"
-
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
- create_charts(self.chart_of_accounts, self.name)
+ create_charts(self.name, self.chart_of_accounts, self.existing_company)
frappe.db.set(self, "default_receivable_account", frappe.db.get_value("Account",
{"company": self.name, "account_type": "Receivable", "is_group": 0}))
frappe.db.set(self, "default_payable_account", frappe.db.get_value("Account",
{"company": self.name, "account_type": "Payable", "is_group": 0}))
+
+ def validate_coa_input(self):
+ if self.create_chart_of_accounts_based_on == "Existing Company":
+ self.chart_of_accounts = None
+ if not self.existing_company:
+ frappe.throw(_("Please select Existing Company for creating Chart of Accounts"))
+
+ else:
+ self.existing_company = None
+ self.create_chart_of_accounts_based_on = "Standard Template"
+ if not self.chart_of_accounts:
+ self.chart_of_accounts = "Standard"
def set_default_accounts(self):
self._set_default_account("default_cash_account", "Cash")
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index afcc3b1..52836a6 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -7,8 +7,40 @@
import frappe
import unittest
-class TestCompany(unittest.TestCase):
- pass
-
-
test_records = frappe.get_test_records('Company')
+
+class TestCompany(unittest.TestCase):
+ def test_coa_based_on_existing_company(self):
+ make_company()
+
+ expected_results = {
+ "Debtors - CFEC": {
+ "account_type": "Receivable",
+ "is_group": 0,
+ "root_type": "Asset",
+ "parent_account": "Accounts Receivable - CFEC",
+ },
+ "_Test Cash - CFEC": {
+ "account_type": "Cash",
+ "is_group": 0,
+ "root_type": "Asset",
+ "parent_account": "Cash In Hand - CFEC"
+ }
+ }
+
+ for account, acc_property in expected_results.items():
+ acc = frappe.get_doc("Account", account)
+ for prop, val in acc_property.items():
+ self.assertEqual(acc.get(prop), val)
+
+
+def make_company():
+ company = frappe.new_doc("Company")
+ company.company_name = "COA from Existing Company"
+ company.abbr = "CFEC"
+ company.default_currency = "INR"
+ company.create_chart_of_accounts_based_on = "Existing Company"
+ company.existing_company = "_Test Company"
+ company.save()
+
+
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 646aef1..395ea51 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -88,6 +88,7 @@
'abbr':args.get('company_abbr'),
'default_currency':args.get('currency'),
'country': args.get('country'),
+ 'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': args.get(('chart_of_accounts')),
'domain': args.get('domain')
}).insert()