feat: Chart of Accounts Importer (#16623)

* bare doctype created for COA utility

* improvise doctype's design

* validation to check no transaction exist for the company

* download file and import coa - client side logic added

* download csv template to create custom chart

* read the custom csv uploaded and parse it to appropriate format

* convert list of list to nested tree structure

* preview the uploaded chart before actual import

* toggle field based on necessity

* tweak create_charts and build_json logic to incorporate COA Import utility

* code cleanify and validation call added

* code enhancement for flexibility and validation added

* show import button only if data is validated

* unset existing data and load new accounts

* disable coa fields if parent_company set, minor improv

* file api fix

* added progress bar

* codacy fixes

* fix: Add account number in template

* fix: TDS account exception handling fix
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 bcb163f..1bf9196 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
@@ -9,8 +9,8 @@
 from six import iteritems
 from frappe.utils.nestedset import rebuild_tree
 
-def create_charts(company, chart_template=None, existing_company=None):
-	chart = get_chart(chart_template, existing_company)
+def create_charts(company, chart_template=None, existing_company=None, custom_chart=None):
+	chart = custom_chart or get_chart(chart_template, existing_company)
 	if chart:
 		accounts = []
 
@@ -40,7 +40,7 @@
 						"report_type": report_type,
 						"account_number": account_number,
 						"account_type": child.get("account_type"),
-						"account_currency": frappe.db.get_value('Company',  company,  "default_currency"),
+						"account_currency": child.get('account_currency') or frappe.db.get_value('Company',  company,  "default_currency"),
 						"tax_rate": child.get("tax_rate")
 					})
 
@@ -207,9 +207,9 @@
 	return (bank_account in accounts)
 
 @frappe.whitelist()
-def build_tree_from_json(chart_template):
+def build_tree_from_json(chart_template, chart_data=None):
 	''' get chart template from its folder and parse the json to be rendered as tree '''
