Merge branch 'develop' of https://github.com/frappe/erpnext into accounting_dimension_filters
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
index 9a6c389..65c5ff1 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -2,7 +2,6 @@
// For license information, please see license.txt
frappe.ui.form.on('Accounting Dimension', {
-
refresh: function(frm) {
frm.set_query('document_type', () => {
let invalid_doctypes = frappe.model.core_doctypes_list;
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index f888d9e..52e9ff8 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -203,7 +203,7 @@
return all_dimensions
@frappe.whitelist()
-def get_dimension_filters():
+def get_dimensions(with_cost_center_and_project=False):
dimension_filters = frappe.db.sql("""
SELECT label, fieldname, document_type
FROM `tabAccounting Dimension`
@@ -214,6 +214,18 @@
FROM `tabAccounting Dimension Detail` c, `tabAccounting Dimension` p
WHERE c.parent = p.name""", as_dict=1)
+ if with_cost_center_and_project:
+ dimension_filters.extend([
+ {
+ 'fieldname': 'cost_center',
+ 'document_type': 'Cost Center'
+ },
+ {
+ 'fieldname': 'project',
+ 'document_type': 'Project'
+ }
+ ])
+
default_dimensions_map = {}
for dimension in default_dimensions:
default_dimensions_map.setdefault(dimension.company, {})
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index 104880f..fc1d7e3 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -11,37 +11,7 @@
class TestAccountingDimension(unittest.TestCase):
def setUp(self):
- frappe.set_user("Administrator")
-
- if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
- dimension = frappe.get_doc({
- "doctype": "Accounting Dimension",
- "document_type": "Department",
- }).insert()
- else:
- dimension1 = frappe.get_doc("Accounting Dimension", "Department")
- dimension1.disabled = 0
- dimension1.save()
-
- if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
- dimension1 = frappe.get_doc({
- "doctype": "Accounting Dimension",
- "document_type": "Location",
- })
-
- dimension1.append("dimension_defaults", {
- "company": "_Test Company",
- "reference_document": "Location",
- "default_dimension": "Block 1",
- "mandatory_for_bs": 1
- })
-
- dimension1.insert()
- dimension1.save()
- else:
- dimension1 = frappe.get_doc("Accounting Dimension", "Location")
- dimension1.disabled = 0
- dimension1.save()
+ create_dimension()
def test_dimension_against_sales_invoice(self):
si = create_sales_invoice(do_not_save=1)
@@ -101,6 +71,38 @@
def tearDown(self):
disable_dimension()
+def create_dimension():
+ frappe.set_user("Administrator")
+
+ if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
+ frappe.get_doc({
+ "doctype": "Accounting Dimension",
+ "document_type": "Department",
+ }).insert()
+ else:
+ dimension = frappe.get_doc("Accounting Dimension", "Department")
+ dimension.disabled = 0
+ dimension.save()
+
+ if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
+ dimension1 = frappe.get_doc({
+ "doctype": "Accounting Dimension",
+ "document_type": "Location",
+ })
+
+ dimension1.append("dimension_defaults", {
+ "company": "_Test Company",
+ "reference_document": "Location",
+ "default_dimension": "Block 1",
+ "mandatory_for_bs": 1
+ })
+
+ dimension1.insert()
+ dimension1.save()
+ else:
+ dimension1 = frappe.get_doc("Accounting Dimension", "Location")
+ dimension1.disabled = 0
+ dimension1.save()
def disable_dimension():
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/__init__.py b/erpnext/accounts/doctype/accounting_dimension_filter/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/__init__.py
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
new file mode 100644
index 0000000..a2526e9
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js
@@ -0,0 +1,70 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Accounting Dimension Filter', {
+ refresh: function(frm, cdt, cdn) {
+ if (frm.doc.accounting_dimension) {
+ frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value');
+ }
+ },
+ onload: function(frm) {
+ frm.set_query('applicable_on_account', 'accounts', function() {
+ return {
+ filters: {
+ 'company': frm.doc.company
+ }
+ };
+ });
+
+ frappe.db.get_list('Accounting Dimension',
+ {fields: ['document_type']}).then((res) => {
+ let options = ['Cost Center', 'Project'];
+
+ res.forEach((dimension) => {
+ options.push(dimension.document_type);
+ });
+
+ frm.set_df_property('accounting_dimension', 'options', options);
+ });
+
+ frm.trigger('setup_filters');
+ },
+
+ setup_filters: function(frm) {
+ let filters = {};
+
+ if (frm.doc.accounting_dimension) {
+ frappe.model.with_doctype(frm.doc.accounting_dimension, function() {
+ if (frappe.model.is_tree(frm.doc.accounting_dimension)) {
+ filters['is_group'] = 0;
+ }
+
+ if (frappe.meta.has_field(frm.doc.accounting_dimension, 'company')) {
+ filters['company'] = frm.doc.company;
+ }
+
+ frm.set_query('dimension_value', 'dimensions', function() {
+ return {
+ filters: filters
+ };
+ });
+ });
+ }
+ },
+
+ accounting_dimension: function(frm) {
+ frm.clear_table("dimensions");
+ let row = frm.add_child("dimensions");
+ row.accounting_dimension = frm.doc.accounting_dimension;
+ frm.refresh_field("dimensions");
+ frm.trigger('setup_filters');
+ },
+});
+
+frappe.ui.form.on('Allowed Dimension', {
+ dimensions_add: function(frm, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ row.accounting_dimension = frm.doc.accounting_dimension;
+ frm.refresh_field("dimensions");
+ }
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json
new file mode 100644
index 0000000..7736b2d
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.json
@@ -0,0 +1,119 @@
+{
+ "actions": [],
+ "autoname": "format:{accounting_dimension}-{#####}",
+ "creation": "2020-11-08 18:28:11.906146",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "accounting_dimension",
+ "disabled",
+ "column_break_2",
+ "company",
+ "allow_or_restrict",
+ "section_break_4",
+ "accounts",
+ "column_break_6",
+ "dimensions"
+ ],
+ "fields": [
+ {
+ "fieldname": "accounting_dimension",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Accounting Dimension",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "hide_border": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "allow_or_restrict",
+ "fieldtype": "Select",
+ "label": "Allow Or Restrict Dimension",
+ "options": "Allow\nRestrict",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Applicable On Account",
+ "options": "Applicable On Account",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "depends_on": "eval:doc.accounting_dimension",
+ "fieldname": "dimensions",
+ "fieldtype": "Table",
+ "label": "Applicable Dimension",
+ "options": "Allowed Dimension",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-11-24 12:34:42.458713",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Accounting Dimension Filter",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py
new file mode 100644
index 0000000..6aef9ca
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+# Copyright, (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _, scrub
+from frappe.model.document import Document
+
+class AccountingDimensionFilter(Document):
+ def validate(self):
+ self.validate_applicable_accounts()
+
+ def validate_applicable_accounts(self):
+ accounts = frappe.db.sql(
+ """
+ SELECT a.applicable_on_account as account
+ FROM `tabApplicable On Account` a, `tabAccounting Dimension Filter` d
+ WHERE d.name = a.parent
+ and d.name != %s
+ and d.accounting_dimension = %s
+ """, (self.name, self.accounting_dimension), as_dict=1)
+
+ account_list = [d.account for d in accounts]
+
+ for account in self.get('accounts'):
+ if account.applicable_on_account in account_list:
+ frappe.throw(_("Row {0}: {1} account already applied for Accounting Dimension {2}").format(
+ account.idx, frappe.bold(account.applicable_on_account), frappe.bold(self.accounting_dimension)))
+
+def get_dimension_filter_map():
+ filters = frappe.db.sql("""
+ SELECT
+ a.applicable_on_account, d.dimension_value, p.accounting_dimension,
+ p.allow_or_restrict, a.is_mandatory
+ FROM
+ `tabApplicable On Account` a, `tabAllowed Dimension` d,
+ `tabAccounting Dimension Filter` p
+ WHERE
+ p.name = a.parent
+ AND p.disabled = 0
+ AND p.name = d.parent
+ """, as_dict=1)
+
+ dimension_filter_map = {}
+
+ for f in filters:
+ f.fieldname = scrub(f.accounting_dimension)
+
+ build_map(dimension_filter_map, f.fieldname, f.applicable_on_account, f.dimension_value,
+ f.allow_or_restrict, f.is_mandatory)
+
+ return dimension_filter_map
+
+def build_map(map_object, dimension, account, filter_value, allow_or_restrict, is_mandatory):
+ map_object.setdefault((dimension, account), {
+ 'allowed_dimensions': [],
+ 'is_mandatory': is_mandatory,
+ 'allow_or_restrict': allow_or_restrict
+ })
+ map_object[(dimension, account)]['allowed_dimensions'].append(filter_value)
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
new file mode 100644
index 0000000..fa700e1
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
+from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
+
+class TestAccountingDimensionFilter(unittest.TestCase):
+ def setUp(self):
+ create_dimension()
+ create_accounting_dimension_filter()
+
+ def test_allowed_dimension_validation(self):
+ si = create_sales_invoice(do_not_save=1)
+ si.items[0].cost_center = 'Main - _TC'
+ si.location = 'Block 1'
+ si.save()
+
+ self.assertRaises(InvalidAccountDimensionError, si.submit)
+
+ def test_mandatory_dimension_validation(self):
+ si = create_sales_invoice(do_not_save=1)
+ si.location = 'Block 1'
+
+ # Test with no department for Sales Account
+ si.items[0].department = ''
+ si.items[0].cost_center = '_Test Cost Center 2 - _TC'
+ si.save()
+
+ self.assertRaises(MandatoryAccountDimensionError, si.submit)
+
+ def tearDown(self):
+ disable_dimension_filter()
+ disable_dimension()
+
+def create_accounting_dimension_filter():
+ if not frappe.db.get_value('Accounting Dimension Filter',
+ {'accounting_dimension': 'Cost Center'}):
+ frappe.get_doc({
+ 'doctype': 'Accounting Dimension Filter',
+ 'accounting_dimension': 'Cost Center',
+ 'allow_or_restrict': 'Allow',
+ 'company': '_Test Company',
+ 'accounts': [{
+ 'applicable_on_account': 'Sales - _TC',
+ }],
+ 'dimensions': [{
+ 'accounting_dimension': 'Cost Center',
+ 'dimension_value': '_Test Cost Center 2 - _TC'
+ }]
+ }).insert()
+ else:
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Cost Center'})
+ doc.disabled = 0
+ doc.save()
+
+ if not frappe.db.get_value('Accounting Dimension Filter',
+ {'accounting_dimension': 'Department'}):
+ frappe.get_doc({
+ 'doctype': 'Accounting Dimension Filter',
+ 'accounting_dimension': 'Department',
+ 'allow_or_restrict': 'Allow',
+ 'company': '_Test Company',
+ 'accounts': [{
+ 'applicable_on_account': 'Sales - _TC',
+ 'is_mandatory': 1
+ }],
+ 'dimensions': [{
+ 'accounting_dimension': 'Department',
+ 'dimension_value': '_Test Department - _TC'
+ }]
+ }).insert()
+ else:
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Department'})
+ doc.disabled = 0
+ doc.save()
+
+def disable_dimension_filter():
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Cost Center'})
+ doc.disabled = 1
+ doc.save()
+
+ doc = frappe.get_doc('Accounting Dimension Filter', {'accounting_dimension': 'Department'})
+ doc.disabled = 1
+ doc.save()
diff --git a/erpnext/accounts/doctype/allowed_dimension/__init__.py b/erpnext/accounts/doctype/allowed_dimension/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/allowed_dimension/__init__.py
diff --git a/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.json b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.json
new file mode 100644
index 0000000..7fe2a3c
--- /dev/null
+++ b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.json
@@ -0,0 +1,43 @@
+{
+ "actions": [],
+ "creation": "2020-11-08 18:22:36.001131",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "accounting_dimension",
+ "dimension_value"
+ ],
+ "fields": [
+ {
+ "fieldname": "accounting_dimension",
+ "fieldtype": "Link",
+ "label": "Accounting Dimension",
+ "options": "DocType",
+ "read_only": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "dimension_value",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "options": "accounting_dimension",
+ "show_days": 1,
+ "show_seconds": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-11-23 09:56:19.744200",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Allowed Dimension",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py
new file mode 100644
index 0000000..c2afc1a
--- /dev/null
+++ b/erpnext/accounts/doctype/allowed_dimension/allowed_dimension.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class AllowedDimension(Document):
+ pass
diff --git a/erpnext/accounts/doctype/applicable_on_account/__init__.py b/erpnext/accounts/doctype/applicable_on_account/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/applicable_on_account/__init__.py
diff --git a/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.json b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.json
new file mode 100644
index 0000000..95e98d0
--- /dev/null
+++ b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.json
@@ -0,0 +1,46 @@
+{
+ "actions": [],
+ "creation": "2020-11-08 18:20:00.944449",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "applicable_on_account",
+ "is_mandatory"
+ ],
+ "fields": [
+ {
+ "fieldname": "applicable_on_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Accounts",
+ "options": "Account",
+ "reqd": 1,
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "columns": 2,
+ "default": "0",
+ "fieldname": "is_mandatory",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Is Mandatory",
+ "show_days": 1,
+ "show_seconds": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-11-22 19:55:13.324136",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Applicable On Account",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py
new file mode 100644
index 0000000..0fccaf3
--- /dev/null
+++ b/erpnext/accounts/doctype/applicable_on_account/applicable_on_account.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class ApplicableOnAccount(Document):
+ pass
diff --git a/erpnext/accounts/doctype/budget/budget.js b/erpnext/accounts/doctype/budget/budget.js
index cadf1e7..e60bc60 100644
--- a/erpnext/accounts/doctype/budget/budget.js
+++ b/erpnext/accounts/doctype/budget/budget.js
@@ -1,24 +1,9 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Budget', {
onload: function(frm) {
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- }
- })
-
- frm.set_query("project", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- }
- })
-
frm.set_query("account", "accounts", function() {
return {
filters: {
@@ -27,15 +12,17 @@
is_group: 0
}
}
- })
-
+ });
+
frm.set_query("monthly_distribution", function() {
return {
filters: {
fiscal_year: frm.doc.fiscal_year
}
}
- })
+ });
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index def9ed6..fd6f01e 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -11,8 +11,10 @@
from erpnext.accounts.party import validate_party_gle_currency, validate_party_frozen_disabled
from erpnext.accounts.utils import get_account_currency
from erpnext.accounts.utils import get_fiscal_year
-from erpnext.exceptions import InvalidAccountCurrency
+from erpnext.exceptions import InvalidAccountCurrency, InvalidAccountDimensionError, MandatoryAccountDimensionError
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
+from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import get_dimension_filter_map
+from six import iteritems
exclude_from_linked_with = True
class GLEntry(Document):
@@ -37,6 +39,7 @@
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
self.validate_dimensions_for_pl_and_bs()
+ self.validate_allowed_dimensions()
validate_frozen_account(self.account, adv_adj)
validate_balance_type(self.account, adv_adj)
@@ -74,11 +77,9 @@
.format(self.voucher_type, self.voucher_no, self.account))
def validate_dimensions_for_pl_and_bs(self):
-
account_type = frappe.db.get_value("Account", self.account, "report_type")
for dimension in get_checks_for_pl_and_bs_accounts():
-
if account_type == "Profit and Loss" \
and self.company == dimension.company and dimension.mandatory_for_pl and not dimension.disabled:
if not self.get(dimension.fieldname):
@@ -91,6 +92,25 @@
frappe.throw(_("Accounting Dimension <b>{0}</b> is required for 'Balance Sheet' account {1}.")
.format(dimension.label, self.account))
+ def validate_allowed_dimensions(self):
+ dimension_filter_map = get_dimension_filter_map()
+ for key, value in iteritems(dimension_filter_map):
+ dimension = key[0]
+ account = key[1]
+
+ if self.account == account:
+ if value['is_mandatory'] and not self.get(dimension):
+ frappe.throw(_("{0} is mandatory for account {1}").format(
+ frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)), MandatoryAccountDimensionError)
+
+ if value['allow_or_restrict'] == 'Allow':
+ if self.get(dimension) and self.get(dimension) not in value['allowed_dimensions']:
+ frappe.throw(_("Invalid value {0} for account {1}").format(
+ frappe.bold(self.get(dimension)), frappe.bold(self.account)), InvalidAccountDimensionError)
+ else:
+ if self.get(dimension) and self.get(dimension) in value['allowed_dimensions']:
+ frappe.throw(_("Invalid value {0} for account {1}").format(
+ frappe.bold(self.get(dimension)), frappe.bold(self.account)), InvalidAccountDimensionError)
def check_pl_account(self):
if self.is_opening=='Yes' and \
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index ff12967..37b03f3 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -120,6 +120,8 @@
}
}
});
+
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
voucher_type: function(frm){
@@ -197,6 +199,7 @@
this.load_defaults();
this.setup_queries();
this.setup_balance_formatter();
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
onload_post_render: function() {
@@ -222,15 +225,6 @@
return erpnext.journal_entry.account_query(me.frm);
});
- me.frm.set_query("cost_center", "accounts", function(doc, cdt, cdn) {
- return {
- filters: {
- company: me.frm.doc.company,
- is_group: 0
- }
- };
- });
-
me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
const row = locals[cdt][cdn];
@@ -406,6 +400,8 @@
}
}
cur_frm.cscript.update_totals(doc);
+
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(this.frm, cdt, cdn, 'accounts');
},
});
diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.js b/erpnext/accounts/doctype/loyalty_program/loyalty_program.js
index 524a671..f90f867 100644
--- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.js
+++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.js
@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Loyalty Program', {
setup: function(frm) {
var help_content =
@@ -46,20 +48,17 @@
};
});
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- };
- });
-
frm.set_value("company", frappe.defaults.get_user_default("Company"));
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
if (frm.doc.loyalty_program_type === "Single Tier Program" && frm.doc.collection_rules.length > 1) {
frappe.throw(__("Please select the Multiple Tier Program type for more than one collection rules."));
}
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}
});
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
index 3ce5701..c087980 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js
@@ -36,6 +36,8 @@
frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
frm.page.set_indicator(__('In Progress'), 'orange');
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
@@ -100,6 +102,7 @@
}
})
}
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
invoice_type: function(frm) {
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index e117471..4318aea 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -1,6 +1,7 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
{% include "erpnext/public/js/controllers/accounts.js" %}
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Payment Entry', {
onload: function(frm) {
@@ -8,6 +9,8 @@
if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
if (!frm.doc.paid_to) frm.set_value("paid_to_account_currency", null);
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
setup: function(frm) {
@@ -88,15 +91,6 @@
}
});
- frm.set_query("cost_center", "deductions", function() {
- return {
- filters: {
- "is_group": 0,
- "company": frm.doc.company
- }
- }
- });
-
frm.set_query("reference_doctype", "references", function() {
if (frm.doc.party_type=="Customer") {
var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
@@ -167,6 +161,7 @@
company: function(frm) {
frm.events.hide_unhide_fields(frm);
frm.events.set_dynamic_labels(frm);
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
contact_person: function(frm) {
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
index 7dd5b01..a74fa06 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -8,7 +8,7 @@
from erpnext.accounts.utils import get_account_currency
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (get_accounting_dimensions,
- get_dimension_filters)
+ get_dimensions)
class PeriodClosingVoucher(AccountsController):
def validate(self):
@@ -58,7 +58,7 @@
for dimension in accounting_dimensions:
dimension_fields.append('t1.{0}'.format(dimension))
- dimension_filters, default_dimensions = get_dimension_filters()
+ dimension_filters, default_dimensions = get_dimensions()
pl_accounts = self.get_pl_balances(dimension_fields)
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js
index 7f4f755..efdeb1a 100755
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.js
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js
@@ -57,6 +57,8 @@
}
};
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
@@ -67,6 +69,7 @@
company: function(frm) {
frm.trigger("toggle_display_account_head");
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
toggle_display_account_head: function(frm) {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 7830cfd..1fb3cfb 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -26,6 +26,11 @@
};
});
},
+
+ company: function() {
+ erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
+ },
+
onload: function() {
this._super();
@@ -41,6 +46,8 @@
if (this.frm.doc.supplier && this.frm.doc.__islocal) {
this.frm.trigger('supplier');
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
refresh: function(doc) {
@@ -511,15 +518,6 @@
}
}
}
-
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company,
- is_group: 0
- }
- };
- });
},
onload: function(frm) {
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 5efc32e..53c29aa 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -5,14 +5,17 @@
cur_frm.pformat.print_heading = 'Invoice';
{% include 'erpnext/selling/sales_common.js' %};
-
-
frappe.provide("erpnext.accounts");
+
+
erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({
setup: function(doc) {
this.setup_posting_date_time_check();
this._super(doc);
},
+ company: function() {
+ erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
+ },
onload: function() {
var me = this;
this._super();
@@ -33,6 +36,7 @@
me.frm.refresh_fields();
}
erpnext.queries.setup_warehouse_query(this.frm);
+ erpnext.accounts.dimensions.setup_dimension_filters(this.frm, this.frm.doctype);
},
refresh: function(doc, dt, dn) {
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
index d0904ee..8e4b806 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
@@ -1,16 +1,18 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-frappe.ui.form.on('Shipping Rule', {
- refresh: function(frm) {
- frm.set_query("cost_center", function() {
- return {
- filters: {
- company: frm.doc.company
- }
- }
- })
+frappe.provide('erpnext.accounts.dimensions');
+frappe.ui.form.on('Shipping Rule', {
+ onload: function(frm) {
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
+ refresh: function(frm) {
frm.set_query("account", function() {
return {
filters: {
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index b2318a2..6f1bb28 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -2,6 +2,7 @@
// For license information, please see license.txt
frappe.provide("erpnext.asset");
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Asset', {
onload: function(frm) {
@@ -32,13 +33,11 @@
};
});
- frm.set_query("cost_center", function() {
- return {
- "filters": {
- "company": frm.doc.company,
- }
- };
- });
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
setup: function(frm) {
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
index a6e6974..79c8861 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.js
@@ -1,6 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Asset Value Adjustment', {
setup: function(frm) {
frm.add_fetch('company', 'cost_center', 'cost_center');
@@ -13,11 +15,19 @@
}
});
},
+
onload: function(frm) {
if(frm.is_new() && frm.doc.asset) {
frm.trigger("set_current_asset_value");
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
asset: function(frm) {
frm.trigger("set_current_asset_value");
},
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 47483c9..822912a 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.buying");
-
+frappe.provide("erpnext.accounts.dimensions");
{% include 'erpnext/public/js/controllers/buying.js' %};
frappe.ui.form.on("Purchase Order", {
@@ -30,6 +30,10 @@
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm) {
set_schedule_date(frm);
if (!frm.doc.transaction_date){
@@ -39,6 +43,8 @@
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
}
});
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 8fe3816..e3aac9a 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -493,6 +493,41 @@
'company': filters.get("company", "")
})
+@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
+def get_filtered_dimensions(doctype, txt, searchfield, start, page_len, filters):
+ from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import get_dimension_filter_map
+ dimension_filters = get_dimension_filter_map()
+ dimension_filters = dimension_filters.get((filters.get('dimension'),filters.get('account')))
+ query_filters = []
+
+ meta = frappe.get_meta(doctype)
+ if meta.is_tree:
+ query_filters.append(['is_group', '=', 0])
+
+ if meta.has_field('company'):
+ query_filters.append(['company', '=', filters.get('company')])
+
+ if txt:
+ query_filters.append([searchfield, 'LIKE', "%%%s%%" % txt])
+
+ if dimension_filters:
+ if dimension_filters['allow_or_restrict'] == 'Allow':
+ query_selector = 'in'
+ else:
+ query_selector = 'not in'
+
+ if len(dimension_filters['allowed_dimensions']) == 1:
+ dimensions = tuple(dimension_filters['allowed_dimensions'] * 2)
+ else:
+ dimensions = tuple(dimension_filters['allowed_dimensions'])
+
+ query_filters.append(['name', query_selector, dimensions])
+
+ output = frappe.get_all(doctype, filters=query_filters)
+ result = [d.name for d in output]
+
+ return [(d,) for d in set(result)]
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.js b/erpnext/education/doctype/fee_schedule/fee_schedule.js
index 75dd446..65b5fa6 100644
--- a/erpnext/education/doctype/fee_schedule/fee_schedule.js
+++ b/erpnext/education/doctype/fee_schedule/fee_schedule.js
@@ -1,6 +1,7 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Fee Schedule', {
setup: function(frm) {
frm.add_fetch('fee_structure', 'receivable_account', 'receivable_account');
@@ -8,6 +9,10 @@
frm.add_fetch('fee_structure', 'cost_center', 'cost_center');
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm) {
frm.set_query('receivable_account', function(doc) {
return {
@@ -50,6 +55,8 @@
}
}
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js
index b331c6d..310c410 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.js
+++ b/erpnext/education/doctype/fee_structure/fee_structure.js
@@ -1,6 +1,8 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Fee Structure', {
setup: function(frm) {
frm.add_fetch('company', 'default_receivable_account', 'receivable_account');
@@ -8,6 +10,10 @@
frm.add_fetch('company', 'cost_center', 'cost_center');
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm) {
frm.set_query('academic_term', function() {
return {
@@ -35,6 +41,8 @@
}
};
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/education/doctype/fees/fees.js b/erpnext/education/doctype/fees/fees.js
index aaf42b4..433bd64 100644
--- a/erpnext/education/doctype/fees/fees.js
+++ b/erpnext/education/doctype/fees/fees.js
@@ -1,6 +1,7 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Fees", {
setup: function(frm) {
@@ -9,6 +10,10 @@
frm.add_fetch("fee_structure", "cost_center", "cost_center");
},
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+
onload: function(frm){
frm.set_query("academic_term",function(){
return{
@@ -45,6 +50,8 @@
if (!frm.doc.posting_date) {
frm.doc.posting_date = frappe.datetime.get_today();
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
diff --git a/erpnext/exceptions.py b/erpnext/exceptions.py
index d92af5d..04291cd 100644
--- a/erpnext/exceptions.py
+++ b/erpnext/exceptions.py
@@ -6,3 +6,5 @@
class InvalidAccountCurrency(frappe.ValidationError): pass
class InvalidCurrency(frappe.ValidationError): pass
class PartyDisabled(frappe.ValidationError):pass
+class InvalidAccountDimensionError(frappe.ValidationError): pass
+class MandatoryAccountDimensionError(frappe.ValidationError): pass
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 221300b..e399b22 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -2,11 +2,21 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.hr");
+frappe.provide("erpnext.accounts.dimensions");
-erpnext.hr.ExpenseClaimController = frappe.ui.form.Controller.extend({
- expense_type: function(doc, cdt, cdn) {
+frappe.ui.form.on('Expense Claim', {
+ onload: function(frm) {
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+ },
+});
+
+frappe.ui.form.on('Expense Claim Detail', {
+ expense_type: function(frm, cdt, cdn) {
var d = locals[cdt][cdn];
- if(!doc.company) {
+ if(!frm.doc.company) {
d.expense_type = "";
frappe.msgprint(__("Please set the Company"));
this.frm.refresh_fields();
@@ -20,7 +30,7 @@
method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
args: {
"expense_claim_type": d.expense_type,
- "company": doc.company
+ "company": frm.doc.company
},
callback: function(r) {
if (r.message) {
@@ -32,8 +42,6 @@
}
});
-$.extend(cur_frm.cscript, new erpnext.hr.ExpenseClaimController({frm: cur_frm}));
-
cur_frm.add_fetch('employee', 'company', 'company');
cur_frm.add_fetch('employee','employee_name','employee_name');
cur_frm.add_fetch('expense_type','description','description');
@@ -167,15 +175,6 @@
};
});
- frm.set_query("cost_center", "expenses", function() {
- return {
- filters: {
- "company": frm.doc.company,
- "is_group": 0
- }
- };
- });
-
frm.set_query("payable_account", function() {
return {
filters: {
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
index cb48abb..4adf97a 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
@@ -3,6 +3,8 @@
var in_progress = false;
+frappe.provide("erpnext.accounts.dimensions");
+
frappe.ui.form.on('Payroll Entry', {
onload: function (frm) {
if (!frm.doc.posting_date) {
@@ -18,6 +20,8 @@
};
});
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+
frm.set_query("payroll_payable_account", function() {
return {
filters: {
@@ -122,21 +126,6 @@
"company": frm.doc.company
}
};
- }),
- frm.set_query("cost_center", function () {
- return {
- filters: {
- "is_group": 0,
- company: frm.doc.company
- }
- };
- }),
- frm.set_query("project", function () {
- return {
- filters: {
- company: frm.doc.company
- }
- };
});
},
@@ -147,6 +136,7 @@
company: function (frm) {
frm.events.clear_employee_table(frm);
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
currency: function (frm) {
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 29f3595..649eb45 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -31,15 +31,6 @@
}
}
});
-
- frm.set_query("cost_center", "taxes", function(doc) {
- return {
- filters: {
- 'company': doc.company,
- "is_group": 0
- }
- }
- });
}
},
validate: function(frm) {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 3bc20f8..b9d884f 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1,6 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+frappe.provide('erpnext.accounts.dimensions');
+
erpnext.TransactionController = erpnext.taxes_and_totals.extend({
setup: function() {
this._super();
@@ -106,6 +108,8 @@
if(!item.warehouse && frm.doc.set_warehouse) {
item.warehouse = frm.doc.set_warehouse;
}
+
+ erpnext.accounts.dimensions.copy_dimension_from_first_row(frm, cdt, cdn, 'items');
}
});
@@ -159,16 +163,6 @@
};
});
}
- if (this.frm.fields_dict["items"].grid.get_field("cost_center")) {
- this.frm.set_query("cost_center", "items", function(doc) {
- return {
- filters: {
- "company": doc.company,
- "is_group": 0
- }
- };
- });
- }
if (this.frm.fields_dict["items"].grid.get_field("expense_account")) {
this.frm.set_query("expense_account", "items", function(doc) {
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index 560a561..98f1b50 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -116,6 +116,25 @@
]
}
+ },
+
+ get_filtered_dimensions: function(doc, child_fields, dimension, company) {
+ let account = '';
+
+ child_fields.forEach((field) => {
+ if (!account) {
+ account = doc[field];
+ }
+ });
+
+ return {
+ query: "erpnext.controllers.queries.get_filtered_dimensions",
+ filters: {
+ 'dimension': dimension,
+ 'account': account,
+ 'company': company
+ }
+ };
}
});
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 891bbe5..2635d47 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -194,15 +194,21 @@
add_dimensions: function(report_name, index) {
let filters = frappe.query_reports[report_name].filters;
- erpnext.dimension_filters.forEach((dimension) => {
- let found = filters.some(el => el.fieldname === dimension['fieldname']);
+ frappe.call({
+ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimensions",
+ callback: function(r) {
+ let accounting_dimensions = r.message[0];
+ accounting_dimensions.forEach((dimension) => {
+ let found = filters.some(el => el.fieldname === dimension['fieldname']);
- if (!found) {
- filters.splice(index, 0 ,{
- "fieldname": dimension["fieldname"],
- "label": __(dimension["label"]),
- "fieldtype": "Link",
- "options": dimension["document_type"]
+ if (!found) {
+ filters.splice(index, 0 ,{
+ "fieldname": dimension["fieldname"],
+ "label": __(dimension["label"]),
+ "fieldtype": "Link",
+ "options": dimension["document_type"]
+ });
+ }
});
}
});
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index b6720c0..c79736d 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -1,52 +1,79 @@
-frappe.provide('frappe.ui.form');
+frappe.provide('erpnext.accounts');
-let default_dimensions = {};
+erpnext.accounts.dimensions = {
+ setup_dimension_filters(frm, doctype) {
+ this.accounting_dimensions = [];
+ this.default_dimensions = {};
+ this.fetch_custom_dimensions(frm, doctype);
+ },
-let doctypes_with_dimensions = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
- "Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Shipping Rule", "Loyalty Program",
- "Fee Schedule", "Fee Structure", "Stock Reconciliation", "Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool",
- "Subscription", "Purchase Order", "Journal Entry", "Material Request", "Purchase Receipt", "Landed Cost Item", "Asset"];
+ fetch_custom_dimensions(frm, doctype) {
+ let me = this;
+ frappe.call({
+ method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimensions",
+ args: {
+ 'with_cost_center_and_project': true
+ },
+ callback: function(r) {
+ me.accounting_dimensions = r.message[0];
+ me.default_dimensions = r.message[1];
+ me.setup_filters(frm, doctype);
+ }
+ });
+ },
-let child_docs = ["Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account",
- "Material Request Item", "Delivery Note Item", "Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction",
- "Landed Cost Item", "Asset Value Adjustment", "Opening Invoice Creation Tool Item", "Subscription Plan"];
+ setup_filters(frm, doctype) {
+ this.accounting_dimensions.forEach((dimension) => {
+ frappe.model.with_doctype(dimension['document_type'], () => {
+ let parent_fields = [];
+ frappe.meta.get_docfields(doctype).forEach((df) => {
+ if (df.fieldtype === 'Link' && df.options === 'Account') {
+ parent_fields.push(df.fieldname);
+ } else if (df.fieldtype === 'Table') {
+ this.setup_child_filters(frm, df.options, df.fieldname, dimension['fieldname']);
+ }
-frappe.call({
- method: "erpnext.accounts.doctype.accounting_dimension.accounting_dimension.get_dimension_filters",
- callback: function(r) {
- erpnext.dimension_filters = r.message[0];
- default_dimensions = r.message[1];
- }
-});
-
-doctypes_with_dimensions.forEach((doctype) => {
- frappe.ui.form.on(doctype, {
- onload: function(frm) {
- erpnext.dimension_filters.forEach((dimension) => {
- frappe.model.with_doctype(dimension['document_type'], () => {
- if(frappe.meta.has_field(dimension['document_type'], 'is_group')) {
- frm.set_query(dimension['fieldname'], {
- "is_group": 0
- });
+ if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
+ this.setup_account_filters(frm, dimension['fieldname'], parent_fields);
}
});
});
- },
+ });
+ },
- company: function(frm) {
- if(frm.doc.company && (Object.keys(default_dimensions || {}).length > 0)
- && default_dimensions[frm.doc.company]) {
- frm.trigger('update_dimension');
- }
- },
+ setup_child_filters(frm, doctype, parentfield, dimension) {
+ let fields = [];
- update_dimension: function(frm) {
- erpnext.dimension_filters.forEach((dimension) => {
+ if (frappe.meta.has_field(doctype, dimension)) {
+ frappe.model.with_doctype(doctype, () => {
+ frappe.meta.get_docfields(doctype).forEach((df) => {
+ if (df.fieldtype === 'Link' && df.options === 'Account') {
+ fields.push(df.fieldname);
+ }
+ });
+
+ frm.set_query(dimension, parentfield, function(doc, cdt, cdn) {
+ let row = locals[cdt][cdn];
+ return erpnext.queries.get_filtered_dimensions(row, fields, dimension, doc.company);
+ });
+ });
+ }
+ },
+
+ setup_account_filters(frm, dimension, fields) {
+ frm.set_query(dimension, function(doc) {
+ return erpnext.queries.get_filtered_dimensions(doc, fields, dimension, doc.company);
+ });
+ },
+
+ update_dimension(frm, doctype) {
+ if (this.accounting_dimensions) {
+ this.accounting_dimensions.forEach((dimension) => {
if(frm.is_new()) {
- if(frm.doc.company && Object.keys(default_dimensions || {}).length > 0
- && default_dimensions[frm.doc.company]) {
+ if(frm.doc.company && Object.keys(this.default_dimensions || {}).length > 0
+ && this.default_dimensions[frm.doc.company]) {
- let default_dimension = default_dimensions[frm.doc.company][dimension['fieldname']];
+ let default_dimension = this.default_dimensions[frm.doc.company][dimension['fieldname']];
if(default_dimension) {
if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
@@ -61,23 +88,14 @@
}
});
}
- });
-});
+ },
-child_docs.forEach((doctype) => {
- frappe.ui.form.on(doctype, {
- items_add: function(frm, cdt, cdn) {
- erpnext.dimension_filters.forEach((dimension) => {
- var row = frappe.get_doc(cdt, cdn);
- frm.script_manager.copy_from_first_row("items", row, [dimension['fieldname']]);
- });
- },
-
- accounts_add: function(frm, cdt, cdn) {
- erpnext.dimension_filters.forEach((dimension) => {
- var row = frappe.get_doc(cdt, cdn);
- frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
+ copy_dimension_from_first_row(frm, cdt, cdn, fieldname) {
+ if (frappe.meta.has_field(frm.doctype, fieldname)) {
+ this.accounting_dimensions.forEach((dimension) => {
+ let row = frappe.get_doc(cdt, cdn);
+ frm.script_manager.copy_from_first_row(fieldname, row, [dimension['fieldname']]);
});
}
- });
-});
\ No newline at end of file
+ }
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 03921c5..1866557 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -7,6 +7,7 @@
frappe.provide("erpnext.stock");
frappe.provide("erpnext.stock.delivery_note");
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on("Delivery Note", {
setup: function(frm) {
@@ -75,7 +76,7 @@
}
});
-
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
print_without_amount: function(frm) {
@@ -317,6 +318,7 @@
company: function(frm) {
frm.trigger("unhide_account_head");
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
unhide_account_head: function(frm) {
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 01edd99..527b0d3 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -2,6 +2,7 @@
// License: GNU General Public License v3. See license.txt
// eslint-disable-next-line
+frappe.provide("erpnext.accounts.dimensions");
{% include 'erpnext/public/js/controllers/buying.js' %};
frappe.ui.form.on('Material Request', {
@@ -66,6 +67,12 @@
filters: {'company': doc.company}
};
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
onload_post_render: function(frm) {
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index bc1d81d..d998729 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -46,6 +46,8 @@
erpnext.queries.setup_queries(frm, "Warehouse", function() {
return erpnext.queries.warehouse(frm.doc);
});
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
refresh: function(frm) {
@@ -75,6 +77,7 @@
company: function(frm) {
frm.trigger("toggle_display_account_head");
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
toggle_display_account_head: function(frm) {
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 27fcbb7..ae21d94 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -1,6 +1,7 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.stock");
+frappe.provide("erpnext.accounts.dimensions");
frappe.ui.form.on('Stock Entry', {
setup: function(frm) {
@@ -97,6 +98,7 @@
});
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
},
setup_quality_inspection: function(frm) {
@@ -312,6 +314,8 @@
frm.set_value("letter_head", company_doc.default_letter_head);
}
frm.trigger("toggle_display_account_head");
+
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
}
},
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index e2121fc..be9404d 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -2,6 +2,7 @@
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext.stock");
+frappe.provide("erpnext.accounts.dimensions")
frappe.ui.form.on("Stock Reconciliation", {
onload: function(frm) {
@@ -26,6 +27,12 @@
if (!frm.doc.expense_account) {
frm.trigger("set_expense_account");
}
+
+ erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
+ },
+
+ company: function(frm) {
+ erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
refresh: function(frm) {