Added serial no, batch no, item group functionality
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json
index 6991da2..c4e6dab 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.json
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json
@@ -822,7 +822,7 @@
    "columns": 0, 
    "fieldname": "apply_discount", 
    "fieldtype": "Check", 
-   "hidden": 0, 
+   "hidden": 1, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
@@ -836,7 +836,7 @@
    "precision": "", 
    "print_hide": 0, 
    "print_hide_if_no_value": 0, 
-   "read_only": 0, 
+   "read_only": 1, 
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
    "reqd": 0, 
@@ -851,7 +851,7 @@
    "collapsible": 0, 
    "columns": 0, 
    "default": "Grand Total", 
-   "depends_on": "apply_discount", 
+   "depends_on": "", 
    "fieldname": "apply_discount_on", 
    "fieldtype": "Select", 
    "hidden": 0, 
@@ -1291,7 +1291,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-07-28 03:40:03.253088", 
+ "modified": "2017-08-27 16:39:00.713225", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "POS Profile", 
diff --git a/erpnext/accounts/doctype/pos_settings/__init__.py b/erpnext/accounts/doctype/pos_settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_settings/__init__.py
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.js b/erpnext/accounts/doctype/pos_settings/pos_settings.js
new file mode 100644
index 0000000..fab766b
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('POS Settings', {
+	refresh: function(frm) {
+
+	}
+});
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.json b/erpnext/accounts/doctype/pos_settings/pos_settings.json
new file mode 100644
index 0000000..ab3976e
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.json
@@ -0,0 +1,93 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2017-08-28 16:46:41.732676", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "type_of_pos", 
+   "fieldtype": "Select", 
+   "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": "Type of POS", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Online\nOffline", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "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
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 1, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2017-08-28 16:46:41.732676", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "POS Settings", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 0, 
+   "delete": 0, 
+   "email": 1, 
+   "export": 0, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 0, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.py b/erpnext/accounts/doctype/pos_settings/pos_settings.py
new file mode 100644
index 0000000..4a71775
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, 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 POSSettings(Document):
+	def validate(self):
+		link = 'point-of-sale' if self.type_of_pos == 'Online' else 'pos'
+		desktop_icon = frappe.db.get_value('Desktop Icon', {'module_name': 'POS'}, 'name')
+		if desktop_icon:
+			doc = frappe.get_doc('Desktop Icon', desktop_icon)
+			doc.link = link
+			doc.save()
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_settings/test_pos_settings.js b/erpnext/accounts/doctype/pos_settings/test_pos_settings.js
new file mode 100644
index 0000000..639c94e
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_settings/test_pos_settings.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: POS Settings", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new POS Settings
+		() => frappe.tests.make('POS Settings', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 9dfacbd..0b6926f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -303,7 +303,7 @@
 
 			for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
 				'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account',
-				'write_off_account', 'write_off_cost_center'):
+				'write_off_account', 'write_off_cost_center', 'apply_discount_on'):
 					if (not for_validate) or (for_validate and not self.get(fieldname)):
 						self.set(fieldname, pos.get(fieldname))
 
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 08630e5..ed5a0f6 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -1,15 +1,16 @@
 
 erpnext.SerialNoBatchSelector = Class.extend({
-	init: function(opts) {
+	init: function(opts, show_dialog) {
 		$.extend(this, opts);
+		this.show_dialog = show_dialog;
 		// frm, item, warehouse_details, has_batch, oldest
 		let d = this.item;
 
 		// Don't show dialog if batch no or serial no already set
-		if(d && d.has_batch_no && !d.batch_no) {
+		if(d && d.has_batch_no && (!d.batch_no || this.show_dialog)) {
 			this.has_batch = 1;
 			this.setup();
-		} else if(d && d.has_serial_no && !d.serial_no) {
+		} else if(d && d.has_serial_no && (!d.serial_no || this.show_dialog)) {
 			this.has_batch = 0;
 			this.setup();
 		}
@@ -93,6 +94,11 @@
 			}
 		});
 
+		if(this.show_dialog) {
+			let d = this.item;
+			this.dialog.set_value('serial_no', d.serial_no);
+		}
+
 		this.dialog.show();
 	},
 
@@ -140,6 +146,7 @@
 			this.map_row_values(this.item, this.values, 'serial_no', 'qty');
 		}
 		refresh_field("items");
+		this.callback && this.callback(this.item)
 	},
 
 	map_row_values: function(row, values, number, qty_field, warehouse) {
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 a3ea04e..4096ed4 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -120,6 +120,7 @@
 					if(!this.frm.doc.customer) {
 						frappe.throw(__('Please select a customer'));
 					}
+
 					this.update_item_in_cart(item_code, 'qty', '+1');
 					this.cart && this.cart.unselect_all();
 				},
