Merge branch 'develop' into fix_picked_qty_in_DN
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index 17e39d5..ce149f9 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -61,7 +61,6 @@
 	def test_debit_credit_output(self):
 		bank_transaction = frappe.get_doc("Bank Transaction", dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"))
 		linked_payments = get_linked_payments(bank_transaction.name, ['payment_entry', 'exact_match'])
-		print(linked_payments)
 		self.assertTrue(linked_payments[0][3])
 
 	# Check error if already reconciled
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index 03c3eb0..f96f591 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -293,6 +293,11 @@
 	accounts_dict = {}
 	for account in accounts:
 		accounts_dict.setdefault(account["account_name"], account)
+		if not hasattr(account, "parent_account"):
+			msg = _("Please make sure the file you are using has 'Parent Account' column present in the header.")
+			msg += "<br><br>"
+			msg += _("Alternatively, you can download the template and fill your data in.")
+			frappe.throw(msg, title=_("Parent Account Missing"))
 		if account["parent_account"] and accounts_dict.get(account["parent_account"]):
 			accounts_dict[account["parent_account"]]["is_group"] = 1
 
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index c2798a3..2e26fd2 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -260,7 +260,10 @@
 			"erpnext.regional.italy.utils.sales_invoice_on_cancel",
 			"erpnext.erpnext_integrations.taxjar_integration.delete_transaction"
 		],
-		"on_trash": "erpnext.regional.check_deletion_permission"
+		"on_trash": "erpnext.regional.check_deletion_permission",
+		"validate": [
+			"erpnext.regional.india.utils.validate_document_name"
+		]
 	},
 	"Purchase Invoice": {
 		"validate": [
@@ -282,9 +285,6 @@
 	('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
 		'validate': ['erpnext.regional.india.utils.set_place_of_supply']
 	},
-	('Sales Invoice', 'Purchase Invoice'): {
-		'validate': ['erpnext.regional.india.utils.validate_document_name']
-	},
 	"Contact": {
 		"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
 		"after_insert": "erpnext.telephony.doctype.call_log.call_log.link_existing_conversations",
diff --git a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
index 7a9727f..aa5a67f 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
@@ -5,7 +5,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import date_diff, add_days, getdate, cint
+from frappe.utils import date_diff, add_days, getdate, cint, format_date
 from frappe.model.document import Document
 from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, \
 	get_holidays_for_employee, create_additional_leave_ledger_entry
@@ -40,7 +40,12 @@
 	def validate_holidays(self):
 		holidays = get_holidays_for_employee(self.employee, self.work_from_date, self.work_end_date)
 		if len(holidays) < date_diff(self.work_end_date, self.work_from_date) + 1:
-			frappe.throw(_("Compensatory leave request days not in valid holidays"))
+			if date_diff(self.work_end_date, self.work_from_date):
+				msg = _("The days between {0} to {1} are not valid holidays.").format(frappe.bold(format_date(self.work_from_date)), frappe.bold(format_date(self.work_end_date)))
+			else:
+				msg = _("{0} is not a holiday.").format(frappe.bold(format_date(self.work_from_date)))
+
+			frappe.throw(msg)
 
 	def on_submit(self):
 		company = frappe.db.get_value("Employee", self.employee, "company")
@@ -63,7 +68,7 @@
 				leave_allocation = self.create_leave_allocation(leave_period, date_difference)
 			self.leave_allocation=leave_allocation.name
 		else:
-			frappe.throw(_("There is no leave period in between {0} and {1}").format(self.work_from_date, self.work_end_date))
+			frappe.throw(_("There is no leave period in between {0} and {1}").format(format_date(self.work_from_date), format_date(self.work_end_date)))
 
 	def on_cancel(self):
 		if self.leave_allocation:
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 629bc57..ed7d588 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -80,6 +80,7 @@
 			self.update_user()
 			self.update_user_permissions()
 		self.reset_employee_emails_cache()
+		self.update_approver_role()
 
 	def update_user_permissions(self):
 		if not self.create_user_permission: return
@@ -145,6 +146,17 @@
 
 		user.save()
 
+	def update_approver_role(self):
+		if self.leave_approver:
+			user = frappe.get_doc("User", self.leave_approver)
+			user.flags.ignore_permissions = True
+			user.add_roles("Leave Approver")
+
+		if self.expense_approver:
+			user = frappe.get_doc("User", self.expense_approver)
+			user.flags.ignore_permissions = True
+			user.add_roles("Expense Approver")
+
 	def validate_date(self):
 		if self.date_of_birth and getdate(self.date_of_birth) > getdate(today()):
 			throw(_("Date of Birth cannot be greater than today."))
@@ -503,7 +515,7 @@
 	})
 
 def has_upload_permission(doc, ptype='read', user=None):
-	if not user: 
+	if not user:
 		user = frappe.session.user
 	if get_doc_permissions(doc, user=user, ptype=ptype).get(ptype):
 		return True
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index e7bb6dc..5010fc3 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -6,7 +6,7 @@
 from frappe import _
 from frappe.utils import get_fullname, flt, cstr, get_link_to_form
 from frappe.model.document import Document
-from erpnext.hr.utils import set_employee_name
+from erpnext.hr.utils import set_employee_name, share_doc_with_approver
 from erpnext.accounts.party import get_party_account
 from erpnext.accounts.general_ledger import make_gl_entries
 from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
@@ -53,6 +53,9 @@
 		elif self.docstatus == 1 and self.approval_status == 'Rejected':
 			self.status = 'Rejected'
 
+	def on_update(self):
+		share_doc_with_approver(self, self.expense_approver)
+
 	def set_payable_account(self):
 		if not self.payable_account and not self.is_paid:
 			self.payable_account = frappe.get_cached_value('Company', self.company, 'default_expense_claim_payable_account')
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index f9e3a44..3f22ca2 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -95,12 +95,12 @@
 	def test_rejected_expense_claim(self):
 		payable_account = get_payable_account(company_name)
 		expense_claim = frappe.get_doc({
-			 "doctype": "Expense Claim",
-			 "employee": "_T-Employee-00001",
-			 "payable_account": payable_account,
-			 "approval_status": "Rejected",
-			 "expenses":
-			 	[{ "expense_type": "Travel", "default_account": "Travel Expenses - _TC4", "amount": 300, "sanctioned_amount": 200 }]
+			"doctype": "Expense Claim",
+			"employee": "_T-Employee-00001",
+			"payable_account": payable_account,
+			"approval_status": "Rejected",
+			"expenses":
+				[{ "expense_type": "Travel", "default_account": "Travel Expenses - _TC4", "amount": 300, "sanctioned_amount": 200 }]
 		})
 		expense_claim.submit()
 
@@ -110,6 +110,34 @@
 		gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': expense_claim.name})
 		self.assertEquals(len(gl_entry), 0)
 
+	def test_expense_approver_perms(self):
+		user = "test_approver_perm_emp@example.com"
+		make_employee(user, "_Test Company")
+
+		# check doc shared
+		payable_account = get_payable_account("_Test Company")
+		expense_claim = make_expense_claim(payable_account, 300, 200, "_Test Company", "Travel Expenses - _TC", do_not_submit=True)
+		expense_claim.expense_approver = user
+		expense_claim.save()
+		self.assertTrue(expense_claim.name in frappe.share.get_shared("Expense Claim", user))
+
+		# check shared doc revoked
+		expense_claim.reload()
+		expense_claim.expense_approver = "test@example.com"
+		expense_claim.save()
+		self.assertTrue(expense_claim.name not in frappe.share.get_shared("Expense Claim", user))
+
+		expense_claim.reload()
+		expense_claim.expense_approver = user
+		expense_claim.save()
+
+		frappe.set_user(user)
+		expense_claim.reload()
+		expense_claim.status = "Approved"
+		expense_claim.submit()
+		frappe.set_user("Administrator")
+
+
 def get_payable_account(company):
 	return frappe.get_cached_value('Company', company, 'default_payable_account')
 
@@ -133,21 +161,21 @@
 
 	currency, cost_center = frappe.db.get_value('Company', company, ['default_currency', 'cost_center'])
 	expense_claim = {
-		 "doctype": "Expense Claim",
-		 "employee": employee,
-		 "payable_account": payable_account,
-		 "approval_status": "Approved",
-		 "company": company,
-		'currency': currency,
-		 "expenses": [{
+		"doctype": "Expense Claim",
+		"employee": employee,
+		"payable_account": payable_account,
+		"approval_status": "Approved",
+		"company": company,
+		"currency": currency,
+		"expenses": [{
 			"expense_type": "Travel",
 			"default_account": account,
 			"currency": currency,
 			"amount": amount,
 			"sanctioned_amount": sanctioned_amount,
 			"cost_center": cost_center
-			}]
-		}
+		}]
+	}
 	if taxes:
 		expense_claim.update(taxes)
 
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 350cead..0bf551e 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -6,7 +6,7 @@
 from frappe import _
 from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
 	comma_or, get_fullname, add_days, nowdate, get_datetime_str
-from erpnext.hr.utils import set_employee_name, get_leave_period
+from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver
 from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
 from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
@@ -43,6 +43,8 @@
 			if frappe.db.get_single_value("HR Settings", "send_leave_notification"):
 				self.notify_leave_approver()
 
+		share_doc_with_approver(self, self.leave_approver)
+
 	def on_submit(self):
 		if self.status == "Open":
 			frappe.throw(_("Only Leave Applications with status 'Approved' and 'Rejected' can be submitted"))
@@ -417,6 +419,7 @@
 			))
 			create_leave_ledger_entry(self, args, submit)
 
+
 def get_allocation_expiry(employee, leave_type, to_date, from_date):
 	''' Returns expiry of carry forward allocation in leave ledger entry '''
 	expiry =  frappe.get_all("Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 48bfa0c..b54c971 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -11,6 +11,7 @@
 from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
 from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
 from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import create_assignment_for_multiple_employees
+from erpnext.hr.doctype.employee.test_employee import make_employee
 
 test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"]
 
@@ -567,6 +568,48 @@
 
 		self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
 
+	def test_leave_approver_perms(self):
+		employee = get_employee()
+		user = "test_approver_perm_emp@example.com"
+		make_employee(user, "_Test Company")
+
+		# set approver for employee
+		employee.reload()
+		employee.leave_approver = user
+		employee.save()
+		self.assertTrue("Leave Approver" in frappe.get_roles(user))
+
+		make_allocation_record(employee.name)
+
+		application = self.get_application(_test_records[0])
+		application.from_date = '2018-01-01'
+		application.to_date = '2018-01-03'
+		application.leave_approver = user
+		application.insert()
+		self.assertTrue(application.name in frappe.share.get_shared("Leave Application", user))
+
+		# check shared doc revoked
+		application.reload()
+		application.leave_approver = "test@example.com"
+		application.save()
+		self.assertTrue(application.name not in frappe.share.get_shared("Leave Application", user))
+
+		application.reload()
+		application.leave_approver = user
+		application.save()
+
+		frappe.set_user(user)
+		application.reload()
+		application.status = "Approved"
+		application.submit()
+
+		# unset leave approver
+		frappe.set_user("Administrator")
+		employee.reload()
+		employee.leave_approver = ""
+		employee.save()
+
+
 def create_carry_forwarded_allocation(employee, leave_type):
 		# initial leave allocation
 		leave_allocation = create_leave_allocation(
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 66dced4..cf13036 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -34,8 +34,8 @@
 	""", (ledger.employee, ledger.leave_type, ledger.from_date, ledger.to_date))
 
 	if leave_application_records:
-		frappe.throw(_("Leave allocation %s is linked with leave application %s"
-			% (ledger.transaction_name, ', '.join(leave_application_records))))
+		frappe.throw(_("Leave allocation {0} is linked with the Leave Application {1}").format(
+			ledger.transaction_name, ', '.join(leave_application_records)))
 
 def create_leave_ledger_entry(ref_doc, args, submit=True):
 	ledger = frappe._dict(
diff --git a/erpnext/hr/doctype/shift_request/shift_request.py b/erpnext/hr/doctype/shift_request/shift_request.py
index 473193d..177c45e 100644
--- a/erpnext/hr/doctype/shift_request/shift_request.py
+++ b/erpnext/hr/doctype/shift_request/shift_request.py
@@ -7,6 +7,7 @@
 from frappe import _
 from frappe.model.document import Document
 from frappe.utils import formatdate, getdate
+from erpnext.hr.utils import share_doc_with_approver
 
 class OverlapError(frappe.ValidationError): pass
 
@@ -17,6 +18,9 @@
 		self.validate_approver()
 		self.validate_default_shift()
 
+	def on_update(self):
+		share_doc_with_approver(self, self.approver)
+
 	def on_submit(self):
 		if self.status not in ["Approved", "Rejected"]:
 			frappe.throw(_("Only Shift Request with status 'Approved' and 'Rejected' can be submitted"))
@@ -29,6 +33,7 @@
 			if self.to_date:
 				assignment_doc.end_date = self.to_date
 			assignment_doc.shift_request = self.name
+			assignment_doc.flags.ignore_permissions = 1
 			assignment_doc.insert()
 			assignment_doc.submit()
 
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py
index 230bb2b..9c0d8e3 100644
--- a/erpnext/hr/doctype/shift_request/test_shift_request.py
+++ b/erpnext/hr/doctype/shift_request/test_shift_request.py
@@ -6,6 +6,7 @@
 import frappe
 import unittest
 from frappe.utils import nowdate, add_days
+from erpnext.hr.doctype.employee.test_employee import make_employee
 
 test_dependencies = ["Shift Type"]
 
@@ -19,19 +20,8 @@
 		set_shift_approver(department)
 		approver = frappe.db.sql("""select approver from `tabDepartment Approver` where parent= %s and parentfield = 'shift_request_approver'""", (department))[0][0]
 
-		shift_request = frappe.get_doc({
-			"doctype": "Shift Request",
-			"shift_type": "Day Shift",
-			"company": "_Test Company",
-			"employee": "_T-Employee-00001",
-			"employee_name": "_Test Employee",
-			"from_date": nowdate(),
-			"to_date": add_days(nowdate(), 10),
-			"approver": approver,
-			"status": "Approved"
-		})
-		shift_request.insert()
-		shift_request.submit()
+		shift_request = make_shift_request(approver)
+
 		shift_assignments = frappe.db.sql('''
 				SELECT shift_request, employee
 				FROM `tabShift Assignment`
@@ -44,8 +34,65 @@
 			shift_assignment_doc = frappe.get_doc("Shift Assignment", {"shift_request": d.get('shift_request')})
 			self.assertEqual(shift_assignment_doc.docstatus, 2)
 
+	def test_shift_request_approver_perms(self):
+		employee = frappe.get_doc("Employee", "_T-Employee-00001")
+		user = "test_approver_perm_emp@example.com"
+		make_employee(user, "_Test Company")
+
+		# set approver for employee
+		employee.reload()
+		employee.shift_request_approver = user
+		employee.save()
+
+		shift_request = make_shift_request(user, do_not_submit=True)
+		self.assertTrue(shift_request.name in frappe.share.get_shared("Shift Request", user))
+
+		# check shared doc revoked
+		shift_request.reload()
+		department = frappe.get_value("Employee", "_T-Employee-00001", "department")
+		set_shift_approver(department)
+		department_approver = frappe.db.sql("""select approver from `tabDepartment Approver` where parent= %s and parentfield = 'shift_request_approver'""", (department))[0][0]
+		shift_request.approver = department_approver
+		shift_request.save()
+		self.assertTrue(shift_request.name not in frappe.share.get_shared("Shift Request", user))
+
+		shift_request.reload()
+		shift_request.approver = user
+		shift_request.save()
+
+		frappe.set_user(user)
+		shift_request.reload()
+		shift_request.status = "Approved"
+		shift_request.submit()
+
+		# unset approver
+		frappe.set_user("Administrator")
+		employee.reload()
+		employee.shift_request_approver = ""
+		employee.save()
+
+
 def set_shift_approver(department):
 	department_doc = frappe.get_doc("Department", department)
 	department_doc.append('shift_request_approver',{'approver': "test1@example.com"})
 	department_doc.save()
 	department_doc.reload()
+
+def make_shift_request(approver, do_not_submit=0):
+	shift_request = frappe.get_doc({
+		"doctype": "Shift Request",
+		"shift_type": "Day Shift",
+		"company": "_Test Company",
+		"employee": "_T-Employee-00001",
+		"employee_name": "_Test Employee",
+		"from_date": nowdate(),
+		"to_date": add_days(nowdate(), 10),
+		"approver": approver,
+		"status": "Approved"
+	}).insert()
+
+	if do_not_submit:
+		return shift_request
+
+	shift_request.submit()
+	return shift_request
\ No newline at end of file
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 0c4c1ca..190eb4f 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -504,3 +504,25 @@
 		lpa = frappe.db.get_all("Leave Policy Assignment", filters={"effective_from": getdate(), "docstatus": 1, "leaves_allocated":0})
 		for assignment in lpa:
 			frappe.get_doc("Leave Policy Assignment", assignment.name).grant_leave_alloc_for_employee()
+
+def share_doc_with_approver(doc, user):
+	# if approver does not have permissions, share
+	if not frappe.has_permission(doc=doc, ptype="submit", user=user):
+		frappe.share.add(doc.doctype, doc.name, user, submit=1,
+			flags={"ignore_share_permission": True})
+
+		frappe.msgprint(_("Shared with the user {0} with {1} access").format(
+			user, frappe.bold("submit"), alert=True))
+
+	# remove shared doc if approver changes
+	doc_before_save = doc.get_doc_before_save()
+	if doc_before_save:
+		approvers = {
+			"Leave Application": "leave_approver",
+			"Expense Claim": "expense_approver",
+			"Shift Request": "approver"
+		}
+
+		approver = approvers.get(doc.doctype)
+		if doc_before_save.get(approver) != doc.get(approver):
+			frappe.share.remove(doc.doctype, doc.name, doc_before_save.get(approver))
diff --git a/erpnext/hr/workspace/hr/hr.json b/erpnext/hr/workspace/hr/hr.json
index f650b24..f4b56a0 100644
--- a/erpnext/hr/workspace/hr/hr.json
+++ b/erpnext/hr/workspace/hr/hr.json
@@ -15,6 +15,7 @@
  "hide_custom": 0,
  "icon": "hr",
  "idx": 0,
+ "is_default": 0,
  "is_standard": 1,
  "label": "HR",
  "links": [
@@ -227,41 +228,11 @@
    "type": "Card Break"
   },
   {
-   "dependencies": "Employee",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Leave Application",
-   "link_to": "Leave Application",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "Employee",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Leave Allocation",
-   "link_to": "Leave Allocation",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "Leave Type",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Leave Policy",
-   "link_to": "Leave Policy",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Leave Period",
-   "link_to": "Leave Period",
+   "label": "Holiday List",
+   "link_to": "Holiday List",
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
@@ -280,8 +251,28 @@
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Holiday List",
-   "link_to": "Holiday List",
+   "label": "Leave Period",
+   "link_to": "Leave Period",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Leave Type",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Leave Policy",
+   "link_to": "Leave Policy",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Leave Policy",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Leave Policy Assignment",
+   "link_to": "Leave Policy Assignment",
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
@@ -290,8 +281,18 @@
    "dependencies": "Employee",
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Compensatory Leave Request",
-   "link_to": "Compensatory Leave Request",
+   "label": "Leave Application",
+   "link_to": "Leave Application",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Employee",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Leave Allocation",
+   "link_to": "Leave Allocation",
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
@@ -317,12 +318,12 @@
    "type": "Link"
   },
   {
-   "dependencies": "Leave Application",
+   "dependencies": "Employee",
    "hidden": 0,
-   "is_query_report": 1,
-   "label": "Employee Leave Balance",
-   "link_to": "Employee Leave Balance",
-   "link_type": "Report",
+   "is_query_report": 0,
+   "label": "Compensatory Leave Request",
+   "link_to": "Compensatory Leave Request",
+   "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
   },
@@ -384,16 +385,6 @@
    "type": "Link"
   },
   {
-   "dependencies": "Attendance",
-   "hidden": 0,
-   "is_query_report": 1,
-   "label": "Monthly Attendance Sheet",
-   "link_to": "Monthly Attendance Sheet",
-   "link_type": "Report",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
    "hidden": 0,
    "is_query_report": 0,
    "label": "Expense Claims",
@@ -423,6 +414,15 @@
   {
    "hidden": 0,
    "is_query_report": 0,
+   "label": "Travel Request",
+   "link_to": "Travel Request",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
    "label": "Settings",
    "onboard": 0,
    "type": "Card Break"
@@ -465,6 +465,15 @@
    "type": "Card Break"
   },
   {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Driver",
+   "link_to": "Driver",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
@@ -544,6 +553,24 @@
   {
    "hidden": 0,
    "is_query_report": 0,
+   "label": "Appointment Letter",
+   "link_to": "Appointment Letter",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Appointment Letter Template",
+   "link_to": "Appointment Letter Template",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
    "label": "Loans",
    "onboard": 0,
    "type": "Card Break"
@@ -628,33 +655,6 @@
   {
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Reports",
-   "onboard": 0,
-   "type": "Card Break"
-  },
-  {
-   "dependencies": "Employee",
-   "hidden": 0,
-   "is_query_report": 1,
-   "label": "Employee Birthday",
-   "link_to": "Employee Birthday",
-   "link_type": "Report",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "Employee",
-   "hidden": 0,
-   "is_query_report": 1,
-   "label": "Employees working on a holiday",
-   "link_to": "Employees working on a holiday",
-   "link_type": "Report",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "hidden": 0,
-   "is_query_report": 0,
    "label": "Performance",
    "onboard": 0,
    "type": "Card Break"
@@ -702,7 +702,74 @@
   {
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Employee Tax and Benefits",
+   "label": "Key Reports",
+   "onboard": 0,
+   "type": "Card Break"
+  },
+  {
+   "dependencies": "Attendance",
+   "hidden": 0,
+   "is_query_report": 1,
+   "label": "Monthly Attendance Sheet",
+   "link_to": "Monthly Attendance Sheet",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Staffing Plan",
+   "hidden": 0,
+   "is_query_report": 1,
+   "label": "Recruitment Analytics",
+   "link_to": "Recruitment Analytics",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Employee",
+   "hidden": 0,
+   "is_query_report": 1,
+   "label": "Employee Analytics",
+   "link_to": "Employee Analytics",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Employee",
+   "hidden": 0,
+   "is_query_report": 1,
+   "label": "Employee Leave Balance",
+   "link_to": "Employee Leave Balance",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Employee",
+   "hidden": 0,
+   "is_query_report": 1,
+   "label": "Employee Leave Balance Summary",
+   "link_to": "Employee Leave Balance Summary",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "Employee Advance",
+   "hidden": 0,
+   "is_query_report": 1,
+   "label": "Employee Advance Summary",
+   "link_to": "Employee Advance Summary",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Other Reports",
    "onboard": 0,
    "type": "Card Break"
   },
@@ -710,74 +777,44 @@
    "dependencies": "Employee",
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Employee Tax Exemption Declaration",
-   "link_to": "Employee Tax Exemption Declaration",
-   "link_type": "DocType",
+   "label": "Employee Information",
+   "link_to": "Employee Information",
+   "link_type": "Report",
    "onboard": 0,
    "type": "Link"
   },
   {
    "dependencies": "Employee",
    "hidden": 0,
-   "is_query_report": 0,
-   "label": "Employee Tax Exemption Proof Submission",
-   "link_to": "Employee Tax Exemption Proof Submission",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "Employee, Payroll Period",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Employee Other Income",
-   "link_to": "Employee Other Income",
-   "link_type": "DocType",
+   "is_query_report": 1,
+   "label": "Employee Birthday",
+   "link_to": "Employee Birthday",
+   "link_type": "Report",
    "onboard": 0,
    "type": "Link"
   },
   {
    "dependencies": "Employee",
    "hidden": 0,
-   "is_query_report": 0,
-   "label": "Employee Benefit Application",
-   "link_to": "Employee Benefit Application",
-   "link_type": "DocType",
+   "is_query_report": 1,
+   "label": "Employees Working on a Holiday",
+   "link_to": "Employees working on a holiday",
+   "link_type": "Report",
    "onboard": 0,
    "type": "Link"
   },
   {
-   "dependencies": "Employee",
+   "dependencies": "Daily Work Summary",
    "hidden": 0,
-   "is_query_report": 0,
-   "label": "Employee Benefit Claim",
-   "link_to": "Employee Benefit Claim",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "Employee",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Employee Tax Exemption Category",
-   "link_to": "Employee Tax Exemption Category",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "Employee",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Employee Tax Exemption Sub Category",
-   "link_to": "Employee Tax Exemption Sub Category",
-   "link_type": "DocType",
+   "is_query_report": 1,
+   "label": "Daily Work Summary Replies",
+   "link_to": "Daily Work Summary Replies",
+   "link_type": "Report",
    "onboard": 0,
    "type": "Link"
   }
  ],
- "modified": "2021-01-21 13:38:38.941001",
+ "modified": "2021-03-24 17:35:21.483297",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
index 2b5df4b..86ea59d 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
@@ -21,6 +21,7 @@
   "interest_payable",
   "payable_amount",
   "column_break_9",
+  "shortfall_amount",
   "payable_principal_amount",
   "penalty_amount",
   "amount_paid",
@@ -31,6 +32,7 @@
   "column_break_21",
   "reference_date",
   "principal_amount_paid",
+  "total_penalty_paid",
   "total_interest_paid",
   "repayment_details",
   "amended_from"
@@ -226,12 +228,25 @@
    "fieldtype": "Percent",
    "label": "Rate Of Interest",
    "read_only": 1
+  },
+  {
+   "fieldname": "shortfall_amount",
+   "fieldtype": "Currency",
+   "label": "Shortfall Amount",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "fieldname": "total_penalty_paid",
+   "fieldtype": "Currency",
+   "label": "Total Penalty Paid",
+   "options": "Company:company:default_currency"
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-11-05 10:06:58.792841",
+ "modified": "2021-04-05 13:45:19.137896",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Repayment",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index bac06c4..5d57ced 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -21,6 +21,7 @@
 	def validate(self):
 		amounts = calculate_amounts(self.against_loan, self.posting_date)
 		self.set_missing_values(amounts)
+		self.check_future_entries()
 		self.validate_amount()
 		self.allocate_amounts(amounts)
 
@@ -60,16 +61,29 @@
 		if not self.payable_amount:
 			self.payable_amount = flt(amounts['payable_amount'], precision)
 
+		shortfall_amount = flt(frappe.db.get_value('Loan Security Shortfall', {'loan': self.against_loan, 'status': 'Pending'},
+			'shortfall_amount'))
+
+		if shortfall_amount:
+			self.shortfall_amount = shortfall_amount
+
 		if amounts.get('due_date'):
 			self.due_date = amounts.get('due_date')
 
+	def check_future_entries(self):
+		future_repayment_date = frappe.db.get_value("Loan Repayment", {"posting_date": (">", self.posting_date),
+			"docstatus": 1, "against_loan": self.against_loan}, 'posting_date')
+
+		if future_repayment_date:
+			frappe.throw("Repayment already made till date {0}".format(getdate(future_repayment_date)))
+
 	def validate_amount(self):
 		precision = cint(frappe.db.get_default("currency_precision")) or 2
 
 		if not self.amount_paid:
 			frappe.throw(_("Amount paid cannot be zero"))
 
-		if self.amount_paid < self.penalty_amount:
+		if not self.shortfall_amount and self.amount_paid < self.penalty_amount:
 			msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
 			frappe.throw(msg)
 
@@ -148,11 +162,28 @@
 	def allocate_amounts(self, repayment_details):
 		self.set('repayment_details', [])
 		self.principal_amount_paid = 0
-		total_interest_paid = 0
-		interest_paid = self.amount_paid - self.penalty_amount
+		self.total_penalty_paid = 0
+		interest_paid = self.amount_paid
 
-		if self.amount_paid - self.penalty_amount > 0:
-			interest_paid = self.amount_paid - self.penalty_amount
+		if self.shortfall_amount and self.amount_paid > self.shortfall_amount:
+			self.principal_amount_paid = self.shortfall_amount
+		elif self.shortfall_amount:
+			self.principal_amount_paid = self.amount_paid
+
+		interest_paid -= self.principal_amount_paid
+
+		if interest_paid > 0:
+			if self.penalty_amount and interest_paid > self.penalty_amount:
+				self.total_penalty_paid = self.penalty_amount
+			elif self.penalty_amount:
+				self.total_penalty_paid = interest_paid
+
+			interest_paid -= self.total_penalty_paid
+
+		total_interest_paid = 0
+		# interest_paid = self.amount_paid - self.principal_amount_paid - self.penalty_amount
+
+		if interest_paid > 0:
 			for lia, amounts in iteritems(repayment_details.get('pending_accrual_entries', [])):
 				if amounts['interest_amount'] + amounts['payable_principal_amount'] <= interest_paid:
 					interest_amount = amounts['interest_amount']
@@ -177,7 +208,7 @@
 					'paid_principal_amount': paid_principal
 				})
 
-		if repayment_details['unaccrued_interest'] and interest_paid:
+		if repayment_details['unaccrued_interest'] and interest_paid > 0:
 			# no of days for which to accrue interest
 			# Interest can only be accrued for an entire day and not partial
 			if interest_paid > repayment_details['unaccrued_interest']:
@@ -193,20 +224,20 @@
 				interest_paid -= no_of_days * per_day_interest
 
 		self.total_interest_paid = total_interest_paid
-		if interest_paid:
+		if interest_paid > 0:
 			self.principal_amount_paid += interest_paid
 
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gle_map = []
 		loan_details = frappe.get_doc("Loan", self.against_loan)
 
-		if self.penalty_amount:
+		if self.total_penalty_paid:
 			gle_map.append(
 				self.get_gl_dict({
 					"account": loan_details.loan_account,
 					"against": loan_details.payment_account,
-					"debit": self.penalty_amount,
-					"debit_in_account_currency": self.penalty_amount,
+					"debit": self.total_penalty_paid,
+					"debit_in_account_currency": self.total_penalty_paid,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.against_loan,
 					"remarks": _("Penalty against loan:") + self.against_loan,
@@ -221,8 +252,8 @@
 				self.get_gl_dict({
 					"account": loan_details.penalty_income_account,
 					"against": loan_details.payment_account,
-					"credit": self.penalty_amount,
-					"credit_in_account_currency": self.penalty_amount,
+					"credit": self.total_penalty_paid,
+					"credit_in_account_currency": self.total_penalty_paid,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.against_loan,
 					"remarks": _("Penalty against loan:") + self.against_loan,
@@ -284,7 +315,9 @@
 
 	return lr
 
-def get_accrued_interest_entries(against_loan):
+def get_accrued_interest_entries(against_loan, posting_date=None):
+	if not posting_date:
+		posting_date = getdate()
 
 	unpaid_accrued_entries = frappe.db.sql(
 		"""
@@ -295,12 +328,13 @@
 				`tabLoan Interest Accrual`
 			WHERE
 				loan = %s
+			AND posting_date <= %s
 			AND (interest_amount - paid_interest_amount > 0 OR
 				payable_principal_amount - paid_principal_amount > 0)
 			AND
 				docstatus = 1
 			ORDER BY posting_date
-		""", (against_loan), as_dict=1)
+		""", (against_loan, posting_date), as_dict=1)
 
 	return unpaid_accrued_entries
 
@@ -312,7 +346,7 @@
 
 	against_loan_doc = frappe.get_doc("Loan", against_loan)
 	loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
-	accrued_interest_entries = get_accrued_interest_entries(against_loan_doc.name)
+	accrued_interest_entries = get_accrued_interest_entries(against_loan_doc.name, posting_date)
 
 	pending_accrual_entries = {}
 
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
index 6539436..8233b7b 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
@@ -12,7 +12,7 @@
 class LoanSecurityShortfall(Document):
 	pass
 
-def update_shortfall_status(loan, security_value):
+def update_shortfall_status(loan, security_value, on_cancel=0):
 	loan_security_shortfall = frappe.db.get_value("Loan Security Shortfall",
 		{"loan": loan, "status": "Pending"}, ['name', 'shortfall_amount'], as_dict=1)
 
diff --git a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json
index 2f4fe24..3d07081 100644
--- a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json
+++ b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json
@@ -70,7 +70,9 @@
   {
    "fieldname": "loan_repayment_entry",
    "fieldtype": "Link",
+   "hidden": 1,
    "label": "Loan Repayment Entry",
+   "no_copy": 1,
    "options": "Loan Repayment",
    "read_only": 1
   },
@@ -83,9 +85,10 @@
    "read_only": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-04-16 13:17:04.798335",
+ "modified": "2021-03-14 20:47:11.725818",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Salary Slip Loan",
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 4050a7d..cd61d2a 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -5,7 +5,7 @@
 from __future__ import unicode_literals
 import unittest
 import frappe
-from frappe.utils import cstr
+from frappe.utils import cstr, flt
 from frappe.test_runner import make_test_records
 from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
 from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
@@ -81,15 +81,27 @@
 		bom = frappe.copy_doc(test_records[2])
 		bom.insert()
 
-		# test amounts in selected currency
-		self.assertEqual(bom.operating_cost, 100)
-		self.assertEqual(bom.raw_material_cost, 351.68)
-		self.assertEqual(bom.total_cost, 451.68)
+		raw_material_cost = 0.0
+		op_cost = 0.0
+
+		for op_row in bom.operations:
+			op_cost += op_row.operating_cost
+
+		for row in bom.items:
+			raw_material_cost += row.amount
+
+		base_raw_material_cost = raw_material_cost * flt(bom.conversion_rate, bom.precision("conversion_rate"))
+		base_op_cost = op_cost * flt(bom.conversion_rate, bom.precision("conversion_rate"))
 
 		# test amounts in selected currency
-		self.assertEqual(bom.base_operating_cost, 6000)
-		self.assertEqual(bom.base_raw_material_cost, 21100.80)
-		self.assertEqual(bom.base_total_cost, 27100.80)
+		self.assertEqual(bom.operating_cost, op_cost)
+		self.assertEqual(bom.raw_material_cost, raw_material_cost)
+		self.assertEqual(bom.total_cost, raw_material_cost + op_cost)
+
+		# test amounts in selected currency
+		self.assertEqual(bom.base_operating_cost, base_op_cost)
+		self.assertEqual(bom.base_raw_material_cost, base_raw_material_cost)
+		self.assertEqual(bom.base_total_cost, base_raw_material_cost + base_op_cost)
 
 	def test_bom_cost_multi_uom_multi_currency_based_on_price_list(self):
 		frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependent", 1)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 8aa0ffd..92074c6 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -47,6 +47,8 @@
 				if d.completed_qty:
 					self.total_completed_qty += d.completed_qty
 
+			self.total_completed_qty = flt(self.total_completed_qty, self.precision("total_completed_qty"))
+
 	def get_overlap_for(self, args, check_next_available_slot=False):
 		production_capacity = 1
 
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
index 395e56f..85bb651 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js
@@ -133,45 +133,59 @@
 				}
 			};
 		});
+
+		frm.set_query('employee', 'employees', () => {
+			if (!frm.doc.company) {
+				frappe.msgprint(__("Please set a Company"));
+				return [];
+			}
+			return {
+				query: "erpnext.payroll.doctype.payroll_entry.payroll_entry.employee_query",
+				filters: frm.events.get_employee_filters(frm)
+			};
+		});
+	},
+
+	get_employee_filters: function (frm) {
+		let filters = {};
+		filters['company'] = frm.doc.company;
+		filters['start_date'] = frm.doc.start_date;
+		filters['end_date'] = frm.doc.end_date;
+
+		if (frm.doc.department) {
+			filters['department'] = frm.doc.department;
+		}
+		if (frm.doc.branch) {
+			filters['branch'] = frm.doc.branch;
+		}
+		if (frm.doc.designation) {
+			filters['designation'] = frm.doc.designation;
+		}
+		if (frm.doc.employees) {
+			filters['employees'] = frm.doc.employees.filter(d => d.employee).map(d => d.employee);
+		}
+		return filters;
 	},
 
 	payroll_frequency: function (frm) {
 		frm.trigger("set_start_end_dates").then( ()=> {
 			frm.events.clear_employee_table(frm);
-			frm.events.get_employee_with_salary_slip_and_set_query(frm);
-		});
-	},
-
-	employee_filters: function (frm, emp_list) {
-		frm.set_query('employee', 'employees', () => {
-			return {
-				filters: {
-					name: ["not in", emp_list]
-				}
-			};
-		});
-	},
-
-	get_employee_with_salary_slip_and_set_query: function (frm) {
-		frappe.db.get_list('Salary Slip', {
-			filters: {
-				start_date: frm.doc.start_date,
-				end_date: frm.doc.end_date,
-				docstatus: 1,
-			},
-			fields: ['employee']
-		}).then((emp) => {
-			var emp_list = [];
-			emp.forEach((employee_data) => {
-				emp_list.push(Object.values(employee_data)[0]);
-			});
-			frm.events.employee_filters(frm, emp_list);
 		});
 	},
 
 	company: function (frm) {
 		frm.events.clear_employee_table(frm);
 		erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+		frm.trigger("set_payable_account_and_currency");
+	},
+
+	set_payable_account_and_currency: function (frm) {
+		frappe.db.get_value("Company", {"name": frm.doc.company}, "default_currency", (r) => {
+			frm.set_value('currency', r.default_currency);
+		});
+		frappe.db.get_value("Company", {"name": frm.doc.company}, "default_payroll_payable_account", (r) => {
+			frm.set_value('payroll_payable_account', r.default_payroll_payable_account);
+		});
 	},
 
 	currency: function (frm) {
@@ -345,11 +359,3 @@
 		})
 	);
 };
-
-frappe.ui.form.on('Payroll Employee Detail', {
-	employee: function(frm) {
-		if (!frm.doc.payroll_frequency) {
-			frappe.throw(__("Please set a Payroll Frequency"));
-		}
-	}
-});
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
index 7890471..fde2e07 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
@@ -10,16 +10,17 @@
 from frappe import _
 from erpnext.accounts.utils import get_fiscal_year
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from frappe.desk.reportview import get_match_cond, get_filters_cond
 
 class PayrollEntry(Document):
 	def onload(self):
 		if not self.docstatus==1 or self.salary_slips_submitted:
-    			return
+			return
 
 		# check if salary slips were manually submitted
 		entries = frappe.db.count("Salary Slip", {'payroll_entry': self.name, 'docstatus': 1}, ['name'])
 		if cint(entries) == len(self.employees):
-				self.set_onload("submitted_ss", True)
+			self.set_onload("submitted_ss", True)
 
 	def validate(self):
 		self.number_of_employees = len(self.employees)
@@ -59,16 +60,16 @@
 			condition = """and payroll_frequency = '%(payroll_frequency)s'"""% {"payroll_frequency": self.payroll_frequency}
 
 		sal_struct = frappe.db.sql_list("""
-				select
-					name from `tabSalary Structure`
-				where
-					docstatus = 1 and
-					is_active = 'Yes'
-					and company = %(company)s
-					and currency = %(currency)s and
-					ifnull(salary_slip_based_on_timesheet,0) = %(salary_slip_based_on_timesheet)s
-					{condition}""".format(condition=condition),
-				{"company": self.company, "currency": self.currency, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet})
+			select
+				name from `tabSalary Structure`
+			where
+				docstatus = 1 and
+				is_active = 'Yes'
+				and company = %(company)s
+				and currency = %(currency)s and
+				ifnull(salary_slip_based_on_timesheet,0) = %(salary_slip_based_on_timesheet)s
+				{condition}""".format(condition=condition),
+			{"company": self.company, "currency": self.currency, "salary_slip_based_on_timesheet":self.salary_slip_based_on_timesheet})
 
 		if sal_struct:
 			cond += "and t2.salary_structure IN %(sal_struct)s "
@@ -176,15 +177,15 @@
 		"""
 			Returns list of salary slips based on selected criteria
 		"""
-		cond = self.get_filter_condition()
 
 		ss_list = frappe.db.sql("""
 			select t1.name, t1.salary_structure, t1.payroll_cost_center from `tabSalary Slip` t1
-			where t1.docstatus = %s and t1.start_date >= %s and t1.end_date <= %s
-			and (t1.journal_entry is null or t1.journal_entry = "") and ifnull(salary_slip_based_on_timesheet,0) = %s %s
-		""" % ('%s', '%s', '%s','%s', cond), (ss_status, self.start_date, self.end_date, self.salary_slip_based_on_timesheet), as_dict=as_dict)
+			where t1.docstatus = %s and t1.start_date >= %s and t1.end_date <= %s and t1.payroll_entry = %s
+			and (t1.journal_entry is null or t1.journal_entry = "") and ifnull(salary_slip_based_on_timesheet,0) = %s
+		""", (ss_status, self.start_date, self.end_date, self.name, self.salary_slip_based_on_timesheet), as_dict=as_dict)
 		return ss_list
 
+	@frappe.whitelist()
 	def submit_salary_slips(self):
 		self.check_permission('write')
 		ss_list = self.get_sal_slip_list(ss_status=0)
@@ -270,26 +271,26 @@
 				exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
 				payable_amount += flt(amount, precision)
 				accounts.append({
-						"account": acc_cc[0],
-						"debit_in_account_currency": flt(amt, precision),
-						"exchange_rate": flt(exchange_rate),
-						"party_type": '',
-						"cost_center": acc_cc[1] or self.cost_center,
-						"project": self.project
-					})
+					"account": acc_cc[0],
+					"debit_in_account_currency": flt(amt, precision),
+					"exchange_rate": flt(exchange_rate),
+					"party_type": '',
+					"cost_center": acc_cc[1] or self.cost_center,
+					"project": self.project
+				})
 
 			# Deductions
 			for acc_cc, amount in deductions.items():
 				exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
 				payable_amount -= flt(amount, precision)
 				accounts.append({
-						"account": acc_cc[0],
-						"credit_in_account_currency": flt(amt, precision),
-						"exchange_rate": flt(exchange_rate),
-						"cost_center": acc_cc[1] or self.cost_center,
-						"party_type": '',
-						"project": self.project
-					})
+					"account": acc_cc[0],
+					"credit_in_account_currency": flt(amt, precision),
+					"exchange_rate": flt(exchange_rate),
+					"cost_center": acc_cc[1] or self.cost_center,
+					"party_type": '',
+					"project": self.project
+				})
 
 			# Payable amount
 			exchange_rate, payable_amt = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, payable_amount, company_currency, currencies)
@@ -335,10 +336,9 @@
 	def make_payment_entry(self):
 		self.check_permission('write')
 
-		cond = self.get_filter_condition()
 		salary_slip_name_list = frappe.db.sql(""" select t1.name from `tabSalary Slip` t1
-			where t1.docstatus = 1 and start_date >= %s and end_date <= %s %s
-			""" % ('%s', '%s', cond), (self.start_date, self.end_date), as_list = True)
+			where t1.docstatus = 1 and start_date >= %s and end_date <= %s and t1.payroll_entry = %s
+			""", (self.start_date, self.end_date, self.name), as_list = True)
 
 		if salary_slip_name_list and len(salary_slip_name_list) > 0:
 			salary_slip_total = 0
@@ -370,20 +370,20 @@
 
 		exchange_rate, amount = self.get_amount_and_exchange_rate_for_journal_entry(self.payment_account, je_payment_amount, company_currency, currencies)
 		accounts.append({
-				"account": self.payment_account,
-				"bank_account": self.bank_account,
-				"credit_in_account_currency": flt(amount, precision),
-				"exchange_rate": flt(exchange_rate),
-			})
+			"account": self.payment_account,
+			"bank_account": self.bank_account,
+			"credit_in_account_currency": flt(amount, precision),
+			"exchange_rate": flt(exchange_rate),
+		})
 
 		exchange_rate, amount = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, je_payment_amount, company_currency, currencies)
 		accounts.append({
-				"account": payroll_payable_account,
-				"debit_in_account_currency": flt(amount, precision),
-				"exchange_rate": flt(exchange_rate),
-				"reference_type": self.doctype,
-				"reference_name": self.name
-			})
+			"account": payroll_payable_account,
+			"debit_in_account_currency": flt(amount, precision),
+			"exchange_rate": flt(exchange_rate),
+			"reference_type": self.doctype,
+			"reference_name": self.name
+		})
 
 		if len(currencies) > 1:
 				multi_currency = 1
@@ -409,6 +409,7 @@
 		self.update(get_start_end_dates(self.payroll_frequency,
 			self.start_date or self.posting_date, self.company))
 
+	@frappe.whitelist()
 	def validate_employee_attendance(self):
 		employees_to_mark_attendance = []
 		days_in_payroll, days_holiday, days_attendance_marked = 0, 0, 0
@@ -424,7 +425,7 @@
 				employees_to_mark_attendance.append({
 					"employee": employee_detail.employee,
 					"employee_name": employee_detail.employee_name
-					})
+				})
 		return employees_to_mark_attendance
 
 	def get_count_holidays_of_employee(self, employee, start_date):
@@ -441,11 +442,11 @@
 	def get_count_employee_attendance(self, employee, start_date):
 		marked_days = 0
 		attendances = frappe.get_all("Attendance",
-				fields = ["count(*)"],
-				filters = {
-					"employee": employee,
-					"attendance_date": ('between', [start_date, self.end_date])
-				}, as_list=1)
+			fields = ["count(*)"],
+			filters = {
+				"employee": employee,
+				"attendance_date": ('between', [start_date, self.end_date])
+			}, as_list=1)
 		if attendances and attendances[0][0]:
 			marked_days = attendances[0][0]
 		return marked_days
@@ -553,6 +554,7 @@
 def create_salary_slips_for_employees(employees, args, publish_progress=True):
 	salary_slips_exists_for = get_existing_salary_slips(employees, args)
 	count=0
+	salary_slips_not_created = []
 	for emp in employees:
 		if emp not in salary_slips_exists_for:
 			args.update({
@@ -566,33 +568,24 @@
 				frappe.publish_progress(count*100/len(set(employees) - set(salary_slips_exists_for)),
 					title = _("Creating Salary Slips..."))
 		else:
-			salary_slip_name = frappe.db.sql(
-				'''SELECT
-						name
-					FROM `tabSalary Slip`
-					WHERE company=%s
-					AND start_date >= %s
-					AND end_date <= %s
-					AND employee = %s
-				''', (args.company, args.start_date, args.end_date, emp), as_dict=True)
-
-			salary_slip_doc = frappe.get_doc('Salary Slip', salary_slip_name[0].name)
-			salary_slip_doc.exchange_rate = args.exchange_rate
-			salary_slip_doc.set_totals()
-			salary_slip_doc.db_update()
+			salary_slips_not_created.append(emp)
 
 	payroll_entry = frappe.get_doc("Payroll Entry", args.payroll_entry)
 	payroll_entry.db_set("salary_slips_created", 1)
 	payroll_entry.notify_update()
 
+	if salary_slips_not_created:
+		frappe.msgprint(_("Salary Slips already exists for employees {}, and will not be processed by this payroll.")
+			.format(frappe.bold(", ".join([emp for emp in salary_slips_not_created]))) , title=_("Message"), indicator="orange")
+
 def get_existing_salary_slips(employees, args):
 	return frappe.db.sql_list("""
 		select distinct employee from `tabSalary Slip`
