Merge branch 'master' into develop
diff --git a/.travis.yml b/.travis.yml
index b74289f..ad9822d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,6 +13,7 @@
   - pip install flake8==3.3.0
   - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
   - sudo rm /etc/apt/sources.list.d/docker.list
+  - sudo apt-get install hhvm && rm -rf /home/travis/.kiex/
   - sudo apt-get purge -y mysql-common mysql-server mysql-client
   - nvm install v7.10.0
   - wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 8a247cc..540e223 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '10.1.27'
+__version__ = '10.1.28'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 2e4dd83..d1c79d0 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -84,7 +84,7 @@
 				d.reference_type = ''
 				d.reference_name = ''
 				d.db_update()
-				
+
 	def unlink_asset_reference(self):
 		for d in self.get("accounts"):
 			if d.reference_type=="Asset" and d.reference_name:
@@ -127,7 +127,7 @@
 				if (d.party_type == 'Customer' and flt(d.credit) > 0) or \
 						(d.party_type == 'Supplier' and flt(d.debit) > 0):
 					if d.is_advance=="No":
-						msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account))
+						msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.idx, d.account), alert=1)
 					elif d.reference_type in ("Sales Order", "Purchase Order") and d.is_advance != "Yes":
 						frappe.throw(_("Row {0}: Payment against Sales/Purchase Order should always be marked as advance").format(d.idx))
 
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index 753540e..0dc6272 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -161,7 +161,8 @@
 			income_expense_account_field = "expense_account"
 
 		item = get_item_dict()
-		return frappe._dict({
+
+		args = frappe._dict({
 			"items": [item],
 			"is_opening": "Yes",
 			"set_posting_time": 1,
@@ -173,6 +174,11 @@
 			"currency": frappe.db.get_value("Company", self.company, "default_currency")
 		})
 
+		if self.invoice_type == "Sales":
+			args["is_pos"] = 0
+
+		return args
+
 @frappe.whitelist()
 def get_temporary_opening_account(company=None):
 	if not company:
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 5b68f1d..9fefc037 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -19,7 +19,13 @@
 
 
 <h2 class="text-center">{%= __(report.report_name) %}</h2>
-<h4 class="text-center">{%= filters.customer || filters.supplier %} </h4>
+<h4 class="text-center">
+	{% if (filters.customer_name) { %}
+		{%= filters.customer_name %}
+	{% } else { %}
+		{%= filters.customer || filters.supplier %}
+	{% } %}
+</h4>
 <h6 class="text-center">
 		{% if (filters.tax_id) { %}
 		{%= __("Tax Id: ")%}	{%= filters.tax_id %}
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index ec1e9f9..1418de3 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -17,8 +17,9 @@
 			"options": "Customer",
 			on_change: () => {
 				var customer = frappe.query_report_filters_by_name.customer.get_value();
-				frappe.db.get_value('Customer', customer, "tax_id", function(value) {
+				frappe.db.get_value('Customer', customer, ["tax_id", "customer_name"], function(value) {
 					frappe.query_report_filters_by_name.tax_id.set_value(value["tax_id"]);
+					frappe.query_report_filters_by_name.customer_name.set_value(value["customer_name"]);
 				});
 			}
 		},
@@ -99,6 +100,12 @@
 			"label": __("Tax Id"),
 			"fieldtype": "Data",
 			"hidden": 1
+		},
+		{
+			"fieldname":"customer_name",
+			"label": __("Customer Name"),
+			"fieldtype": "Data",
+			"hidden": 1
 		}
 	],
 
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index ab189cf..62295d4 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -83,15 +83,15 @@
 			else:
 				ref = valid_items.get(d.item_code, frappe._dict())
 				validate_quantity(doc, d, ref, valid_items, already_returned_items)
-				
+
 				if ref.rate and doc.doctype in ("Delivery Note", "Sales Invoice") and flt(d.rate) > ref.rate:
 					frappe.throw(_("Row # {0}: Rate cannot be greater than the rate used in {1} {2}")
 						.format(d.idx, doc.doctype, doc.return_against))
-							
+
 				elif ref.batch_no and d.batch_no not in ref.batch_no:
 					frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
 						.format(d.idx, doc.doctype, doc.return_against))
-						
+
 				elif ref.serial_no:
 					if not d.serial_no:
 						frappe.throw(_("Row # {0}: Serial No is mandatory").format(d.idx))
@@ -120,25 +120,30 @@
 
 	for column in fields:
 		returned_qty = flt(already_returned_data.get(column, 0)) if len(already_returned_data) > 0 else 0
-		reference_qty = (ref.get(column) if column == 'stock_qty'
-			else ref.get(column) * ref.get("conversion_factor", 1.0))
+
+		if column == 'stock_qty':
+			reference_qty = ref.get(column)
+			current_stock_qty = args.get(column)
+		else:
+			reference_qty = ref.get(column) * ref.get("conversion_factor", 1.0)
+			current_stock_qty = args.get(column) * args.get("conversion_factor", 1.0)
 
 		max_returnable_qty = flt(reference_qty) - returned_qty
 		label = column.replace('_', ' ').title()
 
-		if reference_qty:	
+		if reference_qty:
 			if flt(args.get(column)) > 0:
 				frappe.throw(_("{0} must be negative in return document").format(label))
 			elif returned_qty >= reference_qty and args.get(column):
 				frappe.throw(_("Item {0} has already been returned")
 					.format(args.item_code), StockOverReturnError)
-			elif (abs(args.get(column)) * args.get("conversion_factor", 1.0)) > max_returnable_qty:
+			elif abs(current_stock_qty) > max_returnable_qty:
 				frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
 					.format(args.idx, reference_qty, args.item_code), StockOverReturnError)
 
 def get_ref_item_dict(valid_items, ref_item_row):
 	from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
-	
+
 	valid_items.setdefault(ref_item_row.item_code, frappe._dict({
 		"qty": 0,
 		"rate": 0,
@@ -160,10 +165,10 @@
 
 	if ref_item_row.get("serial_no"):
 		item_dict["serial_no"] += get_serial_nos(ref_item_row.serial_no)
-		
+
 	if ref_item_row.get("batch_no"):
 		item_dict["batch_no"].append(ref_item_row.batch_no)
-		
+
 	return valid_items
 
 def get_already_returned_items(doc):
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 047ef4a..5ecff3f 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -29,6 +29,7 @@
 			self.set_item_wise_tax_breakup()
 
 	def _calculate(self):
+		self.validate_conversion_rate()
 		self.calculate_item_values()
 		self.initialize_taxes()
 		self.determine_exclusive_rate()
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js
index a99a919..cec5356 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.js
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.js
@@ -29,9 +29,10 @@
 		})
 	},
 
-	start_date: function(frm){
+	start_date: function(frm, dt, dn){
 		if(frm.doc.start_date){
 			frm.trigger("set_end_date");
+			get_emp_and_leave_details(frm.doc, dt, dn);
 		}
 	},
 
@@ -65,18 +66,20 @@
 		cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
 	},	
 
-	salary_slip_based_on_timesheet: function(frm) {
+	salary_slip_based_on_timesheet: function(frm, dt, dn) {
 		frm.trigger("toggle_fields");
-		frm.set_value('start_date', '');
+		get_emp_and_leave_details(frm.doc, dt, dn);
 	},
 	
-	payroll_frequency: function(frm) {
+	payroll_frequency: function(frm, dt, dn) {
 		frm.trigger("toggle_fields");
+		frm.set_value('end_date', '');
 		frm.set_value('start_date', '');
+		get_emp_and_leave_details(frm.doc, dt, dn);
 	},
 
-	employee: function(frm){
-		frm.set_value('start_date', '');
+	employee: function(frm, dt, dn) {
+		get_emp_and_leave_details(frm.doc, dt, dn);
 	},
 
 	toggle_fields: function(frm) {
@@ -109,7 +112,7 @@
 
 // Get leave details
 //---------------------------------------------------------------------
-cur_frm.cscript.start_date = function(doc, dt, dn){
+var get_emp_and_leave_details = function(doc, dt, dn) {
 	if(!doc.start_date){
 		return frappe.call({
 			method: 'get_emp_and_leave_details',
@@ -122,11 +125,9 @@
 	}
 }
 
-cur_frm.cscript.payroll_frequency = cur_frm.cscript.salary_slip_based_on_timesheet = cur_frm.cscript.start_date;
-
 cur_frm.cscript.employee = function(doc,dt,dn){
 	doc.salary_structure = ''
-	cur_frm.cscript.start_date(doc, dt, dn)
+	get_emp_and_leave_details(doc, dt, dn);
 }
 
 cur_frm.cscript.leave_without_pay = function(doc,dt,dn){
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 8e6b69b..bdf3c22 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -161,6 +161,28 @@
 	}
 });
 
+frappe.ui.form.on('Salary Structure Employee', {
+	from_date: function(frm, cdt, cdn) {
+		validate_date(frm, cdt, cdn);
+	},
+	to_date: function(frm, cdt, cdn) {
+		validate_date(frm, cdt, cdn);
+	}
+});
+
+var validate_date = function(frm, cdt, cdn) {
+	var doc = locals[cdt][cdn];
+	if(doc.to_date && doc.from_date) {
+		var from_date = frappe.datetime.str_to_obj(doc.from_date);
+		var to_date = frappe.datetime.str_to_obj(doc.to_date);
+
+		if(to_date < from_date) {
+			frappe.model.set_value(cdt, cdn, "to_date", "");
+			frappe.throw(__("From Date cannot be greater than To Date"));
+		}
+	}
+}
+
 
 cur_frm.cscript.amount = function(doc, cdt, cdn){
 	calculate_totals(doc, cdt, cdn);
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 8b53fc3..90a7149 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -567,7 +567,7 @@
 	if not res["bom_no"]:
 		if project:
 			res = get_item_details(item)
-			frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project))
+			frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project), alert=1)
 		else:
 			frappe.throw(_("Default BOM for {0} not found").format(item))
 
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index cdcb059..fdea1b1 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -122,6 +122,7 @@
 						if not wh_detail["is_group"] else ""
 				})
 				warehouse.flags.ignore_permissions = True
+				warehouse.flags.ignore_mandatory = True
 				warehouse.insert()
 
 	def create_default_accounts(self):
diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py
index 7fe7f0c..7f9795b 100644
--- a/erpnext/setup/setup_wizard/operations/company_setup.py
+++ b/erpnext/setup/setup_wizard/operations/company_setup.py
@@ -113,8 +113,7 @@
 				"<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name")	))
 
 def create_website(args):
-	if args.get('setup_website'):
-		website_maker(args)
+	website_maker(args)
 
 def get_fy_details(fy_start_date, fy_end_date):
 	start_year = getdate(fy_start_date).year
diff --git a/erpnext/setup/setup_wizard/operations/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py
index d137676..8ca213b 100644
--- a/erpnext/setup/setup_wizard/operations/default_website.py
+++ b/erpnext/setup/setup_wizard/operations/default_website.py
@@ -12,7 +12,7 @@
 		self.args = args
 		self.company = args.company_name
 		self.tagline = args.company_tagline
-		self.user = args.name
+		self.user = args.get('email')
 		self.make_web_page()
 		self.make_website_settings()
 		self.make_blog()
@@ -50,6 +50,17 @@
 		website_settings.save()
 
 	def make_blog(self):
+		blog_category = frappe.get_doc({
+			"doctype": "Blog Category",
+			"category_name": "general",
+			"published": 1,
+			"title": _("General")
+		}).insert()
+
+		if not self.user:
+			# Admin setup
+			return
+
 		blogger = frappe.new_doc("Blogger")
 		user = frappe.get_doc("User", self.user)
 		blogger.user = self.user
@@ -58,13 +69,6 @@
 		blogger.avatar = user.user_image
 		blogger.insert()
 
-		blog_category = frappe.get_doc({
-			"doctype": "Blog Category",
-			"category_name": "general",
-			"published": 1,
-			"title": _("General")
-		}).insert()
-
 		frappe.get_doc({
 			"doctype": "Blog Post",
 			"title": "Welcome",
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index 750fa38..f36b4e0 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -18,7 +18,8 @@
 					<a class="product-link" href="{{ item.route|abs_url }}">
 						<div class="col-sm-4 col-xs-4 product-image-wrapper">
 							<div class="product-image-img">
-								{{ product_image_square(item.thumbnail or item.image) }}
+								<!-- thumbnail not updated, and used as background image in item card -->
+								{{ product_image_square(item.image) }}
 							<div class="product-text" itemprop="name">{{ item.item_name }}</div>
 							</div>
 						</div>