-	chart = get_chart(chart_template)
+	chart = chart_data or get_chart(chart_template)
 
 	# if no template selected, return as it is
 	if not chart:
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/__init__.py b/erpnext/accounts/doctype/chart_of_accounts_importer/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/__init__.py
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js
new file mode 100644
index 0000000..aea6080
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.js
@@ -0,0 +1,138 @@
+frappe.ui.form.on('Chart of Accounts Importer', {
+	onload: function (frm) {
+		frm.set_value("company", "");
+		frm.set_value("import_file", "");
+	},
+	refresh: function (frm) {
+		// disable default save
+		frm.disable_save();
+
+		// make company mandatory
+		frm.set_df_property('company', 'reqd', frm.doc.company ? 0 : 1);
+		frm.set_df_property('import_file_section', 'hidden', frm.doc.company ? 0 : 1);
+		frm.set_df_property('chart_preview', 'hidden',
+			$(frm.fields_dict['chart_tree'].wrapper).html()!="" ? 0 : 1);
+
+		// Show import button when file is successfully attached
+		if (frm.page && frm.page.show_import_button) {
+			create_import_button(frm);
+		}
+
+		// show download template button when company is properly selected
+		if(frm.doc.company) {
+			// download the csv template file
+			frm.add_custom_button(__("Download template"), function () {
+				let get_template_url = 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.download_template';
+				open_url_post(frappe.request.url, { cmd: get_template_url, doctype: frm.doc.doctype });
+			});
+		} else {
+			frm.set_value("import_file", "");
+		}
+	},
+
+	import_file: function (frm) {
+		if (!frm.doc.import_file) {
+			frm.page.set_indicator("");
+			$(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper on removing file
+		} else {
+			generate_tree_preview(frm);
+			validate_csv_data(frm);
+		}
+	},
+
+	company: function (frm) {
+		// validate that no Gl Entry record for the company exists.
+		frappe.call({
+			method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.validate_company",
+			args: {
+				company: frm.doc.company
+			},
+			callback: function(r) {
+				if(r.message===false) {
+					frm.set_value("company", "");
+					frappe.throw(__("Transactions against the company already exist! "));
+				} else {
+					frm.trigger("refresh");
+				}
+			}
+		});
+	}
+});
+
+var validate_csv_data = function(frm) {
+	frappe.call({
+		method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.validate_accounts",
+		args: {file_name: frm.doc.import_file},
+		callback: function(r) {
+			if(r.message && r.message[0]===true) {
+				frm.page["show_import_button"] = true;
+				frm.page["total_accounts"] = r.message[1];
+				frm.trigger("refresh");
+			} else {
+				frm.page.set_indicator(__('Resolve error and upload again.'), 'orange');
+				frappe.throw(__(r.message));
+			}
+		}
+	});
+};
+
+var create_import_button = function(frm) {
+	frm.page.set_primary_action(__("Start Import"), function () {
+		setup_progress_bar(frm);
+		frappe.call({
+			method: "erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.import_coa",
+			args: {
+				file_name: frm.doc.import_file,
+				company: frm.doc.company
+			},
+			freeze: true,
+			callback: function(r) {
+				if(!r.exc) {
+					clearInterval(frm.page["interval"]);
+					frm.page.set_indicator(__('Import Successfull'), 'blue');
+					frappe.hide_progress();
+					create_reset_button(frm);
+				}
+			}
+		});
+	}).addClass('btn btn-primary');
+};
+
+var create_reset_button = function(frm) {
+	frm.page.set_primary_action(__("Reset"), function () {
+		frm.page.clear_primary_action();
+		delete frm.page["show_import_button"];
+		frm.reload_doc();
+	}).addClass('btn btn-primary');
+};
+
+var generate_tree_preview = function(frm) {
+	let parent = __('All Accounts');
+	$(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper to load new data
+
+	// generate tree structure based on the csv data
+	new frappe.ui.Tree({
+		parent: $(frm.fields_dict['chart_tree'].wrapper),
+		label: parent,
+		expandable: true,
+		method: 'erpnext.accounts.doctype.chart_of_accounts_importer.chart_of_accounts_importer.get_coa',
+		args: {
+			file_name: frm.doc.import_file,
+			parent: parent,
+			doctype: 'Chart of Accounts Importer'
+		},
+		onclick: function(node) {
+			parent = node.value;
+		}
+	});
+};
+
+var setup_progress_bar = function(frm) {
+	frm.page["seconds_elapsed"] = 0;
+	frm.page["execution_time"] = (frm.page["total_accounts"] > 100) ? 100 : frm.page["total_accounts"];
+
+	frm.page["interval"] = setInterval(function()  {
+		frm.page["seconds_elapsed"] += 1;
+		frappe.show_progress(__('Creating Accounts'), frm.page["seconds_elapsed"], frm.page["execution_time"]);
+	}, 250);
+};
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.json b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.json
new file mode 100644
index 0000000..d544e69
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.json
@@ -0,0 +1,226 @@
+{
+ "allow_copy": 1, 
+ "allow_events_in_timeline": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2019-02-01 12:24:34.761380", 
+ "custom": 0, 
+ "description": "Import Chart of Accounts from a csv file",
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "Other", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "company", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Company", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Company", 
+   "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, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "import_file_section",
+   "fieldtype": "Section Break",
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 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, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "",
+   "fieldname": "import_file",
+   "fieldtype": "Attach",
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Attach custom Chart of Accounts file",
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "",
+   "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, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 1,
+   "columns": 0,
+   "fieldname": "chart_preview",
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Chart Preview",
+   "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, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "chart_tree",
+   "fieldtype": "HTML",
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Chart Tree",
+   "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, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 1, 
+ "hide_toolbar": 1, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 1, 
+ "is_submittable": 0, 
+ "issingle": 1, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2019-02-04 23:10:30.136807",
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Chart of Accounts Importer", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 0, 
+   "email": 0, 
+   "export": 0, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 0, 
+   "read": 1, 
+   "report": 0, 
+   "role": "Accounts Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 1, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "", 
+ "sort_order": "DESC", 
+ "track_changes": 0, 
+ "track_seen": 0, 
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
new file mode 100644
index 0000000..948be64
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, csv
+from frappe import _
+from frappe.utils import cstr
+from frappe.model.document import Document
+from frappe.utils.csvutils import UnicodeWriter
+from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts, build_tree_from_json
+
+class ChartofAccountsImporter(Document):
+	pass
+
+@frappe.whitelist()
+def validate_company(company):
+	if frappe.db.get_all('GL Entry', {"company": company}, "name", limit=1):
+		return False
+
+@frappe.whitelist()
+def import_coa(file_name, company):
+	# delete existing data for accounts
+	unset_existing_data(company)
+
+	# create accounts
+	forest = build_forest(generate_data_from_csv(file_name))
+	create_charts(company, custom_chart=forest)
+
+	# trigger on_update for company to reset default accounts
+	set_default_accounts(company)
+
+def generate_data_from_csv(file_name, as_dict=False):
+	''' read csv file and return the generated nested tree '''
+	file_doc = frappe.get_doc('File', {"file_url": file_name})
+	file_path = file_doc.get_full_path()
+
+	data = []
+	with open(file_path, 'r') as in_file:
+		csv_reader = list(csv.reader(in_file))
+		headers = csv_reader[1][1:]
+		del csv_reader[0:2] # delete top row and headers row
+
+		for row in csv_reader:
+			if as_dict:
+				data.append({frappe.scrub(header): row[index+1] for index, header in enumerate(headers)})
+			else:
+				if not row[2]: row[2] = row[1]
+				data.append(row[1:])
+
+	# convert csv data
+	return data
+
+@frappe.whitelist()
+def get_coa(doctype, parent, is_root=False, file_name=None):
+	''' called by tree view (to fetch node's children) '''
+
+	parent = None if parent==_('All Accounts') else parent
+	forest = build_forest(generate_data_from_csv(file_name))
+	accounts = build_tree_from_json("", chart_data=forest) # returns alist of dict in a tree render-able form
+
+	# filter out to show data for the selected node only
+	accounts = [d for d in accounts if d['parent_account']==parent]
+
+	return accounts
+
+def build_forest(data):
+	'''
+		converts list of list into a nested tree
+		if a = [[1,1], [1,2], [3,2], [4,4], [5,4]]
+		tree = {
+			1: {
+				2: {
+					3: {}
+				}
+			},
+			4: {
+				5: {}
+			}
+		}
+	'''
+
+	# set the value of nested dictionary
+	def set_nested(d, path, value):
+		reduce(lambda d, k: d.setdefault(k, {}), path[:-1], d)[path[-1]] = value
+		return d
+
+	# returns the path of any node in list format
+	def return_parent(data, child):
+		for row in data:
+			account_name, parent_account = row[0:2]
+			if parent_account == account_name == child:
+				return [parent_account]
+			elif account_name == child:
+				return [child] + return_parent(data, parent_account)
+
+	charts_map, paths = {}, []
+	for i in data:
+		account_name, _, account_number, is_group, account_type, root_type = i
+		charts_map[account_name] = {}
+		if is_group: charts_map[account_name]["is_group"] = is_group
+		if account_type: charts_map[account_name]["account_type"] = account_type
+		if root_type: charts_map[account_name]["root_type"] = root_type
+		if account_number: charts_map[account_name]["account_number"] = account_number
+		path = return_parent(data, account_name)[::-1]
+		paths.append(path) # List of path is created
+
+	out = {}
+	for path in paths:
+		for n, account_name in enumerate(path):
+			set_nested(out, path[:n+1], charts_map[account_name]) # setting the value of nested dictionary.
+
+	return out
+
+@frappe.whitelist()
+def download_template():
+	data = frappe._dict(frappe.local.form_dict)
+	fields = ["Account Name", "Parent Account", "Account Number", "Is Group", "Account Type", "Root Type"]
+	writer = UnicodeWriter()
+
+	writer.writerow([_('Chart of Accounts Template')])
+	writer.writerow([_("Column Labels : ")] + fields)
+	writer.writerow([_("Start entering data from here : ")])
+
+	# download csv file
+	frappe.response['result'] = cstr(writer.getvalue())
+	frappe.response['type'] = 'csv'
+	frappe.response['doctype'] = data.get('doctype')
+
+@frappe.whitelist()
+def validate_accounts(file_name):
+	accounts = generate_data_from_csv(file_name, as_dict=True)
+
+	accounts_dict = {}
+	for account in accounts:
+		accounts_dict.setdefault(account["account_name"], account)
+		if account["parent_account"] and accounts_dict[account["parent_account"]]:
+			accounts_dict[account["parent_account"]]["is_group"] = 1
+
+	message = validate_root(accounts_dict)
+	if message: return message
+	message = validate_account_types(accounts_dict)
+	if message: return message
+
+	return [True, len(accounts)]
+
+def validate_root(accounts):
+	roots = [accounts[d] for d in accounts if not accounts[d].get('parent_account')]
+	if len(roots) < 4:
+		return _("Number of root accounts cannot be less than 4")
+
+	for account in roots:
+		if not account.get("root_type"):
+			return _("Please enter Root Type for - {0}").format(account.get("account_name"))
+		elif account.get("root_type") not in ("Asset", "Liability", "Expense", "Income", "Equity"):
+			return _('Root Type for "{0}" must be one of the Asset, Liability, Income, Expense and Equity').format(account.get("account_name"))
+
+def validate_account_types(accounts):
+	account_types_for_ledger = ["Cost of Goods Sold", "Depreciation", "Fixed Asset", "Payable", "Receivable", "Stock Adjustment"]
+	account_types = [accounts[d]["account_type"] for d in accounts if not accounts[d]['is_group']]
+
+	missing = list(set(account_types_for_ledger) - set(account_types))
+	if missing:
+		return _("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing))
+
+	account_types_for_group = ["Bank", "Cash", "Stock"]
+	account_groups = [accounts[d]["account_type"] for d in accounts if accounts[d]['is_group']]
+
+	missing = list(set(account_types_for_group) - set(account_groups))
+	if missing:
+		return _("Please identify/create Account (Group) for type - {0}").format(' , '.join(missing))
+
+def unset_existing_data(company):
+	linked = frappe.db.sql('''select fieldname from tabDocField
+		where fieldtype="Link" and options="Account" and parent="Company"''', as_dict=True)
+
+	# remove accounts data from company
+	update_values = {d.fieldname: '' for d in linked}
+	frappe.db.set_value('Company', company, update_values, update_values)
+
+	# remove accounts data from various doctypes
+	for doctype in ["Account", "Party Account", "Mode of Payment Account", "Tax Withholding Account",
+		"Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
+		frappe.db.sql('''delete from `tab{0}` where `company`="%s"''' # nosec
+			.format(doctype) % (company))
+
+def set_default_accounts(company):
+	from erpnext.setup.doctype.company.company import install_country_fixtures
+	company = frappe.get_doc('Company', company)
+	company.update({
+		"default_receivable_account": frappe.db.get_value("Account",
+			{"company": company.name, "account_type": "Receivable", "is_group": 0}),
+		"default_payable_account": frappe.db.get_value("Account",
+			{"company": company.name, "account_type": "Payable", "is_group": 0})
+	})
+
+	company.save()
+	install_country_fixtures(company.name)
+	company.create_default_tax_template()
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.js b/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.js
new file mode 100644
index 0000000..b075a01
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Chart of Accounts Importer", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Chart of Accounts Importer
+		() => frappe.tests.make('Chart of Accounts Importer', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py
new file mode 100644
index 0000000..6ab19b7
--- /dev/null
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/test_chart_of_accounts_importer.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestChartofAccountsImporter(unittest.TestCase):
+	pass
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index c0d44b2..f7057aa 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -395,7 +395,9 @@
 			doc.insert()
 		except frappe.DuplicateEntryError:
 			doc = frappe.get_doc("Tax Withholding Category", d.get("name"))
-			doc.append("accounts", accounts[0])
+
+			if accounts:
+				doc.append("accounts", accounts[0])
 
 			# if fiscal year don't match with any of the already entered data, append rate row
 			fy_exist = [k for k in doc.get('rates') if k.get('fiscal_year')==fiscal_year]
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index b69a64c..4ac11c0 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -276,4 +276,5 @@
 	frm.set_df_property("create_chart_of_accounts_based_on", "read_only", bool);
 	frm.set_df_property("chart_of_accounts", "read_only", bool);
 	frm.set_df_property("existing_company", "read_only", bool);
-};
\ No newline at end of file
+}
+
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index e60e8ad..52c9c5a 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -97,8 +97,6 @@
 			install_country_fixtures(self.name)
 			self.create_default_tax_template()
 
-
-
 		if not frappe.db.get_value("Department", {"company": self.name}):
 			from erpnext.setup.setup_wizard.operations.install_fixtures import install_post_company_fixtures
 			install_post_company_fixtures(frappe._dict({'company_name': self.name}))
@@ -335,6 +333,11 @@
 			where doctype='Global Defaults' and field='default_company'
 			and value=%s""", self.name)
 
+		# reset default company
+		frappe.db.sql("""update `tabSingles` set value=""
+			where doctype='Chart of Accounts Importer' and field='company'
+			and value=%s""", self.name)
+
 		# delete BOMs
 		boms = frappe.db.sql_list("select name from tabBOM where company=%s", self.name)
 		if boms: