Skip to content

Commit

Permalink
Account number in chart of accounts (frappe#10551)
Browse files Browse the repository at this point in the history
* Account number in chart of accounts

* Include account number while renaming account

* Test case fixed

* Standard coa with and without numbers

* Standard coa with and without numbers
  • Loading branch information
nabinhait authored and vishdha committed Nov 20, 2017
1 parent 63207c5 commit 8b86ded
Show file tree
Hide file tree
Showing 27 changed files with 3,791 additions and 3,252 deletions.
46 changes: 46 additions & 0 deletions erpnext/accounts/doctype/account/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ frappe.ui.form.on('Account', {
// show / hide convert buttons
frm.trigger('add_toolbar_buttons');
}

if(!frm.doc.__islocal) {
frm.add_custom_button(__('Update Account Number'), function () {
frm.trigger("update_account_number");
});
}
},
account_type: function (frm) {
if (frm.doc.is_group == 0) {
Expand Down Expand Up @@ -90,6 +96,46 @@ frappe.ui.form.on('Account', {
});
});
}
},

update_account_number: function(frm) {
var d = new frappe.ui.Dialog({
title: __('Update Account Number'),
fields: [
{
"label": "Account Number",
"fieldname": "account_number",
"fieldtype": "Data",
"reqd": 1
}
],
primary_action: function() {
var data = d.get_values();
if(data.account_number === frm.doc.account_number) {
d.hide();
return;
}

frappe.call({
method: "erpnext.accounts.doctype.account.account.update_account_number",
args: {
account_number: data.account_number,
name: frm.doc.name
},
callback: function(r) {
if(!r.exc) {
if(r.message) {
frappe.set_route("Form", "Account", r.message);
} else {
frm.set_value("account_number", data.account_number);
}
d.hide();
}
}
});
},
primary_action_label: __('Update')
});
d.show();
}
});
34 changes: 32 additions & 2 deletions erpnext/accounts/doctype/account/account.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "account_number",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Account Number",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
Expand Down Expand Up @@ -545,7 +575,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-08-11 15:28:35.855809",
"modified": "2017-08-22 17:39:10.711343",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
Expand Down Expand Up @@ -655,7 +685,7 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "",
"search_fields": "account_number",
"show_name_in_global_search": 1,
"sort_order": "ASC",
"track_changes": 1,
Expand Down
79 changes: 70 additions & 9 deletions erpnext/accounts/doctype/account/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from __future__ import unicode_literals
import frappe
from frappe.utils import cint, fmt_money
from frappe.utils import cint, cstr
from frappe import throw, _
from frappe.model.document import Document

Expand All @@ -20,18 +20,14 @@ def onload(self):
self.set_onload("can_freeze_account", True)

def autoname(self):
# first validate if company exists
company = frappe.db.get_value("Company", self.company, ["abbr", "name"], as_dict=True)
if not company:
frappe.throw(_('Company {0} does not exist').format(self.company))

self.name = self.account_name.strip() + ' - ' + company.abbr
self.name = get_account_autoname(self.account_number, self.account_name, self.company)

def validate(self):
if frappe.local.flags.allow_unverified_charts:
return
self.validate_parent()
self.validate_root_details()
validate_account_number(self.name, self.account_number, self.company)
self.validate_group_or_ledger()
self.set_root_and_report_type()
self.validate_mandatory()
Expand All @@ -56,12 +52,15 @@ def validate_parent(self):

def set_root_and_report_type(self):
if self.parent_account:
par = frappe.db.get_value("Account", self.parent_account, ["report_type", "root_type"], as_dict=1)
par = frappe.db.get_value("Account", self.parent_account,
["report_type", "root_type", "account_type"], as_dict=1)

if par.report_type:
self.report_type = par.report_type
if par.root_type:
self.root_type = par.root_type
if par.account_type and not self.account_type:
self.account_type = par.account_type

