Merge branch 'develop' of https://github.com/frappe/erpnext into dimensions
diff --git a/erpnext/accounts/doctype/accounting_dimension/__init__.py b/erpnext/accounts/doctype/accounting_dimension/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension/__init__.py
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
new file mode 100644
index 0000000..0676731
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Accounting Dimension', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
new file mode 100644
index 0000000..13902d6
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json
@@ -0,0 +1,55 @@
+{
+ "autoname": "field:label",
+ "creation": "2019-05-04 18:13:37.002352",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+  "document_type",
+  "label",
+  "fieldname"
+ ],
+ "fields": [
+  {
+   "fieldname": "label",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Label",
+   "unique": 1
+  },
+  {
+   "fieldname": "fieldname",
+   "fieldtype": "Data",
+   "label": "Fieldname"
+  },
+  {
+   "fieldname": "document_type",
+   "fieldtype": "Link",
+   "label": "Document Type",
+   "options": "DocType",
+   "reqd": 1
+  }
+ ],
+ "modified": "2019-05-09 15:30:55.339917",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Accounting Dimension",
+ "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": "ASC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
new file mode 100644
index 0000000..e56492c
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, 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
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe import scrub
+from frappe.utils import cstr
+
+class AccountingDimension(Document):
+
+	def before_insert(self):
+		self.set_fieldname_and_label()
+		self.make_accounting_dimension_in_accounting_doctypes()
+
+	def on_trash(self):
+		self.delete_accounting_dimension()
+
+	def set_fieldname_and_label(self):
+		if not self.label:
+			self.label = cstr(self.document_type)
+
+		if not self.fieldname:
+			self.fieldname = scrub(self.label)
+
+	def make_accounting_dimension_in_accounting_doctypes(self):
+		last_created_accounting_dimension = get_last_created_accounting_dimension()
+
+		doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "BOM", "Sales Order", "Purchase Order",
+			"Stock Entry", "Budget", "Payroll Entry", "Delivery Note"]
+
+		df = {
+			"fieldname": self.fieldname,
+			"label": self.label,
+			"fieldtype": "Link",
+			"options": self.document_type,
+			"insert_after": last_created_accounting_dimension if last_created_accounting_dimension else "project"
+		}
+
+		for doctype in doclist:
+
+			if doctype == "Budget":
+				df.update({
+					"depends_on": "eval:doc.budget_against == '{0}'".format(self.document_type)
+				})
+
+				create_custom_field(doctype, df)
+
+				property_setter = frappe.db.exists("Property Setter", "Budget-budget_against-options")
+
+				if property_setter:
+				else:
+					frappe.get_doc({
+						"doctype": "Property Setter",
+						"doc_type": "Budget",
+						"fieldname": "budget_against"
+					})
+			else:
+				create_custom_field(doctype, df)
+
+	def delete_accounting_dimension(self):
+		doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "BOM", "Sales Order", "Purchase Order",
+			"Stock Entry", "Budget", "Payroll Entry", "Delivery Note"]
+
+		frappe.db.sql("""
+			DELETE FROM `tabCustom Field`
+			WHERE  fieldname = %s
+			AND dt IN (%s)""" %
+			('%s', ', '.join(['%s']* len(doclist))), tuple([self.fieldname] + doclist))
+
+		frappe.db.sql("""
+			DELETE FROM `tabProperty Setter`
+			WHERE  field_name = %s
+			AND doc_type IN (%s)""" %
+			('%s', ', '.join(['%s']* len(doclist))), tuple([self.fieldname] + doclist))
+
+		for doc in doclist:
+			frappe.clear_cache(doctype=doc)
+
+
+def get_last_created_accounting_dimension():
+	last_created_accounting_dimension = frappe.db.sql("select fieldname, max(creation) from `tabAccounting Dimension`", as_dict=1)
+
+	if last_created_accounting_dimension[0]:
+		return last_created_accounting_dimension[0].fieldname
+
+def get_accounting_dimensions():
+	accounting_dimensions = frappe.get_all("Accounting Dimension", fields=["fieldname"])
+
+	return [d.fieldname for d in accounting_dimensions]
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
new file mode 100644
index 0000000..b4368c4
--- /dev/null
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestAccountingDimension(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index cd9f9d9..b2072f0 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -62,3 +62,11 @@
 		},
 	]
 }
+
+let dimension_filters = erpnext.get_dimension_filters();
+
+dimension_filters.then((dimensions) => {
+	dimensions.forEach((dimension) => {
+		frappe.query_reports["Budget Variance Report"].filters[4].options.push(dimension["document_type"]);
+	});
+});
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index fe8de36..fb4f5d0 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -19,9 +19,12 @@
 	else:
 		cost_centers = get_cost_centers(filters)
 
+	print(cost_centers)
+
 	period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
 	cam_map = get_cost_center_account_month_map(filters)
 
+	print(cam_map)
 	data = []
 	for cost_center in cost_centers:
 		cost_center_items = cam_map.get(cost_center)
@@ -45,8 +48,8 @@
 
 						if(filters.get("show_cumulative")):
 							last_total = period_data[0] - period_data[1]
-						
-						period_data[2] = period_data[0] - period_data[1] 
+
+						period_data[2] = period_data[0] - period_data[1]
 						row += period_data
 				totals[2] = totals[0] - totals[1]
 				if filters["period"] != "Yearly" :
@@ -56,7 +59,7 @@
 	return columns, data
 
 def validate_filters(filters):
-	if filters.get("budget_against")=="Project" and filters.get("cost_center"):
+	if filters.get("budget_against") != "Cost Center" and filters.get("cost_center"):
 		frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
 
 def get_columns(filters):
@@ -92,8 +95,11 @@
 	if filters.get("budget_against") == "Cost Center":
 		cond = "order by lft"
 
-	return frappe.db.sql_list("""select name from `tab{tab}` where company=%s
-		{cond}""".format(tab=filters.get("budget_against"), cond=cond), filters.get("company"))
+	if filters.get("budget_against") in ["Cost Center", "Project"]:
+		return frappe.db.sql_list("""select name from `tab{tab}` where company=%s
+			{cond}""".format(tab=filters.get("budget_against"), cond=cond), filters.get("company"))
+	else:
+		return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against")))
 
 #Get cost center & target details
 def get_cost_center_target_details(filters):
@@ -109,7 +115,7 @@
 		""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
 		(filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company), as_dict=True)
 
-	
+
 
 #Get target distribution details of accounts of cost center
 def get_target_distribution_details(filters):
