Treeview permission (#14232)

* Replace frappe.db.sql to frappe.get_list to apply permissions (#14037)

* Replace frappe.db.sql to frappe.get_list to apply permission
- All get_children method had frappe.db.sql in them which
had no permission check, now its replaced with frappe.get_list
which will check permission based on the user.

* Fix codacy
- Remove trailing whitespace

* Add parent filter

* Add ifnull checks
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 9cb93e0..adb8dca 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -497,7 +497,7 @@
 
 	if not value:
 		throw(_("Please set default {0} in Company {1}")
-		      .format(frappe.get_meta("Company").get_label(fieldname), company))
+			.format(frappe.get_meta("Company").get_label(fieldname), company))
 
 	return value
 
@@ -550,16 +550,16 @@
 	pr_valuation_amount = frappe.db.sql("""
 		select sum(pr_item.valuation_rate * pr_item.qty * pr_item.conversion_factor)
 		from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
-	    where pr.name = pr_item.parent and pr.docstatus=1 and pr.company=%s
+		where pr.name = pr_item.parent and pr.docstatus=1 and pr.company=%s
 		and pr.posting_date <= %s and pr_item.item_code in (%s)""" %
-	    ('%s', '%s', ', '.join(['%s']*len(stock_items))), tuple([company, posting_date] + stock_items))[0][0]
+		('%s', '%s', ', '.join(['%s']*len(stock_items))), tuple([company, posting_date] + stock_items))[0][0]
 
 	pi_valuation_amount = frappe.db.sql("""
 		select sum(pi_item.valuation_rate * pi_item.qty * pi_item.conversion_factor)
 		from `tabPurchase Invoice Item` pi_item, `tabPurchase Invoice` pi
-	    where pi.name = pi_item.parent and pi.docstatus=1 and pi.company=%s
+		where pi.name = pi_item.parent and pi.docstatus=1 and pi.company=%s
 		and pi.posting_date <= %s and pi_item.item_code in (%s)""" %
-	    ('%s', '%s', ', '.join(['%s']*len(stock_items))), tuple([company, posting_date] + stock_items))[0][0]
+		('%s', '%s', ', '.join(['%s']*len(stock_items))), tuple([company, posting_date] + stock_items))[0][0]
 
 	# Balance should be
 	stock_rbnb = flt(pr_valuation_amount, 2) - flt(pi_valuation_amount, 2)
@@ -681,29 +681,24 @@
 def get_children(doctype, parent, company, is_root=False):
 	from erpnext.accounts.report.financial_statements import sort_accounts
 
-	fieldname = frappe.db.escape(doctype.lower().replace(' ','_'))
-	doctype = frappe.db.escape(doctype)
+	parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_')
+	fields = [
+		'name as value',
+		'is_group as expandable'
+	]
+	filters = [['docstatus', '<', 2]]
 
-	# root
+	filters.append(['ifnull(`{0}`,"")'.format(parent_fieldname), '=', '' if is_root else parent])
+
 	if is_root:
-		fields = ", root_type, report_type, account_currency" if doctype=="Account" else ""
-		acc = frappe.db.sql(""" select
-			name as value, is_group as expandable {fields}
-			from `tab{doctype}`
-			where ifnull(`parent_{fieldname}`,'') = ''
-			and `company` = %s	and docstatus<2
-			order by name""".format(fields=fields, fieldname = fieldname, doctype=doctype),
-				company, as_dict=1)
+		fields += ['root_type', 'report_type', 'account_currency'] if doctype == 'Account' else []
+		filters.append(['company', '=', company])
+
 	else:
-		# other
-		fields = ", account_currency" if doctype=="Account" else ""
-		acc = frappe.db.sql("""select
-			name as value, is_group as expandable, parent_{fieldname} as parent {fields}
-			from `tab{doctype}`
-			where ifnull(`parent_{fieldname}`,'') = %s
-			and docstatus<2
-			order by name""".format(fields=fields, fieldname=fieldname, doctype=doctype),
-				parent, as_dict=1)
+		fields += ['account_currency'] if doctype == 'Account' else []
+		fields += [parent_fieldname + ' as parent']
+
+	acc = frappe.get_list(doctype, fields=fields, filters=filters)
 
 	if doctype == 'Account':
 		sort_accounts(acc, is_root, key="value")
diff --git a/erpnext/agriculture/doctype/land_unit/land_unit.py b/erpnext/agriculture/doctype/land_unit/land_unit.py
index f577eca..269bbce 100644
--- a/erpnext/agriculture/doctype/land_unit/land_unit.py
+++ b/erpnext/agriculture/doctype/land_unit/land_unit.py
@@ -25,12 +25,12 @@
 	def on_trash(self):
 		ancestors = self.get_ancestors()
 		for ancestor in ancestors:
-			ancestor_doc = frappe.get_doc('Land Unit', ancestor)	
+			ancestor_doc = frappe.get_doc('Land Unit', ancestor)
 			ancestor_child_features, ancestor_non_child_features = ancestor_doc.feature_seperator(child_feature = self.get('land_unit_name'))
 			ancestor_features = ancestor_non_child_features
 			for index,feature in enumerate(ancestor_features):
 				ancestor_features[index] = json.loads(feature)
-			ancestor_doc.set_location_value(features = ancestor_features)	
+			ancestor_doc.set_location_value(features = ancestor_features)
 			ancestor_doc.db_set(fieldname='area', value=ancestor_doc.get('area')-self.get('area'),commit=True)
 		super(LandUnit, self).on_update()
 
@@ -42,7 +42,7 @@
 				features = json.loads(self.get('location')).get('features')
 			new_area = compute_area(features)
 			self.area_difference = new_area - flt(self.area)
-			self.area = new_area	
+			self.area = new_area
 
 			if self.get('parent_land_unit'):
 				ancestors = self.get_ancestors()
@@ -55,8 +55,8 @@
 					ancestor_features = list(set(ancestor_non_child_features))
 					child_features = set(ancestor_child_features)
 
-					if not (self_features.issubset(child_features) and child_features.issubset(self_features)): 
-						features_to_be_appended =	self_features - child_features 
+					if not (self_features.issubset(child_features) and child_features.issubset(self_features)):
+						features_to_be_appended =	self_features - child_features
 						features_to_be_discarded = 	child_features - self_features
 						for feature in features_to_be_discarded:
 							child_features.discard(feature)
@@ -67,7 +67,7 @@
 					ancestor_features.extend(child_features)
 					for index,feature in enumerate(ancestor_features):
 						ancestor_features[index] = json.loads(feature)
-					ancestor_doc.set_location_value(features = ancestor_features)	
+					ancestor_doc.set_location_value(features = ancestor_features)
 					ancestor_doc.db_set(fieldname='area', value=ancestor_doc.get('area')+\
 						self.get('area_difference'),commit=True)
 
@@ -84,18 +84,18 @@
 	def add_child_property(self):
 		location = self.get('location')
 		if location:
-			features = json.loads(location).get('features')	
+			features = json.loads(location).get('features')
 			if type(features) != list:
 				features = json.loads(features)
 			filter_features = [feature for feature in features if feature.get('properties').get('child_feature') != True]
 			for index,feature in enumerate(filter_features):
 				feature['properties'].update({'child_feature': True, 'feature_of': self.land_unit_name})
 				filter_features[index] = json.dumps(filter_features[index])
-			return filter_features 
+			return filter_features
 		return []
 
 	def feature_seperator(self, child_feature=None):
-		doc = self 
+		doc = self
 		child_features = []
 		non_child_features = []
 		location = doc.get('location')
@@ -108,11 +108,11 @@
 					child_features.extend([json.dumps(feature)])
 				else:
 					non_child_features.extend([json.dumps(feature)])
-		
+
 		return child_features, non_child_features
 
 
-def compute_area(features):                                
+def compute_area(features):
 	layer_area = 0
 	for feature in features:
 		if feature.get('geometry').get('type') == 'Polygon':
@@ -128,10 +128,10 @@
 	area = 0
 	if coords and len(coords) > 0:
 		area += math.fabs(ring_area(coords[0]));
-		for i in range(1, len(coords)): 
+		for i in range(1, len(coords)):
 			area -= math.fabs(ring_area(coords[i]));
 	return area;
-	
+
 def ring_area(coords):
 	p1 = 0
 	p2 = 0
@@ -142,7 +142,7 @@
 	i = 0
 	area = 0
 	coords_length = len(coords)
-	if coords_length > 2: 
+	if coords_length > 2:
 		for i in range(0, coords_length):
 			if i == coords_length - 2: # i = N-2
 				lower_index = coords_length - 2;
@@ -169,11 +169,10 @@
 	if is_root:
 		parent = ''
 
-	land_units = frappe.db.sql("""select name as value,
-		is_group as expandable
-		from `tabLand Unit`
-		where ifnull(`parent_land_unit`,'') = %s
-		order by name""", (parent), as_dict=1)
+	land_units = frappe.get_list(doctype,
+		fields = ['name as value', 'is_group as expandable'],
+		filters= [['ifnull(`parent_land_unit`, "")', '=', parent]],
+		order_by='name')
 
 	# return nodes
 	return land_units
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index aaa5930..8035fc9 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -318,26 +318,26 @@
 
 @frappe.whitelist()
 def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False):
-	condition = ''
+	filters = [['company', '=', company]]
+	fields = ['name as value', 'employee_name as title']
 
 	if is_root:
-		parent = ""
+		parent = ''
 	if parent and company and parent!=company:
-		condition = ' and reports_to = "{0}"'.format(frappe.db.escape(parent))
+		filters.append(['reports_to', '=', parent])
 	else:
-		condition = ' and ifnull(reports_to, "")=""'
+		filters.append(['reports_to', '=', ''])
 
-	employee = frappe.db.sql("""
-		select
-			name as value, employee_name as title,
-			exists(select name from `tabEmployee` where reports_to=emp.name) as expandable
-		from
-			`tabEmployee` emp
-		where company='{company}' {condition} order by name"""
-		.format(company=company, condition=condition),  as_dict=1)
+	employees = frappe.get_list(doctype, fields=fields,
+		filters=filters, order_by='name')
 
-	# return employee
-	return employee
+	for employee in employees:
+		is_expandable = frappe.get_all(doctype, filters=[
+			['reports_to', '=', employee.get('value')]
+		])
+		employee.expandable = 1 if is_expandable else 0
+
+	return employees
 
 
 def on_doctype_update():
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 38346dc..18914eb 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -626,18 +626,28 @@
 		return
 
 	if frappe.form_dict.parent:
-		return frappe.db.sql("""select
-			bom_item.item_code,
-			bom_item.bom_no as value,
-			bom_item.stock_qty,
-			if(ifnull(bom_item.bom_no, "")!="", 1, 0) as expandable,
-			item.image,
-			item.description
-			from `tabBOM Item` bom_item, tabItem item
-			where bom_item.parent=%s
-			and bom_item.item_code = item.name
-			order by bom_item.idx
-			""", frappe.form_dict.parent, as_dict=True)
+		bom_items = frappe.get_list('BOM Item',
+			fields=['item_code', 'bom_no as value', 'stock_qty'],
+			filters=[['parent', '=', frappe.form_dict.parent]],
+			order_by='idx')
+
+		item_names = tuple(d.get('item_code') for d in bom_items)
+
+		items = frappe.get_list('Item',
+			fields=['image', 'description', 'name'],
+			filters=[['name', 'in', item_names]]) # to get only required item dicts
+
+		for bom_item in bom_items:
+			# extend bom_item dict with respective item dict
+			bom_item.update(
+				# returns an item dict from items list which matches with item_code
+				(item for item in items if item.get('name')
+					== bom_item.get('item_code')).next()
+			)
+			bom_item.expandable = 0 if bom_item.value in ('', None)  else 1
+
+		return bom_items
+
 
 def get_boms_in_bottom_up_order(bom_no=None):
 	def _get_parent(bom_no):
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index fcaa344..d289b82 100644
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -186,27 +186,25 @@
 
 @frappe.whitelist()
 def get_children(doctype, parent, task=None, project=None, is_root=False):
-	conditions = ''
+
+	filters = [['docstatus', '<', '2']]
 
 	if task:
-		# via filters
-		conditions += ' and parent_task = "{0}"'.format(frappe.db.escape(task))
+		filters.append(['parent_task', '=', task])
 	elif parent and not is_root:
 		# via expand child
-		conditions += ' and parent_task = "{0}"'.format(frappe.db.escape(parent))
+		filters.append(['parent_task', '=', parent])
 	else:
-		conditions += ' and ifnull(parent_task, "")=""'
+		filters.append(['ifnull(`parent_task`, "")', '=', ''])
 
 	if project:
-		conditions += ' and project = "{0}"'.format(frappe.db.escape(project))
+		filters.append(['project', '=', project])
 
-	tasks = frappe.db.sql("""select name as value,
-		subject as title,
-		is_group as expandable
-		from `tabTask`
-		where docstatus < 2
-		{conditions}
-		order by name""".format(conditions=conditions), as_dict=1)
+	tasks = frappe.get_list(doctype, fields=[
+		'name as value',
+		'subject as title',
+		'is_group as expandable'
+	], filters=filters, order_by='name')
 
 	# return tasks
 	return tasks
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 9c47f98..ec60e84 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -144,17 +144,19 @@
 	if is_root:
 		parent = ""
 
-	warehouses = frappe.db.sql("""select name as value,
-		is_group as expandable
-		from `tabWarehouse`
-		where docstatus < 2
-		and ifnull(`parent_warehouse`,'') = %s
-		and (`company` = %s or company is null or company = '')
-		order by name""", (parent, company), as_dict=1)
+	fields = ['name as value', 'is_group as expandable']
+	filters = [
+		['docstatus', '<', '2'],
+		['ifnull(`parent_warehouse`, "")', '=', parent],
+		['company', 'in', (company, None,'')]
+	]
+
+	warehouses = frappe.get_list(doctype, fields=fields, filters=filters, order_by='name')
 
 	# return warehouses
 	for wh in warehouses:
 		wh["balance"] = get_stock_value_on(warehouse=wh.value)
+
 	return warehouses
 
 @frappe.whitelist()