if self.is_group:
db_value = frappe.db.get_value("Account", self.name, ["report_type", "root_type"], as_dict=1)
Expand Down Expand Up @@ -186,6 +185,7 @@ def before_rename(self, old, new, merge=False):
# Add company abbr if not provided
from erpnext.setup.doctype.company.company import get_name_with_abbr
new_account = get_name_with_abbr(new, self.company)
new_account = get_name_with_number(new_account, self.account_number)

# Validate properties before merging
if merge:
Expand All @@ -208,7 +208,25 @@ def after_rename(self, old, new, merge=False):
super(Account, self).after_rename(old, new, merge)

if not merge:
frappe.db.set_value("Account", new, "account_name", " - ".join(new.split(" - ")[:-1]))
new_acc = frappe.db.get_value("Account", new, ["account_name", "account_number"], as_dict=1)

# exclude company abbr
new_parts = new.split(" - ")[:-1]
# update account number and remove from parts
if new_parts[0][0].isdigit():
# if account number is separate by space, split using space
if len(new_parts) == 1:
new_parts = new.split(" ")
if new_acc.account_number != new_parts[0]:
self.account_number = new_parts[0]
self.db_set("account_number", new_parts[0])
new_parts = new_parts[1:]

# update account name
account_name = " - ".join(new_parts)
if new_acc.account_name != account_name:
self.account_name = account_name
self.db_set("account_name", account_name)

def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name from tabAccount
Expand All @@ -229,3 +247,46 @@ def generator():
return account_currency

return frappe.local_cache("account_currency", account, generator)

def get_account_autoname(account_number, account_name, company):
# first validate if company exists
company = frappe.db.get_value("Company", company, ["abbr", "name"], as_dict=True)
if not company:
frappe.throw(_('Company {0} does not exist').format(company))

parts = [account_name.strip(), company.abbr]
if cstr(account_number).strip():
parts.insert(0, cstr(account_number).strip())
return ' - '.join(parts)

def validate_account_number(name, account_number, company):
if account_number:
account_with_same_number = frappe.db.get_value("Account",
{"account_number": account_number, "company": company, "name": ["!=", name]})
if account_with_same_number:
frappe.throw(_("Account Number {0} already used in account {1}")
.format(account_number, account_with_same_number))

@frappe.whitelist()
def update_account_number(name, account_number):
account = frappe.db.get_value("Account", name, ["account_name", "company"], as_dict=True)

validate_account_number(name, account_number, account.company)

frappe.db.set_value("Account", name, "account_number", account_number)

account_name = account.account_name
if account_name[0].isdigit():
separator = " - " if " - " in account_name else " "
account_name = account_name.split(separator, 1)[1]
frappe.db.set_value("Account", name, "account_name", account_name)

new_name = get_account_autoname(account_number, account_name, account.company)
if name != new_name:
frappe.rename_doc("Account", name, new_name)
return new_name