@@ -118,7 +124,7 @@
 		from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
 		where mdp.parent=md.name and md.fiscal_year between %s and %s order by md.fiscal_year""",(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
 			target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
-	
+
 	return target_details
 
 #Get actual details from gl entry
@@ -129,7 +135,7 @@
 	if filters.get("budget_against") == "Cost Center":
 		cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
 		cond = "lft>='{lft}' and rgt<='{rgt}'".format(lft = cc_lft, rgt=cc_rgt)
-	
+
 	ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit,gl.fiscal_year,
 		MONTHNAME(gl.posting_date) as month_name, b.{budget_against} as budget_against
 		from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b
@@ -153,6 +159,7 @@
 def get_cost_center_account_month_map(filters):
 	import datetime
 	cost_center_target_details = get_cost_center_target_details(filters)
+	print(cost_center_target_details)
 	tdd = get_target_distribution_details(filters)
 
 	cam_map = {}
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 2140315..7f0cbaa 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -16,6 +16,7 @@
 from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate)
 
 from six import itervalues
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
 
 def get_period_list(from_fiscal_year, to_fiscal_year, periodicity, accumulated_values=False,
 	company=None, reset_period_on_fy_change=True):
@@ -348,20 +349,23 @@
 	additional_conditions += " and account in ({})"\
 		.format(", ".join([frappe.db.escape(d) for d in accounts]))
 
+	gl_filters = {
+		"company": company,
+		"from_date": from_date,
+		"to_date": to_date,
+	}
+
+	for key, value in filters.items():
+		if value:
+			gl_filters.update({
+				key: value
+			})
+
 	gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
 		where company=%(company)s
 		{additional_conditions}
 		and posting_date <= %(to_date)s
-		order by account, posting_date""".format(additional_conditions=additional_conditions),
-		{
-			"company": company,
-			"from_date": from_date,
-			"to_date": to_date,
-			"cost_center": filters.cost_center,
-			"project": filters.project,
-			"finance_book": filters.get("finance_book")
-		},
-		as_dict=True)
+		order by account, posting_date""".format(additional_conditions=additional_conditions), gl_filters, as_dict=True)
 
 	if filters and filters.get('presentation_currency'):
 		convert_to_presentation_currency(gl_entries, get_currency(filters))
@@ -375,6 +379,8 @@
 def get_additional_conditions(from_date, ignore_closing_entries, filters):
 	additional_conditions = []
 
+	accounting_dimensions = get_accounting_dimensions()
+
 	if ignore_closing_entries:
 		additional_conditions.append("ifnull(voucher_type, '')!='Period Closing Voucher'")
 
@@ -395,6 +401,11 @@
 		if filters.get("finance_book"):
 			additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
 
+	if accounting_dimensions:
+		for dimension in accounting_dimensions:
+			if filters.get(dimension):
+				additional_conditions.append("{0} in (%({0})s)".format(dimension))
+
 	return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
 
 def get_cost_centers_with_children(cost_centers):
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 2826760..481107e 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -214,3 +214,17 @@
 		}
 	]
 }
+
+let dimension_filters = erpnext.get_dimension_filters();
+
+dimension_filters.then((dimensions) => {
+	dimensions.forEach((dimension) => {
+		frappe.query_reports["General Ledger"].filters.push({
+			"fieldname": dimension["fieldname"],
+			"label": __(dimension["label"]),
+			"fieldtype": "Link",
+			"options": dimension["document_type"]
+		});
+	});
+});
+
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 44ca8d3..033b9ba 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -10,6 +10,7 @@
 from erpnext.accounts.utils import get_account_currency
 from erpnext.accounts.report.financial_statements import get_cost_centers_with_children
 from six import iteritems
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
 
 def execute(filters=None):
 	if not filters:
@@ -195,6 +196,13 @@
 	if match_conditions:
 		conditions.append(match_conditions)
 
+	accounting_dimensions = get_accounting_dimensions()
+
+	if accounting_dimensions:
+		for dimension in accounting_dimensions:
+			if filters.get(dimension):
+				conditions.append("{0} in (%({0})s)".format(dimension))
+
 	return "and {}".format(" and ".join(conditions)) if conditions else ""
 
 
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 0672b2d..fda1a40 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -16,6 +16,7 @@
 from erpnext.accounts.doctype.pricing_rule.utils import validate_pricing_rules
 from erpnext.exceptions import InvalidCurrency
 from six import text_type
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
 
 force_item_fields = ("item_group", "brand", "stock_uom", "is_fixed_asset", "item_tax_rate", "pricing_rules")
 
@@ -365,6 +366,14 @@
 			'party': None,
 			'project': self.get("project")
 		})
+
+		accounting_dimensions = get_accounting_dimensions()
+		dimension_dict = frappe._dict()
+
+		for dimension in accounting_dimensions:
+			dimension_dict[dimension] = self.get(dimension)
+
+		gl_dict.update(dimension_dict)
 		gl_dict.update(args)
 
 		if not account_currency:
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 36746cd..2e4b8f2 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -63,7 +63,7 @@
 };
 
 function get_filters(){
-	return [
+	let filters = [
 		{
 			"fieldname":"company",
 			"label": __("Company"),
@@ -149,4 +149,21 @@
 			"options": erpnext.get_presentation_currency_list()
 		}
 	]
+
+	let dimension_filters = erpnext.get_dimension_filters()
+
+	dimension_filters.then((dimensions) => {
+		dimensions.forEach((dimension) => {
+			filters.push({
+				"fieldname": dimension["fieldname"],
+				"label": __(dimension["label"]),
+				"fieldtype": "Link",
+				"options": dimension["document_type"]
+			});
+		});
+	});
+
+	return filters;
 }
+
+
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 6860d6a..540b5ea 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -62,6 +62,14 @@
 		$btn.on("click", function() {
 			me.show_serial_batch_selector(grid_row.frm, grid_row.doc);
 		});
+	},
+
+	get_dimension_filters: async function() {
+		let dimensions = await frappe.db.get_list('Accounting Dimension', {
+			fields: ['label', 'fieldname', 'document_type'],
+		});
+
+		return dimensions;
 	}
 });