-		where docstatus!= 2 and company = %s
+		where docstatus!= 2 and company = %s and payroll_entry = %s
 			and start_date >= %s and end_date <= %s
 			and employee in (%s)
-	""" % ('%s', '%s', '%s', ', '.join(['%s']*len(employees))),
-		[args.company, args.start_date, args.end_date] + employees)
+	""" % ('%s', '%s', '%s', '%s', ', '.join(['%s']*len(employees))),
+		[args.company, args.payroll_entry, args.start_date, args.end_date] + employees)
 
 def submit_salary_slips_for_employees(payroll_entry, salary_slips, publish_progress=True):
 	submitted_ss = []
@@ -644,3 +637,61 @@
 			'txt': "%%%s%%" % frappe.db.escape(txt),
 			'start': start, 'page_len': page_len
 		})
+
+def get_employee_with_existing_salary_slip(start_date, end_date, company):
+	return frappe.db.sql_list("""
+		select employee from `tabSalary Slip`
+		where
+			(start_date between %(start_date)s and %(end_date)s
+		or
+			end_date between %(start_date)s and %(end_date)s
+		or
+			%(start_date)s between start_date and end_date)
+		and company = %(company)s
+		and docstatus = 1
+	""", {'start_date': start_date, 'end_date': end_date, 'company': company})
+
+@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
+def employee_query(doctype, txt, searchfield, start, page_len, filters):
+	filters = frappe._dict(filters)
+	conditions = []
+	exclude_employees = []
+	emp_cond = ''
+	if filters.start_date and filters.end_date:
+		employee_list = get_employee_with_existing_salary_slip(filters.start_date, filters.end_date, filters.company)
+		emp = filters.get('employees')
+		filters.pop('start_date')
+		filters.pop('end_date')
+		if filters.employees is not None:
+			filters.pop('employees')
+		if employee_list:
+			exclude_employees.extend(employee_list)
+		if emp:
+			exclude_employees.extend(emp)
+		if exclude_employees:
+			emp_cond += 'and employee not in %(exclude_employees)s'
+
+	return frappe.db.sql("""select name, employee_name from `tabEmployee`
+		where status = 'Active'
+			and docstatus < 2
+			and ({key} like %(txt)s
+				or employee_name like %(txt)s)
+			{emp_cond}
+			{fcond} {mcond}
+		order by
+			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
+			if(locate(%(_txt)s, employee_name), locate(%(_txt)s, employee_name), 99999),
+			idx desc,
+			name, employee_name
+		limit %(start)s, %(page_len)s""".format(**{
+			'key': searchfield,
+			'fcond': get_filters_cond(doctype, filters, conditions),
+			'mcond': get_match_cond(doctype),
+			'emp_cond': emp_cond
+		}), {
+			'txt': "%%%s%%" % txt,
+			'_txt': txt.replace("%", ""),
+			'start': start,
+			'page_len': page_len,
+			'exclude_employees': exclude_employees})
diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
index 84c3814..7528bf7 100644
--- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
@@ -51,21 +51,22 @@
 
 		company_doc = frappe.get_doc('Company', company)
 		salary_structure = make_salary_structure("_Test Multi Currency Salary Structure", "Monthly", company=company, currency='USD')
