Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account number in chart of accounts #10551

Merged
merged 5 commits into from Nov 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 46 additions & 0 deletions erpnext/accounts/doctype/account/account.js
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
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
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
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
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