Fetch items of item groups defined in the pos profile (#11763)

diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py
index c70526c..5101ffd 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py
@@ -5,6 +5,7 @@
 import frappe
 from frappe import msgprint, _
 from frappe.utils import cint, now
+from erpnext.accounts.doctype.sales_invoice.pos import get_child_nodes
 from erpnext.accounts.doctype.sales_invoice.sales_invoice import set_account_for_mode_of_payment
 
 from frappe.model.document import Document
@@ -95,6 +96,17 @@
 			else:
 				frappe.defaults.set_global_default("is_pos", 1)
 
+def get_item_groups(pos_profile):
+	item_groups = []
+	pos_profile = frappe.get_doc('POS Profile', pos_profile)
+
+	if pos_profile.get('item_groups'):
+		# Get items based on the item groups defined in the POS profile
+		for data in pos_profile.get('item_groups'):
+			item_groups.extend(["'%s'"%d.name for d in get_child_nodes('Item Group', data.item_group)])
+
+	return list(set(item_groups))
+
 @frappe.whitelist()
 def get_series():
 	return frappe.get_meta("Sales Invoice").get_field("naming_series").options or ""
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 41b92c4..409f990 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -271,6 +271,38 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "depends_on": "is_pos", 
+   "fieldname": "pos_profile", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "POS Profile", 
+   "length": 0, 
+   "no_copy": 1, 
+   "options": "POS Profile", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "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, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "offline_pos_name", 
    "fieldtype": "Data", 
    "hidden": 1, 
@@ -301,37 +333,6 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "pos_profile", 
-   "fieldtype": "Link", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "POS Profile", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "POS Profile", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "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, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fieldname": "column_break1", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -4532,7 +4533,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-11-23 12:36:53.731902", 
+ "modified": "2017-11-28 19:12:37.795207", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Sales Invoice", 
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index fb30235..c7745ab 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -1006,6 +1006,14 @@
 						this.filter_items({ item_group: item_group });
 					}
 				},
+				get_query: () => {
+					return {
+						query: 'erpnext.selling.page.point_of_sale.point_of_sale.item_group_query',
+						filters: {
+							pos_profile: this.frm.doc.pos_profile
+						}
+					};
+				}
 			},
 			parent: this.wrapper.find('.item-group-field'),
 			render_input: true
@@ -1174,7 +1182,8 @@
 					page_length,
 					'price_list': this.frm.doc.selling_price_list,
 					item_group,
-					search_value
+					search_value,
+					'pos_profile': this.frm.doc.pos_profile
 				}
 			}).then(r => {
 				// const { items, serial_no, batch_no } = r.message;
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 8dad0a3..d98a017 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -4,9 +4,10 @@
 from __future__ import unicode_literals
 import frappe, json
 from frappe.utils.nestedset import get_root_of
+from erpnext.accounts.doctype.pos_profile.pos_profile import get_item_groups
 
 @frappe.whitelist()
-def get_items(start, page_length, price_list, item_group, search_value=""):
+def get_items(start, page_length, price_list, item_group, search_value="", pos_profile=None):
 	serial_no = ""
 	batch_no = ""
 	barcode = ""
@@ -33,6 +34,9 @@
 
 	item_code, condition = get_conditions(item_code, serial_no, batch_no, barcode)
 
+	if pos_profile:
+		condition += get_item_group_condition(pos_profile)
+
 	lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt'])
 	# locate function is used to sort by closest match from the beginning of the value
 	res = frappe.db.sql("""select i.name as item_code, i.item_name, i.image as item_image,
@@ -95,3 +99,28 @@
 	doc.submit()
 
 	return doc
+
+def get_item_group_condition(pos_profile):
+	cond = "and 1=1"
+	item_groups = get_item_groups(pos_profile)
+	if item_groups:
+		cond = "and i.item_group in (%s)"%(', '.join(['%s']*len(item_groups)))
+
+	return cond % tuple(item_groups)
+
+def item_group_query(doctype, txt, searchfield, start, page_len, filters):
+	item_groups = []
+	cond = "1=1"
+	pos_profile= filters.get('pos_profile')
+
+	if pos_profile:
+		item_groups = get_item_groups(pos_profile)
+
+		if item_groups:
+			cond = "name in (%s)"%(', '.join(['%s']*len(item_groups)))
+			cond = cond % tuple(item_groups)
+
+	return frappe.db.sql(""" select distinct name from `tabItem Group`
+			where {condition} and (name like %(txt)s) limit {start}, {page_len}"""
+		.format(condition = cond, start=start, page_len= page_len),
+			{'txt': '%%%s%%' % txt})