-		create_salary_structure_assignment(employee, salary_structure.name, company=company)
+		create_salary_structure_assignment(employee, salary_structure.name, company=company, currency='USD')
 		frappe.db.sql("""delete from `tabSalary Slip` where employee=%s""",(frappe.db.get_value("Employee", {"user_id": "test_muti_currency_employee@payroll.com"})))
 		salary_slip = get_salary_slip("test_muti_currency_employee@payroll.com", "Monthly", "_Test Multi Currency Salary Structure")
 		dates = get_start_end_dates('Monthly', nowdate())
-		payroll_entry = make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date, 
+		payroll_entry = make_payroll_entry(start_date=dates.start_date, end_date=dates.end_date,
 			payable_account=company_doc.default_payroll_payable_account, currency='USD', exchange_rate=70)
 		payroll_entry.make_payment_entry()
 
 		salary_slip.load_from_db()
 
 		payroll_je = salary_slip.journal_entry
-		payroll_je_doc = frappe.get_doc('Journal Entry', payroll_je)
+		if payroll_je:
+			payroll_je_doc = frappe.get_doc('Journal Entry', payroll_je)
 
-		self.assertEqual(salary_slip.base_gross_pay, payroll_je_doc.total_debit)
-		self.assertEqual(salary_slip.base_gross_pay, payroll_je_doc.total_credit)
+			self.assertEqual(salary_slip.base_gross_pay, payroll_je_doc.total_debit)
+			self.assertEqual(salary_slip.base_gross_pay, payroll_je_doc.total_credit)
 
 		payment_entry = frappe.db.sql('''
 			Select ifnull(sum(je.total_debit),0) as total_debit, ifnull(sum(je.total_credit),0) as total_credit from `tabJournal Entry` je, `tabJournal Entry Account` jea
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js
index 3e8a213..e3993fa 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.js
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js
@@ -39,7 +39,8 @@
 
 		frm.set_query("employee", function() {
 			return {
-				query: "erpnext.controllers.queries.employee_query"
+				query: "erpnext.controllers.queries.employee_query",
+				filters: frm.doc.company
 			};
 		});
 	},
@@ -93,28 +94,31 @@
 	},
 
 	set_exchange_rate: function(frm, company_currency) {
-		if (frm.doc.currency) {
-			var from_currency = frm.doc.currency;
-			if (from_currency != company_currency) {
-				frm.events.hide_loan_section(frm);
-				frappe.call({
-					method: "erpnext.setup.utils.get_exchange_rate",
-					args: {
-						from_currency: from_currency,
-						to_currency: company_currency,
-					},
-					callback: function(r) {
-						frm.set_value("exchange_rate", flt(r.message));
-						frm.set_df_property("exchange_rate", "hidden", 0);
-						frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
-							+ " = [?] " + company_currency);
-					}
-				});
-			} else {
-				frm.set_value("exchange_rate", 1.0);
-				frm.set_df_property("exchange_rate", "hidden", 1);
-				frm.set_df_property("exchange_rate", "description", "");
-			}
+		if (frm.doc.docstatus === 0) {
+			if (frm.doc.currency) {
+				var from_currency = frm.doc.currency;
+				if (from_currency != company_currency) {
+					frm.events.hide_loan_section(frm);
+					frappe.call({
+						method: "erpnext.setup.utils.get_exchange_rate",
+						args: {
+							from_currency: from_currency,
+							to_currency: company_currency,
+						},
+						callback: function(r) {
+							if (r.message) {
+								frm.set_value("exchange_rate", flt(r.message));
+								frm.set_df_property('exchange_rate', 'hidden', 0);
+								frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
+									+ " = [?] " + company_currency);
+							}
+						}
+					});
+				} else {
+					frm.set_value("exchange_rate", 1.0);
+					frm.set_df_property('exchange_rate', 'hidden', 1);
+					frm.set_df_property("exchange_rate", "description", "" );
+				}
 		}
 	},
 
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index aa9acd8..f6d4c7b 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -124,9 +124,12 @@
 
 	def check_existing(self):
 		if not self.salary_slip_based_on_timesheet:
+			cond = ""
+			if self.payroll_entry:
+				cond += "and payroll_entry = '{0}'".format(self.payroll_entry)
 			ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
 						where start_date = %s and end_date = %s and docstatus != 2
-						and employee = %s and name != %s""",
+						and employee = %s and name != %s {0}""".format(cond),
 						(self.start_date, self.end_date, self.employee, self.name))
 			if ret_exist:
 				self.employee = ''
@@ -1053,7 +1056,7 @@
 			repayment_entry.save()
 			repayment_entry.submit()
 
-			loan.loan_repayment_entry = repayment_entry.name
+			frappe.db.set_value("Salary Slip Loan", loan.name, "loan_repayment_entry", repayment_entry.name)
 
 	def cancel_loan_repayment_entry(self):
 		for loan in self.loans:
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 21a20a7..6c2144d 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -737,28 +737,34 @@
 				this.frm.trigger("item_code", cdt, cdn);
 			}
 			else {
-				var valid_serial_nos = [];
-				var serialnos = [];
 				// Replacing all occurences of comma with carriage return
 				item.serial_no = item.serial_no.replace(/,/g, '\n');
-				serialnos = item.serial_no.split("\n");
-				for (var i = 0; i < serialnos.length; i++) {
-					if (serialnos[i] != "") {
-						valid_serial_nos.push(serialnos[i]);
-					}
-				}
 				item.conversion_factor = item.conversion_factor || 1;
-
 				refresh_field("serial_no", item.name, item.parentfield);
-				if(!doc.is_return && cint(user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
-					frappe.model.set_value(item.doctype, item.name,
-						"qty", valid_serial_nos.length / item.conversion_factor);
-					frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
+				if (!doc.is_return && cint(frappe.user_defaults.set_qty_in_transactions_based_on_serial_no_input)) {
+					setTimeout(() => {
+						me.update_qty(cdt, cdn);
+					}, 10000);
 				}
 			}
 		}
 	},
 
+	update_qty: function(cdt, cdn) {
+		var valid_serial_nos = [];
+		var serialnos = [];
+		var item = frappe.get_doc(cdt, cdn);
+		serialnos = item.serial_no.split("\n");
+		for (var i = 0; i < serialnos.length; i++) {
+			if (serialnos[i] != "") {
+				valid_serial_nos.push(serialnos[i]);
+			}
+		}
+		frappe.model.set_value(item.doctype, item.name,
+			"qty", valid_serial_nos.length / item.conversion_factor);
+		frappe.model.set_value(item.doctype, item.name, "stock_qty", valid_serial_nos.length);
+	},
+
 	validate: function() {
 		this.calculate_taxes_and_totals(false);
 	},
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 8eccc3f..3dd1b36 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -787,6 +787,8 @@
 
 		self.invoice.irn = res.get('Irn')
 		self.invoice.ewaybill = res.get('EwbNo')
+		self.invoice.ack_no = res.get('AckNo')
+		self.invoice.ack_date = res.get('AckDt')
 		self.invoice.signed_einvoice = dec_signed_invoice
 		self.invoice.signed_qr_code = res.get('SignedQRCode')
 
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.js b/erpnext/setup/doctype/global_defaults/global_defaults.js
index 552331a..942dd59 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.js
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.js
@@ -17,7 +17,7 @@
 			method: "frappe.client.get_list",
 			args: {
 				doctype: "UOM Conversion Factor",
-				filters: { "category": "Length" },
+				filters: { "category": __("Length") },
 				fields: ["to_uom"],
 				limit_page_length: 500
 			},