[ Enhance ] Setup Wizard - Chart of Accounts (#14698)

* enable selection of coa for user
Give user option to select coa that's been verified along with standard and standard with numbers. Also added a button that opens a dialog and renders the selected chart

* read chart from file and make a tree render-able dict of it

* tree method to return node data for coa setup wizard
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 919f53b..3f639cf 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
@@ -198,3 +198,30 @@
 		_get_account_names(chart)
 
 	return (bank_account in accounts)
+
+@frappe.whitelist()
+def build_tree_from_json(chart_template):
+	''' get chart template from its folder and parse the json to be rendered as tree '''
+	chart = get_chart(chart_template)
+
+	# if no template selected, return as it is
+	if not chart:
+		return
+
+	accounts = []
+	def _import_accounts(children, parent):
+		''' recursively called to form a parent-child based list of dict from chart template '''
+		for account_name, child in iteritems(children):
+			account = {}
+			if account_name in ["account_number", "account_type",\
+				"root_type", "is_group", "tax_rate"]: continue
+
+			account['parent_account'] = parent
+			account['expandable'] = True if identify_is_group(child) else False
+			account['value'] = (child.get('account_number') + ' - ' + account_name) \
+				if child.get('account_number') else account_name
+			accounts.append(account)
+			_import_accounts(child, account['value'])
+
+	_import_accounts(chart, None)
+	return accounts
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index e7ea7e1..f5df4c4 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -814,3 +814,19 @@
 	if cstr(field_value).strip():
 		parts.insert(0, cstr(field_value).strip())
 	return ' - '.join(parts)
+
+@frappe.whitelist()
+def get_coa(doctype, parent, is_root, chart=None):
+	from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import build_tree_from_json
+
+	# add chart to flags to retrieve when called from expand all function
+	chart = chart if chart else frappe.flags.chart
+	frappe.flags.chart = chart
+
+	parent = None if parent==_('All Accounts') else parent
+	accounts = build_tree_from_json(chart) # 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
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 2e44857..29d0077 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -123,6 +123,7 @@
 				fieldname: 'chart_of_accounts', label: __('Chart of Accounts'),
 				options: "", fieldtype: 'Select'
 			},
+			{ fieldname: 'view_coa', label: __('View Chart of Accounts'), fieldtype: 'Button' },
 
 			{ fieldtype: "Section Break", label: __('Financial Year') },
 			{ fieldname: 'fy_start_date', label: __('Start Date'), fieldtype: 'Date', reqd: 1 },
@@ -198,18 +199,11 @@
 			if (country) {
 				frappe.call({
 					method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.get_charts_for_country",
-					args: { "country": country },
+					args: { "country": country, with_standard: true },
 					callback: function (r) {
 						if (r.message) {
 							slide.get_input("chart_of_accounts").empty()
 								.add_options(r.message);
-
-							if (r.message.length === 1) {
-								var field = slide.get_field("chart_of_accounts");
-								field.set_value(r.message[0]);
-								field.df.hidden = 1;
-								field.refresh();
-							}
 						}
 					}
 				})
@@ -217,12 +211,73 @@
 		},
 
 		bind_events: function (slide) {
+			let me = this;
 			slide.get_input("fy_start_date").on("change", function () {
 				var start_date = slide.form.fields_dict.fy_start_date.get_value();
 				var year_end_date =
 					frappe.datetime.add_days(frappe.datetime.add_months(start_date, 12), -1);
 				slide.form.fields_dict.fy_end_date.set_value(year_end_date);
 			});
+
+			slide.get_input("view_coa").on("click", function() {
+				let chart_template = slide.form.fields_dict.chart_of_accounts.get_value();
+				if(!chart_template) return;
+
+				me.charts_modal(slide, chart_template);
+			});
+		},
+
+		charts_modal: function(slide, chart_template) {
+			let parent = __('All Accounts');
+
+			var dialog = new frappe.ui.Dialog({
+				title: chart_template,
+				fields: [
+					{'fieldname': 'expand_all', 'label': __('Expand All'), 'fieldtype': 'Button',
+						click: function() {
+							// expand all nodes on button click
+							coa_tree.load_children(coa_tree.root_node, true);
+						}
+					},
+					{'fieldname': 'collapse_all', 'label': __('Collapse All'), 'fieldtype': 'Button',
+						click: function() {
+							// collapse all nodes
+							coa_tree.get_all_nodes(coa_tree.root_node.data.value, coa_tree.root_node.is_root)
+								.then(data_list => {
+									data_list.map(d => { coa_tree.toggle_node(coa_tree.nodes[d.parent]); });
+								});
+						}
+					}
+				]
+			});
+
+			// render tree structure in the dialog modal
+			let coa_tree = new frappe.ui.Tree({
+				parent: $(dialog.body),
+				label: parent,
+				expandable: true,
+				method: 'erpnext.accounts.utils.get_coa',
+				args: {
+					chart: chart_template,
+					parent: parent,
+					doctype: 'Account'
+				},
+				onclick: function(node) {
+					parent = node.value;
+				}
+			});
+
+			// add class to show buttons side by side
+			$('.modal-content .form-column').addClass('row');
+			$('div[data-fieldname="collapse_all"]')
+				.addClass('col-sm-2 col-xs-3')
+				.css({"width": "auto"});
+			$('div[data-fieldname="expand_all"]')
+				.addClass('col-sm-2 col-xs-3')
+				.css({"width": "auto"});
+
+			dialog.show();
+			coa_tree.load_children(coa_tree.root_node, true); // expand all node trigger
 		}
 	}
 ];