From e379f083bbc5b40faa12c8adf41aedccb8b56f48 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 20 Apr 2021 23:04:39 +0530 Subject: [PATCH 01/33] feat(India): Separate Input and Output GST tax accounts --- .../setup_wizard/data/country_wise_tax.json | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 58764880330..9db2122be2e 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -881,35 +881,70 @@ ] } ], - "*": [ + "sales_tax_templates": [ { - "title": "In State GST", + "title": "Output GST In-state", "taxes": [ { "account_head": { - "account_name": "SGST", + "account_name": "Output Tax SGST", "tax_rate": 9.00 } }, { "account_head": { - "account_name": "CGST", + "account_name": "Output Tax CGST", "tax_rate": 9.00 } } ] }, { - "title": "Out of State GST", + "title": "Output GST Out-state", "taxes": [ { "account_head": { - "account_name": "IGST", + "account_name": "Output Tax IGST", "tax_rate": 18.00 } } ] + } + ], + "purchase_tax_templates": [ + { + "title": "Input GST In-state", + "taxes": [ + { + "account_head": { + "account_name": "Input Tax SGST", + "tax_rate": 9.00, + "root_type": "Asset" + } + }, + { + "account_head": { + "account_name": "Input Tax CGST", + "tax_rate": 9.00, + "root_type": "Asset" + } + } + ] }, + { + "title": "Input GST Out-state", + "taxes": [ + { + "account_head": { + "account_name": "Input Tax IGST", + "tax_rate": 18.00, + "root_type": "Asset" + } + } + ] + } + ], + "*": [ { "title": "VAT 5%", "taxes": [ @@ -1001,7 +1036,7 @@ "Italy VAT 4%":{ "account_name": "IVA 4%", "tax_rate": 4.00 - } + } }, "Ivory Coast": { From 3130ed52ff0625c150b1c0b8492adc4474ddbf60 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 20 Apr 2021 23:23:07 +0530 Subject: [PATCH 02/33] fix: Item Tax templates for GST --- .../setup_wizard/data/country_wise_tax.json | 148 +++++++++++++++++- 1 file changed, 142 insertions(+), 6 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 9db2122be2e..3119eeec498 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -820,29 +820,165 @@ "*": { "item_tax_templates": [ { - "title": "In State GST", + "title": "GST 9%", "taxes": [ { "tax_type": { - "account_name": "SGST", + "account_name": "Output Tax SGST", "tax_rate": 9.00 } }, { "tax_type": { - "account_name": "CGST", + "account_name": "Output Tax CGST", "tax_rate": 9.00 } + }, + { + "tax_type": { + "account_name": "Output Tax IGST", + "tax_rate": 18.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax SGST", + "tax_rate": 9.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST", + "tax_rate": 9.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST", + "tax_rate": 18.00 + } } ] }, { - "title": "Out of State GST", + "title": "GST 5%", "taxes": [ { "tax_type": { - "account_name": "IGST", - "tax_rate": 18.00 + "account_name": "Output Tax SGST", + "tax_rate": 2.5 + } + }, + { + "tax_type": { + "account_name": "Output Tax CGST", + "tax_rate": 2.5 + } + }, + { + "tax_type": { + "account_name": "Output Tax IGST", + "tax_rate": 5.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax SGST", + "tax_rate": 2.5 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST", + "tax_rate": 2.5 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST", + "tax_rate": 5.0 + } + } + ] + }, + { + "title": "GST 12%", + "taxes": [ + { + "tax_type": { + "account_name": "Output Tax SGST", + "tax_rate": 6.0 + } + }, + { + "tax_type": { + "account_name": "Output Tax CGST", + "tax_rate": 6.0 + } + }, + { + "tax_type": { + "account_name": "Output Tax IGST", + "tax_rate": 12.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax SGST", + "tax_rate": 6.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST", + "tax_rate": 6.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST", + "tax_rate": 12.0 + } + } + ] + }, + { + "title": "GST 28%", + "taxes": [ + { + "tax_type": { + "account_name": "Output Tax SGST", + "tax_rate": 14.0 + } + }, + { + "tax_type": { + "account_name": "Output Tax CGST", + "tax_rate": 14.0 + } + }, + { + "tax_type": { + "account_name": "Output Tax IGST", + "tax_rate": 28.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax SGST", + "tax_rate": 14.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST", + "tax_rate": 14.0 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST", + "tax_rate": 28.0 } } ] From 2acc66db2cc55208c73a045a4f5cd64693d06606 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 21 Apr 2021 11:49:02 +0530 Subject: [PATCH 03/33] fix: Add tax categories on company setup --- .../setup_wizard/data/country_wise_tax.json | 22 +++++++++++++++++++ .../setup_wizard/operations/taxes_setup.py | 10 +++++++++ 2 files changed, 32 insertions(+) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 3119eeec498..e3fde60ef36 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -818,6 +818,28 @@ "India": { "chart_of_accounts": { "*": { + "tax_categories": [ + { + "title": "In-Sate", + "is_inter_state": 0, + "gst_state": "" + }, + { + "title": "Out-Sate", + "is_inter_state": 1, + "gst_state": "" + }, + { + "title": "Reverse Charge", + "is_inter_state": 0, + "gst_state": "" + }, + { + "title": "Registered Composition", + "is_inter_state": 0, + "gst_state": "" + } + ], "item_tax_templates": [ { "title": "GST 9%", diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 429a558c589..578a270dd9e 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -78,6 +78,7 @@ def from_detailed_data(company_name, data): sales_tax_templates = tax_templates.get('sales_tax_templates') or tax_templates.get('*') purchase_tax_templates = tax_templates.get('purchase_tax_templates') or tax_templates.get('*') item_tax_templates = tax_templates.get('item_tax_templates') or tax_templates.get('*') + tax_categories = tax_templates.get('tax_categories') if sales_tax_templates: for template in sales_tax_templates: @@ -91,6 +92,10 @@ def from_detailed_data(company_name, data): for template in item_tax_templates: make_item_tax_template(company_name, template) + if tax_categories: + for tax_category in tax_categories: + make_tax_category(tax_category) + def make_taxes_and_charges_template(company_name, doctype, template): template['company'] = company_name @@ -146,6 +151,11 @@ def make_item_tax_template(company_name, template): return frappe.get_doc(template).insert(ignore_permissions=True) +def make_tax_category(tax_category): + """ Make tax category based on title if not already created """ + doctype = 'Tax Category' + if not frappe.db.exists(doctype, tax_category) + frappe.get_doc(tax_category).insert(ignore_permissions=True) def get_or_create_account(company_name, account): """ From 50997709d5f714ed59517177954f0c624a8f7473 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 21 Apr 2021 20:41:57 +0530 Subject: [PATCH 04/33] fix: Update country-wise-tax JSON and tax setup --- .../setup_wizard/data/country_wise_tax.json | 34 ++++++++++++------- .../setup_wizard/operations/taxes_setup.py | 22 ++++++------ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index e3fde60ef36..d21ef03e195 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -820,12 +820,12 @@ "*": { "tax_categories": [ { - "title": "In-Sate", + "title": "In-State", "is_inter_state": 0, "gst_state": "" }, { - "title": "Out-Sate", + "title": "Out-State", "is_inter_state": 1, "gst_state": "" }, @@ -1046,16 +1046,19 @@ { "account_head": { "account_name": "Output Tax SGST", - "tax_rate": 9.00 + "tax_rate": 9.00, + "account_type": "Tax" } }, { "account_head": { "account_name": "Output Tax CGST", - "tax_rate": 9.00 + "tax_rate": 9.00, + "account_type": "Tax" } } - ] + ], + "tax_category": "In-State" }, { "title": "Output GST Out-state", @@ -1063,10 +1066,12 @@ { "account_head": { "account_name": "Output Tax IGST", - "tax_rate": 18.00 + "tax_rate": 18.00, + "account_type": "Tax" } } - ] + ], + "tax_category": "Out-State" } ], "purchase_tax_templates": [ @@ -1077,17 +1082,20 @@ "account_head": { "account_name": "Input Tax SGST", "tax_rate": 9.00, - "root_type": "Asset" + "root_type": "Asset", + "account_type": "Tax" } }, { "account_head": { "account_name": "Input Tax CGST", "tax_rate": 9.00, - "root_type": "Asset" + "root_type": "Asset", + "account_type": "Tax" } } - ] + ], + "tax_category": "In-State" }, { "title": "Input GST Out-state", @@ -1096,10 +1104,12 @@ "account_head": { "account_name": "Input Tax IGST", "tax_rate": 18.00, - "root_type": "Asset" + "root_type": "Asset", + "account_type": "Tax" } } - ] + ], + "tax_category": "Out-State" } ], "*": [ diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 578a270dd9e..bbe301bb373 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -80,6 +80,10 @@ def from_detailed_data(company_name, data): item_tax_templates = tax_templates.get('item_tax_templates') or tax_templates.get('*') tax_categories = tax_templates.get('tax_categories') + if tax_categories: + for tax_category in tax_categories: + make_tax_category(tax_category) + if sales_tax_templates: for template in sales_tax_templates: make_taxes_and_charges_template(company_name, 'Sales Taxes and Charges Template', template) @@ -92,10 +96,6 @@ def from_detailed_data(company_name, data): for template in item_tax_templates: make_item_tax_template(company_name, template) - if tax_categories: - for tax_category in tax_categories: - make_tax_category(tax_category) - def make_taxes_and_charges_template(company_name, doctype, template): template['company'] = company_name @@ -154,8 +154,9 @@ def make_item_tax_template(company_name, template): def make_tax_category(tax_category): """ Make tax category based on title if not already created """ doctype = 'Tax Category' - if not frappe.db.exists(doctype, tax_category) - frappe.get_doc(tax_category).insert(ignore_permissions=True) + if not frappe.db.exists(doctype, tax_category): + tax_category['doctype'] = doctype + frappe.get_doc(tax_category).insert(ignore_permissions=True) def get_or_create_account(company_name, account): """ @@ -167,12 +168,13 @@ def get_or_create_account(company_name, account): existing_accounts = frappe.get_list('Account', filters={ - 'company': company_name, - 'root_type': root_type + 'account_name': account.get('account_name'), + 'account_number': account.get('account_number', '') }, or_filters={ - 'account_name': account.get('account_name'), - 'account_number': account.get('account_number') + 'company': company_name, + 'root_type': root_type, + 'is_group': 0 } ) From 66a71bdd1a78c4b9253080ed229a8dc25995c53c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 21 Apr 2021 20:42:20 +0530 Subject: [PATCH 05/33] fix: Issues on new company setup --- erpnext/regional/india/setup.py | 10 +++++----- .../report/e_invoice_summary/e_invoice_summary.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 9ded8dab5bc..f70ba905068 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -427,13 +427,13 @@ def make_custom_fields(update=True): dict(fieldname='einvoice_section', label='E-Invoice Fields', fieldtype='Section Break', insert_after='gst_vehicle_type', print_hide=1, hidden=1), - + dict(fieldname='ack_no', label='Ack. No.', fieldtype='Data', read_only=1, hidden=1, insert_after='einvoice_section', no_copy=1, print_hide=1), - + dict(fieldname='ack_date', label='Ack. Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_no', no_copy=1, print_hide=1), - dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date', + dict(fieldname='irn_cancel_date', label='Cancel Date', fieldtype='Data', read_only=1, hidden=1, insert_after='ack_date', no_copy=1, print_hide=1), dict(fieldname='signed_einvoice', label='Signed E-Invoice', fieldtype='Code', options='JSON', hidden=1, insert_after='irn_cancel_date', @@ -696,12 +696,12 @@ def set_tax_withholding_category(company): docs = get_tds_details(accounts, fiscal_year) for d in docs: - try: + if not frappe.db.exists("Tax Withholding Category", d.get("name")): doc = frappe.get_doc(d) doc.flags.ignore_permissions = True doc.flags.ignore_mandatory = True doc.insert() - except frappe.DuplicateEntryError: + else: doc = frappe.get_doc("Tax Withholding Category", d.get("name")) if accounts: diff --git a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json index 4deb073a53d..d0000ad50df 100644 --- a/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json +++ b/erpnext/regional/report/e_invoice_summary/e_invoice_summary.json @@ -11,7 +11,7 @@ "is_standard": "Yes", "json": "{}", "letter_head": "Logo", - "modified": "2021-03-12 12:36:48.689413", + "modified": "2021-03-13 12:36:48.689413", "modified_by": "Administrator", "module": "Regional", "name": "E-Invoice Summary", From 204ea1027f84190b5a26e127b88be19f2945337c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 30 Apr 2021 16:35:52 +0530 Subject: [PATCH 06/33] fix: Ignore validations for Tax Setup --- erpnext/regional/india/setup.py | 10 ++++-- erpnext/setup/doctype/company/company.py | 2 +- .../setup_wizard/operations/taxes_setup.py | 34 ++++++++++++++----- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index f70ba905068..aedd6c88aba 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -25,6 +25,7 @@ def setup_company_independent_fixtures(patch=False): frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test) create_gratuity_rule() add_print_formats() + update_accounts_settings_for_taxes() def add_hsn_sac_codes(): # HSN codes @@ -698,6 +699,7 @@ def set_tax_withholding_category(company): for d in docs: if not frappe.db.exists("Tax Withholding Category", d.get("name")): doc = frappe.get_doc(d) + doc.flags.ignore_validate = True doc.flags.ignore_permissions = True doc.flags.ignore_mandatory = True doc.insert() @@ -714,11 +716,12 @@ def set_tax_withholding_category(company): doc.append("rates", d.get('rates')[0]) doc.flags.ignore_permissions = True + doc.flags.ignore_validdate = True doc.flags.ignore_mandatory = True + doc.flags.ignore_links = True doc.save() def set_tds_account(docs, company): - abbr = frappe.get_value("Company", company, "abbr") parent_account = frappe.db.get_value("Account", filters = {"account_name": "Duties and Taxes", "company": company}) if parent_account: docs.extend([ @@ -877,7 +880,6 @@ def get_tds_details(accounts, fiscal_year): ] def create_gratuity_rule(): - # Standard Indain Gratuity Rule if not frappe.db.exists("Gratuity Rule", "Indian Standard Gratuity Rule"): rule = frappe.new_doc("Gratuity Rule") @@ -895,3 +897,7 @@ def create_gratuity_rule(): rule.flags.ignore_mandatory = True rule.save() + +def update_accounts_settings_for_taxes(): + if frappe.db.count('Company') == 1: + frappe.db.set_value('Accounts Settings', None, "add_taxes_from_item_tax_template", 0) \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 64e027dd28b..aa4bc98875f 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -110,7 +110,7 @@ class Company(NestedSet): self.create_default_warehouses() if frappe.flags.country_change: - install_country_fixtures(self.name) + install_country_fixtures(self.name, self.country) self.create_default_tax_template() if not frappe.db.get_value("Department", {"company": self.name}): diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index bbe301bb373..a644da92925 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -123,8 +123,11 @@ def make_taxes_and_charges_template(company_name, doctype, template): if fieldname not in tax_row: tax_row[fieldname] = default_value - return frappe.get_doc(template).insert(ignore_permissions=True) - + doc = frappe.get_doc(template) + doc.flags.ignore_links = True + doc.flags.ignore_validate = True + doc.insert(ignore_permissions=True) + return doc def make_item_tax_template(company_name, template): """Create an Item Tax Template. @@ -149,14 +152,21 @@ def make_item_tax_template(company_name, template): if 'tax_rate' not in tax_row: tax_row['tax_rate'] = account_data.get('tax_rate') - return frappe.get_doc(template).insert(ignore_permissions=True) + doc = frappe.get_doc(template) + doc.flags.ignore_links = True + doc.flags.ignore_validate = True + doc.insert(ignore_permissions=True) + return doc def make_tax_category(tax_category): """ Make tax category based on title if not already created """ doctype = 'Tax Category' if not frappe.db.exists(doctype, tax_category): tax_category['doctype'] = doctype - frappe.get_doc(tax_category).insert(ignore_permissions=True) + doc = frappe.get_doc(tax_category) + doc.flags.ignore_links = True + doc.flags.ignore_validate = True + doc.insert(ignore_permissions=True) def get_or_create_account(company_name, account): """ @@ -169,7 +179,8 @@ def get_or_create_account(company_name, account): existing_accounts = frappe.get_list('Account', filters={ 'account_name': account.get('account_name'), - 'account_number': account.get('account_number', '') + 'account_number': account.get('account_number', ''), + 'company': company_name }, or_filters={ 'company': company_name, @@ -191,8 +202,11 @@ def get_or_create_account(company_name, account): account['root_type'] = root_type account['is_group'] = 0 - return frappe.get_doc(account).insert(ignore_permissions=True, ignore_mandatory=True) - + doc = frappe.get_doc(account) + doc.flags.ignore_links = True + doc.flags.ignore_validate = True + doc.insert(ignore_permissions=True, ignore_mandatory=True) + return doc def get_or_create_tax_group(company_name, root_type): # Look for a group account of type 'Tax' @@ -237,7 +251,11 @@ def get_or_create_tax_group(company_name, root_type): 'account_type': 'Tax', 'account_name': account_name, 'parent_account': root_account.name - }).insert(ignore_permissions=True) + }) + + tax_group_account.flags.ignore_links = True + tax_group_account.flags.ignore_validate = True + tax_group_account.insert(ignore_permissions=True) tax_group_name = tax_group_account.name From a66184fe3cd9527b8b13c9b4897b46ec0dcbed8c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 2 May 2021 12:22:16 +0530 Subject: [PATCH 07/33] fix: Remove redundant get_doc --- erpnext/regional/india/setup.py | 2 +- erpnext/setup/doctype/company/company.py | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index aedd6c88aba..71b5661a4e1 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -646,7 +646,7 @@ def make_custom_fields(update=True): def make_fixtures(company=None): docs = [] - company = company.name if company else frappe.db.get_value("Global Defaults", None, "default_company") + company = company or frappe.db.get_value("Global Defaults", None, "default_company") set_salary_components(docs) set_tds_account(docs, company) diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index aa4bc98875f..779e976181c 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -435,13 +435,12 @@ def get_name_with_abbr(name, company): return " - ".join(parts) -def install_country_fixtures(company): - company_doc = frappe.get_doc("Company", company) - path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(company_doc.country)) +def install_country_fixtures(company, country): + path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country)) if os.path.exists(path.encode("utf-8")): try: - module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(company_doc.country)) - frappe.get_attr(module_name)(company_doc, False) + module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(country)) + frappe.get_attr(module_name)(company, False) except Exception as e: frappe.log_error() frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country))) From f6610c96dd6cf3585dcbadfaf90bc973a60bb40f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 2 May 2021 12:23:11 +0530 Subject: [PATCH 08/33] fix: Gracefully handle duplicate bank account name to make setup faster --- erpnext/accounts/doctype/account/account.py | 6 +++++ .../chart_of_accounts/chart_of_accounts.py | 18 ------------- erpnext/public/js/setup_wizard.js | 26 ------------------- 3 files changed, 6 insertions(+), 44 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 06068238213..60269943cf7 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -28,6 +28,12 @@ class Account(NestedSet): from erpnext.accounts.utils import get_autoname_with_number self.name = get_autoname_with_number(self.account_number, self.account_name, None, self.company) + def before_insert(self): + # Update Bank account name if conflicting with any other account + if frappe.flags.in_install and self.account_type == 'Bank': + if frappe.db.get_value('Account', {'account_name': self.account_name}): + self.account_name = self.account_name + '-1' + def validate(self): from erpnext.accounts.utils import validate_field_number if frappe.local.flags.allow_unverified_charts: 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 0e3b24cda3d..9d3174204bd 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 @@ -188,24 +188,6 @@ def build_account_tree(tree, parent, all_accounts): # call recursively to build a subtree for current account build_account_tree(tree[child.account_name], child, all_accounts) -@frappe.whitelist() -def validate_bank_account(coa, bank_account): - accounts = [] - chart = get_chart(coa) - - if chart: - def _get_account_names(account_master): - for account_name, child in iteritems(account_master): - if account_name not in ["account_number", "account_type", - "root_type", "is_group", "tax_rate"]: - accounts.append(account_name) - - _get_account_names(child) - - _get_account_names(chart) - - return (bank_account in accounts) - @frappe.whitelist() 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 ''' diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index ef03b01698c..a3045724fee 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -139,36 +139,10 @@ erpnext.setup.slides_settings = [ }, validate: function () { - let me = this; - let exist; - if (!this.validate_fy_dates()) { return false; } - // Validate bank name - if(me.values.bank_account){ - frappe.call({ - async: false, - method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.validate_bank_account", - args: { - "coa": me.values.chart_of_accounts, - "bank_account": me.values.bank_account - }, - callback: function (r) { - if(r.message){ - exist = r.message; - me.get_field("bank_account").set_value(""); - let message = __('Account {0} already exists. Please enter a different name for your bank account.', - [me.values.bank_account] - ); - frappe.msgprint(message); - } - } - }); - return !exist; // Return False if exist = true - } - return true; }, From 72e602ae548a4dd16ace8788f574c09374941b68 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 2 May 2021 18:22:29 +0530 Subject: [PATCH 09/33] fix: Add validation for GST Settings --- .../regional/doctype/gst_settings/gst_settings.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.py b/erpnext/regional/doctype/gst_settings/gst_settings.py index bc956e9fa88..af3d92e59a7 100644 --- a/erpnext/regional/doctype/gst_settings/gst_settings.py +++ b/erpnext/regional/doctype/gst_settings/gst_settings.py @@ -19,6 +19,21 @@ class GSTSettings(Document): from tabAddress where country = "India" and ifnull(gstin, '')!='' ''') self.set_onload('data', data) + def validate(self): + # Validate duplicate accounts + self.validate_duplicate_accounts() + + def validate_duplicate_accounts(self): + account_list = [] + for account in self.get('gst_accounts'): + for fieldname in ['cgst_account', 'sgst_account', 'igst_account', 'cess_account']: + if account.get(fieldname) in account_list: + frappe.throw(_("Account {0} appears multiple times").format( + frappe.bold(account.get(fieldname)))) + + if account.get(fieldname): + account_list.append(account.get(fieldname)) + @frappe.whitelist() def send_reminder(): frappe.has_permission('GST Settings', throw=True) From 1bac72b74d41a7284ca5028015a386b6cdaa61b5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 2 May 2021 22:29:48 +0530 Subject: [PATCH 10/33] fix: Add GST accounts to GST Settings --- erpnext/regional/india/setup.py | 52 ++++++++++++++++++++++++ erpnext/setup/doctype/company/company.py | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 71b5661a4e1..2c0a285546c 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -15,6 +15,7 @@ def setup(company=None, patch=True): setup_company_independent_fixtures(patch=patch) if not patch: make_fixtures(company) + setup_gst_settings(company) # TODO: for all countries def setup_company_independent_fixtures(patch=False): @@ -664,6 +665,57 @@ def make_fixtures(company=None): # create records for Tax Withholding Category set_tax_withholding_category(company) +def setup_gst_settings(company): + # Will only add default GST accounts if present + input_account_names = ['Input Tax CGST', 'Input Tax SGST', 'Input Tax IGST'] + output_account_names = ['Output Tax CGST', 'Output Tax SGST', 'Output Tax IGST'] + gst_settings = frappe.get_single('GST Settings') + existing_account_list = [] + + for account in gst_settings.get('gst_accounts'): + for key in ['cgst_account', 'sgst_account', 'igst_account']: + existing_account_list.append(account.get(key)) + + gst_accounts = frappe._dict(frappe.get_all("Account", + {'company': company, 'name': ('like', "%GST%")}, ['account_name', 'name'], as_list=1)) + + all_input_account_exists = 0 + all_output_account_exists = 0 + + for account in input_account_names: + if not gst_accounts.get(account): + all_input_account_exists = 1 + + # Check if already added in GST Settings + if gst_accounts.get(account) in existing_account_list: + all_input_account_exists = 1 + + for account in output_account_names: + if not gst_accounts.get(account): + all_output_account_exists = 1 + + # Check if already added in GST Settings + if gst_accounts.get(account) in existing_account_list: + all_output_account_exists = 1 + + if not all_input_account_exists: + gst_settings.append('gst_accounts', { + 'company': company, + 'cgst_account': gst_accounts.get(input_account_names[0]), + 'sgst_account': gst_accounts.get(input_account_names[1]), + 'igst_account': gst_accounts.get(input_account_names[2]) + }) + + if not all_output_account_exists: + gst_settings.append('gst_accounts', { + 'company': company, + 'cgst_account': gst_accounts.get(output_account_names[0]), + 'sgst_account': gst_accounts.get(output_account_names[1]), + 'igst_account': gst_accounts.get(output_account_names[2]) + }) + + gst_settings.save() + def set_salary_components(docs): docs.extend([ {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 779e976181c..9a74a2e68ef 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -443,7 +443,7 @@ def install_country_fixtures(company, country): frappe.get_attr(module_name)(company, False) except Exception as e: frappe.log_error() - frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country))) + frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(country))) def update_company_current_month_sales(company): From 48b1a82fa1d873470c6b5513742b104ef3f3573e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 29 May 2021 23:54:51 +0530 Subject: [PATCH 11/33] fix: Add accounts and templates for reverse charge --- erpnext/accounts/doctype/account/account.py | 6 - erpnext/accounts/utils.py | 2 +- erpnext/regional/india/setup.py | 68 +++++------ erpnext/setup/doctype/company/company.py | 2 +- .../setup_wizard/data/country_wise_tax.json | 115 +++++++++++++++++- .../setup_wizard/operations/company_setup.py | 23 ---- 6 files changed, 148 insertions(+), 68 deletions(-) diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 645f49bcdc4..1be2fbf5c81 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -28,12 +28,6 @@ class Account(NestedSet): from erpnext.accounts.utils import get_autoname_with_number self.name = get_autoname_with_number(self.account_number, self.account_name, None, self.company) - def before_insert(self): - # Update Bank account name if conflicting with any other account - if frappe.flags.in_install and self.account_type == 'Bank': - if frappe.db.get_value('Account', {'account_name': self.account_name}): - self.account_name = self.account_name + '-1' - def validate(self): from erpnext.accounts.utils import validate_field_number if frappe.local.flags.allow_unverified_charts: diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 5a64e27ccb7..121589930b3 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -784,7 +784,7 @@ def get_children(doctype, parent, company, is_root=False): return acc def create_payment_gateway_account(gateway, payment_channel="Email"): - from erpnext.setup.setup_wizard.operations.company_setup import create_bank_account + from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account company = frappe.db.get_value("Global Defaults", None, "default_company") if not company: diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 28f49e0a7e5..d79ce64fb35 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -698,6 +698,7 @@ def setup_gst_settings(company): # Will only add default GST accounts if present input_account_names = ['Input Tax CGST', 'Input Tax SGST', 'Input Tax IGST'] output_account_names = ['Output Tax CGST', 'Output Tax SGST', 'Output Tax IGST'] + rcm_accounts = ['Input Tax CGST RCM', 'Input Tax SGST RCM', 'Input Tax IGST RCM'] gst_settings = frappe.get_single('GST Settings') existing_account_list = [] @@ -706,45 +707,40 @@ def setup_gst_settings(company): existing_account_list.append(account.get(key)) gst_accounts = frappe._dict(frappe.get_all("Account", - {'company': company, 'name': ('like', "%GST%")}, ['account_name', 'name'], as_list=1)) + {'company': company, 'account_name': ('in', input_account_names + + output_account_names + rcm_accounts)}, ['account_name', 'name'], as_list=1)) - all_input_account_exists = 0 - all_output_account_exists = 0 - - for account in input_account_names: - if not gst_accounts.get(account): - all_input_account_exists = 1 - - # Check if already added in GST Settings - if gst_accounts.get(account) in existing_account_list: - all_input_account_exists = 1 - - for account in output_account_names: - if not gst_accounts.get(account): - all_output_account_exists = 1 - - # Check if already added in GST Settings - if gst_accounts.get(account) in existing_account_list: - all_output_account_exists = 1 - - if not all_input_account_exists: - gst_settings.append('gst_accounts', { - 'company': company, - 'cgst_account': gst_accounts.get(input_account_names[0]), - 'sgst_account': gst_accounts.get(input_account_names[1]), - 'igst_account': gst_accounts.get(input_account_names[2]) - }) - - if not all_output_account_exists: - gst_settings.append('gst_accounts', { - 'company': company, - 'cgst_account': gst_accounts.get(output_account_names[0]), - 'sgst_account': gst_accounts.get(output_account_names[1]), - 'igst_account': gst_accounts.get(output_account_names[2]) - }) + add_accounts_in_gst_settings(company, input_account_names, gst_accounts, + existing_account_list, gst_settings) + add_accounts_in_gst_settings(company, output_account_names, gst_accounts, + existing_account_list, gst_settings) + add_accounts_in_gst_settings(company, rcm_accounts, gst_accounts, + existing_account_list, gst_settings, is_reverse_charge=1) gst_settings.save() +def add_accounts_in_gst_settings(company, account_names, gst_accounts, + existing_account_list, gst_settings, is_reverse_charge=0): + accounts_not_added = 1 + + for account in account_names: + # Default Account Added does not exists + if not gst_accounts.get(account): + accounts_not_added = 0 + + # Check if already added in GST Settings + if gst_accounts.get(account) in existing_account_list: + accounts_not_added = 0 + + if accounts_not_added: + gst_settings.append('gst_accounts', { + 'company': company, + 'cgst_account': gst_accounts.get(account_names[0]), + 'sgst_account': gst_accounts.get(account_names[1]), + 'igst_account': gst_accounts.get(account_names[2]), + 'is_reverse_charge_account': is_reverse_charge + }) + def set_salary_components(docs): docs.extend([ {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', @@ -797,7 +793,7 @@ def set_tax_withholding_category(company): doc.append("rates", d.get('rates')[0]) doc.flags.ignore_permissions = True - doc.flags.ignore_validdate = True + doc.flags.ignore_validate = True doc.flags.ignore_mandatory = True doc.flags.ignore_links = True doc.save() diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 61d63a3f29d..ff96c0b4c47 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -110,8 +110,8 @@ class Company(NestedSet): self.create_default_warehouses() if frappe.flags.country_change: - install_country_fixtures(self.name, self.country) self.create_default_tax_template() + install_country_fixtures(self.name, self.country) if not frappe.db.get_value("Department", {"company": self.name}): from erpnext.setup.setup_wizard.operations.install_fixtures import install_post_company_fixtures diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index d21ef03e195..ee42a87320e 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -830,7 +830,12 @@ "gst_state": "" }, { - "title": "Reverse Charge", + "title": "Reverse Charge In-State", + "is_inter_state": 0, + "gst_state": "" + }, + { + "title": "Reverse Charge Out-State", "is_inter_state": 0, "gst_state": "" }, @@ -879,6 +884,24 @@ "account_name": "Input Tax IGST", "tax_rate": 18.00 } + }, + { + "tax_type": { + "account_name": "Input Tax SGST RCM", + "tax_rate": 9.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST RCM", + "tax_rate": 9.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST RCM", + "tax_rate": 18.00 + } } ] }, @@ -920,6 +943,24 @@ "account_name": "Input Tax IGST", "tax_rate": 5.0 } + }, + { + "tax_type": { + "account_name": "Input Tax SGST RCM", + "tax_rate": 2.50 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST RCM", + "tax_rate": 2.50 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST RCM", + "tax_rate": 5.00 + } } ] }, @@ -961,6 +1002,24 @@ "account_name": "Input Tax IGST", "tax_rate": 12.0 } + }, + { + "tax_type": { + "account_name": "Input Tax SGST RCM", + "tax_rate": 6.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST RCM", + "tax_rate": 6.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST RCM", + "tax_rate": 12.00 + } } ] }, @@ -1002,6 +1061,24 @@ "account_name": "Input Tax IGST", "tax_rate": 28.0 } + }, + { + "tax_type": { + "account_name": "Input Tax SGST RCM", + "tax_rate": 14.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax CGST RCM", + "tax_rate": 14.00 + } + }, + { + "tax_type": { + "account_name": "Input Tax IGST RCM", + "tax_rate": 28.00 + } } ] }, @@ -1110,6 +1187,42 @@ } ], "tax_category": "Out-State" + }, + { + "title": "Input GST RCM In-state", + "taxes": [ + { + "account_head": { + "account_name": "Input Tax SGST RCM", + "tax_rate": 9.00, + "root_type": "Asset", + "account_type": "Tax" + } + }, + { + "account_head": { + "account_name": "Input Tax CGST RCM", + "tax_rate": 9.00, + "root_type": "Asset", + "account_type": "Tax" + } + } + ], + "tax_category": "Reverse Charge In-State" + }, + { + "title": "Input GST RCM Out-state", + "taxes": [ + { + "account_head": { + "account_name": "Input Tax IGST RCM", + "tax_rate": 18.00, + "root_type": "Asset", + "account_type": "Tax" + } + } + ], + "tax_category": "Reverse Charge Out-State" } ], "*": [ diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py index 3f0bb146499..4edf9485dc1 100644 --- a/erpnext/setup/setup_wizard/operations/company_setup.py +++ b/erpnext/setup/setup_wizard/operations/company_setup.py @@ -42,29 +42,6 @@ def enable_shopping_cart(args): 'quotation_series': "QTN-", }).insert() -def create_bank_account(args): - if args.get("bank_account"): - company_name = args.get('company_name') - bank_account_group = frappe.db.get_value("Account", - {"account_type": "Bank", "is_group": 1, "root_type": "Asset", - "company": company_name}) - if bank_account_group: - bank_account = frappe.get_doc({ - "doctype": "Account", - 'account_name': args.get("bank_account"), - 'parent_account': bank_account_group, - 'is_group':0, - 'company': company_name, - "account_type": "Bank", - }) - try: - return bank_account.insert() - except RootNotEditable: - frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account"))) - except frappe.DuplicateEntryError: - # bank account same as a CoA entry - pass - def create_email_digest(): from frappe.utils.user import get_system_managers system_managers = get_system_managers(only_name=True) From b3ed807b70d5bd1b1b94442fd0c4f1d774846d9d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 2 Jun 2021 13:26:21 +0530 Subject: [PATCH 12/33] fix: Regional settings setup --- erpnext/regional/india/setup.py | 3 +-- erpnext/setup/doctype/company/company.py | 2 +- erpnext/setup/setup_wizard/operations/taxes_setup.py | 12 ++++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index d79ce64fb35..fa9f1b7e9ef 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -15,7 +15,6 @@ def setup(company=None, patch=True): setup_company_independent_fixtures(patch=patch) if not patch: make_fixtures(company) - setup_gst_settings(company) # TODO: for all countries def setup_company_independent_fixtures(patch=False): @@ -694,7 +693,7 @@ def make_fixtures(company=None): # create records for Tax Withholding Category set_tax_withholding_category(company) -def setup_gst_settings(company): +def update_regional_tax_settings(country, company): # Will only add default GST accounts if present input_account_names = ['Input Tax CGST', 'Input Tax SGST', 'Input Tax IGST'] output_account_names = ['Output Tax CGST', 'Output Tax SGST', 'Output Tax IGST'] diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index ff96c0b4c47..61d63a3f29d 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -110,8 +110,8 @@ class Company(NestedSet): self.create_default_warehouses() if frappe.flags.country_change: - self.create_default_tax_template() install_country_fixtures(self.name, self.country) + 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 diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index a644da92925..6ac561223ab 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -24,6 +24,7 @@ def setup_taxes_and_charges(company_name: str, country: str): country_wise_tax = simple_to_detailed(country_wise_tax) from_detailed_data(company_name, country_wise_tax.get('chart_of_accounts')) + update_regional_tax_settings(country, company_name) def simple_to_detailed(templates): @@ -97,6 +98,17 @@ def from_detailed_data(company_name, data): make_item_tax_template(company_name, template) +def update_regional_tax_settings(country, company): + path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country)) + if os.path.exists(path.encode("utf-8")): + try: + module_name = "erpnext.regional.{0}.setup.update_regional_tax_settings".format(frappe.scrub(country)) + frappe.get_attr(module_name)(country, company) + except Exception as e: + # Log error and ignore if failed to setup regional tax settings + frappe.log_error() + pass + def make_taxes_and_charges_template(company_name, doctype, template): template['company'] = company_name template['doctype'] = doctype From 7c7c084159b68f99927cc28b4b3b88fa8c415b80 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 2 Jun 2021 14:12:28 +0530 Subject: [PATCH 13/33] fix: Check for tax category --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 4c496090391..9a830d4f2e2 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -176,7 +176,7 @@ def make_item_tax_template(company_name, template): def make_tax_category(tax_category): """ Make tax category based on title if not already created """ doctype = 'Tax Category' - if not frappe.db.exists(doctype, tax_category): + if not frappe.db.exists(doctype, tax_category['title']): tax_category['doctype'] = doctype doc = frappe.get_doc(tax_category) doc.flags.ignore_links = True From 40a4330ec1240492484d67bbdd0eeb777440c34f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 23 Jun 2021 12:38:37 +0530 Subject: [PATCH 14/33] fix: Move tax categories up in country wise json --- .../setup_wizard/data/country_wise_tax.json | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index 6df57f17380..e36bf5cbe0e 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -1164,35 +1164,35 @@ }, "India": { + "tax_categories": [ + { + "title": "In-State", + "is_inter_state": 0, + "gst_state": "" + }, + { + "title": "Out-State", + "is_inter_state": 1, + "gst_state": "" + }, + { + "title": "Reverse Charge In-State", + "is_inter_state": 0, + "gst_state": "" + }, + { + "title": "Reverse Charge Out-State", + "is_inter_state": 1, + "gst_state": "" + }, + { + "title": "Registered Composition", + "is_inter_state": 0, + "gst_state": "" + } + ], "chart_of_accounts": { "*": { - "tax_categories": [ - { - "title": "In-State", - "is_inter_state": 0, - "gst_state": "" - }, - { - "title": "Out-State", - "is_inter_state": 1, - "gst_state": "" - }, - { - "title": "Reverse Charge In-State", - "is_inter_state": 0, - "gst_state": "" - }, - { - "title": "Reverse Charge Out-State", - "is_inter_state": 0, - "gst_state": "" - }, - { - "title": "Registered Composition", - "is_inter_state": 0, - "gst_state": "" - } - ], "item_tax_templates": [ { "title": "GST 9%", From 208b5f9e7303bd89b694aa569c6143d4656c4c6b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 23 Jun 2021 12:44:56 +0530 Subject: [PATCH 15/33] chore: Add comments --- erpnext/setup/setup_wizard/operations/taxes_setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index a664914f08e..d5682b6f4ca 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -143,6 +143,9 @@ def make_taxes_and_charges_template(company_name, doctype, template): tax_row[fieldname] = default_value doc = frappe.get_doc(template) + + # Data in country wise json is already pre validated, hence validations can be ignored + # Ingone validations to make doctypes faster doc.flags.ignore_links = True doc.flags.ignore_validate = True doc.insert(ignore_permissions=True) @@ -172,6 +175,9 @@ def make_item_tax_template(company_name, template): tax_row['tax_rate'] = account_data.get('tax_rate') doc = frappe.get_doc(template) + + # Data in country wise json is already pre validated, hence validations can be ignored + # Ingone validations to make doctypes faster doc.flags.ignore_links = True doc.flags.ignore_validate = True doc.insert(ignore_permissions=True) From 35e11fbea6baeb140a08bee8a30a2d156f20e7b1 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 23 Jun 2021 13:17:01 +0530 Subject: [PATCH 16/33] fix: Tests --- erpnext/setup/setup_wizard/operations/install_fixtures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 5c725d332de..9c7d9e5259d 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -480,7 +480,7 @@ def update_stock_settings(): stock_settings.save() def create_bank_account(args): - if not args.bank_account: + if not args.get('bank_account'): return company_name = args.company_name From 0bfffddac470cb003efba73d4ee6c1bca2620609 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 23 Jun 2021 15:37:17 +0530 Subject: [PATCH 17/33] fix: Test Cases --- erpnext/setup/setup_wizard/operations/install_fixtures.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 9c7d9e5259d..7dfb9f4d3c2 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -483,14 +483,14 @@ def create_bank_account(args): if not args.get('bank_account'): return - company_name = args.company_name + company_name = args.get('company_name') bank_account_group = frappe.db.get_value("Account", {"account_type": "Bank", "is_group": 1, "root_type": "Asset", "company": company_name}) if bank_account_group: bank_account = frappe.get_doc({ "doctype": "Account", - 'account_name': args.bank_account, + 'account_name': args.get('bank_account'), 'parent_account': bank_account_group, 'is_group':0, 'company': company_name, @@ -499,10 +499,10 @@ def create_bank_account(args): try: doc = bank_account.insert() - frappe.db.set_value("Company", args.company_name, "default_bank_account", bank_account.name, update_modified=False) + frappe.db.set_value("Company", args.get('company_name'), "default_bank_account", bank_account.name, update_modified=False) except RootNotEditable: - frappe.throw(_("Bank account cannot be named as {0}").format(args.bank_account)) + frappe.throw(_("Bank account cannot be named as {0}").format(args.get('bank_account'))) except frappe.DuplicateEntryError: # bank account same as a CoA entry pass From 1e5482cedd605f2398f6dbeff4efe40a8cbc1848 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 26 Jun 2021 23:49:32 +0530 Subject: [PATCH 18/33] fix: Revert Changes --- erpnext/public/js/setup_wizard.js | 26 +++++++ .../setup_wizard/data/country_wise_tax.json | 72 ++++++++++++------- .../setup_wizard/operations/taxes_setup.py | 15 ++-- 3 files changed, 81 insertions(+), 32 deletions(-) diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index a3045724fee..6f5d67c7462 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -139,10 +139,36 @@ erpnext.setup.slides_settings = [ }, validate: function () { + let me = this; + let exist; + if (!this.validate_fy_dates()) { return false; } + // Validate bank name + if(me.values.bank_account) { + frappe.call({ + async: false, + method: "erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts.validate_bank_account", + args: { + "coa": me.values.chart_of_accounts, + "bank_account": me.values.bank_account + }, + callback: function (r) { + if(r.message){ + exist = r.message; + me.get_field("bank_account").set_value(""); + let message = __('Account {0} already exists. Please enter a different name for your bank account.', + [me.values.bank_account] + ); + frappe.msgprint(message); + } + } + }); + return !exist; // Return False if exist = true + } + return true; }, diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json index e36bf5cbe0e..34af093a231 100644 --- a/erpnext/setup/setup_wizard/data/country_wise_tax.json +++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json @@ -1218,37 +1218,43 @@ { "tax_type": { "account_name": "Input Tax SGST", - "tax_rate": 9.00 + "tax_rate": 9.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST", - "tax_rate": 9.00 + "tax_rate": 9.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST", - "tax_rate": 18.00 + "tax_rate": 18.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax SGST RCM", - "tax_rate": 9.00 + "tax_rate": 9.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST RCM", - "tax_rate": 9.00 + "tax_rate": 9.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST RCM", - "tax_rate": 18.00 + "tax_rate": 18.00, + "root_type": "Asset" } } ] @@ -1277,37 +1283,43 @@ { "tax_type": { "account_name": "Input Tax SGST", - "tax_rate": 2.5 + "tax_rate": 2.5, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST", - "tax_rate": 2.5 + "tax_rate": 2.5, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST", - "tax_rate": 5.0 + "tax_rate": 5.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax SGST RCM", - "tax_rate": 2.50 + "tax_rate": 2.50, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST RCM", - "tax_rate": 2.50 + "tax_rate": 2.50, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST RCM", - "tax_rate": 5.00 + "tax_rate": 5.00, + "root_type": "Asset" } } ] @@ -1336,37 +1348,43 @@ { "tax_type": { "account_name": "Input Tax SGST", - "tax_rate": 6.0 + "tax_rate": 6.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST", - "tax_rate": 6.0 + "tax_rate": 6.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST", - "tax_rate": 12.0 + "tax_rate": 12.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax SGST RCM", - "tax_rate": 6.00 + "tax_rate": 6.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST RCM", - "tax_rate": 6.00 + "tax_rate": 6.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST RCM", - "tax_rate": 12.00 + "tax_rate": 12.00, + "root_type": "Asset" } } ] @@ -1395,37 +1413,43 @@ { "tax_type": { "account_name": "Input Tax SGST", - "tax_rate": 14.0 + "tax_rate": 14.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST", - "tax_rate": 14.0 + "tax_rate": 14.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST", - "tax_rate": 28.0 + "tax_rate": 28.0, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax SGST RCM", - "tax_rate": 14.00 + "tax_rate": 14.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax CGST RCM", - "tax_rate": 14.00 + "tax_rate": 14.00, + "root_type": "Asset" } }, { "tax_type": { "account_name": "Input Tax IGST RCM", - "tax_rate": 28.00 + "tax_rate": 28.00, + "root_type": "Asset" } } ] diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index d5682b6f4ca..9f73f214bd1 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -203,16 +203,15 @@ def get_or_create_account(company_name, account): existing_accounts = frappe.get_list('Account', filters={ - 'account_name': account.get('account_name'), - 'account_number': account.get('account_number', ''), - 'company': company_name + 'company': company_name, + 'root_type': root_type }, or_filters={ - 'company': company_name, - 'root_type': root_type, - 'is_group': 0 - } - ) + 'account_name': account.get('account_name'), + 'account_number': account.get('account_number') + }) + + print(company_name, account, existing_accounts) if existing_accounts: return frappe.get_doc('Account', existing_accounts[0].name) From cf445eb7b4f057dfb57c0861745051d5e65dccb9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 26 Jun 2021 23:59:47 +0530 Subject: [PATCH 19/33] fix: Add validate bank account method back --- .../chart_of_accounts/chart_of_accounts.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 9b6842d896c..927adc7086c 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 @@ -188,6 +188,24 @@ def build_account_tree(tree, parent, all_accounts): # call recursively to build a subtree for current account build_account_tree(tree[child.account_name], child, all_accounts) +@frappe.whitelist() +def validate_bank_account(coa, bank_account): + accounts = [] + chart = get_chart(coa) + + if chart: + def _get_account_names(account_master): + for account_name, child in iteritems(account_master): + if account_name not in ["account_number", "account_type", + "root_type", "is_group", "tax_rate"]: + accounts.append(account_name) + + _get_account_names(child) + + _get_account_names(chart) + + return (bank_account in accounts) + @frappe.whitelist() 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 ''' From ebc46c1e09b26fc6a26ad386272affd78fa2948e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 28 Jun 2021 10:52:38 +0530 Subject: [PATCH 20/33] fix: Update account heads in GST test cases --- .../sales_invoice/test_sales_invoice.py | 63 ++++++++++--------- .../gstr_3b_report/test_gstr_3b_report.py | 28 ++++----- .../setup_wizard/operations/taxes_setup.py | 2 - 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 114b7d2d352..dbc7f8632fc 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1957,6 +1957,33 @@ class TestSalesInvoice(unittest.TestCase): einvoice = make_einvoice(si) validate_totals(einvoice) + def test_item_tax_net_range(self): + item = create_item("T Shirt") + + item.set('taxes', []) + item.append("taxes", { + "item_tax_template": "_Test Account Excise Duty @ 10 - _TC", + "minimum_net_rate": 0, + "maximum_net_rate": 500 + }) + + item.append("taxes", { + "item_tax_template": "_Test Account Excise Duty @ 12 - _TC", + "minimum_net_rate": 501, + "maximum_net_rate": 1000 + }) + + item.save() + + sales_invoice = create_sales_invoice(item = "T Shirt", rate=700, do_not_submit=True) + self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC") + + # Apply discount + sales_invoice.apply_discount_on = 'Net Total' + sales_invoice.discount_amount = 300 + sales_invoice.save() + self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC") + def get_sales_invoice_for_e_invoice(): si = make_sales_invoice_for_ewaybill() si.naming_series = 'INV-2020-.#####' @@ -1985,32 +2012,6 @@ def get_sales_invoice_for_e_invoice(): return si - def test_item_tax_net_range(self): - item = create_item("T Shirt") - - item.set('taxes', []) - item.append("taxes", { - "item_tax_template": "_Test Account Excise Duty @ 10 - _TC", - "minimum_net_rate": 0, - "maximum_net_rate": 500 - }) - - item.append("taxes", { - "item_tax_template": "_Test Account Excise Duty @ 12 - _TC", - "minimum_net_rate": 501, - "maximum_net_rate": 1000 - }) - - item.save() - - sales_invoice = create_sales_invoice(item = "T Shirt", rate=700, do_not_submit=True) - self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC") - - # Apply discount - sales_invoice.apply_discount_on = 'Net Total' - sales_invoice.discount_amount = 300 - sales_invoice.save() - self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC") def make_test_address_for_ewaybill(): if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'): @@ -2087,9 +2088,9 @@ def make_sales_invoice_for_ewaybill(): if not gst_account: gst_settings.append("gst_accounts", { "company": "_Test Company", - "cgst_account": "CGST - _TC", - "sgst_account": "SGST - _TC", - "igst_account": "IGST - _TC", + "cgst_account": "Output Tax CGST - _TC", + "sgst_account": "Output Tax SGST - _TC", + "igst_account": "Output Tax IGST - _TC", }) gst_settings.save() @@ -2106,7 +2107,7 @@ def make_sales_invoice_for_ewaybill(): si.append("taxes", { "charge_type": "On Net Total", - "account_head": "CGST - _TC", + "account_head": "Output Tax CGST - _TC", "cost_center": "Main - _TC", "description": "CGST @ 9.0", "rate": 9 @@ -2114,7 +2115,7 @@ def make_sales_invoice_for_ewaybill(): si.append("taxes", { "charge_type": "On Net Total", - "account_head": "SGST - _TC", + "account_head": "Output Tax SGST - _TC", "cost_center": "Main - _TC", "description": "SGST @ 9.0", "rate": 9 diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py index 3857ce1cdb8..065f80d610a 100644 --- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py @@ -46,14 +46,14 @@ class TestGSTR3BReport(unittest.TestCase): make_sales_invoice() create_purchase_invoices() - if frappe.db.exists("GSTR 3B Report", "GSTR3B-March-2019-_Test Address-Billing"): - report = frappe.get_doc("GSTR 3B Report", "GSTR3B-March-2019-_Test Address-Billing") + if frappe.db.exists("GSTR 3B Report", "GSTR3B-March-2019-_Test Address GST-Billing"): + report = frappe.get_doc("GSTR 3B Report", "GSTR3B-March-2019-_Test Address GST-Billing") report.save() else: report = frappe.get_doc({ "doctype": "GSTR 3B Report", "company": "_Test Company GST", - "company_address": "_Test Address-Billing", + "company_address": "_Test Address GST-Billing", "year": getdate().year, "month": month_number_mapping.get(getdate().month) }).insert() @@ -89,7 +89,7 @@ class TestGSTR3BReport(unittest.TestCase): si.append("taxes", { "charge_type": "On Net Total", - "account_head": "IGST - _GST", + "account_head": "Output Tax IGST - _GST", "cost_center": "Main - _GST", "description": "IGST @ 18.0", "rate": 18 @@ -117,7 +117,7 @@ def make_sales_invoice(): si.append("taxes", { "charge_type": "On Net Total", - "account_head": "IGST - _GST", + "account_head": "Output Tax IGST - _GST", "cost_center": "Main - _GST", "description": "IGST @ 18.0", "rate": 18 @@ -138,7 +138,7 @@ def make_sales_invoice(): si1.append("taxes", { "charge_type": "On Net Total", - "account_head": "IGST - _GST", + "account_head": "Output Tax IGST - _GST", "cost_center": "Main - _GST", "description": "IGST @ 18.0", "rate": 18 @@ -159,7 +159,7 @@ def make_sales_invoice(): si2.append("taxes", { "charge_type": "On Net Total", - "account_head": "IGST - _GST", + "account_head": "Output Tax IGST - _GST", "cost_center": "Main - _GST", "description": "IGST @ 18.0", "rate": 18 @@ -195,7 +195,7 @@ def create_purchase_invoices(): pi.append("taxes", { "charge_type": "On Net Total", - "account_head": "CGST - _GST", + "account_head": "Input Tax CGST - _GST", "cost_center": "Main - _GST", "description": "CGST @ 9.0", "rate": 9 @@ -203,7 +203,7 @@ def create_purchase_invoices(): pi.append("taxes", { "charge_type": "On Net Total", - "account_head": "SGST - _GST", + "account_head": "Input Tax SGST - _GST", "cost_center": "Main - _GST", "description": "SGST @ 9.0", "rate": 9 @@ -410,10 +410,10 @@ def make_company(): company.country = "India" company.insert() - if not frappe.db.exists('Address', '_Test Address-Billing'): + if not frappe.db.exists('Address', '_Test Address GST-Billing'): address = frappe.get_doc({ + "address_title": "_Test Address GST", "address_line1": "_Test Address Line 1", - "address_title": "_Test Address", "address_type": "Billing", "city": "_Test City", "state": "Test State", @@ -444,9 +444,9 @@ def set_account_heads(): if not gst_account: gst_settings.append("gst_accounts", { "company": "_Test Company GST", - "cgst_account": "CGST - _GST", - "sgst_account": "SGST - _GST", - "igst_account": "IGST - _GST", + "cgst_account": "Output Tax CGST - _GST", + "sgst_account": "Output Tax SGST - _GST", + "igst_account": "Output Tax IGST - _GST" }) gst_settings.save() diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py index 9f73f214bd1..c7cc0005186 100644 --- a/erpnext/setup/setup_wizard/operations/taxes_setup.py +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -211,8 +211,6 @@ def get_or_create_account(company_name, account): 'account_number': account.get('account_number') }) - print(company_name, account, existing_accounts) - if existing_accounts: return frappe.get_doc('Account', existing_accounts[0].name) From 752f099e9dd5187669d11b6420dece399d072aff Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 1 Jul 2021 17:20:24 +0530 Subject: [PATCH 21/33] fix: Order Items by weightage in the web items query --- erpnext/shopping_cart/product_query.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/shopping_cart/product_query.py b/erpnext/shopping_cart/product_query.py index d96d803416c..6c92d967d0c 100644 --- a/erpnext/shopping_cart/product_query.py +++ b/erpnext/shopping_cart/product_query.py @@ -71,7 +71,8 @@ class ProductQuery: ], or_filters=self.or_filters, start=start, - limit=self.page_length + limit=self.page_length, + order_by="weightage desc" ) items_dict = {item.name: item for item in items} @@ -86,7 +87,8 @@ class ProductQuery: filters=self.filters, or_filters=self.or_filters, start=start, - limit=self.page_length + limit=self.page_length, + order_by="weightage desc" ) # Combine results having context of website item groups into item results From b6076f772d6fd9928ddadb8572e391a7beb33c92 Mon Sep 17 00:00:00 2001 From: Afshan Date: Fri, 2 Jul 2021 15:39:16 +0530 Subject: [PATCH 22/33] fix: only "Tax" type accounts should be shown for selection in GST Settings --- erpnext/regional/doctype/gst_settings/gst_settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.js b/erpnext/regional/doctype/gst_settings/gst_settings.js index 808f9bc0789..cd682c5403e 100644 --- a/erpnext/regional/doctype/gst_settings/gst_settings.js +++ b/erpnext/regional/doctype/gst_settings/gst_settings.js @@ -35,6 +35,7 @@ frappe.ui.form.on('GST Settings', { return { filters: { company: row.company, + account_type: "Tax", is_group: 0 } }; From a0599e5ac2d4da456256ab00bbe2105e03d3e821 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 5 Jul 2021 10:09:42 +0530 Subject: [PATCH 23/33] fix: Test cases for M-pesa --- .../doctype/mpesa_settings/test_mpesa_settings.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py index 3c2e59ab821..2dfd5aad5db 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py @@ -9,13 +9,17 @@ from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings import p from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice class TestMpesaSettings(unittest.TestCase): + def setUp(self): + # create payment gateway in setup + create_mpesa_settings(payment_gateway_name="_Test") + create_mpesa_settings(payment_gateway_name="_Account Balance") + create_mpesa_settings(payment_gateway_name="Payment") + def tearDown(self): frappe.db.sql('delete from `tabMpesa Settings`') frappe.db.sql('delete from `tabIntegration Request` where integration_request_service = "Mpesa"') def test_creation_of_payment_gateway(self): - create_mpesa_settings(payment_gateway_name="_Test") - mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test") self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"})) self.assertTrue(mode_of_payment.name) @@ -47,7 +51,6 @@ class TestMpesaSettings(unittest.TestCase): integration_request.delete() def test_processing_of_callback_payload(self): - create_mpesa_settings(payment_gateway_name="Payment") mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account") frappe.db.set_value("Account", mpesa_account, "account_currency", "KES") frappe.db.set_value("Customer", "_Test Customer", "default_currency", "KES") @@ -90,7 +93,6 @@ class TestMpesaSettings(unittest.TestCase): pos_invoice.delete() def test_processing_of_multiple_callback_payload(self): - create_mpesa_settings(payment_gateway_name="Payment") mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account") frappe.db.set_value("Account", mpesa_account, "account_currency", "KES") frappe.db.set_value("Mpesa Settings", "Payment", "transaction_limit", "500") @@ -141,7 +143,6 @@ class TestMpesaSettings(unittest.TestCase): pos_invoice.delete() def test_processing_of_only_one_succes_callback_payload(self): - create_mpesa_settings(payment_gateway_name="Payment") mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account") frappe.db.set_value("Account", mpesa_account, "account_currency", "KES") frappe.db.set_value("Mpesa Settings", "Payment", "transaction_limit", "500") From db682d9e4cdea680f2ab0d4e589000e54baf6a20 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 5 Jul 2021 13:46:03 +0530 Subject: [PATCH 24/33] fix: Create mode of payment if doesn't exists --- .../doctype/mpesa_settings/test_mpesa_settings.py | 3 ++- erpnext/erpnext_integrations/utils.py | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py index 2dfd5aad5db..f592c180a3b 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py @@ -7,6 +7,7 @@ import frappe import unittest from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_settings import process_balance_info, verify_transaction from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice +from erpnext.erpnext_integrations.utils import create_mode_of_payment class TestMpesaSettings(unittest.TestCase): def setUp(self): @@ -20,7 +21,7 @@ class TestMpesaSettings(unittest.TestCase): frappe.db.sql('delete from `tabIntegration Request` where integration_request_service = "Mpesa"') def test_creation_of_payment_gateway(self): - mode_of_payment = frappe.get_doc("Mode of Payment", "Mpesa-_Test") + mode_of_payment = create_mode_of_payment('Mpesa-_Test', payment_type="Phone") self.assertTrue(frappe.db.exists("Payment Gateway Account", {'payment_gateway': "Mpesa-_Test"})) self.assertTrue(mode_of_payment.name) self.assertEqual(mode_of_payment.type, "Phone") diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index 3840e781b4c..b764701103d 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -52,7 +52,8 @@ def create_mode_of_payment(gateway, payment_type="General"): "payment_gateway": gateway }, ['payment_account']) - if not frappe.db.exists("Mode of Payment", gateway) and payment_gateway_account: + mode_of_payment = frappe.db.exists("Mode of Payment", gateway) + if not mode_of_payment and payment_gateway_account: mode_of_payment = frappe.get_doc({ "doctype": "Mode of Payment", "mode_of_payment": gateway, @@ -66,6 +67,10 @@ def create_mode_of_payment(gateway, payment_type="General"): }) mode_of_payment.insert(ignore_permissions=True) + return mode_of_payment + else: + return frappe.get_doc("Mode of Payment", mode_of_payment) + def get_tracking_url(carrier, tracking_number): # Return the formatted Tracking URL. tracking_url = '' From 5638fbb1aac81bc1196c9a942e1abb9310983ce6 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 5 Jul 2021 13:54:05 +0530 Subject: [PATCH 25/33] fix: bom stock report not working --- .../manufacturing/report/bom_stock_report/bom_stock_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py index 1c6758e6f36..ed8b93929a1 100644 --- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py +++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py @@ -70,12 +70,12 @@ def get_bom_stock(filters): ON bom_item.item_code = ledger.item_code {conditions} WHERE - bom_item.parent = '{bom}' and bom_item.parenttype='BOM' + bom_item.parent = {bom} and bom_item.parenttype='BOM' GROUP BY bom_item.item_code""".format( qty_field=qty_field, table=table, conditions=conditions, - bom=bom, + bom=frappe.db.escape(bom), qty_to_produce=qty_to_produce or 1) ) From 15b336df28c6a8746bea4edb362400bd6c1f8c3d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 5 Jul 2021 14:45:33 +0530 Subject: [PATCH 26/33] fix: Test cases --- erpnext/erpnext_integrations/utils.py | 2 +- erpnext/hr/doctype/expense_claim/test_expense_claim.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index b764701103d..a5e162f8b5d 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -68,7 +68,7 @@ def create_mode_of_payment(gateway, payment_type="General"): mode_of_payment.insert(ignore_permissions=True) return mode_of_payment - else: + elif mode_of_payment: return frappe.get_doc("Mode of Payment", mode_of_payment) def get_tracking_url(carrier, tracking_number): diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 578eccf787d..141561fcdcc 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -72,7 +72,8 @@ class TestExpenseClaim(unittest.TestCase): def test_expense_claim_gl_entry(self): payable_account = get_payable_account(company_name) taxes = generate_taxes() - expense_claim = make_expense_claim(payable_account, 300, 200, company_name, "Travel Expenses - _TC4", do_not_submit=True, taxes=taxes) + expense_claim = make_expense_claim(payable_account, 300, 200, company_name, "Travel Expenses - _TC4", + do_not_submit=True, taxes=taxes) expense_claim.submit() gl_entries = frappe.db.sql("""select account, debit, credit @@ -145,7 +146,7 @@ def generate_taxes(): parent_account = frappe.db.get_value('Account', {'company': company_name, 'is_group':1, 'account_type': 'Tax'}, 'name') - account = create_account(company=company_name, account_name="CGST", account_type="Tax", parent_account=parent_account) + account = create_account(company=company_name, account_name="Output Tax CGST", account_type="Tax", parent_account=parent_account) return {'taxes':[{ "account_head": account, "rate": 0, From 9b6d9a41f4a66fefcb02e7ec0c4f3a4100c4d3ac Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 5 Jul 2021 17:08:27 +0530 Subject: [PATCH 27/33] fix: Test Cases --- .../doctype/mpesa_settings/test_mpesa_settings.py | 1 + erpnext/hr/doctype/expense_claim/test_expense_claim.py | 2 +- erpnext/setup/setup_wizard/operations/install_fixtures.py | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py index f592c180a3b..b0e662d3f32 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py @@ -204,6 +204,7 @@ def create_mpesa_settings(payment_gateway_name="Express"): doc = frappe.get_doc(dict( #nosec doctype="Mpesa Settings", + sandbox=1, payment_gateway_name=payment_gateway_name, consumer_key="5sMu9LVI1oS3oBGPJfh3JyvLHwZOdTKn", consumer_secret="VI1oS3oBGPJfh3JyvLHw", diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 141561fcdcc..96ea686706c 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -83,7 +83,7 @@ class TestExpenseClaim(unittest.TestCase): self.assertTrue(gl_entries) expected_values = dict((d[0], d) for d in [ - ['CGST - _TC4',18.0, 0.0], + ['Output Tax CGST - _TC4',18.0, 0.0], [payable_account, 0.0, 218.0], ["Travel Expenses - _TC4", 200.0, 0.0] ]) diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 7dfb9f4d3c2..3dcb63867c1 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -449,6 +449,8 @@ def install_defaults(args=None): set_active_domains(args) update_stock_settings() update_shopping_cart_settings(args) + + args.update({"set_default": 1}) create_bank_account(args) def set_global_defaults(args): @@ -499,7 +501,10 @@ def create_bank_account(args): try: doc = bank_account.insert() - frappe.db.set_value("Company", args.get('company_name'), "default_bank_account", bank_account.name, update_modified=False) + if args.get('set_default'): + frappe.db.set_value("Company", args.get('company_name'), "default_bank_account", bank_account.name, update_modified=False) + + return doc except RootNotEditable: frappe.throw(_("Bank account cannot be named as {0}").format(args.get('bank_account'))) From 842674ce79c8f2130d60b90b05afd9feb9c05bb0 Mon Sep 17 00:00:00 2001 From: Mohammed Yusuf Shaikh <49878143+mohammedyusufshaikh@users.noreply.github.com> Date: Tue, 6 Jul 2021 13:34:32 +0530 Subject: [PATCH 28/33] fix: Added a message to enable appontment booking if disabled (#26334) --- erpnext/www/book_appointment/index.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py index 7bfac89f308..ccfa97bc62f 100644 --- a/erpnext/www/book_appointment/index.py +++ b/erpnext/www/book_appointment/index.py @@ -2,6 +2,7 @@ import frappe import datetime import json import pytz +from frappe import _ WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] @@ -14,7 +15,8 @@ def get_context(context): if is_enabled: return context else: - frappe.local.flags.redirect_location = '/404' + frappe.redirect_to_message(_("Appointment Scheduling Disabled"), _("Appointment Scheduling has been disabled for this site"), + http_status_code=302, indicator_color="red") raise frappe.Redirect @frappe.whitelist(allow_guest=True) From c8eca8a448de4e4654c16141fc61f047d563cf55 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Tue, 6 Jul 2021 14:37:57 +0530 Subject: [PATCH 29/33] fix: remove cancelled entries in consolidated financial statements (#26331) --- .../consolidated_financial_statement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py index 7793af737f9..56a67bb0989 100644 --- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py +++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py @@ -380,7 +380,7 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g gl_entries = frappe.db.sql("""select gl.posting_date, gl.account, gl.debit, gl.credit, gl.is_opening, gl.company, gl.fiscal_year, gl.debit_in_account_currency, gl.credit_in_account_currency, gl.account_currency, acc.account_name, acc.account_number - from `tabGL Entry` gl, `tabAccount` acc where acc.name = gl.account and gl.company = %(company)s + from `tabGL Entry` gl, `tabAccount` acc where acc.name = gl.account and gl.company = %(company)s and gl.is_cancelled = 0 {additional_conditions} and gl.posting_date <= %(to_date)s and acc.lft >= %(lft)s and acc.rgt <= %(rgt)s order by gl.account, gl.posting_date""".format(additional_conditions=additional_conditions), { From 7f794cc0ea062ed8c3a799400cd9d2b044a164af Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 6 Jul 2021 17:58:44 +0530 Subject: [PATCH 30/33] fix: Purchase Invoice advance test case --- .../purchase_invoice/test_purchase_invoice.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 2f5d36c8fab..311745d3cd8 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1010,21 +1010,21 @@ class TestPurchaseInvoice(unittest.TestCase): # Check GLE for Purchase Invoice # Zero net effect on final TDS Payable on invoice expected_gle = [ - ['_Test Account Cost for Goods Sold - _TC', 30000, 0], - ['_Test Account Excise Duty - _TC', 0, 3000], - ['Creditors - _TC', 0, 27000], - ['TDS Payable - _TC', 3000, 3000] + ['_Test Account Cost for Goods Sold - _TC', 30000], + ['_Test Account Excise Duty - _TC', -3000], + ['Creditors - _TC', -27000], + ['TDS Payable - _TC', 0] ] - gl_entries = frappe.db.sql("""select account, debit, credit + gl_entries = frappe.db.sql("""select account, sum(debit - credit) as amount from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s + group by account order by account asc""", (purchase_invoice.name), as_dict=1) for i, gle in enumerate(gl_entries): self.assertEqual(expected_gle[i][0], gle.account) - self.assertEqual(expected_gle[i][1], gle.debit) - self.assertEqual(expected_gle[i][2], gle.credit) + self.assertEqual(expected_gle[i][1], gle.amount) def update_tax_witholding_category(company, account, date): from erpnext.accounts.utils import get_fiscal_year From 5e99aa7f65ea424159b6122b50064023427f89c8 Mon Sep 17 00:00:00 2001 From: Noah Jacob Date: Tue, 6 Jul 2021 18:00:35 +0530 Subject: [PATCH 31/33] fix: stock_rbnb not defined (#26354) --- erpnext/stock/doctype/purchase_receipt/purchase_receipt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index e488b695b5f..82c87a83a50 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -386,6 +386,7 @@ class PurchaseReceipt(BuyingController): against_account = ", ".join([d.account for d in gl_entries if flt(d.debit) > 0]) total_valuation_amount = sum(valuation_tax.values()) amount_including_divisional_loss = negative_expense_to_be_booked + stock_rbnb = self.get_company_default("stock_received_but_not_billed") i = 1 for tax in self.get("taxes"): if valuation_tax.get(tax.name): From 422325bb74ff39f6e4ebe7367d57ecf3622d56b2 Mon Sep 17 00:00:00 2001 From: Saqib Date: Tue, 6 Jul 2021 18:09:21 +0530 Subject: [PATCH 32/33] test: fetching of previous sle (#26352) --- .../test_stock_ledger_entry.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index ba31ad7b06b..af2ada8c9a4 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -54,7 +54,7 @@ class TestStockLedgerEntry(unittest.TestCase): ) # _Test Item for Reposting transferred from Stores to FG warehouse on 30-04-2020 - make_stock_entry( + se = make_stock_entry( item_code="_Test Item for Reposting", source="Stores - _TC", target="Finished Goods - _TC", @@ -64,29 +64,29 @@ class TestStockLedgerEntry(unittest.TestCase): posting_date='2020-04-30', posting_time='14:00' ) - target_wh_sle = get_previous_sle({ + target_wh_sle = frappe.db.get_value('Stock Ledger Entry', { "item_code": "_Test Item for Reposting", "warehouse": "Finished Goods - _TC", - "posting_date": '2020-04-30', - "posting_time": '14:00' - }) + "voucher_type": "Stock Entry", + "voucher_no": se.name + }, ["valuation_rate"], as_dict=1) self.assertEqual(target_wh_sle.get("valuation_rate"), 150) # Repack entry on 5-5-2020 repack = create_repack_entry(company=company, posting_date='2020-05-05', posting_time='14:00') - finished_item_sle = get_previous_sle({ + finished_item_sle = frappe.db.get_value('Stock Ledger Entry', { "item_code": "_Test Finished Item for Reposting", "warehouse": "Finished Goods - _TC", - "posting_date": '2020-05-05', - "posting_time": '14:00' - }) + "voucher_type": "Stock Entry", + "voucher_no": repack.name + }, ["incoming_rate", "valuation_rate"], as_dict=1) self.assertEqual(finished_item_sle.get("incoming_rate"), 540) self.assertEqual(finished_item_sle.get("valuation_rate"), 540) # Reconciliation for _Test Item for Reposting at Stores on 12-04-2020: Qty = 50, Rate = 150 - create_stock_reconciliation( + sr = create_stock_reconciliation( item_code="_Test Item for Reposting", warehouse="Stores - _TC", qty=50, @@ -109,12 +109,12 @@ class TestStockLedgerEntry(unittest.TestCase): self.assertEqual(target_wh_sle.get("valuation_rate"), 175) # Check valuation rate of repacked item after back-dated entry at Stores - finished_item_sle = get_previous_sle({ + finished_item_sle = frappe.db.get_value('Stock Ledger Entry', { "item_code": "_Test Finished Item for Reposting", "warehouse": "Finished Goods - _TC", - "posting_date": '2020-05-05', - "posting_time": '14:00' - }) + "voucher_type": "Stock Entry", + "voucher_no": repack.name + }, ["incoming_rate", "valuation_rate"], as_dict=1) self.assertEqual(finished_item_sle.get("incoming_rate"), 790) self.assertEqual(finished_item_sle.get("valuation_rate"), 790) From 0bd190b88592faeae6783fa7cfd9f9b70bd93fb4 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 6 Jul 2021 14:24:42 +0530 Subject: [PATCH 33/33] fix: stock entry with putaway rule not working --- erpnext/stock/doctype/putaway_rule/putaway_rule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py index ea26caced04..0f50bcd6ea8 100644 --- a/erpnext/stock/doctype/putaway_rule/putaway_rule.py +++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py @@ -97,7 +97,7 @@ def apply_putaway_rule(doctype, items, company, sync=None, purpose=None): at_capacity, rules = get_ordered_putaway_rules(item_code, company, source_warehouse=source_warehouse) if not rules: - warehouse = source_warehouse or item.warehouse + warehouse = source_warehouse or item.get('warehouse') if at_capacity: # rules available, but no free space items_not_accomodated.append([item_code, pending_qty])