def get_name_with_number(new_account, account_number):
if account_number and not new_account[0].isdigit():
new_account = account_number + " - " + new_account
return new_account
2 changes: 2 additions & 0 deletions erpnext/accounts/doctype/account/account_tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ frappe.treeview_settings["Account"] = {
fields: [
{fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers")},
{fieldtype:'Data', fieldname:'account_number', label:__('Account Number'),
description: __("Number of new Account, it will be included in the account name as a prefix")},
{fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
{fieldtype:'Select', fieldname:'root_type', label:__('Root Type'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ def _import_accounts(children, parent, root_type, root_account=False):
if root_account:
root_type = child.get("root_type")

if account_name not in ["account_type", "root_type", "is_group", "tax_rate"]:
if account_name not in ["account_number", "account_type",
"root_type", "is_group", "tax_rate"]:

account_name_in_db = unidecode(account_name.strip().lower())
if account_name_in_db in accounts:
count = accounts.count(account_name_in_db)
account_name = account_name + " " + cstr(count)
account_number = cstr(child.get("account_number")).strip()
account_name, account_name_in_db = add_suffix_if_duplicate(account_name,
account_number, accounts)

is_group = identify_is_group(child)
report_type = "Balance Sheet" if root_type in ["Asset", "Liability", "Equity"] \
Expand All @@ -35,6 +35,7 @@ def _import_accounts(children, parent, root_type, root_account=False):
"is_group": is_group,
"root_type": root_type,
"report_type": report_type,
"account_number": account_number,
"account_type": child.get("account_type"),
"account_currency": frappe.db.get_value("Company", company, "default_currency"),
"tax_rate": child.get("tax_rate")
Expand All @@ -53,10 +54,23 @@ def _import_accounts(children, parent, root_type, root_account=False):

_import_accounts(chart, None, None, root_account=True)

def add_suffix_if_duplicate(account_name, account_number, accounts):
if account_number:
account_name_in_db = unidecode(" - ".join([account_number,
account_name.strip().lower()]))
else:
account_name_in_db = unidecode(account_name.strip().lower())

if account_name_in_db in accounts:
count = accounts.count(account_name_in_db)
account_name = account_name + " " + cstr(count)

return account_name, account_name_in_db

def identify_is_group(child):
if child.get("is_group"):
is_group = child.get("is_group")
elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate"])):
elif len(set(child.keys()) - set(["account_type", "root_type", "is_group", "tax_rate", "account_number"])):
is_group = 1
else:
is_group = 0
Expand All @@ -71,6 +85,10 @@ def get_chart(chart_template, existing_company=None):
elif chart_template == "Standard":
from erpnext.accounts.doctype.account.chart_of_accounts.verified import standard_chart_of_accounts
return standard_chart_of_accounts.get()
elif chart_template == "Standard with Numbers":
from erpnext.accounts.doctype.account.chart_of_accounts.verified \
import standard_chart_of_accounts_with_account_number
return standard_chart_of_accounts_with_account_number.get()
else:
folders = ("verified",)
if frappe.local.flags.allow_unverified_charts:
Expand All @@ -86,7 +104,7 @@ def get_chart(chart_template, existing_company=None):
return json.loads(chart).get("tree")

@frappe.whitelist()
def get_charts_for_country(country):
def get_charts_for_country(country, with_standard=False):
charts = []

def _get_chart_name(content):
Expand All @@ -111,26 +129,26 @@ def _get_chart_name(content):
with open(os.path.join(path, fname), "r") as f:
_get_chart_name(f.read())

if len(charts) != 1:
charts.append("Standard")
if len(charts) != 1 or with_standard:
charts += ["Standard", "Standard with Numbers"]

return charts


def get_account_tree_from_existing_company(existing_company):
all_accounts = frappe.get_all('Account',
filters={'company': existing_company},
fields = ["name", "account_name", "parent_account", "account_type",
"is_group", "root_type", "tax_rate"],
all_accounts = frappe.get_all('Account',
filters={'company': existing_company},
fields = ["name", "account_name", "parent_account", "account_type",
"is_group", "root_type", "tax_rate", "account_number"],
order_by="lft, rgt")

account_tree = {}

# fill in tree starting with root accounts (those with no parent)
if all_accounts:
build_account_tree(account_tree, None, all_accounts)
return account_tree

def build_account_tree(tree, parent, all_accounts):
# find children
parent_account = parent.name if parent else ""
Expand All @@ -139,17 +157,16 @@ def build_account_tree(tree, parent, all_accounts):
# if no children, but a group account
if not children and parent.is_group:
tree["is_group"] = 1
tree["account_number"] = parent.account_number

# build a subtree for each child
for child in children:
if child.account_type == "Stock" and not child.is_group:
tree["is_group"] = 1
continue

# start new subtree
tree[child.account_name] = {}

# assign account_type and root_type
if child.account_type:
tree[child.account_name]["account_number"] = child.account_number
if child.account_type:
tree[child.account_name]["account_type"] = child.account_type
if child.tax_rate:
Expand Down

0 comments on commit 8b86ded

Please sign in to comment.