From 9244fe563a019cabf91028c56ff9edf0a1e8f54b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 2 Oct 2021 20:35:11 +0530 Subject: [PATCH] fix: Chart Of Accounts import button not visible (cherry picked from commit 3529622a0d28e9cdd6e602b5450ca79d13cfa0ed) --- .../chart_of_accounts_importer.js | 72 ++++++++++++------- .../chart_of_accounts_importer.py | 49 +++++++------ 2 files changed, 74 insertions(+), 47 deletions(-) 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 index f67c59c254..9766a463d1 100644 --- 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 @@ -12,11 +12,6 @@ frappe.ui.form.on('Chart of Accounts Importer', { 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); - } }, download_template: function(frm) { @@ -78,7 +73,12 @@ frappe.ui.form.on('Chart of Accounts Importer', { frm.page.set_indicator(""); $(frm.fields_dict['chart_tree'].wrapper).empty(); // empty wrapper on removing file } else { - generate_tree_preview(frm); + frappe.run_serially([ + () => validate_coa(frm), + () => generate_tree_preview(frm), + () => create_import_button(frm), + () => frm.set_df_property('chart_preview', 'hidden', 0), + ]); } }, @@ -104,24 +104,26 @@ frappe.ui.form.on('Chart of Accounts Importer', { }); var create_import_button = function(frm) { - frm.page.set_primary_action(__("Import"), function () { - 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, - freeze_message: __("Creating Accounts..."), - callback: function(r) { - if(!r.exc) { - clearInterval(frm.page["interval"]); - frm.page.set_indicator(__('Import Successful'), 'blue'); - create_reset_button(frm); + if (frm.page.show_import_button) { + frm.page.set_primary_action(__("Import"), function () { + return 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, + freeze_message: __("Creating Accounts..."), + callback: function(r) { + if(!r.exc) { + clearInterval(frm.page["interval"]); + frm.page.set_indicator(__('Import Successful'), 'blue'); + create_reset_button(frm); + } } - } - }); - }).addClass('btn btn-primary'); + }); + }).addClass('btn btn-primary'); + } }; var create_reset_button = function(frm) { @@ -132,13 +134,35 @@ var create_reset_button = function(frm) { }).addClass('btn btn-primary'); }; +var validate_coa = function(frm) { + if (frm.doc.import_file) { + let parent = __('All Accounts'); + + return frappe.call({ + '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', + file_type: frm.doc.file_type, + for_validate: 1 + }, + callback: function(r) { + if (r.message['show_import_button']) { + frm.page['show_import_button'] = Boolean(r.message['show_import_button']); + } + } + }) + } +}; + var generate_tree_preview = function(frm) { if (frm.doc.import_file) { 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({ + return new frappe.ui.Tree({ parent: $(frm.fields_dict['chart_tree'].wrapper), label: parent, expandable: true, 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 index 9a0234a91f..fa61ca21f8 100644 --- 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 @@ -64,6 +64,7 @@ def import_coa(file_name, company): else: data = generate_data_from_excel(file_doc, extension) + frappe.local.flags.ignore_root_company_validation = True forest = build_forest(data) create_charts(company, custom_chart=forest) @@ -128,7 +129,7 @@ def generate_data_from_excel(file_doc, extension, as_dict=False): return data @frappe.whitelist() -def get_coa(doctype, parent, is_root=False, file_name=None): +def get_coa(doctype, parent, is_root=False, file_name=None, for_validate=0): ''' called by tree view (to fetch node's children) ''' file_doc, extension = get_file(file_name) @@ -140,14 +141,20 @@ def get_coa(doctype, parent, is_root=False, file_name=None): data = generate_data_from_excel(file_doc, extension) validate_columns(data) - validate_accounts(data) - forest = build_forest(data) - accounts = build_tree_from_json("", chart_data=forest) # returns alist of dict in a tree render-able form + validate_accounts(file_doc, extension) - # filter out to show data for the selected node only - accounts = [d for d in accounts if d['parent_account']==parent] + if not for_validate: + forest = build_forest(data) + accounts = build_tree_from_json("", chart_data=forest) # returns a list of dict in a tree render-able form - return accounts + # filter out to show data for the selected node only + accounts = [d for d in accounts if d['parent_account']==parent] + + return accounts + else: + return { + 'show_import_button': 1 + } def build_forest(data): ''' @@ -279,7 +286,7 @@ def get_template(template_type): def get_sample_template(writer): template = [ ["Application Of Funds(Assets)", "", "", "", 1, "", "Asset"], - ["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"], + # ["Sources Of Funds(Liabilities)", "", "", "", 1, "", "Liability"], ["Equity", "", "", "", 1, "", "Equity"], ["Expenses", "", "", "", 1, "", "Expense"], ["Income", "", "", "", 1, "", "Income"], @@ -304,10 +311,7 @@ def get_sample_template(writer): @frappe.whitelist() -def validate_accounts(file_name): - - file_doc, extension = get_file(file_name) - +def validate_accounts(file_doc, extension): if extension == 'csv': accounts = generate_data_from_csv(file_doc, as_dict=True) else: @@ -326,8 +330,6 @@ def validate_accounts(file_name): validate_root(accounts_dict) - validate_account_types(accounts_dict) - return [True, len(accounts)] def validate_root(accounts): @@ -340,9 +342,19 @@ def validate_root(accounts): elif account.get("root_type") not in get_root_types() and account.get("account_name"): error_messages.append(_("Root Type for {0} must be one of the Asset, Liability, Income, Expense and Equity").format(account.get("account_name"))) + validate_missing_roots(roots) + if error_messages: frappe.throw("
".join(error_messages)) +def validate_missing_roots(roots): + root_types_added = set(d.get('root_type') for d in roots) + + missing = list(set(get_root_types()) - root_types_added) + + if missing: + frappe.throw(_("Please add Root Account for - {0}").format(' , '.join(missing))) + def get_root_types(): return ('Asset', 'Liability', 'Expense', 'Income', 'Equity') @@ -368,15 +380,6 @@ def get_mandatory_account_types(): {'account_type': 'Stock', 'root_type': 'Asset'} ] - -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 cint(accounts[d]['is_group']) == 1] - - missing = list(set(account_types_for_ledger) - set(account_types)) - if missing: - frappe.throw(_("Please identify/create Account (Ledger) 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)