@@ -131,53 +132,76 @@
 	}
 
 	update_item_in_cart(item_code, field='qty', value=1) {
-
 		if(this.cart.exists(item_code)) {
 			const item = this.frm.doc.items.find(i => i.item_code === item_code);
 
-			if (typeof value === 'string') {
+			if (typeof value === 'string' && !in_list(['serial_no', 'batch_no'], field)) {
 				// value can be of type '+1' or '-1'
 				value = item[field] + flt(value);
 			}
 
-			if (field === 'serial_no') {
-				value = item.serial_no + '\n' + value;
+			if(field === 'serial_no') {
+				value = item.serial_no + '\n'+ value;
 			}
 
-			this.update_item_in_frm(item, field, value)
-				.then(() => {
-					// update cart
-					this.cart.add_item(item);
-				})
-				.then(() => {
-					this.cart.update_taxes_and_totals();
-					this.cart.update_grand_total();
-				});
-
-			// if (barcode) {
-			// 	const value = barcode['serial_no'] ?
-			// 		item.serial_no + '\n' + barcode['serial_no'] : barcode['batch_no'];
-			// 	frappe.model.set_value(item.doctype, item.name,
-			// 		Object.keys(barcode)[0], value);
-			// } else {
-			// }
+			if(field === 'qty' && (item.serial_no || item.batch_no)) {
+				this.select_batch_and_serial_no(item)
+			} else {
+				this.update_item_in_frm(item, field, value)
+					.then(() => {
+						// update cart
+						this.update_cart_data(item);
+					})
+			}
 			return;
 		}
 
+		let args = { item_code: item_code };
+		if (in_list(['serial_no', 'batch_no'], field)) {
+			args[field] = value;
+		}
+
 		// add to cur_frm
-		const item = this.frm.add_child('items', { item_code: item_code });
+		const item = this.frm.add_child('items', args);
 		this.frm.script_manager
 			.trigger('item_code', item.doctype, item.name)
 			.then(() => {
 				// update cart
-				this.cart.add_item(item);
-				this.cart.update_taxes_and_totals();
-				this.cart.update_grand_total();
+				this.update_cart_data(item)
 			});
 	}
 
+	select_batch_and_serial_no(item) {
+		let dialog = new erpnext.SerialNoBatchSelector({
+			frm: this.frm,
+			item: item,
+			warehouse_details: {
+				type: "Warehouse",
+				name: item.warehouse
+			},
+			callback: (item) => {
+				this.update_item_in_frm(item)
+					.then(() => {
+						// update cart
+						this.update_cart_data(item);
+					})
+			}
+		}, true)
+	}
+
+	update_cart_data(item) {
+		this.cart.add_item(item);
+		this.cart.update_taxes_and_totals();
+		this.cart.update_grand_total();
+	}
+
 	update_item_in_frm(item, field, value) {
-		return frappe.model.set_value(item.doctype, item.name, field, value)
+		if (field) {
+			frappe.model.set_value(item.doctype, item.name, field, value)
+		}
+
+		return this.frm.script_manager
+			.trigger('qty', item.doctype, item.name)
 			.then(() => {
 				if (field === 'qty' && value === 0) {
 					frappe.model.clear_doc(item.doctype, item.name);
@@ -307,7 +331,7 @@
 			this.make_new_invoice();
 		});
 
-		this.page.add_menu_item(__("Email"), function () {
+		this.page.add_menu_item(__("Email"), () => {
 			this.frm.email_doc();
 		});
 	}
@@ -398,11 +422,11 @@
 				<div class="list-item__content list-item__content--flex-2 text-muted">${__('Discount')}</div>
 				<div class="list-item__content discount-inputs">
 					<input type="text"
-						class="form-control discount-percentage text-right"
+						class="form-control additional_discount_percentage text-right"
 						placeholder="% 0.00"
 					>
 					<input type="text"
-						class="form-control discount-amount text-right"
+						class="form-control discount_amount text-right"
 						placeholder="${get_currency_symbol(this.frm.doc.currency)} 0.00"
 					>
 				</div>
@@ -561,7 +585,7 @@
 		if(item.qty > 0) {
 			$item.find('.quantity input').val(item.qty);
 			$item.find('.discount').text(item.discount_percentage);
-			$item.find('.rate').text(item.rate);
+			$item.find('.rate').text(format_currency(item.rate, this.frm.doc.currency));
 		} else {
 			$item.remove();
 		}
@@ -671,6 +695,28 @@
 		// 	me.$cart_items.find('.list-item').removeClass('current-item qty disc rate');
 		// 	me.selected_item = null;
 		// });
+
+		this.wrapper.find('.additional_discount_percentage').on('change', (e) => {
+			frappe.model.set_value(this.frm.doctype, this.frm.docname,
+				'additional_discount_percentage', e.target.value)
+				.then(() => {
+					let discount_wrapper = this.wrapper.find('.discount_amount')
+					discount_wrapper.val(this.frm.doc.discount_amount)
+					discount_wrapper.trigger('change')
+				})
+		})
+
+		this.wrapper.find('.discount_amount').on('change', (e) => {
+			frappe.model.set_value(this.frm.doctype, this.frm.docname,
+				'discount_amount', e.target.value)
+			this.frm.trigger('discount_amount')
+				.then(() => {
+					let discount_wrapper = this.wrapper.find('.additional_discount_percentage');
+					discount_wrapper.val(this.frm.doc.additional_discount_percentage);
+					this.update_taxes_and_totals()
+					this.update_grand_total()
+				})
+		})
 	}
 
 	set_selected_item($item) {
@@ -749,21 +795,19 @@
 
 		this.search_field.$input.on('input', (e) => {
 			const search_term = e.target.value;
-			this.filter_items(search_term);
+			this.filter_items({ search_term });
 		});
 
-
-		// Item group field
 		this.item_group_field = frappe.ui.form.make_control({
 			df: {
-				fieldtype: 'Select',
+				fieldtype: 'Link',
 				label: 'Item Group',
-				options: [
-					'All Item Groups',
-					'Raw Materials',
-					'Finished Goods'
-				],
-				default: 'All Item Groups'
+				options: 'Item Group',
+				default: 'All Item Groups',
+				onchange: () => {
+					console.log("in the item_group")
+					this.filter_items({ item_group: this.item_group_field.get_value() })
+				},
 			},
 			parent: this.wrapper.find('.item-group-field'),
 			render_input: true
@@ -805,21 +849,24 @@
 		this.clusterize.update(row_items);
 	}
 
-	filter_items(search_term) {
-		search_term = search_term.toLowerCase();
+	filter_items({ search_term='', item_group='All Item Groups' }={}) {
+		if (search_term) {
+			search_term = search_term.toLowerCase();
 
-
-		// memoize
-		this.search_index = this.search_index || {};
-		if (this.search_index[search_term]) {
-			const items = this.search_index[search_term];
-			this.render_items(items);
-			return;
+			// memoize
+			this.search_index = this.search_index || {};
+			if (this.search_index[search_term]) {
+				const items = this.search_index[search_term];
+				this.render_items(items);
+				return;
+			}
 		}
 
-		this.get_items({search_value: search_term})
+		this.get_items({search_value: search_term, item_group })
 			.then((items) => {
-				this.search_index[search_term] = items;
+				if (search_term) {
+					this.search_index[search_term] = items;
+				}
 
 				this.render_items(items);
 				if(this.serial_no) {
@@ -884,7 +931,7 @@
 		return template;
 	}
 
-	get_items({start = 0, page_length = 40, search_value=''}={}) {
+	get_items({start = 0, page_length = 40, search_value='', item_group="All Item Groups"}={}) {
 		return new Promise(res => {
 			frappe.call({
 				method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items",
@@ -892,7 +939,8 @@
 					start,
 					page_length,
 					'price_list': this.pos_profile.selling_price_list,
-					search_value,
+					item_group,
+					search_value
 				}
 			}).then(r => {
 				const { items, serial_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 73546a0..d34fc54 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -12,7 +12,7 @@
 from erpnext.controllers.accounts_controller import get_taxes_and_charges
 
 @frappe.whitelist()
-def get_items(start, page_length, price_list, search_value=""):
+def get_items(start, page_length, price_list, item_group, search_value=""):
 	condition = ""
 	serial_no = ""
 	item_code = search_value
@@ -23,6 +23,7 @@
 		if serial_no_data:
 			serial_no, item_code = serial_no_data
 
+	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,
 		item_det.price_list_rate, item_det.currency
@@ -33,9 +34,10 @@
 			(item_det.item_code=i.name or item_det.item_code=i.variant_of)
 		where
 			i.disabled = 0 and i.has_variants = 0
+			and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt})
 			and (i.item_code like %(item_code)s
 			or i.item_name like %(item_code)s)
-		limit {start}, {page_length}""".format(start=start, page_length=page_length),
+		limit {start}, {page_length}""".format(start=start, page_length=page_length, lft=lft, rgt=rgt),
 		{
 			'item_code': '%%%s%%'%(frappe.db.escape(item_code)),
 			'price_list': price_list
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 80ef708..8d084dc 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -79,7 +79,7 @@
 		and out.warehouse and out.stock_qty > 0:
 
 		if out.has_serial_no:
-			out.serial_no = get_serial_no(out)
+			out.serial_no = get_serial_no(out, args.serial_no)
 
 		if out.has_batch_no and not args.get("batch_no"):
 			out.batch_no = get_batch_no(out.item_code, out.warehouse, out.qty)
@@ -554,7 +554,8 @@
 	return out
 
 @frappe.whitelist()
-def get_serial_no(args):
+def get_serial_no(args, serial_nos=None):
+	serial_no = None
 	if isinstance(args, basestring):
 		args = json.loads(args)
 		args = frappe._dict(args)
@@ -568,4 +569,9 @@
 			args = json.dumps({"item_code": args.get('item_code'),"warehouse": args.get('warehouse'),"stock_qty": args.get('stock_qty')})
 			args = process_args(args)
 			serial_no = get_serial_nos_by_fifo(args)
-			return serial_no
+
+	if not serial_no and serial_nos:
+		# For POS
+		serial_no = serial_nos
+
+	return serial_no