diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 164f120067..2c151443d8 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -117,7 +117,9 @@ class Account(NestedSet):
for d in frappe.db.get_values('Account', filters=filters, fieldname=["company", "name"], as_dict=True):
parent_acc_name_map[d["company"]] = d["name"]
+
if not parent_acc_name_map: return
+
self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
def validate_group_or_ledger(self):
@@ -289,10 +291,30 @@ def validate_account_number(name, account_number, company):
.format(account_number, account_with_same_number))
@frappe.whitelist()
-def update_account_number(name, account_name, account_number=None):
-
+def update_account_number(name, account_name, account_number=None, from_descendant=False):
account = frappe.db.get_value("Account", name, "company", as_dict=True)
if not account: return
+
+ old_acc_name, old_acc_number = frappe.db.get_value('Account', name, \
+ ["account_name", "account_number"])
+
+ # check if account exists in parent company
+ ancestors = get_ancestors_of("Company", account.company)
+ allow_independent_account_creation = frappe.get_value("Company", account.company, "allow_account_creation_against_child_company")
+
+ if ancestors and not allow_independent_account_creation:
+ for ancestor in ancestors:
+ if frappe.db.get_value("Account", {'account_name': old_acc_name, 'company': ancestor}, 'name'):
+ # same account in parent company exists
+ allow_child_account_creation = _("Allow Account Creation Against Child Company")
+
+ message = _("Account {0} exists in parent company {1}.").format(frappe.bold(old_acc_name), frappe.bold(ancestor))
+ message += "
" + _("Renaming it is only allowed via parent company {0}, \
+ to avoid mismatch.").format(frappe.bold(ancestor)) + "
"
+ message += _("To overrule this, enable '{0}' in company {1}").format(allow_child_account_creation, frappe.bold(account.company))
+
+ frappe.throw(message, title=_("Rename Not Allowed"))
+
validate_account_number(name, account_number, account.company)
if account_number:
frappe.db.set_value("Account", name, "account_number", account_number.strip())
@@ -300,6 +322,12 @@ def update_account_number(name, account_name, account_number=None):
frappe.db.set_value("Account", name, "account_number", "")
frappe.db.set_value("Account", name, "account_name", account_name.strip())
+ if not from_descendant:
+ # Update and rename in child company accounts as well
+ descendants = get_descendants_of('Company', account.company)
+ if descendants:
+ sync_update_account_number_in_child(descendants, old_acc_name, account_name, account_number, old_acc_number)
+
new_name = get_account_autoname(account_number, account_name, account.company)
if name != new_name:
frappe.rename_doc("Account", name, new_name, force=1)
@@ -330,3 +358,14 @@ def get_root_company(company):
# return the topmost company in the hierarchy
ancestors = get_ancestors_of('Company', company, "lft asc")
return [ancestors[0]] if ancestors else []
+
+def sync_update_account_number_in_child(descendants, old_acc_name, account_name, account_number=None, old_acc_number=None):
+ filters = {
+ "company": ["in", descendants],
+ "account_name": old_acc_name,
+ }
+ if old_acc_number:
+ filters["account_number"] = old_acc_number
+
+ for d in frappe.db.get_values('Account', filters=filters, fieldname=["company", "name"], as_dict=True):
+ update_account_number(d["name"], account_name, account_number, from_descendant=True)
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index 89bb0184af..b6a950b1b5 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -5,8 +5,7 @@ from __future__ import unicode_literals
import unittest
import frappe
from erpnext.stock import get_warehouse_account, get_company_default_inventory_account
-from erpnext.accounts.doctype.account.account import update_account_number
-from erpnext.accounts.doctype.account.account import merge_account
+from erpnext.accounts.doctype.account.account import update_account_number, merge_account
class TestAccount(unittest.TestCase):
def test_rename_account(self):
@@ -99,7 +98,8 @@ class TestAccount(unittest.TestCase):
"Softwares - _TC", doc.is_group, doc.root_type, doc.company)
def test_account_sync(self):
- del frappe.local.flags["ignore_root_company_validation"]
+ frappe.local.flags.pop("ignore_root_company_validation", None)
+
acc = frappe.new_doc("Account")
acc.account_name = "Test Sync Account"
acc.parent_account = "Temporary Accounts - _TC3"
@@ -111,6 +111,55 @@ class TestAccount(unittest.TestCase):
self.assertEqual(acc_tc_4, "Test Sync Account - _TC4")
self.assertEqual(acc_tc_5, "Test Sync Account - _TC5")
+ def test_account_rename_sync(self):
+ frappe.local.flags.pop("ignore_root_company_validation", None)
+
+ acc = frappe.new_doc("Account")
+ acc.account_name = "Test Rename Account"
+ acc.parent_account = "Temporary Accounts - _TC3"
+ acc.company = "_Test Company 3"
+ acc.insert()
+
+ # Rename account in parent company
+ update_account_number(acc.name, "Test Rename Sync Account", "1234")
+
+ # Check if renamed in children
+ self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Rename Sync Account", "company": "_Test Company 4", "account_number": "1234"}))
+ self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Rename Sync Account", "company": "_Test Company 5", "account_number": "1234"}))
+
+ frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC3")
+ frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC4")
+ frappe.delete_doc("Account", "1234 - Test Rename Sync Account - _TC5")
+
+ def test_child_company_account_rename_sync(self):
+ frappe.local.flags.pop("ignore_root_company_validation", None)
+
+ acc = frappe.new_doc("Account")
+ acc.account_name = "Test Group Account"
+ acc.parent_account = "Temporary Accounts - _TC3"
+ acc.is_group = 1
+ acc.company = "_Test Company 3"
+ acc.insert()
+
+ self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Group Account", "company": "_Test Company 4"}))
+ self.assertTrue(frappe.db.exists("Account", {'account_name': "Test Group Account", "company": "_Test Company 5"}))
+
+ # Try renaming child company account
+ acc_tc_5 = frappe.db.get_value('Account', {'account_name': "Test Group Account", "company": "_Test Company 5"})
+ self.assertRaises(frappe.ValidationError, update_account_number, acc_tc_5, "Test Modified Account")
+
+ # Rename child company account with allow_account_creation_against_child_company enabled
+ frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 1)
+
+ update_account_number(acc_tc_5, "Test Modified Account")
+ self.assertTrue(frappe.db.exists("Account", {'name': "Test Modified Account - _TC5", "company": "_Test Company 5"}))
+
+ frappe.db.set_value("Company", "_Test Company 5", "allow_account_creation_against_child_company", 0)
+
+ to_delete = ["Test Group Account - _TC3", "Test Group Account - _TC4", "Test Modified Account - _TC5"]
+ for doc in to_delete:
+ frappe.delete_doc("Account", doc)
+
def _make_test_records(verbose):
from frappe.test_runner import make_test_objects