Merge branch 'develop' of https://github.com/frappe/erpnext into develop
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index 53ff222..68aeb6d 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -326,7 +326,7 @@
 			"reference_doctype": args.dt,
 			"reference_name": args.dn,
 			"party_type": args.get("party_type") or "Customer",
-			"party": args.get("party") or ref_doc.customer,
+			"party": args.get("party") or ref_doc.get("customer"),
 			"bank_account": bank_account
 		})
 
@@ -420,7 +420,7 @@
 
 def update_payment_req_status(doc, method):
 	from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
-	
+
 	for ref in doc.references:
 		payment_request_name = frappe.db.get_value("Payment Request",
 			{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
@@ -430,7 +430,7 @@
 			ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
 			pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
 			status = pay_req_doc.status
-			
+
 			if status != "Paid" and not ref_details.outstanding_amount:
 				status = 'Paid'
 			elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 9292b63..3cf4d59 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -261,12 +261,25 @@
 				price_list: this.frm.doc.buying_price_list
 			}, function() {
 				me.apply_pricing_rule();
-
 				me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
+				me.frm.doc.tax_withholding_category = me.frm.supplier_tds;
 				me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
+				me.frm.set_df_property("tax_withholding_category", "hidden", me.frm.supplier_tds ? 0 : 1);
 			})
 	},
 
+	apply_tds: function(frm) {
+		var me = this;
+
+		if (!me.frm.doc.apply_tds) {
+			me.frm.set_value("tax_withholding_category", '');
+			me.frm.set_df_property("tax_withholding_category", "hidden", 1);
+		} else {
+			me.frm.set_value("tax_withholding_category", me.frm.supplier_tds);
+			me.frm.set_df_property("tax_withholding_category", "hidden", 0);
+		}
+	},
+
 	credit_to: function() {
 		var me = this;
 		if(this.frm.doc.credit_to) {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 0e09454..98ba5c7 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -13,6 +13,7 @@
   "supplier_name",
   "tax_id",
   "due_date",
+  "tax_withholding_category",
   "column_break1",
   "company",
   "posting_date",
@@ -1294,13 +1295,21 @@
    "fieldtype": "Check",
    "label": "Is Internal Supplier",
    "read_only": 1
+  },
+  {
+   "fieldname": "tax_withholding_category",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Tax Withholding Category",
+   "options": "Tax Withholding Category",
+   "print_hide": 1
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 204,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-17 13:05:25.199832",
+ "modified": "2020-04-18 13:05:25.199832",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 0283d30..b1ae194 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1002,7 +1002,7 @@
 		if not self.apply_tds:
 			return
 
-		tax_withholding_details = get_party_tax_withholding_details(self)
+		tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
 
 		if not tax_withholding_details:
 			return
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
index 1741869..0e748f8 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "hash",
  "creation": "2013-05-21 16:16:04",
  "doctype": "DocType",
@@ -14,11 +15,11 @@
   "col_break1",
   "account_head",
   "description",
+  "section_break_10",
+  "rate",
   "accounting_dimensions_section",
   "cost_center",
   "dimension_col_break",
-  "section_break_10",
-  "rate",
   "section_break_9",
   "tax_amount",
   "tax_amount_after_discount_amount",
@@ -27,8 +28,7 @@
   "base_tax_amount",
   "base_total",
   "base_tax_amount_after_discount_amount",
-  "item_wise_tax_detail",
-  "parenttype"
+  "item_wise_tax_detail"
  ],
  "fields": [
   {
@@ -53,6 +53,7 @@
   },
   {
    "columns": 2,
+   "default": "On Net Total",
    "fieldname": "charge_type",
    "fieldtype": "Select",
    "in_list_view": 1,
@@ -197,15 +198,6 @@
    "read_only": 1
   },
   {
-   "fieldname": "parenttype",
-   "fieldtype": "Data",
-   "hidden": 1,
-   "label": "Parenttype",
-   "oldfieldname": "parenttype",
-   "oldfieldtype": "Data",
-   "print_hide": 1
-  },
-  {
    "fieldname": "accounting_dimensions_section",
    "fieldtype": "Section Break",
    "label": "Accounting Dimensions"
@@ -217,11 +209,14 @@
  ],
  "idx": 1,
  "istable": 1,
- "modified": "2019-05-25 23:08:38.281025",
+ "links": [],
+ "modified": "2020-03-12 14:53:47.679439",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Taxes and Charges",
  "owner": "Administrator",
  "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js
index ba6c03b..6336db1 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js
@@ -26,16 +26,24 @@
 			&& !frm.doc.is_return && !frm.doc.ewaybill) {
 
 			frm.add_custom_button('E-Way Bill JSON', () => {
-				var w = window.open(
-					frappe.urllib.get_full_url(
-						"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
-						+ "dt=" + encodeURIComponent(frm.doc.doctype)
-						+ "&dn=" + encodeURIComponent(frm.doc.name)
-					)
-				);
-				if (!w) {
-					frappe.msgprint(__("Please enable pop-ups")); return;
-				}
+				frappe.call({
+					method: 'erpnext.regional.india.utils.generate_ewb_json',
+					args: {
+						'dt': frm.doc.doctype,
+						'dn': [frm.doc.name]
+					},
+					callback: function(r) {
+						if (r.message) {
+							const args = {
+								cmd: 'erpnext.regional.india.utils.download_ewb_json',
+								data: r.message,
+								docname: frm.doc.name
+							};
+							open_url_post(frappe.request.url, args);
+						}
+					}
+				});
+
 			}, __("Create"));
 		}
 	}
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
index d175827..3e1c522 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india_list.js
@@ -16,17 +16,23 @@
 			}
 		}
 
-		var w = window.open(
-			frappe.urllib.get_full_url(
-				"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
-				+ "dt=" + encodeURIComponent(doclist.doctype)
-				+ "&dn=" + encodeURIComponent(docnames)
-			)
-		);
-		if (!w) {
-			frappe.msgprint(__("Please enable pop-ups")); return;
-		}
-
+		frappe.call({
+			method: 'erpnext.regional.india.utils.generate_ewb_json',
+			args: {
+				'dt': doclist.doctype,
+				'dn': docnames
+			},
+			callback: function(r) {
+				if (r.message) {
+					const args = {
+						cmd: 'erpnext.regional.india.utils.download_ewb_json',
+						data: r.message,
+						docname: docnames
+					};
+					open_url_post(frappe.request.url, args);
+				}
+			}
+		});
 	};
 
 	doclist.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index a6113cd..60e41f9 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -587,7 +587,9 @@
 		frm.set_query("account_for_change_amount", function() {
 			return {
 				filters: {
-					account_type: ['in', ["Cash", "Bank"]]
+					account_type: ['in', ["Cash", "Bank"]],
+					company: frm.doc.company,
+					is_group: 0
 				}
 			};
 		});
@@ -668,7 +670,8 @@
 		frm.fields_dict["loyalty_redemption_account"].get_query = function() {
 			return {
 				filters:{
-					"company": frm.doc.company
+					"company": frm.doc.company,
+					"is_group": 0
 				}
 			}
 		};
@@ -677,7 +680,8 @@
 		frm.fields_dict["loyalty_redemption_cost_center"].get_query = function() {
 			return {
 				filters:{
-					"company": frm.doc.company
+					"company": frm.doc.company,
+					"is_group": 0
 				}
 			}
 		};
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index a2819af..88b54fe 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1892,7 +1892,7 @@
 
 		si.submit()
 
-		data = get_ewb_data("Sales Invoice", si.name)
+		data = get_ewb_data("Sales Invoice", [si.name])
 
 		self.assertEqual(data['version'], '1.0.1118')
 		self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 6c31e9e..dd6b4fd 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -6,23 +6,42 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import flt
+from frappe.utils import flt, getdate
 from erpnext.accounts.utils import get_fiscal_year
 
 class TaxWithholdingCategory(Document):
 	pass
 
-def get_party_tax_withholding_details(ref_doc):
-	tax_withholding_category = frappe.db.get_value('Supplier', ref_doc.supplier, 'tax_withholding_category')
+def get_party_tax_withholding_details(ref_doc, tax_withholding_category=None):
+
+	pan_no = ''
+	suppliers = []
+
+	if not tax_withholding_category:
+		tax_withholding_category, pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, ['tax_withholding_category', 'pan'])
+
 	if not tax_withholding_category:
 		return
 
+	if not pan_no:
+		pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, 'pan')
+
+	# Get others suppliers with the same PAN No
+	if pan_no:
+		suppliers = [d.name for d in  frappe.get_all('Supplier', fields=['name'], filters={'pan': pan_no})]
+
+	if not suppliers:
+		suppliers.append(ref_doc.supplier)
+
 	fy = get_fiscal_year(ref_doc.posting_date, company=ref_doc.company)
 	tax_details = get_tax_withholding_details(tax_withholding_category, fy[0], ref_doc.company)
 	if not tax_details:
 		frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}')
 			.format(tax_withholding_category, ref_doc.company))
-	tds_amount = get_tds_amount(ref_doc, tax_details, fy)
+
+	tds_amount = get_tds_amount(suppliers, ref_doc.net_total, ref_doc.company,
+		tax_details, fy,  ref_doc.posting_date, pan_no)
+
 	tax_row = get_tax_row(tax_details, tds_amount)
 
 	return tax_row
@@ -51,6 +70,7 @@
 	frappe.throw(_("No Tax Withholding data found for the current Fiscal Year."))
 
 def get_tax_row(tax_details, tds_amount):
+
 	return {
 		"category": "Total",
 		"add_deduct_tax": "Deduct",
@@ -60,25 +80,36 @@
 		"tax_amount": tds_amount
 	}
 
-def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
+def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_details, posting_date, pan_no=None):
 	fiscal_year, year_start_date, year_end_date = fiscal_year_details
 	tds_amount = 0
 	tds_deducted = 0
 
-	def _get_tds(amount):
+	def _get_tds(amount, rate):
 		if amount <= 0:
 			return 0
 
-		return amount * tax_details.rate / 100
+		return amount * rate / 100
+
+	ldc_name = frappe.db.get_value('Lower Deduction Certificate',
+		{
+			'pan_no': pan_no,
+			'fiscal_year': fiscal_year
+		}, 'name')
+	ldc = ''
+
+	if ldc_name:
+		ldc = frappe.get_doc('Lower Deduction Certificate', ldc_name)
 
 	entries = frappe.db.sql("""
 			select voucher_no, credit
 			from `tabGL Entry`
-			where party=%s and fiscal_year=%s and credit > 0
-		""", (ref_doc.supplier, fiscal_year), as_dict=1)
+			where company = %s and
+			party in %s and fiscal_year=%s and credit > 0
+		""", (company, tuple(suppliers), fiscal_year), as_dict=1)
 
 	vouchers = [d.voucher_no for d in entries]
-	advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year)
+	advance_vouchers = get_advance_vouchers(suppliers, fiscal_year=fiscal_year, company=company)
 
 	tds_vouchers = vouchers + advance_vouchers
 
@@ -93,7 +124,20 @@
 		tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
 
 	if tds_deducted:
-		tds_amount = _get_tds(ref_doc.net_total)
+		if ldc:
+			limit_consumed = frappe.db.get_value('Purchase Invoice',
+				{
+					'supplier': ('in', suppliers),
+					'apply_tds': 1,
+					'docstatus': 1
+				}, 'sum(net_total)')
+
+		if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, limit_consumed, net_total,
+			ldc.certificate_limit):
+
+			tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
+		else:
+			tds_amount = _get_tds(net_total, tax_details.rate)
 	else:
 		supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
 			fields = ['sum(net_amount)'],
@@ -106,43 +150,79 @@
 			fields = ['sum(credit_in_account_currency)'],
 			filters = {
 				'parent': ('in', vouchers), 'docstatus': 1,
-				'party': ref_doc.supplier,
+				'party': ('in', suppliers),
 				'reference_type': ('not in', ['Purchase Invoice'])
 			}, as_list=1)
 
 		supplier_credit_amount += (jv_supplier_credit_amt[0][0]
 			if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
 
-		supplier_credit_amount += ref_doc.net_total
+		supplier_credit_amount += net_total
 
-		debit_note_amount = get_debit_note_amount(ref_doc.supplier, year_start_date, year_end_date)
+		debit_note_amount = get_debit_note_amount(suppliers, year_start_date, year_end_date)
 		supplier_credit_amount -= debit_note_amount
 
 		if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
 			or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
-			tds_amount = _get_tds(supplier_credit_amount)
+
+			if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, tds_deducted, net_total,
+				ldc.certificate_limit):
+				tds_amount = get_ltds_amount(supplier_credit_amount, 0, ldc.certificate_limit, ldc.rate,
+					tax_details)
+			else:
+				tds_amount = _get_tds(supplier_credit_amount, tax_details.rate)
 
 	return tds_amount
 
-def get_advance_vouchers(supplier, fiscal_year=None, company=None, from_date=None, to_date=None):
+def get_advance_vouchers(suppliers, fiscal_year=None, company=None, from_date=None, to_date=None):
 	condition = "fiscal_year=%s" % fiscal_year
+
+	if company:
+		condition += "and company =%s" % (company)
 	if from_date and to_date:
-		condition = "company=%s and posting_date between %s and %s" % (company, from_date, to_date)
+		condition += "and posting_date between %s and %s" % (company, from_date, to_date)
+
+	## Appending the same supplier again if length of suppliers list is 1
+	## since tuple of single element list contains None, For example ('Test Supplier 1', )
+	## and the below query fails
+	if len(suppliers) == 1:
+		suppliers.append(suppliers[0])
 
 	return frappe.db.sql_list("""
 		select distinct voucher_no
 		from `tabGL Entry`
-		where party=%s and %s and debit > 0
-	""", (supplier, condition)) or []
+		where party in %s and %s and debit > 0
+	""", (tuple(suppliers), condition)) or []
 
-def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None):
-	condition = ""
+def get_debit_note_amount(suppliers, year_start_date, year_end_date, company=None):
+	condition = "and 1=1"
 	if company:
 		condition = " and company=%s " % company
 
+	if len(suppliers) == 1:
+		suppliers.append(suppliers[0])
+
 	return flt(frappe.db.sql("""
 		select abs(sum(net_total))
 		from `tabPurchase Invoice`
-		where supplier=%s %s and is_return=1 and docstatus=1
-			and posting_date between %s and %s
-	""", (supplier, condition, year_start_date, year_end_date)))
\ No newline at end of file
+		where supplier in %s and is_return=1 and docstatus=1
+			and posting_date between %s and %s %s
+	""", (tuple(suppliers), year_start_date, year_end_date, condition)))
+
+def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
+	if current_amount < (certificate_limit - deducted_amount):
+		return current_amount * rate/100
+	else:
+		ltds_amount = (certificate_limit - deducted_amount)
+		tds_amount = current_amount - ltds_amount
+
+		return ltds_amount * rate/100 + tds_amount * tax_details.rate/100
+
+def is_valid_certificate(valid_from, valid_upto, posting_date, deducted_amount, current_amount, certificate_limit):
+	valid = False
+
+	if ((getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and
+			certificate_limit > deducted_amount):
+		valid = True
+
+	return valid
\ No newline at end of file
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index b62238b..c2c7207 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -84,6 +84,7 @@
 
 def get_profit_loss_data(fiscal_year, companies, columns, filters):
 	income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
+	company_currency = get_company_currency(filters)
 
 	data = []
 	data.extend(income or [])
@@ -93,7 +94,7 @@
 
 	chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
 
-	report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True)
+	report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
 
 	return data, None, chart, report_summary
 
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 6ef6d6e..4e22b05 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -55,27 +55,27 @@
 	columns = []
 	column_map = frappe._dict({
 		"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
-		"posting_date": _("Posting Date") + ":Date",
-		"posting_time": _("Posting Time"),
-		"item_code": _("Item Code") + ":Link/Item",
-		"item_name": _("Item Name"),
-		"item_group": _("Item Group") + ":Link/Item Group",
-		"brand": _("Brand"),
-		"description": _("Description"),
-		"warehouse": _("Warehouse") + ":Link/Warehouse",
-		"qty": _("Qty") + ":Float",
-		"base_rate": _("Avg. Selling Rate") + ":Currency/currency",
-		"buying_rate": _("Valuation Rate") + ":Currency/currency",
-		"base_amount": _("Selling Amount") + ":Currency/currency",
-		"buying_amount": _("Buying Amount") + ":Currency/currency",
-		"gross_profit": _("Gross Profit") + ":Currency/currency",
-		"gross_profit_percent": _("Gross Profit %") + ":Percent",
-		"project": _("Project") + ":Link/Project",
+		"posting_date": _("Posting Date") + ":Date:100",
+		"posting_time": _("Posting Time") + ":Data:100",
+		"item_code": _("Item Code") + ":Link/Item:100",
+		"item_name": _("Item Name") + ":Data:100",
+		"item_group": _("Item Group") + ":Link/Item Group:100",
+		"brand": _("Brand") + ":Link/Brand:100",
+		"description": _("Description") +":Data:100",
+		"warehouse": _("Warehouse") + ":Link/Warehouse:100",
+		"qty": _("Qty") + ":Float:80",
+		"base_rate": _("Avg. Selling Rate") + ":Currency/currency:100",
+		"buying_rate": _("Valuation Rate") + ":Currency/currency:100",
+		"base_amount": _("Selling Amount") + ":Currency/currency:100",
+		"buying_amount": _("Buying Amount") + ":Currency/currency:100",
+		"gross_profit": _("Gross Profit") + ":Currency/currency:100",
+		"gross_profit_percent": _("Gross Profit %") + ":Percent:100",
+		"project": _("Project") + ":Link/Project:100",
 		"sales_person": _("Sales person"),
-		"allocated_amount": _("Allocated Amount") + ":Currency/currency",
-		"customer": _("Customer") + ":Link/Customer",
-		"customer_group": _("Customer Group") + ":Link/Customer Group",
-		"territory": _("Territory") + ":Link/Territory"
+		"allocated_amount": _("Allocated Amount") + ":Currency/currency:100",
+		"customer": _("Customer") + ":Link/Customer:100",
+		"customer_group": _("Customer Group") + ":Link/Customer Group:100",
+		"territory": _("Territory") + ":Link/Territory:100"
 	})
 
 	for col in group_wise_columns.get(scrub(filters.group_by)):
@@ -85,7 +85,8 @@
 		"fieldname": "currency",
 		"label" : _("Currency"),
 		"fieldtype": "Link",
-		"options": "Currency"
+		"options": "Currency",
+		"hidden": 1
 	})
 
 	return columns
@@ -277,7 +278,7 @@
 			from `tabPurchase Invoice Item` a
 			where a.item_code = %s and a.docstatus=1
 			and modified <= %s
-			order by a.modified desc limit 1""", (item_code,self.filters.to_date))
+			order by a.modified desc limit 1""", (item_code, self.filters.to_date))
 		else:
 			last_purchase_rate = frappe.db.sql("""
 			select (a.base_rate / a.conversion_factor)
diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
index 2e805f8..c7cfee7 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
@@ -44,9 +44,14 @@
 	out = []
 	for supplier in filters.supplier:
 		tds = frappe.get_doc("Tax Withholding Category", supplier.tax_withholding_category)
-		rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year][0]
+		rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year]
+
+		if rate:
+			rate = rate[0]
+
 		try:
 			account = [d.account for d in tds.accounts if d.company == filters.company][0]
+
 		except IndexError:
 			account = []
 		total_invoiced_amount, tds_deducted = get_invoice_and_tds_amount(supplier.name, account,
@@ -76,7 +81,7 @@
 	supplier_credit_amount = flt(sum([d.credit for d in entries]))
 
 	vouchers = [d.voucher_no for d in entries]
-	vouchers += get_advance_vouchers(supplier, company=company,
+	vouchers += get_advance_vouchers([supplier], company=company,
 		from_date=from_date, to_date=to_date)
 
 	tds_deducted = 0
@@ -89,7 +94,7 @@
 		""".format(', '.join(["'%s'" % d for d in vouchers])),
 			(account, from_date, to_date, company))[0][0])
 
-	debit_note_amount = get_debit_note_amount(supplier, from_date, to_date, company=company)
+	debit_note_amount = get_debit_note_amount([supplier], from_date, to_date, company=company)
 
 	total_invoiced_amount = supplier_credit_amount + tds_deducted - debit_note_amount
 
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 3111a3a..4a8146a 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -27,15 +27,6 @@
 		frm.set_indicator_formatter('item_code',
 			function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
 
-		frm.set_query("blanket_order", "items", function() {
-			return {
-				filters: {
-					"company": frm.doc.company,
-					"docstatus": 1
-				}
-			}
-		});
-
 		frm.set_query("expense_account", "items", function() {
 			return {
 				query: "erpnext.controllers.queries.get_expense_account",
@@ -365,9 +356,7 @@
 					method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
 					source_doctype: "Material Request",
 					target: me.frm,
-					setters: {
-						company: me.frm.doc.company
-					},
+					setters: {},
 					get_query_filters: {
 						material_request_type: "Purchase",
 						docstatus: 1,
@@ -384,7 +373,7 @@
 					source_doctype: "Supplier Quotation",
 					target: me.frm,
 					setters: {
-						company: me.frm.doc.company
+						supplier: me.frm.doc.supplier
 					},
 					get_query_filters: {
 						docstatus: 1,
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 578858c..a4f60fb 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -54,11 +54,6 @@
   "items_section",
   "scan_barcode",
   "items",
-  "section_break_48",
-  "pricing_rules",
-  "raw_material_details",
-  "set_reserve_warehouse",
-  "supplied_items",
   "sb_last_purchase",
   "total_qty",
   "base_total",
@@ -67,6 +62,11 @@
   "total_net_weight",
   "total",
   "net_total",
+  "section_break_48",
+  "pricing_rules",
+  "raw_material_details",
+  "set_reserve_warehouse",
+  "supplied_items",
   "taxes_section",
   "tax_category",
   "column_break_50",
@@ -105,23 +105,25 @@
   "payment_schedule_section",
   "payment_terms_template",
   "payment_schedule",
+  "tracking_section",
+  "per_billed",
+  "column_break_75",
+  "per_received",
   "terms_section_break",
   "tc_name",
   "terms",
   "more_info",
   "status",
   "ref_sq",
+  "column_break_74",
   "party_account_currency",
   "inter_company_order_reference",
-  "column_break_74",
-  "per_received",
-  "per_billed",
   "column_break5",
   "letter_head",
   "select_print_heading",
   "column_break_86",
-  "group_same_items",
   "language",
+  "group_same_items",
   "subscription_section",
   "from_date",
   "to_date",
@@ -220,7 +222,7 @@
    "allow_on_submit": 1,
    "fieldname": "schedule_date",
    "fieldtype": "Date",
-   "label": "Reqd By Date"
+   "label": "Required By"
   },
   {
    "allow_on_submit": 1,
@@ -432,6 +434,7 @@
    "fieldtype": "Section Break"
   },
   {
+   "description": "Sets 'Warehouse' in each row of the Items table.",
    "fieldname": "set_warehouse",
    "fieldtype": "Link",
    "label": "Set Target Warehouse",
@@ -827,6 +830,7 @@
    "read_only": 1
   },
   {
+   "collapsible": 1,
    "fieldname": "payment_schedule_section",
    "fieldtype": "Section Break",
    "label": "Payment Terms"
@@ -917,7 +921,8 @@
    "fieldname": "inter_company_order_reference",
    "fieldtype": "Link",
    "label": "Inter Company Order Reference",
-   "options": "Sales Order"
+   "options": "Sales Order",
+   "read_only": 1
   },
   {
    "fieldname": "column_break_74",
@@ -930,8 +935,6 @@
    "in_list_view": 1,
    "label": "% Received",
    "no_copy": 1,
-   "oldfieldname": "per_received",
-   "oldfieldtype": "Currency",
    "print_hide": 1,
    "read_only": 1
   },
@@ -942,8 +945,6 @@
    "in_list_view": 1,
    "label": "% Billed",
    "no_copy": 1,
-   "oldfieldname": "per_billed",
-   "oldfieldtype": "Currency",
    "print_hide": 1,
    "read_only": 1
   },
@@ -998,6 +999,7 @@
    "print_hide": 1
   },
   {
+   "collapsible": 1,
    "fieldname": "subscription_section",
    "fieldtype": "Section Break",
    "label": "Subscription Section"
@@ -1050,13 +1052,23 @@
    "fieldtype": "Link",
    "label": "Set Reserve Warehouse",
    "options": "Warehouse"
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "tracking_section",
+   "fieldtype": "Section Break",
+   "label": "Tracking"
+  },
+  {
+   "fieldname": "column_break_75",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 105,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-17 13:04:28.185197",
+ "modified": "2020-04-24 12:13:14.186280",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index e37e1dd..7a52c28 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -18,10 +18,6 @@
   "col_break1",
   "image",
   "image_view",
-  "manufacture_details",
-  "manufacturer",
-  "column_break_14",
-  "manufacturer_part_no",
   "quantity_and_rate",
   "qty",
   "stock_uom",
@@ -44,7 +40,6 @@
   "base_amount",
   "pricing_rules",
   "is_free_item",
-  "is_fixed_asset",
   "section_break_29",
   "net_rate",
   "net_amount",
@@ -52,11 +47,6 @@
   "base_net_rate",
   "base_net_amount",
   "billed_amt",
-  "item_weight_details",
-  "weight_per_unit",
-  "total_weight",
-  "column_break_40",
-  "weight_uom",
   "warehouse_and_reference",
   "warehouse",
   "delivered_by_supplier",
@@ -80,20 +70,31 @@
   "column_break_60",
   "received_qty",
   "returned_qty",
+  "manufacture_details",
+  "manufacturer",
+  "column_break_14",
+  "manufacturer_part_no",
+  "more_info_section_break",
+  "is_fixed_asset",
+  "item_tax_rate",
   "accounting_details",
   "expense_account",
   "column_break_68",
+  "item_weight_details",
+  "weight_per_unit",
+  "total_weight",
+  "column_break_40",
+  "weight_uom",
   "accounting_dimensions_section",
   "cost_center",
   "dimension_col_break",
   "section_break_72",
-  "page_break",
-  "item_tax_rate"
+  "page_break"
  ],
  "fields": [
   {
    "bold": 1,
-   "columns": 3,
+   "columns": 2,
    "fieldname": "item_code",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -133,7 +134,7 @@
    "fieldname": "schedule_date",
    "fieldtype": "Date",
    "in_list_view": 1,
-   "label": "Reqd By Date",
+   "label": "Required By",
    "oldfieldname": "schedule_date",
    "oldfieldtype": "Date",
    "print_hide": 1,
@@ -216,15 +217,16 @@
    "print_hide": 1
   },
   {
+   "columns": 1,
    "fieldname": "uom",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "UOM",
    "oldfieldname": "uom",
    "oldfieldtype": "Link",
    "options": "UOM",
    "print_width": "100px",
-   "reqd": 1,
-   "width": "100px"
+   "reqd": 1
   },
   {
    "fieldname": "conversion_factor",
@@ -685,6 +687,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "collapsible": 1,
    "fieldname": "manufacture_details",
    "fieldtype": "Section Break",
    "label": "Manufacture"
@@ -717,12 +720,17 @@
    "fieldtype": "Check",
    "label": "Is Fixed Asset",
    "read_only": 1
+  },
+  {
+   "fieldname": "more_info_section_break",
+   "fieldtype": "Section Break",
+   "label": "More Information"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-04-07 18:35:17.558928",
+ "modified": "2020-04-21 11:55:58.643393",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order Item",
diff --git a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json
index 8435bbb..c3e1bf5 100644
--- a/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json
+++ b/erpnext/buying/doctype/purchase_order_item_supplied/purchase_order_item_supplied.json
@@ -1,20 +1,26 @@
 {
+ "actions": [],
  "creation": "2013-02-22 01:27:42",
  "doctype": "DocType",
  "editable_grid": 1,
+ "engine": "InnoDB",
  "field_order": [
   "main_item_code",
-  "rm_item_code",
-  "required_qty",
-  "supplied_qty",
-  "rate",
-  "amount",
-  "column_break_6",
   "bom_detail_no",
-  "reference_name",
-  "conversion_factor",
   "stock_uom",
-  "reserve_warehouse"
+  "conversion_factor",
+  "column_break_6",
+  "rm_item_code",
+  "reference_name",
+  "reserve_warehouse",
+  "section_break2",
+  "rate",
+  "col_break2",
+  "amount",
+  "section_break1",
+  "required_qty",
+  "col_break1",
+  "supplied_qty"
  ],
  "fields": [
   {
@@ -120,15 +126,34 @@
    "in_list_view": 1,
    "label": "Supplied Qty",
    "read_only": 1
+  },
+  {
+   "fieldname": "section_break1",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "col_break1",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "section_break2",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "col_break2",
+   "fieldtype": "Column Break"
   }
  ],
  "hide_toolbar": 1,
  "idx": 1,
  "istable": 1,
- "modified": "2019-08-20 13:37:32.702068",
+ "links": [],
+ "modified": "2020-03-12 15:43:53.862897",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order Item Supplied",
  "owner": "dhanalekshmi@webnotestech.com",
- "permissions": []
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
 }
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier/supplier_dashboard.py b/erpnext/buying/doctype/supplier/supplier_dashboard.py
index d0d5b73..1625103 100644
--- a/erpnext/buying/doctype/supplier/supplier_dashboard.py
+++ b/erpnext/buying/doctype/supplier/supplier_dashboard.py
@@ -23,15 +23,11 @@
 			},
 			{
 				'label': _('Payments'),
-				'items': ['Payment Entry']
-			},
-			{
-				'label': _('Bank'),
-				'items': ['Bank Account']
+				'items': ['Payment Entry', 'Bank Account']
 			},
 			{
 				'label': _('Pricing'),
 				'items': ['Pricing Rule']
 			}
 		]
-	}
\ No newline at end of file
+	}
diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
index 866bf0c..3966879 100644
--- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py
+++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py
@@ -141,19 +141,18 @@
 	conditions = ""
 
 	if filters.get("company"):
-		conditions += " AND company=%s"% frappe.db.escape(filters.get('company'))
+		conditions += " AND par.company=%s" % frappe.db.escape(filters.get('company'))
 
 	if filters.get("cost_center") or filters.get("project"):
 		conditions += """
-			AND (cost_center=%s
-			OR project=%s)
-			"""% (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
+			AND (child.`cost_center`=%s OR child.`project`=%s)
+			""" % (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
 
 	if filters.get("from_date"):
-		conditions += " AND transaction_date>=%s"% filters.get('from_date')
+		conditions += " AND par.transaction_date>='%s'" % filters.get('from_date')
 
 	if filters.get("to_date"):
-		conditions += " AND transaction_date<=%s"% filters.get('to_date')
+		conditions += " AND par.transaction_date<='%s'" % filters.get('to_date')
 	return conditions
 
 def get_data(filters):
@@ -162,7 +161,6 @@
 	mr_records, procurement_record_against_mr = get_mapped_mr_details(conditions)
 	pr_records = get_mapped_pr_records()
 	pi_records = get_mapped_pi_records()
-	print(pi_records)
 
 	procurement_record=[]
 	if procurement_record_against_mr:
@@ -198,16 +196,16 @@
 	mr_records = {}
 	mr_details = frappe.db.sql("""
 		SELECT
-			mr.transaction_date,
-			mr.per_ordered,
-			mr_item.name,
-			mr_item.parent,
-			mr_item.amount
-		FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
+			par.transaction_date,
+			par.per_ordered,
+			child.name,
+			child.parent,
+			child.amount
+		FROM `tabMaterial Request` par, `tabMaterial Request Item` child
 		WHERE
-			mr.per_ordered>=0
-			AND mr.name=mr_item.parent
-			AND mr.docstatus=1
+			par.per_ordered>=0
+			AND par.name=child.parent
+			AND par.docstatus=1
 			{conditions}
 		""".format(conditions=conditions), as_dict=1) #nosec
 
@@ -254,29 +252,29 @@
 def get_po_entries(conditions):
 	return frappe.db.sql("""
 		SELECT
-			po_item.name,
-			po_item.parent,
-			po_item.cost_center,
-			po_item.project,
-			po_item.warehouse,
-			po_item.material_request,
-			po_item.material_request_item,
-			po_item.description,
-			po_item.stock_uom,
-			po_item.qty,
-			po_item.amount,
-			po_item.base_amount,
-			po_item.schedule_date,
-			po.transaction_date,
-			po.supplier,
-			po.status,
-			po.owner
-		FROM `tabPurchase Order` po, `tabPurchase Order Item` po_item
+			child.name,
+			child.parent,
+			child.cost_center,
+			child.project,
+			child.warehouse,
+			child.material_request,
+			child.material_request_item,
+			child.description,
+			child.stock_uom,
+			child.qty,
+			child.amount,
+			child.base_amount,
+			child.schedule_date,
+			par.transaction_date,
+			par.supplier,
+			par.status,
+			par.owner
+		FROM `tabPurchase Order` par, `tabPurchase Order Item` child
 		WHERE
-			po.docstatus = 1
-			AND po.name = po_item.parent
-			AND po.status not in  ("Closed","Completed","Cancelled")
+			par.docstatus = 1
+			AND par.name = child.parent
+			AND par.status not in  ("Closed","Completed","Cancelled")
 			{conditions}
 		GROUP BY
-			po.name,po_item.item_code
+			par.name, child.item_code
 		""".format(conditions=conditions), as_dict=1) #nosec
\ No newline at end of file
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index c14bb66..5febfd6 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -371,6 +371,19 @@
 		fields = ["name", "parent_account"],
 		limit_start=start, limit_page_length=page_len, as_list=True)
 
+def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
+	return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
+		from `tabBlanket Order` bo, `tabBlanket Order Item` boi
+		where
+			boi.parent = bo.name
+			and boi.item_code = {item_code}
+			and bo.blanket_order_type = '{blanket_order_type}'
+			and bo.company = {company}
+			and bo.docstatus = 1"""
+		.format(item_code = frappe.db.escape(filters.get("item")),
+			blanket_order_type = filters.get("blanket_order_type"),
+			company = frappe.db.escape(filters.get("company"))
+		))
 
 @frappe.whitelist()
 def get_income_account(doctype, txt, searchfield, start, page_len, filters):
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 55a2c43..9d453af 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe, erpnext
-from frappe.utils import cint, flt, cstr
+from frappe.utils import cint, flt, cstr, get_link_to_form, today, getdate
 from frappe import _
 import frappe.defaults
 from erpnext.accounts.utils import get_fiscal_year
@@ -55,6 +55,13 @@
 						frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
 							.format(d.idx, serial_no_data.name, d.batch_no))
 
+			if d.qty > 0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
+				expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
+
+				if expiry_date and getdate(expiry_date) < getdate(self.posting_date):
+					frappe.throw(_("Row #{0}: The batch {1} has already expired.")
+						.format(d.idx, get_link_to_form("Batch", d.get("batch_no"))))
+
 	def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
 			default_cost_center=None):
 
diff --git a/erpnext/crm/desk_page/crm/crm.json b/erpnext/crm/desk_page/crm/crm.json
index 4a599fe..ca13d6a 100644
--- a/erpnext/crm/desk_page/crm/crm.json
+++ b/erpnext/crm/desk_page/crm/crm.json
@@ -12,13 +12,18 @@
   },
   {
    "hidden": 0,
-   "label": "Settings",
-   "links": "[\n    {\n        \"description\": \"Manage Customer Group Tree.\",\n        \"icon\": \"fa fa-sitemap\",\n        \"label\": \"Customer Group\",\n        \"link\": \"Tree/Customer Group\",\n        \"name\": \"Customer Group\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Manage Territory Tree.\",\n        \"icon\": \"fa fa-sitemap\",\n        \"label\": \"Territory\",\n        \"link\": \"Tree/Territory\",\n        \"name\": \"Territory\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Manage Sales Person Tree.\",\n        \"icon\": \"fa fa-sitemap\",\n        \"label\": \"Sales Person\",\n        \"link\": \"Tree/Sales Person\",\n        \"name\": \"Sales Person\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Sales campaigns.\",\n        \"label\": \"Campaign\",\n        \"name\": \"Campaign\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n        \"label\": \"Email Campaign\",\n        \"name\": \"Email Campaign\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Send mass SMS to your contacts\",\n        \"label\": \"SMS Center\",\n        \"name\": \"SMS Center\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Logs for maintaining sms delivery status\",\n        \"label\": \"SMS Log\",\n        \"name\": \"SMS Log\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Setup SMS gateway settings\",\n        \"label\": \"SMS Settings\",\n        \"name\": \"SMS Settings\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Email Group\",\n        \"name\": \"Email Group\",\n        \"type\": \"doctype\"\n    }\n]"
+   "label": "Maintenance",
+   "links": "[\n    {\n        \"description\": \"Plan for maintenance visits.\",\n        \"label\": \"Maintenance Schedule\",\n        \"name\": \"Maintenance Schedule\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Visit report for maintenance call.\",\n        \"label\": \"Maintenance Visit\",\n        \"name\": \"Maintenance Visit\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Warranty Claim against Serial No.\",\n        \"label\": \"Warranty Claim\",\n        \"name\": \"Warranty Claim\",\n        \"type\": \"doctype\"\n    }\n]"
   },
   {
    "hidden": 0,
-   "label": "Maintenance",
-   "links": "[\n    {\n        \"description\": \"Plan for maintenance visits.\",\n        \"label\": \"Maintenance Schedule\",\n        \"name\": \"Maintenance Schedule\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Visit report for maintenance call.\",\n        \"label\": \"Maintenance Visit\",\n        \"name\": \"Maintenance Visit\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Warranty Claim against Serial No.\",\n        \"label\": \"Warranty Claim\",\n        \"name\": \"Warranty Claim\",\n        \"type\": \"doctype\"\n    }\n]"
+   "label": "Campaign",
+   "links": "[\n    {\n        \"description\": \"Sales campaigns.\",\n        \"label\": \"Campaign\",\n        \"name\": \"Campaign\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n        \"label\": \"Email Campaign\",\n        \"name\": \"Email Campaign\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Create and Schedule social media posts\",\n        \"label\": \"Social Media Post\",\n        \"name\": \"Social Media Post\",\n        \"type\": \"doctype\"\n    }\n]"
+  },
+  {
+   "hidden": 0,
+   "label": "Settings",
+   "links": "[\n    {\n        \"description\": \"Manage Customer Group Tree.\",\n        \"icon\": \"fa fa-sitemap\",\n        \"label\": \"Customer Group\",\n        \"link\": \"Tree/Customer Group\",\n        \"name\": \"Customer Group\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Manage Territory Tree.\",\n        \"icon\": \"fa fa-sitemap\",\n        \"label\": \"Territory\",\n        \"link\": \"Tree/Territory\",\n        \"name\": \"Territory\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Manage Sales Person Tree.\",\n        \"icon\": \"fa fa-sitemap\",\n        \"label\": \"Sales Person\",\n        \"link\": \"Tree/Sales Person\",\n        \"name\": \"Sales Person\",\n        \"onboard\": 1,\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Send mass SMS to your contacts\",\n        \"label\": \"SMS Center\",\n        \"name\": \"SMS Center\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Logs for maintaining sms delivery status\",\n        \"label\": \"SMS Log\",\n        \"name\": \"SMS Log\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Setup SMS gateway settings\",\n        \"label\": \"SMS Settings\",\n        \"name\": \"SMS Settings\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Email Group\",\n        \"name\": \"Email Group\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Twitter Settings\",\n        \"name\": \"Twitter Settings\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"LinkedIn Settings\",\n        \"name\": \"LinkedIn Settings\",\n        \"type\": \"doctype\"\n    }\n]"
   }
  ],
  "category": "Modules",
@@ -33,7 +38,7 @@
  "idx": 0,
  "is_standard": 1,
  "label": "CRM",
- "modified": "2020-04-01 11:28:51.219999",
+ "modified": "2020-04-27 22:32:26.682911",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "CRM",
@@ -42,7 +47,7 @@
  "pin_to_top": 0,
  "shortcuts": [
   {
-   "format": "Open",
+   "format": "{} Open",
    "label": "Lead",
    "link_to": "Lead",
    "stats_filter": "{\"status\":\"Open\"}",
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.js b/erpnext/crm/doctype/twitter_settings/twitter_settings.js
index 8f9c419..b55946a 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.js
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.js
@@ -16,23 +16,27 @@
 		}
 	},
 	refresh: function(frm){
-		let msg,color;
+		let msg, color, flag=false;
 		if (frm.doc.session_status == "Active"){
 			msg = __("Session Active");
 			color = 'green';
+			flag = true;
 		}
-		else {
+		else if(frm.doc.consumer_key && frm.doc.consumer_secret) {
 			msg = __("Session Not Active. Save doc to login.");
 			color = 'red';
+			flag = true;
 		}
 
-		frm.dashboard.set_headline_alert(
-			`<div class="row">
-				<div class="col-xs-12">
-					<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">${msg}</span></span>
-				</div>
-			</div>`
-		);
+		if (flag){
+			frm.dashboard.set_headline_alert(
+				`<div class="row">
+					<div class="col-xs-12">
+						<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">${msg}</span></span>
+					</div>
+				</div>`
+			);
+		}
 	},
 	login: function(frm){
 		if (frm.doc.consumer_key && frm.doc.consumer_secret){
diff --git a/erpnext/education/doctype/fees/fees.js b/erpnext/education/doctype/fees/fees.js
index e2c6f1d..17ef449 100644
--- a/erpnext/education/doctype/fees/fees.js
+++ b/erpnext/education/doctype/fees/fees.js
@@ -112,6 +112,8 @@
 				args: {
 					"dt": frm.doc.doctype,
 					"dn": frm.doc.name,
+					"party_type": "Student",
+					"party": frm.doc.student,
 					"recipient_id": frm.doc.student_email
 				},
 				callback: function(r) {
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index aa616e6..f31003b 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -75,7 +75,8 @@
 		self.make_gl_entries()
 
 		if self.send_payment_request and self.student_email:
-			pr = make_payment_request(dt="Fees", dn=self.name, recipient_id=self.student_email,
+			pr = make_payment_request(party_type="Student", party=self.student, dt="Fees",
+					dn=self.name, recipient_id=self.student_email,
 					submit_doc=True, use_dummy_message=True)
 			frappe.msgprint(_("Payment request {0} created").format(getlink("Payment Request", pr.name)))
 
diff --git a/erpnext/education/doctype/student/student_dashboard.py b/erpnext/education/doctype/student/student_dashboard.py
index 0cbd17b..d261462 100644
--- a/erpnext/education/doctype/student/student_dashboard.py
+++ b/erpnext/education/doctype/student/student_dashboard.py
@@ -6,6 +6,9 @@
 		'heatmap': True,
 		'heatmap_message': _('This is based on the attendance of this Student'),
 		'fieldname': 'student',
+		'non_standard_fieldnames': {
+			'Bank Account': 'party'
+		},
 		'transactions': [
 			{
 				'label': _('Admission'),
@@ -29,7 +32,7 @@
 			},
 			{
 				'label': _('Fee'),
-				'items': ['Fees']
+				'items': ['Fees', 'Bank Account']
 			}
 		]
-	}
\ No newline at end of file
+	}
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index 9a32c73..a756532 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -43,7 +43,7 @@
 
 def get_fee_validity(patient_appointments):
 	if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
-		return
+		return []
 
 	items_to_invoice = []
 	for appointment in patient_appointments:
@@ -110,7 +110,7 @@
 		filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1}
 	)
 	for lab_test in lab_tests:
-		item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.lab_test_code, ['item', 'is_billable'])
+		item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.template, ['item', 'is_billable'])
 		if is_billable:
 			lab_tests_to_invoice.append({
 				'reference_type': 'Lab Test',
diff --git a/erpnext/hr/doctype/attendance/attendance.json b/erpnext/hr/doctype/attendance/attendance.json
index eaca9f6..906f6f7 100644
--- a/erpnext/hr/doctype/attendance/attendance.json
+++ b/erpnext/hr/doctype/attendance/attendance.json
@@ -87,11 +87,12 @@
    "search_index": 1
   },
   {
-   "depends_on": "eval:doc.status==\"On Leave\"",
+   "depends_on": "eval:in_list([\"On Leave\", \"Half Day\"], doc.status)",
    "fieldname": "leave_type",
    "fieldtype": "Link",
    "in_standard_filter": 1,
    "label": "Leave Type",
+   "mandatory_depends_on": "eval:in_list([\"On Leave\", \"Half Day\"], doc.status)",
    "oldfieldname": "leave_type",
    "oldfieldtype": "Link",
    "options": "Leave Type"
@@ -100,6 +101,7 @@
    "fieldname": "leave_application",
    "fieldtype": "Link",
    "label": "Leave Application",
+   "no_copy": 1,
    "options": "Leave Application",
    "read_only": 1
   },
@@ -175,7 +177,8 @@
  "icon": "fa fa-ok",
  "idx": 1,
  "is_submittable": 1,
- "modified": "2020-02-19 14:25:32.945842",
+ "links": [],
+ "modified": "2020-04-11 11:40:14.319496",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Attendance",
diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py
index 9e965db..b6c8065 100644
--- a/erpnext/hr/doctype/attendance/attendance.py
+++ b/erpnext/hr/doctype/attendance/attendance.py
@@ -7,33 +7,15 @@
 from frappe.utils import getdate, nowdate
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import cstr, get_datetime, get_datetime_str
-from frappe.utils import update_progress_bar
+from frappe.utils import cstr, get_datetime, formatdate
 
 class Attendance(Document):
-	def validate_duplicate_record(self):
-		res = frappe.db.sql("""select name from `tabAttendance` where employee = %s and attendance_date = %s
-			and name != %s and docstatus != 2""",
-			(self.employee, getdate(self.attendance_date), self.name))
-		if res:
-			frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee))
-
-	def check_leave_record(self):
-		leave_record = frappe.db.sql("""select leave_type, half_day, half_day_date from `tabLeave Application`
-			where employee = %s and %s between from_date and to_date and status = 'Approved'
-			and docstatus = 1""", (self.employee, self.attendance_date), as_dict=True)
-		if leave_record:
-			for d in leave_record:
-				if d.half_day_date == getdate(self.attendance_date):
-					self.status = 'Half Day'
-					frappe.msgprint(_("Employee {0} on Half day on {1}").format(self.employee, self.attendance_date))
-				else:
-					self.status = 'On Leave'
-					self.leave_type = d.leave_type
-					frappe.msgprint(_("Employee {0} is on Leave on {1}").format(self.employee, self.attendance_date))
-
-		if self.status == "On Leave" and not leave_record:
-			frappe.throw(_("No leave record found for employee {0} for {1}").format(self.employee, self.attendance_date))
+	def validate(self):
+		from erpnext.controllers.status_updater import validate_status
+		validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
+		self.validate_attendance_date()
+		self.validate_duplicate_record()
+		self.check_leave_record()
 
 	def validate_attendance_date(self):
 		date_of_joining = frappe.db.get_value("Employee", self.employee, "date_of_joining")
@@ -44,19 +26,52 @@
 		elif date_of_joining and getdate(self.attendance_date) < getdate(date_of_joining):
 			frappe.throw(_("Attendance date can not be less than employee's joining date"))
 
+	def validate_duplicate_record(self):
+		res = frappe.db.sql("""
+			select name from `tabAttendance`
+			where employee = %s
+				and attendance_date = %s
+				and name != %s
+				and docstatus != 2
+		""", (self.employee, getdate(self.attendance_date), self.name))
+		if res:
+			frappe.throw(_("Attendance for employee {0} is already marked").format(self.employee))
+
+	def check_leave_record(self):
+		leave_record = frappe.db.sql("""
+			select leave_type, half_day, half_day_date
+			from `tabLeave Application`
+			where employee = %s 
+				and %s between from_date and to_date
+				and status = 'Approved'
+				and docstatus = 1
+		""", (self.employee, self.attendance_date), as_dict=True)
+		if leave_record:
+			for d in leave_record:
+				self.leave_type = d.leave_type
+				if d.half_day_date == getdate(self.attendance_date):
+					self.status = 'Half Day'
+					frappe.msgprint(_("Employee {0} on Half day on {1}")
+						.format(self.employee, formatdate(self.attendance_date)))
+				else:
+					self.status = 'On Leave'
+					frappe.msgprint(_("Employee {0} is on Leave on {1}")
+						.format(self.employee, formatdate(self.attendance_date)))
+
+		if self.status in ("On Leave", "Half Day"):
+			if not leave_record:
+				frappe.msgprint(_("No leave record found for employee {0} on {1}")
+					.format(self.employee, formatdate(self.attendance_date)), alert=1)
+		elif self.leave_type:
+			self.leave_type = None
+			self.leave_application = None
+
 	def validate_employee(self):
 		emp = frappe.db.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
 		 	self.employee)
 		if not emp:
 			frappe.throw(_("Employee {0} is not active or does not exist").format(self.employee))
 
-	def validate(self):
-		from erpnext.controllers.status_updater import validate_status
-		validate_status(self.status, ["Present", "Absent", "On Leave", "Half Day", "Work From Home"])
-		self.validate_attendance_date()
-		self.validate_duplicate_record()
-		self.check_leave_record()
-
 @frappe.whitelist()
 def get_events(start, end, filters=None):
 	events = []
@@ -90,18 +105,20 @@
 		if e not in events:
 			events.append(e)
 
-def mark_attendance(employee, attendance_date, status, shift=None):
-	employee_doc = frappe.get_doc('Employee', employee)
+def mark_attendance(employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False):
 	if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
-		doc_dict = {
+		company = frappe.db.get_value('Employee', employee, 'company')
+		attendance = frappe.get_doc({
 			'doctype': 'Attendance',
 			'employee': employee,
 			'attendance_date': attendance_date,
 			'status': status,
-			'company': employee_doc.company,
-			'shift': shift
-		}
-		attendance = frappe.get_doc(doc_dict).insert()
+			'company': company,
+			'shift': shift,
+			'leave_type': leave_type
+		})
+		attendance.flags.ignore_validate = ignore_validate
+		attendance.insert()
 		attendance.submit()
 		return attendance.name
 
diff --git a/erpnext/hr/doctype/employee/employee_dashboard.py b/erpnext/hr/doctype/employee/employee_dashboard.py
index 11ad83b..0203332 100644
--- a/erpnext/hr/doctype/employee/employee_dashboard.py
+++ b/erpnext/hr/doctype/employee/employee_dashboard.py
@@ -6,6 +6,9 @@
 		'heatmap': True,
 		'heatmap_message': _('This is based on the attendance of this Employee'),
 		'fieldname': 'employee',
+		'non_standard_fieldnames': {
+			'Bank Account': 'party'
+		},
 		'transactions': [
 			{
 				'label': _('Leave and Attendance'),
@@ -33,7 +36,7 @@
 			},
 			{
 				'label': _('Payroll'),
-				'items': ['Salary Structure Assignment', 'Salary Slip', 'Additional Salary', 'Timesheet','Employee Incentive', 'Retention Bonus']
+				'items': ['Salary Structure Assignment', 'Salary Slip', 'Additional Salary', 'Timesheet','Employee Incentive', 'Retention Bonus', 'Bank Account']
 			},
 			{
 				'label': _('Training'),
diff --git a/erpnext/hr/doctype/employee_other_income/__init__.py b/erpnext/hr/doctype/employee_other_income/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/employee_other_income/__init__.py
diff --git a/erpnext/hr/doctype/employee_other_income/employee_other_income.js b/erpnext/hr/doctype/employee_other_income/employee_other_income.js
new file mode 100644
index 0000000..c1a74e8
--- /dev/null
+++ b/erpnext/hr/doctype/employee_other_income/employee_other_income.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Other Income', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/hr/doctype/employee_other_income/employee_other_income.json b/erpnext/hr/doctype/employee_other_income/employee_other_income.json
new file mode 100644
index 0000000..2dd6c10
--- /dev/null
+++ b/erpnext/hr/doctype/employee_other_income/employee_other_income.json
@@ -0,0 +1,138 @@
+{
+ "actions": [],
+ "autoname": "HR-INCOME-.######",
+ "creation": "2020-03-18 15:04:40.767434",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "employee_name",
+  "payroll_period",
+  "column_break_3",
+  "company",
+  "source",
+  "amount",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee",
+   "reqd": 1
+  },
+  {
+   "fieldname": "payroll_period",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Payroll Period",
+   "options": "Payroll Period",
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
+  {
+   "fieldname": "source",
+   "fieldtype": "Data",
+   "label": "Source"
+  },
+  {
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Amount",
+   "options": "Company:company:default_currency",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Employee Other Income",
+   "print_hide": 1,
+   "read_only": 1
+  }
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-03-19 18:06:45.361830",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Other Income",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Employee",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_other_income/employee_other_income.py b/erpnext/hr/doctype/employee_other_income/employee_other_income.py
new file mode 100644
index 0000000..ab63c0d
--- /dev/null
+++ b/erpnext/hr/doctype/employee_other_income/employee_other_income.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, 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 EmployeeOtherIncome(Document):
+	pass
diff --git a/erpnext/hr/doctype/employee_other_income/test_employee_other_income.py b/erpnext/hr/doctype/employee_other_income/test_employee_other_income.py
new file mode 100644
index 0000000..2eeca7a
--- /dev/null
+++ b/erpnext/hr/doctype/employee_other_income/test_employee_other_income.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestEmployeeOtherIncome(unittest.TestCase):
+	pass
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
index e102ff8..18fad85 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
@@ -1,620 +1,180 @@
 {
- "allow_copy": 0, 
- "allow_events_in_timeline": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "HR-TAX-DEC-.YYYY.-.#####", 
- "beta": 0, 
- "creation": "2018-04-13 16:53:36.175504", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-TAX-DEC-.YYYY.-.#####",
+ "creation": "2018-04-13 16:53:36.175504",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "employee_name",
+  "department",
+  "column_break_2",
+  "payroll_period",
+  "company",
+  "amended_from",
+  "section_break_8",
+  "declarations",
+  "section_break_10",
+  "total_declared_amount",
+  "column_break_12",
+  "total_exemption_amount"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "employee", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Employee", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Employee", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.employee_name", 
-   "fetch_if_empty": 0, 
-   "fieldname": "employee_name", 
-   "fieldtype": "Data", 
-   "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": "Employee Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.department", 
-   "fetch_if_empty": 0, 
-   "fieldname": "department", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Department", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Department", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "column_break_2", 
-   "fieldtype": "Column Break", 
-   "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, 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "payroll_period", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Payroll Period", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Payroll Period", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "payroll_period",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Payroll Period",
+   "options": "Payroll Period",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.company", 
-   "fetch_if_empty": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.company",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "amended_from", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Amended From", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Employee Tax Exemption Declaration", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Employee Tax Exemption Declaration",
+   "print_hide": 1,
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "section_break_8", 
-   "fieldtype": "Section Break", 
-   "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, 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "section_break_8",
+   "fieldtype": "Section Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "declarations", 
-   "fieldtype": "Table", 
-   "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": "Declarations", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Employee Tax Exemption Declaration Category", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "declarations",
+   "fieldtype": "Table",
+   "label": "Declarations",
+   "options": "Employee Tax Exemption Declaration Category"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "section_break_10", 
-   "fieldtype": "Section Break", 
-   "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, 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "section_break_10",
+   "fieldtype": "Section Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "total_declared_amount", 
-   "fieldtype": "Currency", 
-   "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": "Total Declared Amount", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "total_declared_amount",
+   "fieldtype": "Currency",
+   "label": "Total Declared Amount",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "column_break_12", 
-   "fieldtype": "Column Break", 
-   "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, 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_12",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "total_exemption_amount", 
-   "fieldtype": "Currency", 
-   "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": "Total Exemption Amount", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "other_incomes_section", 
-   "fieldtype": "Section Break", 
-   "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": "Other Incomes", 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "income_from_other_sources", 
-   "fieldtype": "Currency", 
-   "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": "Income From Other Sources", 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "total_exemption_amount",
+   "fieldtype": "Currency",
+   "label": "Total Exemption Amount",
+   "read_only": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 1, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2019-05-11 16:13:50.472670", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Employee Tax Exemption Declaration", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-03-18 14:56:25.625717",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Tax Exemption Declaration",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Employee", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Employee",
+   "share": 1,
+   "submit": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "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, 
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
index f2bba7a..fb71a28 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
@@ -8,31 +8,17 @@
 from frappe import _
 from frappe.utils import flt
 from frappe.model.mapper import get_mapped_doc
-from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_annual_eligible_hra_exemption
-
-class DuplicateDeclarationError(frappe.ValidationError): pass
+from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
+	calculate_annual_eligible_hra_exemption, validate_duplicate_exemption_for_payroll_period
 
 class EmployeeTaxExemptionDeclaration(Document):
 	def validate(self):
 		validate_tax_declaration(self.declarations)
-		self.validate_duplicate()
+		validate_duplicate_exemption_for_payroll_period(self.doctype, self.name, self.payroll_period, self.employee)
 		self.set_total_declared_amount()
 		self.set_total_exemption_amount()
 		self.calculate_hra_exemption()
 
-	def validate_duplicate(self):
-		duplicate = frappe.db.get_value("Employee Tax Exemption Declaration",
-			filters = {
-				"employee": self.employee,
-				"payroll_period": self.payroll_period,
-				"name": ["!=", self.name],
-				"docstatus": ["!=", 2]
-			}
-		)
-		if duplicate:
-			frappe.throw(_("Duplicate Tax Declaration of {0} for period {1}")
-				.format(self.employee, self.payroll_period), DuplicateDeclarationError)
-
 	def set_total_declared_amount(self):
 		self.total_declared_amount = 0.0
 		for d in self.declarations:
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
index 9c87bbd..9549fd1 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
@@ -6,7 +6,7 @@
 import frappe, erpnext
 import unittest
 from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration import DuplicateDeclarationError
+from erpnext.hr.utils import DuplicateDeclarationError
 
 class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
 	def setUp(self):
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
index c170c16..8b117a2 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
@@ -21,8 +21,6 @@
   "total_actual_amount",
   "column_break_12",
   "exemption_amount",
-  "other_incomes_section",
-  "income_from_other_sources",
   "attachment_section",
   "attachments",
   "amended_from"
@@ -112,16 +110,6 @@
    "read_only": 1
   },
   {
-   "fieldname": "other_incomes_section",
-   "fieldtype": "Section Break",
-   "label": "Other Incomes"
-  },
-  {
-   "fieldname": "income_from_other_sources",
-   "fieldtype": "Currency",
-   "label": "Income From Other Sources"
-  },
-  {
    "fieldname": "attachment_section",
    "fieldtype": "Section Break"
   },
@@ -142,7 +130,7 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-03-02 19:02:15.398486",
+ "modified": "2020-03-18 14:55:51.420016",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Employee Tax Exemption Proof Submission",
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
index 97ceb63..5bc33a6 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
@@ -7,7 +7,8 @@
 from frappe.model.document import Document
 from frappe import _
 from frappe.utils import flt
-from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_hra_exemption_for_period
+from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, \
+	calculate_hra_exemption_for_period, validate_duplicate_exemption_for_payroll_period
 
 class EmployeeTaxExemptionProofSubmission(Document):
 	def validate(self):
@@ -15,6 +16,7 @@
 		self.set_total_actual_amount()
 		self.set_total_exemption_amount()
 		self.calculate_hra_exemption()
+		validate_duplicate_exemption_for_payroll_period(self.doctype, self.name, self.payroll_period, self.employee)
 
 	def set_total_actual_amount(self):
 		self.total_actual_amount = flt(self.get("house_rent_payment_amount"))
@@ -32,4 +34,4 @@
 				self.exemption_amount += hra_exemption["total_eligible_hra_exemption"]
 				self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
 				self.monthly_house_rent = hra_exemption["monthly_house_rent"]
-				self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]
\ No newline at end of file
+				self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 88f3865..fb23103 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -17,7 +17,7 @@
 			return;
 		}
 		return frappe.call({
-			method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account",
+			method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
 			args: {
 				"expense_claim_type": d.expense_type,
 				"company": doc.company
@@ -25,6 +25,7 @@
 			callback: function(r) {
 				if (r.message) {
 					d.default_account = r.message.account;
+					d.cost_center = r.message.cost_center;
 				}
 			}
 		});
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index fe8afdf..ad9d86b 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -2,9 +2,9 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
-import frappe
+import frappe, erpnext
 from frappe import _
-from frappe.utils import get_fullname, flt, cstr
+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.accounts.party import get_party_account
@@ -192,7 +192,8 @@
 	def validate_account_details(self):
 		for data in self.expenses:
 			if not data.cost_center:
-				frappe.throw(_("Cost center is required to book an expense claim"))
+				frappe.throw(_("Row {0}: {1} is required in the expenses table to book an expense claim.")
+					.format(data.idx, frappe.bold("Cost Center")))
 
 		if self.is_paid:
 			if not self.mode_of_payment:
@@ -309,12 +310,22 @@
 	return je.as_dict()
 
 @frappe.whitelist()
+def get_expense_claim_account_and_cost_center(expense_claim_type, company):
+	data = get_expense_claim_account(expense_claim_type, company)
+	cost_center = erpnext.get_default_cost_center(company)
+
+	return {
+		"account": data.get("account"),
+		"cost_center": cost_center
+	}
+
+@frappe.whitelist()
 def get_expense_claim_account(expense_claim_type, company):
 	account = frappe.db.get_value("Expense Claim Account",
 		{"parent": expense_claim_type, "company": company}, "default_account")
 	if not account:
-		frappe.throw(_("Please set default account in Expense Claim Type {0}")
-			.format(expense_claim_type))
+		frappe.throw(_("Set the default account for the {0} {1}")
+			.format(frappe.bold("Expense Claim Type"), get_link_to_form("Expense Claim Type", expense_claim_type)))
 
 	return {
 		"account": account
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index 90f4988..9161ed8 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -13,10 +13,12 @@
   "stop_birthday_reminders",
   "expense_approver_mandatory_in_expense_claim",
   "payroll_settings",
+  "payroll_based_on", 
+  "max_working_hours_against_timesheet", 
   "include_holidays_in_total_working_days",
   "disable_rounded_total",
-  "max_working_hours_against_timesheet",
   "column_break_11",
+  "daily_wages_fraction_for_half_day", 
   "email_salary_slip_to_employee",
   "encrypt_salary_slips_in_emails",
   "password_policy",
@@ -184,13 +186,27 @@
    "fieldtype": "Link",
    "label": "Role Allowed to Create Backdated Leave Application",
    "options": "Role"
+  },
+  {
+   "default": "Leave",
+   "fieldname": "payroll_based_on",
+   "fieldtype": "Select",
+   "label": "Calculate Working Days in Payroll based on",
+   "options": "Leave\nAttendance"
+  },
+  {
+   "default": "0.5",
+   "description": "The fraction of daily wages to be paid for half-day attendance",
+   "fieldname": "daily_wages_fraction_for_half_day",
+   "fieldtype": "Float",
+   "label": "Daily Wages Fraction for Half Day"
   }
  ],
  "icon": "fa fa-cog",
  "idx": 1,
  "issingle": 1,
  "links": [],
- "modified": "2020-01-06 18:46:30.189815",
+ "modified": "2020-04-13 21:20:59.382394",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR Settings",
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.py b/erpnext/hr/doctype/hr_settings/hr_settings.py
index bf91906..5ed4c87 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.py
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.py
@@ -15,6 +15,9 @@
 		self.set_naming_series()
 		self.validate_password_policy()
 
+		if not self.daily_wages_fraction_for_half_day:
+			self.daily_wages_fraction_for_half_day = 0.5
+
 	def set_naming_series(self):
 		from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
 		set_by_naming_series("Employee", "employee_number",
diff --git a/erpnext/hr/doctype/income_tax_slab/__init__.py b/erpnext/hr/doctype/income_tax_slab/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab/__init__.py
diff --git a/erpnext/hr/doctype/income_tax_slab/income_tax_slab.js b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.js
new file mode 100644
index 0000000..73a54eb
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.js
@@ -0,0 +1,6 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Income Tax Slab', {
+
+});
diff --git a/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
new file mode 100644
index 0000000..6d89b19
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.json
@@ -0,0 +1,160 @@
+{
+ "actions": [],
+ "autoname": "Prompt",
+ "creation": "2020-03-17 16:50:35.564915",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "effective_from",
+  "company",
+  "column_break_3",
+  "allow_tax_exemption",
+  "standard_tax_exemption_amount",
+  "disabled",
+  "amended_from",
+  "taxable_salary_slabs_section",
+  "slabs",
+  "taxes_and_charges_on_income_tax_section",
+  "other_taxes_and_charges"
+ ],
+ "fields": [
+  {
+   "fieldname": "effective_from",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Effective from",
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "description": "If enabled, Tax Exemption Declaration will be considered for income tax calculation.",
+   "fieldname": "allow_tax_exemption",
+   "fieldtype": "Check",
+   "label": "Allow Tax Exemption"
+  },
+  {
+   "fieldname": "taxable_salary_slabs_section",
+   "fieldtype": "Section Break",
+   "label": "Taxable Salary Slabs"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Income Tax Slab",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "slabs",
+   "fieldtype": "Table",
+   "label": "Taxable Salary Slabs",
+   "options": "Taxable Salary Slab",
+   "reqd": 1
+  },
+  {
+   "allow_on_submit": 1,
+   "default": "0",
+   "fieldname": "disabled",
+   "fieldtype": "Check",
+   "label": "Disabled"
+  },
+  {
+   "depends_on": "allow_tax_exemption",
+   "fieldname": "standard_tax_exemption_amount",
+   "fieldtype": "Currency",
+   "label": "Standard Tax Exemption Amount",
+   "options": "Company:company:default_currency"
+  },
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company"
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "taxes_and_charges_on_income_tax_section",
+   "fieldtype": "Section Break",
+   "label": "Taxes and Charges on Income Tax"
+  },
+  {
+   "fieldname": "other_taxes_and_charges",
+   "fieldtype": "Table",
+   "label": "Other Taxes and Charges",
+   "options": "Income Tax Slab Other Charges"
+  }
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-04-24 12:28:36.805904",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Income Tax Slab",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Administrator",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/income_tax_slab/income_tax_slab.py b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.py
new file mode 100644
index 0000000..253f023
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab/income_tax_slab.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, 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 IncomeTaxSlab(Document):
+	pass
diff --git a/erpnext/hr/doctype/income_tax_slab/test_income_tax_slab.py b/erpnext/hr/doctype/income_tax_slab/test_income_tax_slab.py
new file mode 100644
index 0000000..deaaf65
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab/test_income_tax_slab.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestIncomeTaxSlab(unittest.TestCase):
+	pass
diff --git a/erpnext/hr/doctype/income_tax_slab_other_charges/__init__.py b/erpnext/hr/doctype/income_tax_slab_other_charges/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab_other_charges/__init__.py
diff --git a/erpnext/hr/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json b/erpnext/hr/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json
new file mode 100644
index 0000000..b23fb3d
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.json
@@ -0,0 +1,75 @@
+{
+ "actions": [],
+ "creation": "2020-04-24 11:46:59.041180",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "description",
+  "column_break_2",
+  "percent",
+  "conditions_section",
+  "min_taxable_income",
+  "column_break_7",
+  "max_taxable_income"
+ ],
+ "fields": [
+  {
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break"
+  },
+  {
+   "columns": 2,
+   "fieldname": "min_taxable_income",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Min Taxable Income",
+   "options": "Company:company:default_currency"
+  },
+  {
+   "columns": 4,
+   "fieldname": "description",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Description",
+   "reqd": 1
+  },
+  {
+   "columns": 2,
+   "fieldname": "percent",
+   "fieldtype": "Percent",
+   "in_list_view": 1,
+   "label": "Percent",
+   "reqd": 1
+  },
+  {
+   "fieldname": "conditions_section",
+   "fieldtype": "Section Break",
+   "label": "Conditions"
+  },
+  {
+   "fieldname": "column_break_7",
+   "fieldtype": "Column Break"
+  },
+  {
+   "columns": 2,
+   "fieldname": "max_taxable_income",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Max Taxable Income",
+   "options": "Company:company:default_currency"
+  }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-04-24 13:27:43.598967",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Income Tax Slab Other Charges",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py b/erpnext/hr/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py
new file mode 100644
index 0000000..b4098ec
--- /dev/null
+++ b/erpnext/hr/doctype/income_tax_slab_other_charges/income_tax_slab_other_charges.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, 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 IncomeTaxSlabOtherCharges(Document):
+	pass
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index d13bb45..03fe3fa 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -30,16 +30,16 @@
 	def validate_leave_allocation_days(self):
 		company = frappe.db.get_value("Employee", self.employee, "company")
 		leave_period = get_leave_period(self.from_date, self.to_date, company)
-		max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+		max_leaves_allowed = flt(frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed"))
 		if max_leaves_allowed > 0:
 			leave_allocated = 0
 			if leave_period:
 				leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type,
 					leave_period[0].from_date, leave_period[0].to_date)
-			leave_allocated += self.new_leaves_allocated
+			leave_allocated += flt(self.new_leaves_allocated)
 			if leave_allocated > max_leaves_allowed:
 				frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")
-				.format(self.leave_type, self.employee))
+					.format(self.leave_type, self.employee))
 
 	def on_submit(self):
 		self.create_leave_ledger_entry()
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index c441751..47b1bb7 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -374,7 +374,8 @@
 				leaves=self.total_leave_days * -1,
 				from_date=self.from_date,
 				to_date=self.to_date,
-				is_lwp=lwp
+				is_lwp=lwp,
+				holiday_list=get_holiday_list_for_employee(self.employee)
 			)
 			create_leave_ledger_entry(self, args, submit)
 
@@ -384,7 +385,9 @@
 			from_date=self.from_date,
 			to_date=expiry_date,
 			leaves=(date_diff(expiry_date, self.from_date) + 1) * -1,
-			is_lwp=lwp
+			is_lwp=lwp,
+			holiday_list=get_holiday_list_for_employee(self.employee),
+
 		)
 		create_leave_ledger_entry(self, args, submit)
 
@@ -410,7 +413,7 @@
 	return expiry[0]['to_date'] if expiry else None
 
 @frappe.whitelist()
-def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None):
+def get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day = None, half_day_date = None, holiday_list = None):
 	number_of_days = 0
 	if cint(half_day) == 1:
 		if from_date == to_date:
@@ -424,7 +427,7 @@
 		number_of_days = date_diff(to_date, from_date) + 1
 
 	if not frappe.db.get_value("Leave Type", leave_type, "include_holiday"):
-		number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date))
+		number_of_days = flt(number_of_days) - flt(get_holidays(employee, from_date, to_date, holiday_list=holiday_list))
 	return number_of_days
 
 @frappe.whitelist()
@@ -575,7 +578,7 @@
 					{'name': leave_entry.transaction_name}, ['half_day_date'])
 
 			leave_days += get_number_of_leave_days(employee, leave_type,
-				leave_entry.from_date, leave_entry.to_date, half_day, half_day_date) * -1
+				leave_entry.from_date, leave_entry.to_date, half_day, half_day_date, holiday_list=leave_entry.holiday_list) * -1
 
 	return leave_days
 
@@ -589,7 +592,7 @@
 	''' Returns leave entries between from_date and to_date. '''
 	return frappe.db.sql("""
 		SELECT
-			employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type,
+			employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, holiday_list,
 			is_carry_forward, is_expired
 		FROM `tabLeave Ledger Entry`
 		WHERE employee=%(employee)s AND leave_type=%(leave_type)s
@@ -607,9 +610,10 @@
 	}, as_dict=1)
 
 @frappe.whitelist()
-def get_holidays(employee, from_date, to_date):
+def get_holidays(employee, from_date, to_date, holiday_list = None):
 	'''get holidays between two dates for the given employee'''
-	holiday_list = get_holiday_list_for_employee(employee)
+	if not holiday_list:
+		holiday_list = get_holiday_list_for_employee(employee)
 
 	holidays = frappe.db.sql("""select count(distinct holiday_date) from `tabHoliday` h1, `tabHoliday List` h2
 		where h1.parent = h2.name and h1.holiday_date between %s and %s
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
index 771e706..a5ac3f3 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "creation": "2019-05-09 15:47:39.760406",
  "doctype": "DocType",
  "engine": "InnoDB",
@@ -12,6 +13,7 @@
   "column_break_7",
   "from_date",
   "to_date",
+  "holiday_list",
   "is_carry_forward",
   "is_expired",
   "is_lwp",
@@ -98,11 +100,18 @@
    "fieldname": "is_lwp",
    "fieldtype": "Check",
    "label": "Is Leave Without Pay"
+  },
+  {
+   "fieldname": "holiday_list",
+   "fieldtype": "Link",
+   "label": "Holiday List",
+   "options": "Holiday List"
   }
  ],
  "in_create": 1,
  "is_submittable": 1,
- "modified": "2019-08-20 14:40:04.130799",
+ "links": [],
+ "modified": "2020-02-27 14:40:10.502605",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Ledger Entry",
diff --git a/erpnext/hr/doctype/payroll_period/payroll_period.json b/erpnext/hr/doctype/payroll_period/payroll_period.json
index c9bac09..c0fa506 100644
--- a/erpnext/hr/doctype/payroll_period/payroll_period.json
+++ b/erpnext/hr/doctype/payroll_period/payroll_period.json
@@ -1,401 +1,102 @@
 {
- "allow_copy": 0, 
- "allow_events_in_timeline": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 0, 
- "autoname": "Prompt", 
- "beta": 0, 
- "creation": "2018-04-13 15:18:53.698553", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "Prompt",
+ "creation": "2018-04-13 15:18:53.698553",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "column_break_2",
+  "start_date",
+  "end_date",
+  "section_break_5",
+  "periods"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "column_break_2", 
-   "fieldtype": "Column Break", 
-   "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, 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "start_date", 
-   "fieldtype": "Date", 
-   "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": "Start Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "start_date",
+   "fieldtype": "Date",
+   "label": "Start Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "end_date", 
-   "fieldtype": "Date", 
-   "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": "End Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "end_date",
+   "fieldtype": "Date",
+   "label": "End Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "section_break_5", 
-   "fieldtype": "Section Break", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Payroll Periods", 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "section_break_5",
+   "fieldtype": "Section Break",
+   "hidden": 1,
+   "label": "Payroll Periods"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "periods", 
-   "fieldtype": "Table", 
-   "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": "Payroll Periods", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Payroll Period Date", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "section_break_7", 
-   "fieldtype": "Section Break", 
-   "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": "Taxable Salary Slabs", 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "taxable_salary_slabs", 
-   "fieldtype": "Table", 
-   "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": "Taxable Salary Slabs", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Taxable Salary Slab", 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
-  {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_if_empty": 0, 
-   "fieldname": "standard_tax_exemption_amount", 
-   "fieldtype": "Currency", 
-   "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": "Standard Tax Exemption Amount", 
-   "length": 0, 
-   "no_copy": 0, 
-   "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, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "periods",
+   "fieldtype": "Table",
+   "label": "Payroll Periods",
+   "options": "Payroll Period Date"
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2019-04-26 01:45:03.160929", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Payroll Period", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "links": [],
+ "modified": "2020-03-18 18:13:23.859980",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Payroll Period",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "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, 
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/payroll_period/payroll_period.py b/erpnext/hr/doctype/payroll_period/payroll_period.py
index c176959..6956c38 100644
--- a/erpnext/hr/doctype/payroll_period/payroll_period.py
+++ b/erpnext/hr/doctype/payroll_period/payroll_period.py
@@ -45,8 +45,9 @@
 				+ _(") for {0}").format(self.company)
 			frappe.throw(msg)
 
-def get_payroll_period_days(start_date, end_date, employee):
-	company = frappe.db.get_value("Employee", employee, "company")
+def get_payroll_period_days(start_date, end_date, employee, company=None):
+	if not company:
+		company = frappe.db.get_value("Employee", employee, "company")
 	payroll_period = frappe.db.sql("""
 		select name, start_date, end_date
 		from `tabPayroll Period`
diff --git a/erpnext/hr/doctype/salary_component/salary_component.json b/erpnext/hr/doctype/salary_component/salary_component.json
index 986030d..5487e1d 100644
--- a/erpnext/hr/doctype/salary_component/salary_component.json
+++ b/erpnext/hr/doctype/salary_component/salary_component.json
@@ -1,264 +1,263 @@
 {
-    "allow_import": 1,
-    "allow_rename": 1,
-    "autoname": "field:salary_component",
-    "creation": "2016-06-30 15:42:43.631931",
-    "doctype": "DocType",
-    "document_type": "Setup",
-    "editable_grid": 1,
-    "engine": "InnoDB",
-    "field_order": [
-     "salary_component",
-     "salary_component_abbr",
-     "type",
-     "description",
-     "column_break_4",
-     "is_payable",
-     "depends_on_payment_days",
-     "is_tax_applicable",
-     "deduct_full_tax_on_selected_payroll_date",
-     "round_to_the_nearest_integer",
-     "statistical_component",
-     "do_not_include_in_total",
-     "disabled",
-     "flexible_benefits",
-     "is_flexible_benefit",
-     "max_benefit_amount",
-     "column_break_9",
-     "pay_against_benefit_claim",
-     "only_tax_impact",
-     "create_separate_payment_entry_against_benefit_claim",
-     "section_break_11",
-     "variable_based_on_taxable_salary",
-     "section_break_5",
-     "accounts",
-     "condition_and_formula",
-     "condition",
-     "amount",
-     "amount_based_on_formula",
-     "formula",
-     "column_break_28",
-     "help"
-    ],
-    "fields": [
-     {
-      "fieldname": "salary_component",
-      "fieldtype": "Data",
-      "in_list_view": 1,
-      "label": "Name",
-      "reqd": 1,
-      "unique": 1
-     },
-     {
-      "fieldname": "salary_component_abbr",
-      "fieldtype": "Data",
-      "in_list_view": 1,
-      "label": "Abbr",
-      "print_width": "120px",
-      "reqd": 1,
-      "width": "120px"
-     },
-     {
-      "fieldname": "type",
-      "fieldtype": "Select",
-      "in_standard_filter": 1,
-      "label": "Type",
-      "options": "Earning\nDeduction",
-      "reqd": 1
-     },
-     {
-      "default": "1",
-      "depends_on": "eval:doc.type == \"Earning\"",
-      "fieldname": "is_tax_applicable",
-      "fieldtype": "Check",
-      "label": "Is Tax Applicable"
-     },
-     {
-      "default": "1",
-      "fieldname": "is_payable",
-      "fieldtype": "Check",
-      "label": "Is Payable"
-     },
-     {
-      "default": "1",
-      "fieldname": "depends_on_payment_days",
-      "fieldtype": "Check",
-      "label": "Depends on Payment Days",
-      "print_hide": 1
-     },
-     {
-      "default": "0",
-      "fieldname": "do_not_include_in_total",
-      "fieldtype": "Check",
-      "label": "Do Not Include in Total"
-     },
-     {
-      "default": "0",
-      "depends_on": "is_tax_applicable",
-      "fieldname": "deduct_full_tax_on_selected_payroll_date",
-      "fieldtype": "Check",
-      "label": "Deduct Full Tax on Selected Payroll Date"
-     },
-     {
-      "fieldname": "column_break_4",
-      "fieldtype": "Column Break"
-     },
-     {
-      "default": "0",
-      "fieldname": "disabled",
-      "fieldtype": "Check",
-      "label": "Disabled"
-     },
-     {
-      "fieldname": "description",
-      "fieldtype": "Small Text",
-      "in_list_view": 1,
-      "label": "Description"
-     },
-     {
-      "default": "0",
-      "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
-      "fieldname": "statistical_component",
-      "fieldtype": "Check",
-      "label": "Statistical Component"
-     },
-     {
-      "depends_on": "eval:doc.type==\"Earning\" && doc.statistical_component!=1",
-      "fieldname": "flexible_benefits",
-      "fieldtype": "Section Break",
-      "label": "Flexible Benefits"
-     },
-     {
-      "default": "0",
-      "fieldname": "is_flexible_benefit",
-      "fieldtype": "Check",
-      "label": "Is Flexible Benefit"
-     },
-     {
-      "depends_on": "is_flexible_benefit",
-      "fieldname": "max_benefit_amount",
-      "fieldtype": "Currency",
-      "label": "Max Benefit Amount (Yearly)"
-     },
-     {
-      "fieldname": "column_break_9",
-      "fieldtype": "Column Break"
-     },
-     {
-      "default": "0",
-      "depends_on": "is_flexible_benefit",
-      "fieldname": "pay_against_benefit_claim",
-      "fieldtype": "Check",
-      "label": "Pay Against Benefit Claim"
-     },
-     {
-      "default": "0",
-      "depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
-      "fieldname": "only_tax_impact",
-      "fieldtype": "Check",
-      "label": "Only Tax Impact (Cannot Claim But Part of Taxable Income)"
-     },
-     {
-      "default": "0",
-      "depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
-      "fieldname": "create_separate_payment_entry_against_benefit_claim",
-      "fieldtype": "Check",
-      "label": "Create Separate Payment Entry Against Benefit Claim"
-     },
-     {
-      "depends_on": "eval:doc.type=='Deduction'",
-      "fieldname": "section_break_11",
-      "fieldtype": "Section Break"
-     },
-     {
-      "default": "0",
-      "fieldname": "variable_based_on_taxable_salary",
-      "fieldtype": "Check",
-      "label": "Variable Based On Taxable Salary"
-     },
-     {
-      "depends_on": "eval:doc.statistical_component != 1",
-      "fieldname": "section_break_5",
-      "fieldtype": "Section Break",
-      "label": "Accounts"
-     },
-     {
-      "fieldname": "accounts",
-      "fieldtype": "Table",
-      "label": "Accounts",
-      "options": "Salary Component Account"
-     },
-     {
-      "collapsible": 1,
-      "depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
-      "fieldname": "condition_and_formula",
-      "fieldtype": "Section Break",
-      "label": "Condition and Formula"
-     },
-     {
-      "fieldname": "condition",
-      "fieldtype": "Code",
-      "label": "Condition"
-     },
-     {
-      "default": "0",
-      "fieldname": "amount_based_on_formula",
-      "fieldtype": "Check",
-      "label": "Amount based on formula"
-     },
-     {
-      "depends_on": "amount_based_on_formula",
-      "fieldname": "formula",
-      "fieldtype": "Code",
-      "label": "Formula"
-     },
-     {
-      "depends_on": "eval:doc.amount_based_on_formula!==1",
-      "fieldname": "amount",
-      "fieldtype": "Currency",
-      "label": "Amount"
-     },
-     {
-      "fieldname": "column_break_28",
-      "fieldtype": "Column Break"
-     },
-     {
-      "fieldname": "help",
-      "fieldtype": "HTML",
-      "label": "Help",
-      "options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base &lt; 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS &gt; 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
-     },
-     {
-      "default": "0",
-      "fieldname": "round_to_the_nearest_integer",
-      "fieldtype": "Check",
-      "label": "Round to the Nearest Integer"
-     }
-    ],
-    "icon": "fa fa-flag",
-    "modified": "2019-06-05 11:34:14.231228",
-    "modified_by": "Administrator",
-    "module": "HR",
-    "name": "Salary Component",
-    "owner": "Administrator",
-    "permissions": [
-     {
-      "create": 1,
-      "delete": 1,
-      "email": 1,
-      "export": 1,
-      "print": 1,
-      "read": 1,
-      "report": 1,
-      "role": "HR User",
-      "share": 1,
-      "write": 1
-     },
-     {
-      "read": 1,
-      "role": "Employee"
-     }
-    ],
-    "sort_field": "modified",
-    "sort_order": "DESC"
-   }
\ No newline at end of file
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:salary_component",
+ "creation": "2016-06-30 15:42:43.631931",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "salary_component",
+  "salary_component_abbr",
+  "type",
+  "description",
+  "column_break_4",
+  "depends_on_payment_days",
+  "is_tax_applicable",
+  "deduct_full_tax_on_selected_payroll_date",
+  "variable_based_on_taxable_salary",
+  "exempted_from_income_tax",
+  "round_to_the_nearest_integer",
+  "statistical_component",
+  "do_not_include_in_total",
+  "disabled",
+  "flexible_benefits",
+  "is_flexible_benefit",
+  "max_benefit_amount",
+  "column_break_9",
+  "pay_against_benefit_claim",
+  "only_tax_impact",
+  "create_separate_payment_entry_against_benefit_claim",
+  "section_break_5",
+  "accounts",
+  "condition_and_formula",
+  "condition",
+  "amount",
+  "amount_based_on_formula",
+  "formula",
+  "column_break_28",
+  "help"
+ ],
+ "fields": [
+  {
+   "fieldname": "salary_component",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Name",
+   "reqd": 1,
+   "unique": 1
+  },
+  {
+   "fieldname": "salary_component_abbr",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Abbr",
+   "print_width": "120px",
+   "reqd": 1,
+   "width": "120px"
+  },
+  {
+   "fieldname": "type",
+   "fieldtype": "Select",
+   "in_standard_filter": 1,
+   "label": "Type",
+   "options": "Earning\nDeduction",
+   "reqd": 1
+  },
+  {
+   "default": "1",
+   "depends_on": "eval:doc.type == \"Earning\"",
+   "fieldname": "is_tax_applicable",
+   "fieldtype": "Check",
+   "label": "Is Tax Applicable"
+  },
+  {
+   "default": "1",
+   "fieldname": "depends_on_payment_days",
+   "fieldtype": "Check",
+   "label": "Depends on Payment Days",
+   "print_hide": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "do_not_include_in_total",
+   "fieldtype": "Check",
+   "label": "Do Not Include in Total"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.is_tax_applicable && doc.type=='Earning'",
+   "fieldname": "deduct_full_tax_on_selected_payroll_date",
+   "fieldtype": "Check",
+   "label": "Deduct Full Tax on Selected Payroll Date"
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "fieldname": "disabled",
+   "fieldtype": "Check",
+   "label": "Disabled"
+  },
+  {
+   "fieldname": "description",
+   "fieldtype": "Small Text",
+   "in_list_view": 1,
+   "label": "Description"
+  },
+  {
+   "default": "0",
+   "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
+   "fieldname": "statistical_component",
+   "fieldtype": "Check",
+   "label": "Statistical Component"
+  },
+  {
+   "depends_on": "eval:doc.type==\"Earning\" && doc.statistical_component!=1",
+   "fieldname": "flexible_benefits",
+   "fieldtype": "Section Break",
+   "label": "Flexible Benefits"
+  },
+  {
+   "default": "0",
+   "fieldname": "is_flexible_benefit",
+   "fieldtype": "Check",
+   "label": "Is Flexible Benefit"
+  },
+  {
+   "depends_on": "is_flexible_benefit",
+   "fieldname": "max_benefit_amount",
+   "fieldtype": "Currency",
+   "label": "Max Benefit Amount (Yearly)"
+  },
+  {
+   "fieldname": "column_break_9",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "depends_on": "is_flexible_benefit",
+   "fieldname": "pay_against_benefit_claim",
+   "fieldtype": "Check",
+   "label": "Pay Against Benefit Claim"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.is_flexible_benefit == 1 & doc.create_separate_payment_entry_against_benefit_claim !=1",
+   "fieldname": "only_tax_impact",
+   "fieldtype": "Check",
+   "label": "Only Tax Impact (Cannot Claim But Part of Taxable Income)"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.is_flexible_benefit == 1 & doc.only_tax_impact !=1",
+   "fieldname": "create_separate_payment_entry_against_benefit_claim",
+   "fieldtype": "Check",
+   "label": "Create Separate Payment Entry Against Benefit Claim"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.type == \"Deduction\"",
+   "fieldname": "variable_based_on_taxable_salary",
+   "fieldtype": "Check",
+   "label": "Variable Based On Taxable Salary"
+  },
+  {
+   "depends_on": "eval:doc.statistical_component != 1",
+   "fieldname": "section_break_5",
+   "fieldtype": "Section Break",
+   "label": "Accounts"
+  },
+  {
+   "fieldname": "accounts",
+   "fieldtype": "Table",
+   "label": "Accounts",
+   "options": "Salary Component Account"
+  },
+  {
+   "collapsible": 1,
+   "depends_on": "eval:doc.is_flexible_benefit != 1 && doc.variable_based_on_taxable_salary != 1",
+   "fieldname": "condition_and_formula",
+   "fieldtype": "Section Break",
+   "label": "Condition and Formula"
+  },
+  {
+   "fieldname": "condition",
+   "fieldtype": "Code",
+   "label": "Condition"
+  },
+  {
+   "default": "0",
+   "fieldname": "amount_based_on_formula",
+   "fieldtype": "Check",
+   "label": "Amount based on formula"
+  },
+  {
+   "depends_on": "amount_based_on_formula",
+   "fieldname": "formula",
+   "fieldtype": "Code",
+   "label": "Formula"
+  },
+  {
+   "depends_on": "eval:doc.amount_based_on_formula!==1",
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "label": "Amount"
+  },
+  {
+   "fieldname": "column_break_28",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "help",
+   "fieldtype": "HTML",
+   "label": "Help",
+   "options": "<h3>Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base &lt; 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS &gt; 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
+  },
+  {
+   "default": "0",
+   "fieldname": "round_to_the_nearest_integer",
+   "fieldtype": "Check",
+   "label": "Round to the Nearest Integer"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.type == \"Deduction\" && !doc.variable_based_on_taxable_salary",
+   "description": "If checked, the full amount will be deducted from taxable income before calculating income tax. Otherwise, it can be exempted via Employee Tax Exemption Declaration.",
+   "fieldname": "exempted_from_income_tax",
+   "fieldtype": "Check",
+   "label": "Exempted from Income Tax"
+  }
+ ],
+ "icon": "fa fa-flag",
+ "links": [],
+ "modified": "2020-04-24 14:50:28.994054",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Salary Component",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "read": 1,
+   "role": "Employee"
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_component/test_records.json b/erpnext/hr/doctype/salary_component/test_records.json
index 7b22b48..104b44f 100644
--- a/erpnext/hr/doctype/salary_component/test_records.json
+++ b/erpnext/hr/doctype/salary_component/test_records.json
@@ -3,14 +3,12 @@
 		"doctype": "Salary Component",
 		"salary_component": "_Test Basic Salary",
 		"type": "Earning",
-		"is_payable": 1,
 		"is_tax_applicable": 1
 	},
 	{
 		"doctype": "Salary Component",
 		"salary_component": "_Test Allowance",
 		"type": "Earning",
-		"is_payable": 1,
 		"is_tax_applicable": 1
 	},
 	{
@@ -27,14 +25,12 @@
 		"doctype": "Salary Component",
 		"salary_component": "Basic",
 		"type": "Earning",
-		"is_payable": 1,
 		"is_tax_applicable": 1
 	},
 	{
 		"doctype": "Salary Component",
 		"salary_component": "Leave Encashment",
 		"type": "Earning",
-		"is_payable": 1,
 		"is_tax_applicable": 1
 	}
 ]
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_component/test_salary_component.py b/erpnext/hr/doctype/salary_component/test_salary_component.py
index 965cc9e..4f7db0c 100644
--- a/erpnext/hr/doctype/salary_component/test_salary_component.py
+++ b/erpnext/hr/doctype/salary_component/test_salary_component.py
@@ -18,6 +18,5 @@
 				"doctype": "Salary Component",
 				"salary_component": component_name,
 				"type": args.get("type") or "Earning",
-				"is_payable": args.get("is_payable") or 1,
 				"is_tax_applicable": args.get("is_tax_applicable") or 1
 			}).insert()
diff --git a/erpnext/hr/doctype/salary_detail/salary_detail.json b/erpnext/hr/doctype/salary_detail/salary_detail.json
index bde735d..545f56a 100644
--- a/erpnext/hr/doctype/salary_detail/salary_detail.json
+++ b/erpnext/hr/doctype/salary_detail/salary_detail.json
@@ -12,6 +12,7 @@
   "deduct_full_tax_on_selected_payroll_date",
   "depends_on_payment_days",
   "is_tax_applicable",
+  "exempted_from_income_tax",
   "is_flexible_benefit",
   "variable_based_on_taxable_salary",
   "section_break_2",
@@ -62,6 +63,7 @@
   },
   {
    "default": "0",
+   "depends_on": "eval:doc.parentfield=='earnings'",
    "fetch_from": "salary_component.is_tax_applicable",
    "fieldname": "is_tax_applicable",
    "fieldtype": "Check",
@@ -71,6 +73,7 @@
   },
   {
    "default": "0",
+   "depends_on": "eval:doc.parentfield=='earnings'",
    "fetch_from": "salary_component.is_flexible_benefit",
    "fieldname": "is_flexible_benefit",
    "fieldtype": "Check",
@@ -80,6 +83,7 @@
   },
   {
    "default": "0",
+   "depends_on": "eval:doc.parentfield=='deductions'",
    "fetch_from": "salary_component.variable_based_on_taxable_salary",
    "fieldname": "variable_based_on_taxable_salary",
    "fieldtype": "Check",
@@ -187,11 +191,20 @@
    "fieldtype": "HTML",
    "label": "Condition and Formula Help",
    "options": "<h3>Condition and Formula Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base &lt; 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS &gt; 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:doc.parentfield=='deductions'",
+   "fetch_from": "salary_component.exempted_from_income_tax",
+   "fieldname": "exempted_from_income_tax",
+   "fieldtype": "Check",
+   "label": "Exempted from Income Tax",
+   "read_only": 1
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2019-12-31 17:15:25.646689",
+ "modified": "2020-04-24 20:00:16.475295",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Salary Detail",
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js
index f430eee..1c4d4e3 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.js
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.js
@@ -51,7 +51,7 @@
 	},
 
 	end_date: function(frm) {
-		frm.events.get_emp_and_leave_details(frm);
+		frm.events.get_emp_and_working_day_details(frm);
 	},
 
 	set_end_date: function(frm){
@@ -86,7 +86,7 @@
 
 	salary_slip_based_on_timesheet: function(frm) {
 		frm.trigger("toggle_fields");
-		frm.events.get_emp_and_leave_details(frm);
+		frm.events.get_emp_and_working_day_details(frm);
 	},
 
 	payroll_frequency: function(frm) {
@@ -95,15 +95,14 @@
 	},
 
 	employee: function(frm) {
-		frm.events.get_emp_and_leave_details(frm);
+		frm.events.get_emp_and_working_day_details(frm);
 	},
 
 	leave_without_pay: function(frm){
 		if (frm.doc.employee && frm.doc.start_date && frm.doc.end_date) {
 			return frappe.call({
-				method: 'process_salary_based_on_leave',
+				method: 'process_salary_based_on_working_days',
 				doc: frm.doc,
-				args: {"lwp": frm.doc.leave_without_pay},
 				callback: function(r, rt) {
 					frm.refresh();
 				}
@@ -115,12 +114,12 @@
 		frm.toggle_display(['hourly_wages', 'timesheets'], cint(frm.doc.salary_slip_based_on_timesheet)===1);
 
 		frm.toggle_display(['payment_days', 'total_working_days', 'leave_without_pay'],
-			frm.doc.payroll_frequency!="");
+			frm.doc.payroll_frequency != "");
 	},
 
-	get_emp_and_leave_details: function(frm) {
+	get_emp_and_working_day_details: function(frm) {
 		return frappe.call({
-			method: 'get_emp_and_leave_details',
+			method: 'get_emp_and_working_day_details',
 			doc: frm.doc,
 			callback: function(r, rt) {
 				frm.refresh();
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json
index 097d3a0..54a8164 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.json
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.json
@@ -11,20 +11,20 @@
   "employee_name",
   "department",
   "designation",
+  "branch",
   "column_break1",
-  "company",
+  "status",
   "journal_entry",
   "payroll_entry",
+  "company",
   "letter_head",
-  "branch",
-  "status",
   "section_break_10",
   "salary_slip_based_on_timesheet",
-  "payroll_frequency",
   "start_date",
   "end_date",
   "column_break_15",
   "salary_structure",
+  "payroll_frequency",
   "total_working_days",
   "leave_without_pay",
   "payment_days",
@@ -309,6 +309,7 @@
   {
    "fieldname": "earning",
    "fieldtype": "Column Break",
+   "label": "Earning",
    "oldfieldtype": "Column Break",
    "width": "50%"
   },
@@ -323,6 +324,7 @@
   {
    "fieldname": "deduction",
    "fieldtype": "Column Break",
+   "label": "Deduction",
    "oldfieldtype": "Column Break",
    "width": "50%"
   },
@@ -463,7 +465,7 @@
  "idx": 9,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-09 20:02:53.159827",
+ "modified": "2020-04-14 20:02:53.159827", 
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Salary Slip",
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 223c4e3..8a4da7e 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -5,7 +5,7 @@
 import frappe, erpnext
 import datetime, math
 
-from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words
+from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate
 from frappe.model.naming import make_autoname
 
 from frappe import msgprint, _
@@ -44,9 +44,9 @@
 
 		if not (len(self.get("earnings")) or len(self.get("deductions"))):
 			# get details from salary structure
-			self.get_emp_and_leave_details()
+			self.get_emp_and_working_day_details()
 		else:
-			self.get_leave_details(lwp = self.leave_without_pay)
+			self.get_working_days_details(lwp = self.leave_without_pay)
 
 		self.calculate_net_pay()
 
@@ -117,7 +117,7 @@
 			self.start_date = date_details.start_date
 			self.end_date = date_details.end_date
 
-	def get_emp_and_leave_details(self):
+	def get_emp_and_working_day_details(self):
 		'''First time, load all the components from salary structure'''
 		if self.employee:
 			self.set("earnings", [])
@@ -129,7 +129,8 @@
 			joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
 				["date_of_joining", "relieving_date"])
 
-			self.get_leave_details(joining_date, relieving_date)
+			#getin leave details
+			self.get_working_days_details(joining_date, relieving_date)
 			struct = self.check_sal_struct(joining_date, relieving_date)
 
 			if struct:
@@ -188,10 +189,9 @@
 
 		make_salary_slip(self._salary_structure_doc.name, self)
 
-	def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None, for_preview=0):
-		if not joining_date:
-			joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
-				["date_of_joining", "relieving_date"])
+	def get_working_days_details(self, joining_date=None, relieving_date=None, lwp=None, for_preview=0):
+		payroll_based_on = frappe.db.get_value("HR Settings", None, "payroll_based_on")
+		include_holidays_in_total_working_days = frappe.db.get_single_value("HR Settings", "include_holidays_in_total_working_days")
 
 		working_days = date_diff(self.end_date, self.start_date) + 1
 		if for_preview:
@@ -200,24 +200,42 @@
 			return
 
 		holidays = self.get_holidays_for_employee(self.start_date, self.end_date)
-		actual_lwp = self.calculate_lwp(holidays, working_days)
-		if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
+		
+		if not cint(include_holidays_in_total_working_days):
 			working_days -= len(holidays)
 			if working_days < 0:
 				frappe.throw(_("There are more holidays than working days this month."))
 
+		if not payroll_based_on:
+			frappe.throw(_("Please set Payroll based on in HR settings"))
+		
+		if payroll_based_on == "Attendance":
+			actual_lwp = self.calculate_lwp_based_on_attendance(holidays)
+		else:
+			actual_lwp = self.calculate_lwp_based_on_leave_application(holidays, working_days)
+
 		if not lwp:
 			lwp = actual_lwp
 		elif lwp != actual_lwp:
-			frappe.msgprint(_("Leave Without Pay does not match with approved Leave Application records"))
+			frappe.msgprint(_("Leave Without Pay does not match with approved {} records")
+				.format(payroll_based_on))
 
-		self.total_working_days = working_days
 		self.leave_without_pay = lwp
+		self.total_working_days = working_days
 
-		payment_days = flt(self.get_payment_days(joining_date, relieving_date)) - flt(lwp)
-		self.payment_days = payment_days > 0 and payment_days or 0
+		payment_days = self.get_payment_days(joining_date,
+			relieving_date, include_holidays_in_total_working_days)
 
-	def get_payment_days(self, joining_date, relieving_date):
+		if flt(payment_days) > flt(lwp):
+			self.payment_days = flt(payment_days) - flt(lwp)
+		else:
+			self.payment_days = 0
+
+	def get_payment_days(self, joining_date, relieving_date, include_holidays_in_total_working_days):
+		if not joining_date:
+			joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
+				["date_of_joining", "relieving_date"])
+
 		start_date = getdate(self.start_date)
 		if joining_date:
 			if getdate(self.start_date) <= joining_date <= getdate(self.end_date):
@@ -235,9 +253,10 @@
 
 		payment_days = date_diff(end_date, start_date) + 1
 
-		if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
+		if not cint(include_holidays_in_total_working_days):
 			holidays = self.get_holidays_for_employee(start_date, end_date)
 			payment_days -= len(holidays)
+
 		return payment_days
 
 	def get_holidays_for_employee(self, start_date, end_date):
@@ -256,27 +275,67 @@
 
 		return holidays
 
-	def calculate_lwp(self, holidays, working_days):
+	def calculate_lwp_based_on_leave_application(self, holidays, working_days):
 		lwp = 0
 		holidays = "','".join(holidays)
+		daily_wages_fraction_for_half_day = \
+			flt(frappe.db.get_value("HR Settings", None, "daily_wages_fraction_for_half_day")) or 0.5
+
 		for d in range(working_days):
 			dt = add_days(cstr(getdate(self.start_date)), d)
 			leave = frappe.db.sql("""
 				SELECT t1.name,
-					CASE WHEN t1.half_day_date = %(dt)s or t1.to_date = t1.from_date
+					CASE WHEN (t1.half_day_date = %(dt)s or t1.to_date = t1.from_date)
 					THEN t1.half_day else 0 END
 				FROM `tabLeave Application` t1, `tabLeave Type` t2
 				WHERE t2.name = t1.leave_type
 				AND t2.is_lwp = 1
 				AND t1.docstatus = 1
 				AND t1.employee = %(employee)s
-				AND CASE WHEN t2.include_holiday != 1 THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
-				WHEN t2.include_holiday THEN %(dt)s between from_date and to_date and ifnull(t1.salary_slip, '') = ''
-				END
+				AND ifnull(t1.salary_slip, '') = ''
+				AND CASE
+					WHEN t2.include_holiday != 1
+						THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date
+					WHEN t2.include_holiday
+						THEN %(dt)s between from_date and to_date
+					END
 				""".format(holidays), {"employee": self.employee, "dt": dt})
 
 			if leave:
-				lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1)
+				is_half_day_leave = cint(leave[0][1])
+				lwp += (1 - daily_wages_fraction_for_half_day) if is_half_day_leave else 1
+
+		return lwp
+	
+	def calculate_lwp_based_on_attendance(self, holidays):
+		lwp = 0
+
+		daily_wages_fraction_for_half_day = \
+			flt(frappe.db.get_value("HR Settings", None, "daily_wages_fraction_for_half_day")) or 0.5
+
+		lwp_leave_types = dict(frappe.get_all("Leave Type", {"is_lwp": 1}, ["name", "include_holiday"], as_list=1))
+
+		attendances = frappe.db.sql('''
+			SELECT attendance_date, status, leave_type
+			FROM `tabAttendance`
+			WHERE
+				status in ("Absent", "Half Day", "On leave")
+				AND employee = %s
+				AND docstatus = 1
+				AND attendance_date between %s and %s
+		''', values=(self.employee, self.start_date, self.end_date), as_dict=1)
+		
+		for d in attendances:
+			if d.status in ('Half Day', 'On Leave') and d.leave_type and d.leave_type not in lwp_leave_types:
+				continue
+
+			if formatdate(d.attendance_date, "yyyy-mm-dd") in holidays:
+				if d.status == "Absent" or \
+					(d.leave_type and d.leave_type in lwp_leave_types and not lwp_leave_types[d.leave_type]):
+						continue
+
+			lwp += (1 - daily_wages_fraction_for_half_day) if d.status == "Half Day" else 1
+
 		return lwp
 
 	def add_earning_for_hourly_wages(self, doc, salary_component, amount):
@@ -451,7 +510,8 @@
 					'is_flexible_benefit': struct_row.is_flexible_benefit,
 					'variable_based_on_taxable_salary': struct_row.variable_based_on_taxable_salary,
 					'deduct_full_tax_on_selected_payroll_date': struct_row.deduct_full_tax_on_selected_payroll_date,
-					'additional_amount': amount if struct_row.get("is_additional_component") else 0
+					'additional_amount': amount if struct_row.get("is_additional_component") else 0,
+					'exempted_from_income_tax': struct_row.exempted_from_income_tax
 				})
 		else:
 			if struct_row.get("is_additional_component"):
@@ -482,10 +542,12 @@
 		return self.calculate_variable_tax(payroll_period, tax_component)
 
 	def calculate_variable_tax(self, payroll_period, tax_component):
+		# get Tax slab from salary structure assignment for the employee and payroll period
+		tax_slab = self.get_income_tax_slabs(payroll_period)
+
 		# get remaining numbers of sub-period (period for which one salary is processed)
 		remaining_sub_periods = get_period_factor(self.employee,
 			self.start_date, self.end_date, self.payroll_frequency, payroll_period)[1]
-
 		# get taxable_earnings, paid_taxes for previous period
 		previous_taxable_earnings = self.get_taxable_earnings_for_prev_period(payroll_period.start_date, self.start_date)
 		previous_total_paid_taxes = self.get_tax_paid_in_period(payroll_period.start_date, self.start_date, tax_component)
@@ -507,23 +569,27 @@
 			unclaimed_taxable_benefits += current_taxable_earnings_for_payment_days.flexi_benefits
 
 		# Total exemption amount based on tax exemption declaration
-		total_exemption_amount, other_incomes = self.get_total_exemption_amount_and_other_incomes(payroll_period)
+		total_exemption_amount = self.get_total_exemption_amount(payroll_period, tax_slab)
+
+		#Employee Other Incomes
+		other_incomes = self.get_income_form_other_sources(payroll_period) or 0.0
 
 		# Total taxable earnings including additional and other incomes
 		total_taxable_earnings = previous_taxable_earnings + current_structured_taxable_earnings + future_structured_taxable_earnings \
 			+ current_additional_earnings + other_incomes + unclaimed_taxable_benefits - total_exemption_amount
-
+		
 		# Total taxable earnings without additional earnings with full tax
 		total_taxable_earnings_without_full_tax_addl_components = total_taxable_earnings - current_additional_earnings_with_full_tax
 
 		# Structured tax amount
-		total_structured_tax_amount = self.calculate_tax_by_tax_slab(payroll_period, total_taxable_earnings_without_full_tax_addl_components)
+		total_structured_tax_amount = self.calculate_tax_by_tax_slab(
+			total_taxable_earnings_without_full_tax_addl_components, tax_slab)
 		current_structured_tax_amount = (total_structured_tax_amount - previous_total_paid_taxes) / remaining_sub_periods
-
+		
 		# Total taxable earnings with additional earnings with full tax
 		full_tax_on_additional_earnings = 0.0
 		if current_additional_earnings_with_full_tax:
-			total_tax_amount = self.calculate_tax_by_tax_slab(payroll_period, total_taxable_earnings)
+			total_tax_amount = self.calculate_tax_by_tax_slab(total_taxable_earnings, tax_slab)
 			full_tax_on_additional_earnings = total_tax_amount - total_structured_tax_amount
 
 		current_tax_amount = current_structured_tax_amount + full_tax_on_additional_earnings
@@ -532,12 +598,30 @@
 
 		return current_tax_amount
 
+	def get_income_tax_slabs(self, payroll_period):
+		income_tax_slab, ss_assignment_name = frappe.db.get_value("Salary Structure Assignment",
+			{"employee": self.employee, "salary_structure": self.salary_structure, "docstatus": 1}, ["income_tax_slab", 'name'])
+
+		if not income_tax_slab:
+			frappe.throw(_("Income Tax Slab not set in Salary Structure Assignment: {0}").format(ss_assignment_name))
+
+		income_tax_slab_doc = frappe.get_doc("Income Tax Slab", income_tax_slab)
+		if income_tax_slab_doc.disabled:
+			frappe.throw(_("Income Tax Slab: {0} is disabled").format(income_tax_slab))
+
+		if getdate(income_tax_slab_doc.effective_from) > getdate(payroll_period.start_date):
+			frappe.throw(_("Income Tax Slab must be effective on or before Payroll Period Start Date: {0}")
+				.format(payroll_period.start_date))
+
+		return income_tax_slab_doc
+
+
 	def get_taxable_earnings_for_prev_period(self, start_date, end_date):
 		taxable_earnings = frappe.db.sql("""
 			select sum(sd.amount)
 			from
 				`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
-			where
+			where 
 				sd.parentfield='earnings'
 				and sd.is_tax_applicable=1
 				and is_flexible_benefit=0
@@ -550,7 +634,28 @@
 				"from_date": start_date,
 				"to_date": end_date
 			})
-		return flt(taxable_earnings[0][0]) if taxable_earnings else 0
+		taxable_earnings = flt(taxable_earnings[0][0]) if taxable_earnings else 0
+
+		exempted_amount = frappe.db.sql("""
+			select sum(sd.amount)
+			from
+				`tabSalary Detail` sd join `tabSalary Slip` ss on sd.parent=ss.name
+			where
+				sd.parentfield='deductions'
+				and sd.exempted_from_income_tax=1
+				and is_flexible_benefit=0
+				and ss.docstatus=1
+				and ss.employee=%(employee)s
+				and ss.start_date between %(from_date)s and %(to_date)s
+				and ss.end_date between %(from_date)s and %(to_date)s
+			""", {
+				"employee": self.employee,
+				"from_date": start_date,
+				"to_date": end_date
+			})
+		exempted_amount = flt(exempted_amount[0][0]) if exempted_amount else 0
+
+		return taxable_earnings - exempted_amount
 
 	def get_tax_paid_in_period(self, start_date, end_date, tax_component):
 		# find total_tax_paid, tax paid for benefit, additional_salary
@@ -610,6 +715,13 @@
 				else:
 					taxable_earnings += amount
 
+		for ded in self.deductions:
+			if ded.exempted_from_income_tax:
+				amount = ded.amount
+				if based_on_payment_days:
+					amount = self.get_amount_based_on_payment_days(ded, joining_date, relieving_date)[0]
+				taxable_earnings -= flt(amount)
+
 		return frappe._dict({
 			"taxable_earnings": taxable_earnings,
 			"additional_income": additional_income,
@@ -672,40 +784,63 @@
 
 		return total_benefits_paid - total_benefits_claimed
 
-	def get_total_exemption_amount_and_other_incomes(self, payroll_period):
-		total_exemption_amount, other_incomes = 0, 0
-		if self.deduct_tax_for_unsubmitted_tax_exemption_proof:
-			exemption_proof = frappe.db.get_value("Employee Tax Exemption Proof Submission",
-				{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
-				["exemption_amount", "income_from_other_sources"])
-			if exemption_proof:
-				total_exemption_amount, other_incomes = exemption_proof
-		else:
-			declaration = frappe.db.get_value("Employee Tax Exemption Declaration",
-				{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
-				["total_exemption_amount", "income_from_other_sources"])
-			if declaration:
-				total_exemption_amount, other_incomes = declaration
+	def get_total_exemption_amount(self, payroll_period, tax_slab):
+		total_exemption_amount = 0
+		if tax_slab.allow_tax_exemption:
+			if self.deduct_tax_for_unsubmitted_tax_exemption_proof:
+				exemption_proof = frappe.db.get_value("Employee Tax Exemption Proof Submission",
+					{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
+					["exemption_amount"])
+				if exemption_proof:
+					total_exemption_amount = exemption_proof
+			else:
+				declaration = frappe.db.get_value("Employee Tax Exemption Declaration",
+					{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
+					["total_exemption_amount"])
+				if declaration:
+					total_exemption_amount = declaration
 
-		return total_exemption_amount, other_incomes
+			total_exemption_amount += flt(tax_slab.standard_tax_exemption_amount)
 
-	def calculate_tax_by_tax_slab(self, payroll_period, annual_taxable_earning):
-		payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
-		annual_taxable_earning -= flt(payroll_period_obj.standard_tax_exemption_amount)
+		return total_exemption_amount
+
+	def get_income_form_other_sources(self, payroll_period):
+		return frappe.get_all("Employee Other Income",
+			filters={
+				"employee": self.employee,
+				"payroll_period": payroll_period.name,
+				"company": self.company,
+				"docstatus": 1
+			},
+			fields="SUM(amount) as total_amount"
+		)[0].total_amount
+
+	def calculate_tax_by_tax_slab(self, annual_taxable_earning, tax_slab):
 		data = self.get_data_for_eval()
 		data.update({"annual_taxable_earning": annual_taxable_earning})
-		taxable_amount = 0
-		for slab in payroll_period_obj.taxable_salary_slabs:
+		tax_amount = 0
+		for slab in tax_slab.slabs:
 			if slab.condition and not self.eval_tax_slab_condition(slab.condition, data):
 				continue
 			if not slab.to_amount and annual_taxable_earning > slab.from_amount:
-				taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
+				tax_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
 				continue
 			if annual_taxable_earning > slab.from_amount and annual_taxable_earning < slab.to_amount:
-				taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
+				tax_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
 			elif annual_taxable_earning > slab.from_amount and annual_taxable_earning > slab.to_amount:
-				taxable_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
-		return taxable_amount
+				tax_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
+
+		# other taxes and charges on income tax
+		for d in tax_slab.other_taxes_and_charges:
+			if flt(d.min_taxable_income) and flt(d.min_taxable_income) > tax_amount:
+				continue
+
+			if flt(d.max_taxable_income) and flt(d.max_taxable_income) < tax_amount:
+				continue
+			
+			tax_amount += tax_amount * flt(d.percent) / 100
+
+		return tax_amount
 
 	def eval_tax_slab_condition(self, condition, data):
 		try:
@@ -869,7 +1004,7 @@
 		if not self.salary_slip_based_on_timesheet:
 			self.get_date_details()
 		self.pull_emp_details()
-		self.get_leave_details(for_preview=for_preview)
+		self.get_working_days_details(for_preview=for_preview)
 		self.calculate_net_pay()
 
 	def pull_emp_details(self):
@@ -878,8 +1013,8 @@
 			self.bank_name = emp.bank_name
 			self.bank_account_no = emp.bank_ac_no
 
-	def process_salary_based_on_leave(self, lwp=0):
-		self.get_leave_details(lwp=lwp)
+	def process_salary_based_on_working_days(self):
+		self.get_working_days_details(lwp=self.leave_without_pay)
 		self.calculate_net_pay()
 
 def unlink_ref_doc_from_salary_slip(ref_no):
diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
index ecccac7..fc687a3 100644
--- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
@@ -21,18 +21,105 @@
 		make_earning_salary_component(setup=True, company_list=["_Test Company"])
 		make_deduction_salary_component(setup=True, company_list=["_Test Company"])
 
-		for dt in ["Leave Application", "Leave Allocation", "Salary Slip"]:
+		for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Attendance"]:
 			frappe.db.sql("delete from `tab%s`" % dt)
 
 		self.make_holiday_list()
 
 		frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List")
 		frappe.db.set_value("HR Settings", None, "email_salary_slip_to_employee", 0)
-
+		frappe.db.set_value('HR Settings', None, 'leave_status_notification_template', None)
+		frappe.db.set_value('HR Settings', None, 'leave_approval_notification_template', None)
+		
 	def tearDown(self):
 		frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
 		frappe.set_user("Administrator")
 
+	def test_payment_days_based_on_attendance(self):
+		from erpnext.hr.doctype.attendance.attendance import mark_attendance
+		no_of_days = self.get_no_of_days()
+
+		# Payroll based on attendance
+		frappe.db.set_value("HR Settings", None, "payroll_based_on", "Attendance")
+		frappe.db.set_value("HR Settings", None, "daily_wages_fraction_for_half_day", 0.75)
+
+		emp_id = make_employee("test_for_attendance@salary.com")
+		frappe.db.set_value("Employee", emp_id, {"relieving_date": None, "status": "Active"})
+
+		frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0)
+
+		month_start_date = get_first_day(nowdate())
+		month_end_date = get_last_day(nowdate())
+
+		first_sunday = frappe.db.sql("""
+			select holiday_date from `tabHoliday`
+			where parent = 'Salary Slip Test Holiday List'
+				and holiday_date between %s and %s
+			order by holiday_date
+		""", (month_start_date, month_end_date))[0][0]
+
+		mark_attendance(emp_id, first_sunday, 'Absent', ignore_validate=True) # invalid lwp
+		mark_attendance(emp_id, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # valid lwp
+		mark_attendance(emp_id, add_days(first_sunday, 2), 'Half Day', leave_type='Leave Without Pay', ignore_validate=True) # valid 0.75 lwp
+		mark_attendance(emp_id, add_days(first_sunday, 3), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # valid lwp
+		mark_attendance(emp_id, add_days(first_sunday, 4), 'On Leave', leave_type='Casual Leave', ignore_validate=True) # invalid lwp
+		mark_attendance(emp_id, add_days(first_sunday, 7), 'On Leave', leave_type='Leave Without Pay', ignore_validate=True) # invalid lwp
+
+		ss = make_employee_salary_slip("test_for_attendance@salary.com", "Monthly")
+
+		self.assertEqual(ss.leave_without_pay, 2.25)
+
+		days_in_month = no_of_days[0]
+		no_of_holidays = no_of_days[1]
+
+		self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 2.25)
+
+		#Gross pay calculation based on attendances
+		gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
+
+		self.assertEqual(ss.gross_pay, gross_pay)
+
+		frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
+
+	def test_payment_days_based_on_leave_application(self):
+		no_of_days = self.get_no_of_days()
+
+		# Payroll based on attendance
+		frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
+
+		emp_id = make_employee("test_for_attendance@salary.com")
+		frappe.db.set_value("Employee", emp_id, {"relieving_date": None, "status": "Active"})
+
+		frappe.db.set_value("Leave Type", "Leave Without Pay", "include_holiday", 0)
+
+		month_start_date = get_first_day(nowdate())
+		month_end_date = get_last_day(nowdate())
+
+		first_sunday = frappe.db.sql("""
+			select holiday_date from `tabHoliday`
+			where parent = 'Salary Slip Test Holiday List'
+				and holiday_date between %s and %s
+			order by holiday_date
+		""", (month_start_date, month_end_date))[0][0]
+
+		make_leave_application(emp_id, first_sunday, add_days(first_sunday, 3), "Leave Without Pay")
+
+		ss = make_employee_salary_slip("test_for_attendance@salary.com", "Monthly")
+
+		self.assertEqual(ss.leave_without_pay, 3)
+
+		days_in_month = no_of_days[0]
+		no_of_holidays = no_of_days[1]
+
+		self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 3)
+
+		#Gross pay calculation based on attendances
+		gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay))
+
+		self.assertEqual(ss.gross_pay, gross_pay)
+
+		frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
+
 	def test_salary_slip_with_holidays_included(self):
 		no_of_days = self.get_no_of_days()
 		frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1)
@@ -47,10 +134,7 @@
 		self.assertEqual(ss.payment_days, no_of_days[0])
 		self.assertEqual(ss.earnings[0].amount, 50000)
 		self.assertEqual(ss.earnings[1].amount, 3000)
-		self.assertEqual(ss.deductions[0].amount, 5000)
-		self.assertEqual(ss.deductions[1].amount, 5000)
 		self.assertEqual(ss.gross_pay, 78000)
-		self.assertEqual(ss.net_pay, 68000.0)
 
 	def test_salary_slip_with_holidays_excluded(self):
 		no_of_days = self.get_no_of_days()
@@ -67,10 +151,7 @@
 		self.assertEqual(ss.earnings[0].amount, 50000)
 		self.assertEqual(ss.earnings[0].default_amount, 50000)
 		self.assertEqual(ss.earnings[1].amount, 3000)
-		self.assertEqual(ss.deductions[0].amount, 5000)
-		self.assertEqual(ss.deductions[1].amount, 5000)
 		self.assertEqual(ss.gross_pay, 78000)
-		self.assertEqual(ss.net_pay, 68000.0)
 
 	def test_payment_days(self):
 		no_of_days = self.get_no_of_days()
@@ -80,8 +161,8 @@
 		# set joinng date in the same month
 		make_employee("test_employee@salary.com")
 		if getdate(nowdate()).day >= 15:
-			date_of_joining = getdate(add_days(nowdate(),-10))
 			relieving_date = getdate(add_days(nowdate(),-10))
+			date_of_joining = getdate(add_days(nowdate(),-10))
 		elif getdate(nowdate()).day < 15 and getdate(nowdate()).day >= 5:
 			date_of_joining = getdate(add_days(nowdate(),-3))
 			relieving_date = getdate(add_days(nowdate(),-3))
@@ -131,9 +212,7 @@
 	def test_email_salary_slip(self):
 		frappe.db.sql("delete from `tabEmail Queue`")
 
-		hr_settings = frappe.get_doc("HR Settings", "HR Settings")
-		hr_settings.email_salary_slip_to_employee = 1
-		hr_settings.save()
+		frappe.db.set_value("HR Settings", None, "email_salary_slip_to_employee", 1)
 
 		make_employee("test_employee@salary.com")
 		ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
@@ -203,8 +282,11 @@
 		# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
 		frappe.db.sql("""delete from `tabPayroll Period`""")
 		frappe.db.sql("""delete from `tabSalary Component`""")
+	
 		payroll_period = create_payroll_period()
-		create_tax_slab(payroll_period)
+
+		create_tax_slab(payroll_period, allow_tax_exemption=True)
+
 		employee = make_employee("test_tax@salary.slip")
 		delete_docs = [
 			"Salary Slip",
@@ -230,8 +312,7 @@
 			payroll_period, deduct_random=False)
 		tax_paid = get_tax_paid_in_period(employee)
 
-		# total taxable income 586000, 250000 @ 5%, 86000 @ 20% ie. 12500 + 17200
-		annual_tax = 113568
+		annual_tax = 113589.0
 		try:
 			self.assertEqual(tax_paid, annual_tax)
 		except AssertionError:
@@ -255,8 +336,7 @@
 			raise
 
 		# Submit proof for total 120000
-		data["proof-1"] = create_proof_submission(employee, payroll_period, 50000)
-		data["proof-2"] = create_proof_submission(employee, payroll_period, 70000)
+		data["proof"] = create_proof_submission(employee, payroll_period, 120000)
 
 		# Submit benefit claim for total 50000
 		data["benefit-1"] = create_benefit_claim(employee, payroll_period, 15000, "Medical Allowance")
@@ -270,7 +350,7 @@
 
 		# total taxable income 416000, 166000 @ 5% ie. 8300
 		try:
-			self.assertEqual(tax_paid, 88608)
+			self.assertEqual(tax_paid, 82389.0)
 		except AssertionError:
 			print("\nSalary Slip - Tax calculation failed on following case\n", data, "\n")
 			raise
@@ -285,7 +365,7 @@
 		# total taxable income 566000, 250000 @ 5%, 66000 @ 20%, 12500 + 13200
 		tax_paid = get_tax_paid_in_period(employee)
 		try:
-			self.assertEqual(tax_paid, 121211)
+			self.assertEqual(tax_paid, annual_tax)
 		except AssertionError:
 			print("\nSalary Slip - Tax calculation failed on following case\n", data, "\n")
 			raise
@@ -322,11 +402,11 @@
 
 		return [no_of_days_in_month[1], no_of_holidays_in_month]
 
-
 def make_employee_salary_slip(user, payroll_frequency, salary_structure=None):
 	from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure
 	if not salary_structure:
 		salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip"
+
 	employee = frappe.db.get_value("Employee", {"user_id": user})
 	salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee)
 	salary_slip = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})})
@@ -456,17 +536,15 @@
 		{
 			"salary_component": 'Professional Tax',
 			"abbr":'PT',
-			"condition": 'base > 10000',
-			"formula": 'base*.1',
 			"type": "Deduction",
-			"amount_based_on_formula": 1
+			"amount": 200,
+			"exempted_from_income_tax": 1
+
 		},
 		{
 			"salary_component": 'TDS',
 			"abbr":'T',
-			"formula": 'base*.1',
 			"type": "Deduction",
-			"amount_based_on_formula": 1,
 			"depends_on_payment_days": 0,
 			"variable_based_on_taxable_salary": 1,
 			"round_to_the_nearest_integer": 1
@@ -477,9 +555,7 @@
 			"salary_component": 'TDS',
 			"abbr":'T',
 			"condition": 'employment_type=="Intern"',
-			"formula": 'base*.1',
 			"type": "Deduction",
-			"amount_based_on_formula": 1,
 			"round_to_the_nearest_integer": 1
 		})
 	if setup or test_tax:
@@ -535,29 +611,47 @@
 	}).submit()
 	return claim_date
 
-def create_tax_slab(payroll_period):
-	data = [
+def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False):
+	if frappe.db.exists("Income Tax Slab", "Tax Slab: " + payroll_period.name):
+		return
+
+	slabs = [
 		{
 			"from_amount": 250000,
 			"to_amount": 500000,
-			"percent_deduction": 5.2,
+			"percent_deduction": 5,
 			"condition": "annual_taxable_earning > 500000"
 		},
 		{
 			"from_amount": 500001,
 			"to_amount": 1000000,
-			"percent_deduction": 20.8
+			"percent_deduction": 20
 		},
 		{
 			"from_amount": 1000001,
-			"percent_deduction": 31.2
+			"percent_deduction": 30
 		}
 	]
-	payroll_period.taxable_salary_slabs = []
-	for item in data:
-		payroll_period.append("taxable_salary_slabs", item)
-	payroll_period.standard_tax_exemption_amount = 52500
-	payroll_period.save()
+
+	income_tax_slab = frappe.new_doc("Income Tax Slab")
+	income_tax_slab.name = "Tax Slab: " + payroll_period.name
+	income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2)
+
+	if allow_tax_exemption:
+		income_tax_slab.allow_tax_exemption = 1
+		income_tax_slab.standard_tax_exemption_amount = 50000
+
+	for item in slabs:
+		income_tax_slab.append("slabs", item)
+
+	income_tax_slab.append("other_taxes_and_charges", {
+		"description": "cess",
+		"percent": 4
+	})
+
+	income_tax_slab.save()
+	if not dont_submit:
+		income_tax_slab.submit()
 
 def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True):
 	deducted_dates = []
@@ -595,3 +689,17 @@
 		"type": "Earning"
 	}).submit()
 	return salary_date
+
+def make_leave_application(employee, from_date, to_date, leave_type, company=None):
+	leave_application = frappe.get_doc(dict(
+		doctype = 'Leave Application',
+		employee = employee,
+		leave_type = leave_type,
+		from_date = from_date,
+		to_date = to_date,
+		company = company or erpnext.get_default_company() or "_Test Company",
+		docstatus = 1,
+		status = "Approved",
+		leave_approver = 'test@example.com'
+	))
+	leave_application.submit()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index 7120448..7748403 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -82,6 +82,7 @@
                 {fieldname:"employee", fieldtype: "Link", options: "Employee", label: __("Employee")},
 				{fieldname:'base_variable', fieldtype:'Section Break'},
 				{fieldname:'from_date', fieldtype:'Date', label: __('From Date'), "reqd": 1},
+				{fieldname:'income_tax_slab', fieldtype:'Link', label: __('Income Tax Slab'), options: 'Income Tax Slab'},
 				{fieldname:'base_col_br', fieldtype:'Column Break'},
 				{fieldname:'base', fieldtype:'Currency', label: __('Base')},
 				{fieldname:'variable', fieldtype:'Currency', label: __('Variable')}
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index 568277f..5ba7f1c 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -16,6 +16,7 @@
 		self.validate_amount()
 		self.strip_condition_and_formula_fields()
 		self.validate_max_benefits_with_flexi()
+		self.validate_component_based_on_tax_slab()
 
 	def set_missing_values(self):
 		overwritten_fields = ["depends_on_payment_days", "variable_based_on_taxable_salary", "is_tax_applicable", "is_flexible_benefit"]
@@ -34,6 +35,12 @@
 						for fieldname in overwritten_fields_if_missing:
 							d.set(fieldname, component_default_value.get(fieldname))
 
+	def validate_component_based_on_tax_slab(self):
+		for row in self.deductions:
+			if row.variable_based_on_taxable_salary and (row.amount or row.formula):
+				frappe.throw(_("Row #{0}: Cannot set amount or formula for Salary Component {1} with Variable Based On Taxable Salary")
+					.format(row.idx, row.salary_component))
+
 	def validate_amount(self):
 		if flt(self.net_pay) < 0 and self.salary_slip_based_on_timesheet:
 			frappe.throw(_("Net pay cannot be negative"))
@@ -82,21 +89,23 @@
 
 	@frappe.whitelist()
 	def assign_salary_structure(self, company=None, grade=None, department=None, designation=None,employee=None,
-			from_date=None, base=None,variable=None):
+			from_date=None, base=None, variable=None, income_tax_slab=None):
 		employees = self.get_employees(company= company, grade= grade,department= department,designation= designation,name=employee)
 
 		if employees:
 			if len(employees) > 20:
 				frappe.enqueue(assign_salary_structure_for_employees, timeout=600,
-					employees=employees, salary_structure=self,from_date=from_date, base=base,variable=variable)
+					employees=employees, salary_structure=self,from_date=from_date,
+					base=base, variable=variable, income_tax_slab=income_tax_slab)
 			else:
-				assign_salary_structure_for_employees(employees, self, from_date=from_date, base=base,variable=variable)
+				assign_salary_structure_for_employees(employees, self, from_date=from_date,
+					base=base, variable=variable, income_tax_slab=income_tax_slab)
 		else:
 			frappe.msgprint(_("No Employee Found"))
 
 
 
-def assign_salary_structure_for_employees(employees, salary_structure, from_date=None, base=None,variable=None):
+def assign_salary_structure_for_employees(employees, salary_structure, from_date=None, base=None, variable=None, income_tax_slab=None):
 	salary_structures_assignments = []
 	existing_assignments_for = get_existing_assignments(employees, salary_structure, from_date)
 	count=0
@@ -105,7 +114,8 @@
 			continue
 		count +=1
 
-		salary_structures_assignment = create_salary_structures_assignment(employee, salary_structure, from_date, base, variable)
+		salary_structures_assignment = create_salary_structures_assignment(employee,
+			salary_structure, from_date, base, variable, income_tax_slab)
 		salary_structures_assignments.append(salary_structures_assignment)
 		frappe.publish_progress(count*100/len(set(employees) - set(existing_assignments_for)), title = _("Assigning Structures..."))
 
@@ -113,7 +123,7 @@
 		frappe.msgprint(_("Structures have been assigned successfully"))
 
 
-def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable):
+def create_salary_structures_assignment(employee, salary_structure, from_date, base, variable, income_tax_slab=None):
 	assignment = frappe.new_doc("Salary Structure Assignment")
 	assignment.employee = employee
 	assignment.salary_structure = salary_structure.name
@@ -121,6 +131,7 @@
 	assignment.from_date = from_date
 	assignment.base = base
 	assignment.variable = variable
+	assignment.income_tax_slab = income_tax_slab
 	assignment.save(ignore_permissions = True)
 	assignment.submit()
 	return assignment.name
@@ -138,7 +149,7 @@
 	return salary_structures_assignments
 
 @frappe.whitelist()
-def make_salary_slip(source_name, target_doc = None, employee = None, as_print = False, print_format = None, for_preview=0):
+def make_salary_slip(source_name, target_doc = None, employee = None, as_print = False, print_format = None, for_preview=0, ignore_permissions=False):
 	def postprocess(source, target):
 		if employee:
 			employee_details = frappe.db.get_value("Employee", employee,
@@ -158,7 +169,7 @@
 				"name": "salary_structure"
 			}
 		}
-	}, target_doc, postprocess, ignore_child_tables=True)
+	}, target_doc, postprocess, ignore_child_tables=True, ignore_permissions=ignore_permissions)
 
 	if cint(as_print):
 		doc.name = 'Preview for {0}'.format(employee)
diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
index 6ca6dfd..c1869f0 100644
--- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
@@ -9,8 +9,9 @@
 from frappe.utils import nowdate, add_days, add_years, getdate, add_months
 from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
 from erpnext.hr.doctype.salary_slip.test_salary_slip import make_earning_salary_component,\
-	make_deduction_salary_component, make_employee_salary_slip
+	make_deduction_salary_component, make_employee_salary_slip, create_tax_slab
 from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_payroll_period
 
 
 test_dependencies = ["Fiscal Year"]
@@ -70,10 +71,8 @@
 			self.assertEqual(sal_slip.get("earnings")[1].amount, 3000)
 			self.assertEqual(sal_slip.get("earnings")[2].amount, 25000)
 			self.assertEqual(sal_slip.get("gross_pay"), 78000)
-			self.assertEqual(sal_slip.get("deductions")[0].amount, 5000)
-			self.assertEqual(sal_slip.get("deductions")[1].amount, 5000)
-			self.assertEqual(sal_slip.get("total_deduction"), 10000)
-			self.assertEqual(sal_slip.get("net_pay"), 68000)
+			self.assertEqual(sal_slip.get("deductions")[0].amount, 200)
+			self.assertEqual(sal_slip.get("net_pay"), 78000 - sal_slip.get("total_deduction"))
 
 	def test_whitespaces_in_formula_conditions_fields(self):
 		salary_structure = make_salary_structure("Salary Structure Sample", "Monthly", dont_submit=True)
@@ -112,6 +111,7 @@
 	test_tax=False, company=None):
 	if test_tax:
 		frappe.db.sql("""delete from `tabSalary Structure` where name=%s""",(salary_structure))
+
 	if not frappe.db.exists('Salary Structure', salary_structure):
 		details = {
 			"doctype": "Salary Structure",
@@ -124,7 +124,8 @@
 		}
 		if other_details and isinstance(other_details, dict):
 			details.update(other_details)
-		salary_structure_doc = frappe.get_doc(details).insert()
+		salary_structure_doc = frappe.get_doc(details)
+		salary_structure_doc.insert()
 		if not dont_submit:
 			salary_structure_doc.submit()
 	else:
@@ -139,13 +140,18 @@
 def create_salary_structure_assignment(employee, salary_structure, from_date=None, company=None):
 	if frappe.db.exists("Salary Structure Assignment", {"employee": employee}):
 		frappe.db.sql("""delete from `tabSalary Structure Assignment` where employee=%s""",(employee))
+
+	payroll_period = create_payroll_period()
+	create_tax_slab(payroll_period, allow_tax_exemption=True)
+
 	salary_structure_assignment = frappe.new_doc("Salary Structure Assignment")
 	salary_structure_assignment.employee = employee
 	salary_structure_assignment.base = 50000
 	salary_structure_assignment.variable = 5000
-	salary_structure_assignment.from_date = from_date or add_months(nowdate(), -1)
+	salary_structure_assignment.from_date = from_date or add_days(nowdate(), -1)
 	salary_structure_assignment.salary_structure = salary_structure
 	salary_structure_assignment.company = company or erpnext.get_default_company()
 	salary_structure_assignment.save(ignore_permissions=True)
+	salary_structure_assignment.income_tax_slab = "Tax Slab: _Test Payroll Period"
 	salary_structure_assignment.submit()
 	return salary_structure_assignment
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
index 56a05e0..818e853 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.js
@@ -20,6 +20,16 @@
 				}
 			}
 		});
+
+		frm.set_query("income_tax_slab", function() {
+			return {
+				filters: {
+					company: frm.doc.company,
+					docstatus: 1,
+					disabled: 0
+				}
+			}
+		});
 	},
 	employee: function(frm) {
 		if(frm.doc.employee){
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json
index 380c889..0098aa8 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json
@@ -10,11 +10,12 @@
   "employee",
   "employee_name",
   "department",
-  "designation",
+  "company",
   "column_break_6",
+  "designation",
   "salary_structure",
   "from_date",
-  "company",
+  "income_tax_slab",
   "section_break_7",
   "base",
   "column_break_9",
@@ -113,11 +114,17 @@
    "options": "Salary Structure Assignment",
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "income_tax_slab",
+   "fieldtype": "Link",
+   "label": "Income Tax Slab",
+   "options": "Income Tax Slab"
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2019-12-31 16:35:34.415099",
+ "modified": "2020-04-25 18:24:23.617088",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Salary Structure Assignment",
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 35c8630..97be5cd 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -1,85 +1,186 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
 
 from __future__ import unicode_literals
 import frappe
-from frappe import _
 from frappe.utils import flt
-from erpnext.hr.doctype.leave_application.leave_application \
-	import get_leave_balance_on, get_leaves_for_period
-
-from erpnext.hr.report.employee_leave_balance_summary.employee_leave_balance_summary \
-	import get_department_leave_approver_map
+from frappe import _
+from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on, get_leave_allocation_records
 
 def execute(filters=None):
-	leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
+	if filters.to_date <= filters.from_date:
+		frappe.throw(_('From date can not be greater than than To date'))
 
-	columns = get_columns(leave_types)
-	data = get_data(filters, leave_types)
+	columns = get_columns()
+	data = get_data(filters)
 
 	return columns, data
 
-def get_columns(leave_types):
-	columns = [
-		_("Employee") + ":Link.Employee:150",
-		_("Employee Name") + "::200",
-		_("Department") +"::150"
-	]
-
-	for leave_type in leave_types:
-		columns.append(_(leave_type) + " " + _("Opening") + ":Float:160")
-		columns.append(_(leave_type) + " " + _("Taken") + ":Float:160")
-		columns.append(_(leave_type) + " " + _("Balance") + ":Float:160")
+def get_columns():
+	columns = [{
+		'label': _('Leave Type'),
+		'fieldtype': 'Link',
+		'fieldname': 'leave_type',
+		'width': 200,
+		'options': 'Leave Type'
+	}, {
+		'label': _('Employee'),
+		'fieldtype': 'Link',
+		'fieldname': 'employee',
+		'width': 100,
+		'options': 'Employee'
+	}, {
+		'label': _('Employee Name'),
+		'fieldtype': 'Data',
+		'fieldname': 'employee_name',
+		'width': 100,
+	}, {
+		'label': _('Opening Balance'),
+		'fieldtype': 'float',
+		'fieldname': 'opening_balance',
+		'width': 130,
+	}, {
+		'label': _('Leaves Allocated'),
+		'fieldtype': 'float',
+		'fieldname': 'leaves_allocated',
+		'width': 130,
+	}, {
+		'label': _('Leaves Taken'),
+		'fieldtype': 'float',
+		'fieldname': 'leaves_taken',
+		'width': 130,
+	}, {
+		'label': _('Leaves Expired'),
+		'fieldtype': 'float',
+		'fieldname': 'leaves_expired',
+		'width': 130,
+	}, {
+		'label': _('Closing Balance'),
+		'fieldtype': 'float',
+		'fieldname': 'closing_balance',
+		'width': 130,
+	}]
 
 	return columns
 
-def get_conditions(filters):
-	conditions = {
-		"status": "Active",
-		"company": filters.company,
-	}
-	if filters.get("department"):
-		conditions.update({"department": filters.get("department")})
-	if filters.get("employee"):
-		conditions.update({"employee": filters.get("employee")})
+def get_data(filters):
+	leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
 
-	return conditions
-
-def get_data(filters, leave_types):
-	user = frappe.session.user
 	conditions = get_conditions(filters)
 
-	if filters.to_date <= filters.from_date:
-		frappe.throw(_("From date can not be greater than than To date"))
-
-	active_employees = frappe.get_all("Employee",
-		filters=conditions,
-		fields=["name", "employee_name", "department", "user_id", "leave_approver"])
-
+	user = frappe.session.user
 	department_approver_map = get_department_leave_approver_map(filters.get('department'))
 
+	active_employees = frappe.get_list('Employee',
+		filters=conditions,
+		fields=['name', 'employee_name', 'department', 'user_id', 'leave_approver'])
+
 	data = []
-	for employee in active_employees:
-		leave_approvers = department_approver_map.get(employee.department_name, [])
-		if employee.leave_approver:
-			leave_approvers.append(employee.leave_approver)
 
-		if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
-			row = [employee.name, employee.employee_name, employee.department]
+	for leave_type in leave_types:
+		if len(active_employees) > 1:
+			data.append({
+				'leave_type': leave_type
+			})
+		else:
+			row = frappe._dict({
+				'leave_type': leave_type
+			})
 
-			for leave_type in leave_types:
-				# leaves taken
+		for employee in active_employees:
+
+			leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
+
+			if (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
+				or ("HR Manager" in frappe.get_roles(user)):
+				if len(active_employees) > 1:
+					row = frappe._dict()
+				row.employee = employee.name,
+				row.employee_name = employee.employee_name
+
 				leaves_taken = get_leaves_for_period(employee.name, leave_type,
 					filters.from_date, filters.to_date) * -1
 
-				# opening balance
+				new_allocation, expired_leaves = get_allocated_and_expired_leaves(filters.from_date, filters.to_date, employee.name, leave_type)
+
+
 				opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
+				closing = get_leave_balance_on(employee.name, leave_type, filters.to_date)
 
-				# closing balance
-				closing = max(opening - leaves_taken, 0)
+				row.leaves_allocated = new_allocation
+				row.leaves_expired = expired_leaves - leaves_taken if expired_leaves - leaves_taken > 0 else 0
+				row.opening_balance = opening
+				row.leaves_taken = leaves_taken
+				row.closing_balance = closing
+				row.indent = 1
+				data.append(row)
+				new_leaves_allocated = 0
 
-				row += [opening, leaves_taken, closing]
 
-			data.append(row)
+	return data
 
-	return data
\ No newline at end of file
+def get_conditions(filters):
+	conditions={
+		'status': 'Active',
+	}
+	if filters.get('employee'):
+		conditions['name'] = filters.get('employee')
+
+	if filters.get('employee'):
+		conditions['name'] = filters.get('employee')
+
+	return conditions
+
+def get_department_leave_approver_map(department=None):
+	conditions=''
+	if department:
+		conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department}
+
+	# get current department and all its child
+	department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec
+
+	# retrieve approvers list from current department and from its subsequent child departments
+	approver_list = frappe.get_all('Department Approver', filters={
+		'parentfield': 'leave_approvers',
+		'parent': ('in', department_list)
+	}, fields=['parent', 'approver'], as_list=1)
+
+	approvers = {}
+
+	for k, v in approver_list:
+		approvers.setdefault(k, []).append(v)
+
+	return approvers
+
+def get_allocated_and_expired_leaves(from_date, to_date, employee, leave_type):
+
+	from frappe.utils import getdate
+
+	new_allocation = 0
+	expired_leaves = 0
+
+	records= frappe.db.sql("""
+		SELECT
+			employee, leave_type, from_date, to_date, leaves, transaction_name,
+			is_carry_forward, is_expired
+		FROM `tabLeave Ledger Entry`
+		WHERE employee=%(employee)s AND leave_type=%(leave_type)s
+			AND docstatus=1 AND leaves>0
+			AND (from_date between %(from_date)s AND %(to_date)s
+				OR to_date between %(from_date)s AND %(to_date)s
+				OR (from_date < %(from_date)s AND to_date > %(to_date)s))
+	""", {
+		"from_date": from_date,
+		"to_date": to_date,
+		"employee": employee,
+		"leave_type": leave_type
+	}, as_dict=1)
+
+	for record in records:
+		if record.to_date <= getdate(to_date):
+			expired_leaves += record.leaves
+
+		if record.from_date >= getdate(from_date):
+			new_allocation += record.leaves
+
+	return new_allocation, expired_leaves
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
index 3fb8f6e..cb05d11 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.js
@@ -5,18 +5,11 @@
 frappe.query_reports['Employee Leave Balance Summary'] = {
 	filters: [
 		{
-			fieldname:'from_date',
-			label: __('From Date'),
+			fieldname:'date',
+			label: __('Date'),
 			fieldtype: 'Date',
 			reqd: 1,
-			default: frappe.defaults.get_default('year_start_date')
-		},
-		{
-			fieldname:'to_date',
-			label: __('To Date'),
-			fieldtype: 'Date',
-			reqd: 1,
-			default: frappe.defaults.get_default('year_end_date')
+			default: frappe.datetime.now_date()
 		},
 		{
 			fieldname:'company',
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
index 777de02..a5cdecf 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -1,130 +1,75 @@
-# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import flt
 from frappe import _
-from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on
+from frappe.utils import flt
+from erpnext.hr.doctype.leave_application.leave_application \
+	import get_leave_balance_on, get_leaves_for_period
+
+from erpnext.hr.report.employee_leave_balance.employee_leave_balance \
+	import get_department_leave_approver_map
 
 def execute(filters=None):
-	if filters.to_date <= filters.from_date:
-		frappe.throw(_('From date can not be greater than than To date'))
+	leave_types = frappe.db.sql_list("select name from `tabLeave Type` order by name asc")
 
-	columns = get_columns()
-	data = get_data(filters)
+	columns = get_columns(leave_types)
+	data = get_data(filters, leave_types)
 
 	return columns, data
 
-def get_columns():
-	columns = [{
-		'label': _('Leave Type'),
-		'fieldtype': 'Link',
-		'fieldname': 'leave_type',
-		'width': 300,
-		'options': 'Leave Type'
-	}, {
-		'label': _('Employee'),
-		'fieldtype': 'Link',
-		'fieldname': 'employee',
-		'width': 100,
-		'options': 'Employee'
-	}, {
-		'label': _('Employee Name'),
-		'fieldtype': 'Data',
-		'fieldname': 'employee_name',
-		'width': 100,
-	}, {
-		'label': _('Opening Balance'),
-		'fieldtype': 'float',
-		'fieldname': 'opening_balance',
-		'width': 160,
-	}, {
-		'label': _('Leaves Taken'),
-		'fieldtype': 'float',
-		'fieldname': 'leaves_taken',
-		'width': 160,
-	}, {
-		'label': _('Closing Balance'),
-		'fieldtype': 'float',
-		'fieldname': 'closing_balance',
-		'width': 160,
-	}]
+def get_columns(leave_types):
+	columns = [
+		_("Employee") + ":Link.Employee:150",
+		_("Employee Name") + "::200",
+		_("Department") +"::150"
+	]
+
+	for leave_type in leave_types:
+		columns.append(_(leave_type) + ":Float:160")
 
 	return columns
 
-def get_data(filters):
-	leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
-
-	conditions = get_conditions(filters)
-
-	user = frappe.session.user
-	department_approver_map = get_department_leave_approver_map(filters.get('department'))
-
-	active_employees = frappe.get_list('Employee',
-		filters=conditions,
-		fields=['name', 'employee_name', 'department', 'user_id', 'leave_approver'])
-
-	data = []
-
-	for leave_type in leave_types:
-		data.append({
-			'leave_type': leave_type
-		})
-		for employee in active_employees:
-			
-			leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
-
-			if (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
-				or ("HR Manager" in frappe.get_roles(user)):
-				row = frappe._dict({
-					'employee': employee.name,
-					'employee_name': employee.employee_name
-				})
-
-				leaves_taken = get_leaves_for_period(employee.name, leave_type,
-					filters.from_date, filters.to_date) * -1
-
-				opening = get_leave_balance_on(employee.name, leave_type, filters.from_date)
-				closing = get_leave_balance_on(employee.name, leave_type, filters.to_date)
-
-				row.opening_balance = opening
-				row.leaves_taken = leaves_taken
-				row.closing_balance = closing
-				row.indent = 1
-				data.append(row)
-
-	return data
-
 def get_conditions(filters):
-	conditions={
-		'status': 'Active',
+	conditions = {
+		"status": "Active",
+		"company": filters.company,
 	}
-	if filters.get('employee'):
-		conditions['name'] = filters.get('employee')
-
-	if filters.get('employee'):
-		conditions['name'] = filters.get('employee')
+	if filters.get("department"):
+		conditions.update({"department": filters.get("department")})
+	if filters.get("employee"):
+		conditions.update({"employee": filters.get("employee")})
 
 	return conditions
 
-def get_department_leave_approver_map(department=None):
-	conditions=''
-	if department:
-		conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department}
+def get_data(filters, leave_types):
+	user = frappe.session.user
+	conditions = get_conditions(filters)
 
-	# get current department and all its child
-	department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec
+	active_employees = frappe.get_all("Employee",
+		filters=conditions,
+		fields=["name", "employee_name", "department", "user_id", "leave_approver"])
 
-	# retrieve approvers list from current department and from its subsequent child departments
-	approver_list = frappe.get_all('Department Approver', filters={
-		'parentfield': 'leave_approvers',
-		'parent': ('in', department_list)
-	}, fields=['parent', 'approver'], as_list=1)
+	department_approver_map = get_department_leave_approver_map(filters.get('department'))
 
-	approvers = {}
+	data = []
+	for employee in active_employees:
+		leave_approvers = department_approver_map.get(employee.department_name, [])
+		if employee.leave_approver:
+			leave_approvers.append(employee.leave_approver)
 
-	for k, v in approver_list:
-		approvers.setdefault(k, []).append(v)
+		if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
+			row = [employee.name, employee.employee_name, employee.department]
 
-	return approvers
+			for leave_type in leave_types:
+
+				# opening balance
+				opening = get_leave_balance_on(employee.name, leave_type, filters.date)
+
+
+				row += [opening]
+
+			data.append(row)
+
+	return data
\ No newline at end of file
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index ef27600..cd12510 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -9,6 +9,8 @@
 from frappe.desk.form import assign_to
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
 
+class DuplicateDeclarationError(frappe.ValidationError): pass
+
 class EmployeeBoardingController(Document):
 	'''
 		Create the project and the task for the boarding process
@@ -226,6 +228,17 @@
 	else:
 		frappe.throw(_("Please set leave policy for employee {0} in Employee / Grade record").format(employee))
 
+def validate_duplicate_exemption_for_payroll_period(doctype, docname, payroll_period, employee):
+	existing_record = frappe.db.exists(doctype, {
+		"payroll_period": payroll_period,
+		"employee": employee,
+		'docstatus': ['<', 2],
+		'name': ['!=', docname]
+	})
+	if existing_record:
+		frappe.throw(_("{0} already exists for employee {1} and period {2}")
+			.format(doctype, employee, payroll_period), DuplicateDeclarationError)
+
 def validate_tax_declaration(declarations):
 	subcategories = []
 	for d in declarations:
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.json b/erpnext/loan_management/doctype/loan_security/loan_security.json
index e6984ee..e879b17 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.json
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.json
@@ -1,15 +1,17 @@
 {
+ "actions": [],
+ "allow_rename": 1,
  "autoname": "field:loan_security_name",
  "creation": "2019-09-02 15:07:08.885593",
  "doctype": "DocType",
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
-  "loan_security_type",
-  "loan_security_code",
   "loan_security_name",
   "unit_of_measure",
+  "loan_security_code",
   "column_break_3",
+  "loan_security_type",
   "haircut",
   "disabled"
  ],
@@ -17,7 +19,9 @@
   {
    "fieldname": "loan_security_name",
    "fieldtype": "Data",
+   "in_list_view": 1,
    "label": "Loan Security Name",
+   "reqd": 1,
    "unique": 1
   },
   {
@@ -33,8 +37,10 @@
   {
    "fieldname": "loan_security_type",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Loan Security Type",
-   "options": "Loan Security Type"
+   "options": "Loan Security Type",
+   "reqd": 1
   },
   {
    "fieldname": "loan_security_code",
@@ -52,11 +58,15 @@
    "fetch_from": "loan_security_type.unit_of_measure",
    "fieldname": "unit_of_measure",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Unit Of Measure",
-   "options": "UOM"
+   "options": "UOM",
+   "read_only": 1,
+   "reqd": 1
   }
  ],
- "modified": "2019-11-16 11:36:37.901656",
+ "links": [],
+ "modified": "2020-04-28 14:07:54.506896",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security",
@@ -87,7 +97,6 @@
    "write": 1
   }
  ],
- "quick_entry": 1,
  "search_fields": "loan_security_code",
  "sort_field": "modified",
  "sort_order": "DESC",
diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
index 5f29609..f46b88c 100644
--- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
+++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
@@ -9,9 +9,9 @@
   "loan_security_type",
   "unit_of_measure",
   "haircut",
-  "disabled",
   "column_break_5",
-  "loan_to_value_ratio"
+  "loan_to_value_ratio",
+  "disabled"
  ],
  "fields": [
   {
@@ -23,7 +23,9 @@
   {
    "fieldname": "loan_security_type",
    "fieldtype": "Data",
+   "in_list_view": 1,
    "label": "Loan Security Type",
+   "reqd": 1,
    "unique": 1
   },
   {
@@ -34,8 +36,10 @@
   {
    "fieldname": "unit_of_measure",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Unit Of Measure",
-   "options": "UOM"
+   "options": "UOM",
+   "reqd": 1
   },
   {
    "fieldname": "column_break_5",
@@ -48,7 +52,7 @@
   }
  ],
  "links": [],
- "modified": "2020-02-28 12:43:20.364447",
+ "modified": "2020-04-28 14:06:49.046177",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security Type",
diff --git a/erpnext/non_profit/doctype/member/member_dashboard.py b/erpnext/non_profit/doctype/member/member_dashboard.py
index 945fb7b..743db25 100644
--- a/erpnext/non_profit/doctype/member/member_dashboard.py
+++ b/erpnext/non_profit/doctype/member/member_dashboard.py
@@ -6,10 +6,17 @@
 		'heatmap': True,
 		'heatmap_message': _('Member Activity'),
 		'fieldname': 'member',
+		'non_standard_fieldnames': {
+			'Bank Account': 'party'
+		},
 		'transactions': [
 			{
 				'label': _('Membership Details'),
 				'items': ['Membership']
+			},
+			{
+				'label': _('Fee'),
+				'items': ['Bank Account']
 			}
 		]
-	}
\ No newline at end of file
+	}
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index eb2b35c..a216f53 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -661,6 +661,7 @@
 erpnext.patches.v12_0.create_irs_1099_field_united_states
 erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
 erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
+erpnext.patches.v12_0.add_permission_in_lower_deduction
 erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
 erpnext.patches.v12_0.rename_account_type_doctype
 erpnext.patches.v12_0.recalculate_requested_qty_in_bin
@@ -668,5 +669,9 @@
 erpnext.patches.v12_0.set_total_batch_quantity
 erpnext.patches.v12_0.rename_mws_settings_fields
 erpnext.patches.v12_0.set_updated_purpose_in_pick_list
+erpnext.patches.v12_0.set_default_payroll_based_on
 erpnext.patches.v12_0.repost_stock_ledger_entries_for_target_warehouse
-erpnext.patches.v12_0.update_end_date_and_status_in_email_campaign
\ No newline at end of file
+erpnext.patches.v12_0.update_end_date_and_status_in_email_campaign
+erpnext.patches.v13_0.move_tax_slabs_from_payroll_period_to_income_tax_slab #123
+erpnext.patches.v12_0.fix_quotation_expired_status
+erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/add_permissions_in_gst_settings.py b/erpnext/patches/v11_0/add_permissions_in_gst_settings.py
index 121a202..d793611 100644
--- a/erpnext/patches/v11_0/add_permissions_in_gst_settings.py
+++ b/erpnext/patches/v11_0/add_permissions_in_gst_settings.py
@@ -6,4 +6,5 @@
 	if not company:
 		return
 
+	frappe.reload_doc("regional", "doctype", "lower_deduction_certificate")
 	add_permissions()
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/set_salary_component_properties.py b/erpnext/patches/v11_0/set_salary_component_properties.py
index fa3605b..83fb53d 100644
--- a/erpnext/patches/v11_0/set_salary_component_properties.py
+++ b/erpnext/patches/v11_0/set_salary_component_properties.py
@@ -5,8 +5,7 @@
 	frappe.reload_doc('hr', 'doctype', 'salary_detail')
 	frappe.reload_doc('hr', 'doctype', 'salary_component')
 
-	frappe.db.sql("update `tabSalary Component` set is_payable=1, is_tax_applicable=1 where type='Earning'")
-	frappe.db.sql("update `tabSalary Component` set is_payable=0 where type='Deduction'")
+	frappe.db.sql("update `tabSalary Component` set is_tax_applicable=1 where type='Earning'")
 
 	frappe.db.sql("""update `tabSalary Component` set variable_based_on_taxable_salary=1
 	    where type='Deduction' and name in ('TDS', 'Tax Deducted at Source')""")
diff --git a/erpnext/patches/v12_0/add_permission_in_lower_deduction.py b/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
new file mode 100644
index 0000000..af9bf74
--- /dev/null
+++ b/erpnext/patches/v12_0/add_permission_in_lower_deduction.py
@@ -0,0 +1,13 @@
+import frappe
+from frappe.permissions import add_permission, update_permission_property
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	frappe.reload_doc('regional', 'doctype', 'Lower Deduction Certificate')
+
+	add_permission('Lower Deduction Certificate', 'Accounts Manager', 0)
+	update_permission_property('Lower Deduction Certificate', 'Accounts Manager', 0, 'write', 1)
+	update_permission_property('Lower Deduction Certificate', 'Accounts Manager', 0, 'create', 1)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py
new file mode 100644
index 0000000..c8708d8
--- /dev/null
+++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py
@@ -0,0 +1,34 @@
+import frappe
+
+def execute():
+	# fixes status of quotations which have status 'Expired' despite having valid sales order created
+
+	# filter out submitted expired quotations which has sales order created
+	cond = "qo.docstatus = 1 and qo.status = 'Expired'"
+	invalid_so_against_quo = """
+		SELECT 
+			so.name FROM `tabSales Order` so, `tabSales Order Item` so_item
+		WHERE 
+			so_item.docstatus = 1 and so.docstatus = 1
+			and so_item.parent = so.name
+			and so_item.prevdoc_docname = qo.name
+			and qo.valid_till < so.transaction_date""" # check if SO was created after quotation expired
+		
+	frappe.db.sql(
+		"""UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and exists({invalid_so_against_quo})"""
+			.format(cond=cond, invalid_so_against_quo=invalid_so_against_quo)
+		)
+	
+	valid_so_against_quo = """
+		SELECT 
+			so.name FROM `tabSales Order` so, `tabSales Order Item` so_item
+		WHERE 
+			so_item.docstatus = 1 and so.docstatus = 1
+			and so_item.parent = so.name
+			and so_item.prevdoc_docname = qo.name
+			and qo.valid_till >= so.transaction_date""" # check if SO was created before quotation expired
+
+	frappe.db.sql(
+		"""UPDATE `tabQuotation` qo SET qo.status = 'Closed' WHERE {cond} and exists({valid_so_against_quo})"""
+			.format(cond=cond, valid_so_against_quo=valid_so_against_quo)
+		)
diff --git a/erpnext/patches/v12_0/set_default_payroll_based_on.py b/erpnext/patches/v12_0/set_default_payroll_based_on.py
new file mode 100644
index 0000000..04b54a6
--- /dev/null
+++ b/erpnext/patches/v12_0/set_default_payroll_based_on.py
@@ -0,0 +1,6 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	frappe.reload_doc("hr", "doctype", "hr_settings")
+	frappe.db.set_value("HR Settings", None, "payroll_based_on", "Leave")
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
new file mode 100644
index 0000000..91931ee
--- /dev/null
+++ b/erpnext/patches/v12_0/update_appointment_reminder_scheduler_entry.py
@@ -0,0 +1,7 @@
+import frappe
+
+def execute():
+	job = frappe.db.exists('Scheduled Job Type', 'patient_appointment.send_appointment_reminder')
+	if job:
+		method = 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.send_appointment_reminder'
+		frappe.db.set_value('Scheduled Job Type', job, 'method', method)
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/__init__.py b/erpnext/patches/v13_0/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/patches/v13_0/__init__.py
diff --git a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
new file mode 100644
index 0000000..179be2c
--- /dev/null
+++ b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
@@ -0,0 +1,99 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+	if not frappe.db.table_exists("Payroll Period"):
+		return
+
+	for doctype in ("income_tax_slab", "salary_structure_assignment", "employee_other_income", "income_tax_slab_other_charges"):
+		frappe.reload_doc("hr", "doctype", doctype)
+
+
+	for company in frappe.get_all("Company"):
+		payroll_periods =  frappe.db.sql("""
+			SELECT
+				name, start_date, end_date, standard_tax_exemption_amount
+			FROM
+				`tabPayroll Period`
+			WHERE company=%s
+			ORDER BY start_date DESC
+		""", company.name, as_dict = 1)
+			
+		for i, period in enumerate(payroll_periods):
+			income_tax_slab = frappe.new_doc("Income Tax Slab")
+			income_tax_slab.name = "Tax Slab:" + period.name
+
+			if i == 0:
+				income_tax_slab.disabled = 0
+			else:
+				income_tax_slab.disabled = 1
+
+			income_tax_slab.effective_from = period.start_date
+			income_tax_slab.company = company.name
+			income_tax_slab.allow_tax_exemption = 1
+			income_tax_slab.standard_tax_exemption_amount = period.standard_tax_exemption_amount
+
+			income_tax_slab.flags.ignore_mandatory = True
+			income_tax_slab.submit()
+
+			frappe.db.sql(
+			""" UPDATE `tabTaxable Salary Slab`
+				SET parent = %s , parentfield = 'slabs' , parenttype = "Income Tax Slab"
+				WHERE parent = %s
+			""", (income_tax_slab.name, period.name), as_dict = 1)
+
+			if i == 0:
+				frappe.db.sql("""
+					UPDATE
+						`tabSalary Structure Assignment`
+					set
+						income_tax_slab = %s
+					where
+						company = %s
+						and from_date >= %s
+						and docstatus < 2
+				""", (income_tax_slab.name, company.name, period.start_date))
+
+	# move other incomes to separate document
+	migrated = []
+	proofs = frappe.get_all("Employee Tax Exemption Proof Submission",
+		filters = {'docstatus': 1},
+		fields =['payroll_period', 'employee', 'company', 'income_from_other_sources']
+	)
+	for proof in proofs:
+		if proof.income_from_other_sources:
+			employee_other_income = frappe.new_doc("Employee Other Income")
+			employee_other_income.employee = proof.employee
+			employee_other_income.payroll_period = proof.payroll_period
+			employee_other_income.company = proof.company
+			employee_other_income.amount = proof.income_from_other_sources
+
+			try:
+				employee_other_income.submit()
+				migrated.append([proof.employee, proof.payroll_period])
+			except:
+				pass
+
+	declerations = frappe.get_all("Employee Tax Exemption Declaration",
+		filters = {'docstatus': 1},
+		fields =['payroll_period', 'employee', 'company', 'income_from_other_sources']
+	)
+
+	for declaration in declerations:
+		if declaration.income_from_other_sources \
+				and [declaration.employee, declaration.payroll_period] not in migrated:
+			employee_other_income = frappe.new_doc("Employee Other Income")
+			employee_other_income.employee = declaration.employee
+			employee_other_income.payroll_period = declaration.payroll_period
+			employee_other_income.company = declaration.company
+			employee_other_income.amount = declaration.income_from_other_sources
+
+			try:
+				employee_other_income.submit()
+			except:
+				pass
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 4296447..c9d7728 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -175,6 +175,20 @@
 			};
 		}
 
+		if (this.frm.fields_dict["items"].grid.get_field('blanket_order')) {
+			this.frm.set_query("blanket_order", "items", function(doc, cdt, cdn) {
+				var item = locals[cdt][cdn];
+				return {
+					query: "erpnext.controllers.queries.get_blanket_orders",
+					filters: {
+						"company": doc.company,
+						"blanket_order_type": doc.doctype === "Sales Order" ? "Selling" : "Purchasing",
+						"item": item.item_code
+					}
+				}
+			});
+		}
+
 	},
 	onload: function() {
 		var me = this;
@@ -288,7 +302,7 @@
 		this.setup_sms();
 		this.setup_quality_inspection();
 		let scan_barcode_field = this.frm.get_field('scan_barcode');
-		if (scan_barcode_field) {
+		if (scan_barcode_field && scan_barcode_field.get_value()) {
 			scan_barcode_field.set_value("");
 			scan_barcode_field.set_new_description("");
 
diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js
index 75c5a82..b223fc5 100644
--- a/erpnext/public/js/utils/dimension_tree_filter.js
+++ b/erpnext/public/js/utils/dimension_tree_filter.js
@@ -24,7 +24,7 @@
 		onload: function(frm) {
 			erpnext.dimension_filters.forEach((dimension) => {
 				frappe.model.with_doctype(dimension['document_type'], () => {
-					if (frappe.meta.has_field(dimension['document_type'], 'is_group')) {
+					if(frappe.meta.has_field(dimension['document_type'], 'is_group')) {
 						frm.set_query(dimension['fieldname'], {
 							"is_group": 0
 						});
@@ -42,19 +42,21 @@
 
 		update_dimension: function(frm) {
 			erpnext.dimension_filters.forEach((dimension) => {
-				if (frm.is_new()) {
-					if (frm.doc.company && Object.keys(default_dimensions || {}).length > 0
+				if(frm.is_new()) {
+					if(frm.doc.company && Object.keys(default_dimensions || {}).length > 0
 						&& default_dimensions[frm.doc.company]) {
 
-						if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
-							frm.set_value(dimension['fieldname'],
-								default_dimensions[frm.doc.company][dimension['document_type']]);
-						}
+						let default_dimension = default_dimensions[frm.doc.company][dimension['document_type']];
 
-						$.each(frm.doc.items || frm.doc.accounts || [], function(i, row) {
-							frappe.model.set_value(row.doctype, row.name, dimension['fieldname'],
-								default_dimensions[frm.doc.company][dimension['document_type']])
-						});
+						if(default_dimension) {
+							if (frappe.meta.has_field(doctype, dimension['fieldname'])) {
+								frm.set_value(dimension['fieldname'], default_dimension);
+							}
+
+							$.each(frm.doc.items || frm.doc.accounts || [], function(i, row) {
+								frappe.model.set_value(row.doctype, row.name, dimension['fieldname'], default_dimension);
+							});
+						}
 					}
 				}
 			});
@@ -76,20 +78,6 @@
 				var row = frappe.get_doc(cdt, cdn);
 				frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
 			});
-		},
-
-		items_add: function(frm, cdt, cdn) {
-			erpnext.dimension_filters.forEach((dimension) => {
-				var row = frappe.get_doc(cdt, cdn);
-				frm.script_manager.copy_from_first_row("items", row, [dimension['fieldname']]);
-			});
-		},
-
-		accounts_add: function(frm, cdt, cdn) {
-			erpnext.dimension_filters.forEach((dimension) => {
-				var row = frappe.get_doc(cdt, cdn);
-				frm.script_manager.copy_from_first_row("accounts", row, [dimension['fieldname']]);
-			});
 		}
 	});
 });
\ No newline at end of file
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/__init__.py b/erpnext/regional/doctype/lower_deduction_certificate/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/doctype/lower_deduction_certificate/__init__.py
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.js b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.js
new file mode 100644
index 0000000..8257bf8
--- /dev/null
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Lower Deduction Certificate', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
new file mode 100644
index 0000000..f48fe6f
--- /dev/null
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.json
@@ -0,0 +1,138 @@
+{
+ "actions": [],
+ "autoname": "field:certificate_no",
+ "creation": "2020-03-10 23:12:10.072631",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "certificate_details_section",
+  "section_code",
+  "fiscal_year",
+  "column_break_3",
+  "certificate_no",
+  "section_break_3",
+  "supplier",
+  "column_break_7",
+  "pan_no",
+  "validity_details_section",
+  "valid_from",
+  "column_break_10",
+  "valid_upto",
+  "section_break_9",
+  "rate",
+  "column_break_14",
+  "certificate_limit"
+ ],
+ "fields": [
+  {
+   "fieldname": "certificate_no",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Certificate No",
+   "reqd": 1,
+   "unique": 1
+  },
+  {
+   "fieldname": "section_code",
+   "fieldtype": "Select",
+   "label": "Section Code",
+   "options": "192\n193\n194\n194A\n194C\n194D\n194H\n194I\n194J\n194LA\n194LBB\n194LBC\n195",
+   "reqd": 1
+  },
+  {
+   "fieldname": "section_break_3",
+   "fieldtype": "Section Break",
+   "label": "Deductee Details"
+  },
+  {
+   "fieldname": "supplier",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Supplier",
+   "options": "Supplier",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "supplier.pan",
+   "fetch_if_empty": 1,
+   "fieldname": "pan_no",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "PAN No",
+   "reqd": 1
+  },
+  {
+   "fieldname": "validity_details_section",
+   "fieldtype": "Section Break",
+   "label": "Validity Details"
+  },
+  {
+   "fieldname": "valid_upto",
+   "fieldtype": "Date",
+   "label": "Valid Upto",
+   "reqd": 1
+  },
+  {
+   "fieldname": "section_break_9",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "rate",
+   "fieldtype": "Percent",
+   "label": "Rate Of TDS As Per Certificate",
+   "reqd": 1
+  },
+  {
+   "fieldname": "certificate_limit",
+   "fieldtype": "Currency",
+   "label": "Certificate Limit",
+   "reqd": 1
+  },
+  {
+   "fieldname": "certificate_details_section",
+   "fieldtype": "Section Break",
+   "label": "Certificate Details"
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "column_break_10",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "column_break_14",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "column_break_7",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "valid_from",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Valid From",
+   "reqd": 1
+  },
+  {
+   "fieldname": "fiscal_year",
+   "fieldtype": "Link",
+   "label": "Fiscal Year",
+   "options": "Fiscal Year",
+   "reqd": 1
+  }
+ ],
+ "links": [],
+ "modified": "2020-04-23 23:04:41.203721",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Lower Deduction Certificate",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
new file mode 100644
index 0000000..e8a8ed8
--- /dev/null
+++ b/erpnext/regional/doctype/lower_deduction_certificate/lower_deduction_certificate.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import getdate
+from frappe.model.document import Document
+from erpnext.accounts.utils import get_fiscal_year
+
+class LowerDeductionCertificate(Document):
+	def validate(self):
+		if getdate(self.valid_upto) < getdate(self.valid_from):
+			frappe.throw(_("Valid Upto date cannot be before Valid From date"))
+
+		fiscal_year = get_fiscal_year(fiscal_year=self.fiscal_year, as_dict=True)
+
+		if not (fiscal_year.year_start_date <= getdate(self.valid_from) \
+			<= fiscal_year.year_end_date):
+			frappe.throw(_("Valid From date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
+
+		if not (fiscal_year.year_start_date <= getdate(self.valid_upto) \
+			<= fiscal_year.year_end_date):
+			frappe.throw(_("Valid Upto date not in Fiscal Year {0}").format(frappe.bold(self.fiscal_year)))
+
diff --git a/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
new file mode 100644
index 0000000..7e95020
--- /dev/null
+++ b/erpnext/regional/doctype/lower_deduction_certificate/test_lower_deduction_certificate.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestLowerDeductionCertificate(unittest.TestCase):
+	pass
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 4be6804..8593966 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -61,7 +61,7 @@
 			)).insert()
 
 def add_permissions():
-	for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report'):
+	for doctype in ('GST HSN Code', 'GST Settings', 'GSTR 3B Report', 'Lower Deduction Certificate'):
 		add_permission(doctype, 'All', 0)
 		for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
 			add_permission(doctype, role, 0)
@@ -531,12 +531,18 @@
 
 def set_salary_components(docs):
 	docs.extend([
-		{'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
-		{'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'},
-		{'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'},
-		{'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'},
-		{'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'},
-		{'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'}
+		{'doctype': 'Salary Component', 'salary_component': 'Professional Tax',
+			'description': 'Professional Tax', 'type': 'Deduction', 'exempted_from_income_tax': 1},
+		{'doctype': 'Salary Component', 'salary_component': 'Provident Fund',
+			'description': 'Provident fund', 'type': 'Deduction', 'is_tax_applicable': 1},
+		{'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance',
+			'description': 'House Rent Allowance', 'type': 'Earning', 'is_tax_applicable': 1},
+		{'doctype': 'Salary Component', 'salary_component': 'Basic',
+			'description': 'Basic', 'type': 'Earning', 'is_tax_applicable': 1},
+		{'doctype': 'Salary Component', 'salary_component': 'Arrear',
+			'description': 'Arrear', 'type': 'Earning', 'is_tax_applicable': 1},
+		{'doctype': 'Salary Component', 'salary_component': 'Leave Encashment',
+			'description': 'Leave Encashment', 'type': 'Earning', 'is_tax_applicable': 1}
 	])
 
 def set_tax_withholding_category(company):
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 0282382..3309858 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -288,7 +288,7 @@
 	})
 
 def get_component_amt_from_salary_slip(employee, salary_structure, basic_component, hra_component):
-	salary_slip = make_salary_slip(salary_structure, employee=employee, for_preview=1)
+	salary_slip = make_salary_slip(salary_structure, employee=employee, for_preview=1, ignore_permissions=True)
 	basic_amt, hra_amt = 0, 0
 	for earning in salary_slip.earnings:
 		if earning.salary_component == basic_component:
@@ -372,7 +372,6 @@
 		return exemptions
 
 def get_ewb_data(dt, dn):
-	dn = dn.split(',')
 
 	ewaybills = []
 	for doc_name in dn:
@@ -453,16 +452,22 @@
 
 @frappe.whitelist()
 def generate_ewb_json(dt, dn):
+	dn = json.loads(dn)
+	return get_ewb_data(dt, dn)
 
-	data = get_ewb_data(dt, dn)
+@frappe.whitelist()
+def download_ewb_json():
+	data = frappe._dict(frappe.local.form_dict)
 
-	frappe.local.response.filecontent = json.dumps(data, indent=4, sort_keys=True)
+	frappe.local.response.filecontent = json.dumps(data['data'], indent=4, sort_keys=True)
 	frappe.local.response.type = 'download'
 
-	if len(data['billLists']) > 1:
+	billList = json.loads(data['data'])['billLists']
+
+	if len(billList) > 1:
 		doc_name = 'Bulk'
 	else:
-		doc_name = dn
+		doc_name = data['docname']
 
 	frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(doc_name, frappe.utils.random_string(5))
 
diff --git a/erpnext/selling/desk_page/retail/retail.json b/erpnext/selling/desk_page/retail/retail.json
index 9f3912d..7b30af2 100644
--- a/erpnext/selling/desk_page/retail/retail.json
+++ b/erpnext/selling/desk_page/retail/retail.json
@@ -17,7 +17,7 @@
  "idx": 0,
  "is_standard": 1,
  "label": "Retail",
- "modified": "2020-04-01 11:28:50.966145",
+ "modified": "2020-04-26 22:42:39.346750",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Retail",
diff --git a/erpnext/selling/doctype/customer/customer_dashboard.py b/erpnext/selling/doctype/customer/customer_dashboard.py
index 654dd48..22e30e3 100644
--- a/erpnext/selling/doctype/customer/customer_dashboard.py
+++ b/erpnext/selling/doctype/customer/customer_dashboard.py
@@ -11,7 +11,8 @@
 		'non_standard_fieldnames': {
 			'Payment Entry': 'party',
 			'Quotation': 'party_name',
-			'Opportunity': 'party_name'
+			'Opportunity': 'party_name',
+			'Bank Account': 'party'
 		},
 		'dynamic_links': {
 			'party_name': ['Customer', 'quotation_to']
@@ -27,7 +28,7 @@
 			},
 			{
 				'label': _('Payments'),
-				'items': ['Payment Entry']
+				'items': ['Payment Entry', 'Bank Account']
 			},
 			{
 				'label': _('Support'),
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 7c47b8a..7cfec5a 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -193,12 +193,23 @@
 	return doclist
 
 def set_expired_status():
-	frappe.db.sql("""
-		UPDATE
-			`tabQuotation` SET `status` = 'Expired'
-		WHERE
-			`status` not in ('Ordered', 'Expired', 'Lost', 'Cancelled') AND `valid_till` < %s
-		""", (nowdate()))
+	# filter out submitted non expired quotations whose validity has been ended
+	cond = "qo.docstatus = 1 and qo.status != 'Expired' and qo.valid_till < %s"
+	# check if those QUO have SO against it
+	so_against_quo = """
+		SELECT 
+			so.name FROM `tabSales Order` so, `tabSales Order Item` so_item
+		WHERE 
+			so_item.docstatus = 1 and so.docstatus = 1
+			and so_item.parent = so.name
+			and so_item.prevdoc_docname = qo.name"""
+
+	# if not exists any SO, set status as Expired
+	frappe.db.sql(
+		"""UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and not exists({so_against_quo})"""
+			.format(cond=cond, so_against_quo=so_against_quo),
+			(nowdate())
+		)
 
 @frappe.whitelist()
 def make_sales_invoice(source_name, target_doc=None):
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 3c1ffe9..45a43c5 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -65,15 +65,6 @@
 			}
 		});
 
-		frm.set_query("blanket_order", "items", function() {
-			return {
-				filters: {
-					"company": frm.doc.company,
-					"docstatus": 1
-				}
-			}
-		});
-
 		erpnext.queries.setup_warehouse_query(frm);
 	},
 
@@ -148,7 +139,7 @@
 					}
 
 					this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create'));
-					
+
 					const order_is_a_sale = ["Sales", "Shopping Cart"].indexOf(doc.order_type) !== -1;
 					const order_is_maintenance = ["Maintenance"].indexOf(doc.order_type) !== -1;
 					// order type has been customised then show all the action buttons
diff --git a/erpnext/stock/doctype/delivery_note/regional/india.js b/erpnext/stock/doctype/delivery_note/regional/india.js
index 0c1ca5c..5e1ff98 100644
--- a/erpnext/stock/doctype/delivery_note/regional/india.js
+++ b/erpnext/stock/doctype/delivery_note/regional/india.js
@@ -3,21 +3,28 @@
 erpnext.setup_auto_gst_taxation('Delivery Note');
 
 frappe.ui.form.on('Delivery Note', {
-    refresh: function(frm) {
-        if(frm.doc.docstatus == 1 && !frm.is_dirty() && !frm.doc.ewaybill) {
+	refresh: function(frm) {
+		if(frm.doc.docstatus == 1 && !frm.is_dirty() && !frm.doc.ewaybill) {
 			frm.add_custom_button('E-Way Bill JSON', () => {
-				var w = window.open(
-					frappe.urllib.get_full_url(
-						"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
-						+ "dt=" + encodeURIComponent(frm.doc.doctype)
-						+ "&dn=" + encodeURIComponent(frm.doc.name)
-					)
-				);
-				if (!w) {
-					frappe.msgprint(__("Please enable pop-ups")); return;
-				}
+				frappe.call({
+					method: 'erpnext.regional.india.utils.generate_ewb_json',
+					args: {
+						'dt': frm.doc.doctype,
+						'dn': [frm.doc.name]
+					},
+					callback: function(r) {
+						if (r.message) {
+							const args = {
+								cmd: 'erpnext.regional.india.utils.download_ewb_json',
+								data: r.message,
+								docname: frm.doc.name
+							};
+							open_url_post(frappe.request.url, args);
+						}
+					}
+				});
 			}, __("Create"));
 		}
-    }
+	}
 })
 
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index a025f06..a6fbb66 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -95,8 +95,6 @@
 		};
 	},
 
-	},
-
 	optimize_route: function (frm) {
 		if (!frm.doc.driver_address) {
 			frappe.throw(__("Cannot Optimize Route as Driver Address is Missing."));
diff --git a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json
index eab08e2..9646f2d 100644
--- a/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json
+++ b/erpnext/stock/doctype/quality_inspection_template/quality_inspection_template.json
@@ -1,186 +1,96 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "field:quality_inspection_template_name", 
- "beta": 0, 
- "creation": "2018-01-24 16:23:41.691127", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:quality_inspection_template_name",
+ "creation": "2018-01-24 16:23:41.691127",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "quality_inspection_template_name",
+  "item_quality_inspection_parameter"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "quality_inspection_template_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Quality Inspection Template Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "quality_inspection_template_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Quality Inspection Template Name",
+   "reqd": 1,
+   "unique": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_quality_inspection_parameter", 
-   "fieldtype": "Table", 
-   "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": "Item Quality Inspection Parameter", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Item Quality Inspection Parameter", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "item_quality_inspection_parameter",
+   "fieldtype": "Table",
+   "label": "Item Quality Inspection Parameter",
+   "options": "Item Quality Inspection Parameter",
+   "reqd": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-02-21 12:05:29.304432", 
- "modified_by": "Administrator", 
- "module": "Stock", 
- "name": "Quality Inspection Template", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "links": [
+  {
+   "group": "Quality Inspection",
+   "link_doctype": "Quality Inspection",
+   "link_fieldname": "quality_inspection_template"
+  }
+ ],
+ "modified": "2020-04-26 20:13:02.810132",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Quality Inspection Template",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Stock User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Stock User",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Quality Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Quality Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Manufacturing User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Manufacturing User",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "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
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index d1048fc..e4412e0 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -215,9 +215,7 @@
 					source_doctype: "Material Request",
 					target: frm,
 					date_field: "schedule_date",
-					setters: {
-						company: frm.doc.company,
-					},
+					setters: {},
 					get_query_filters: {
 						docstatus: 1,
 						material_request_type: ["in", ["Material Transfer", "Material Issue"]],
@@ -312,10 +310,9 @@
 			callback: function(r) {
 				if (!r.exe && r.message){
 					frappe.model.set_value(cdt, cdn, "serial_no", r.message);
-
-					if (callback) {
-						callback();
-					}
+				}
+				if (callback) {
+					callback();
 				}
 			}
 		});
@@ -511,9 +508,10 @@
 			item.amount = flt(item.basic_amount + flt(item.additional_cost),
 				precision("amount", item));
 
-			item.valuation_rate = flt(flt(item.basic_rate)
-				+ (flt(item.additional_cost) / flt(item.transfer_qty)),
-				precision("valuation_rate", item));
+			if (flt(item.transfer_qty)) {
+				item.valuation_rate = flt(flt(item.basic_rate) + (flt(item.additional_cost) / flt(item.transfer_qty)),
+					precision("valuation_rate", item));
+			}
 		}
 
 		refresh_field('items');
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index bdd0bd0..704ae41 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "allow_import": 1,
  "autoname": "naming_series:",
  "creation": "2013-04-09 11:43:55",
@@ -12,7 +13,6 @@
   "stock_entry_type",
   "outgoing_stock_entry",
   "purpose",
-  "company",
   "work_order",
   "purchase_order",
   "delivery_note_no",
@@ -20,6 +20,7 @@
   "pick_list",
   "purchase_receipt_no",
   "col2",
+  "company",
   "posting_date",
   "posting_time",
   "set_posting_time",
@@ -65,6 +66,7 @@
   "dimension_col_break",
   "printing_settings",
   "select_print_heading",
+  "print_settings_col_break",
   "letter_head",
   "more_info",
   "is_opening",
@@ -291,6 +293,7 @@
    "fieldtype": "Section Break"
   },
   {
+   "description": "Sets 'Source Warehouse' in each row of the items table.",
    "fieldname": "from_warehouse",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -320,6 +323,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "description": "Sets 'Target Warehouse' in each row of the items table.",
    "fieldname": "to_warehouse",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -622,12 +626,17 @@
    "label": "Pick List",
    "options": "Pick List",
    "read_only": 1
+  },
+  {
+   "fieldname": "print_settings_col_break",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 1,
  "is_submittable": 1,
- "modified": "2019-09-27 14:38:20.801420",
+ "links": [],
+ "modified": "2020-04-23 12:56:52.881752",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Entry",
diff --git a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
index a848c80..c16a41c 100644
--- a/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
+++ b/erpnext/stock/doctype/stock_entry_detail/stock_entry_detail.json
@@ -14,12 +14,12 @@
   "t_warehouse",
   "sec_break1",
   "item_code",
-  "item_group",
   "col_break2",
   "item_name",
   "section_break_8",
   "description",
   "column_break_10",
+  "item_group",
   "image",
   "image_view",
   "quantity_and_rate",
@@ -178,6 +178,7 @@
    "bold": 1,
    "fieldname": "basic_rate",
    "fieldtype": "Currency",
+   "in_list_view": 1,
    "label": "Basic Rate (as per Stock UOM)",
    "oldfieldname": "incoming_rate",
    "oldfieldtype": "Currency",
@@ -420,6 +421,7 @@
    "options": "Item"
   },
   {
+   "collapsible": 1,
    "fieldname": "reference_section",
    "fieldtype": "Section Break",
    "label": "Reference"
@@ -466,7 +468,6 @@
    "fetch_from": "item_code.item_group",
    "fieldname": "item_group",
    "fieldtype": "Data",
-   "in_list_view": 1,
    "label": "Item Group"
   },
   {
@@ -495,7 +496,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-03-19 12:34:09.836295",
+ "modified": "2020-04-23 19:19:28.539769",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Entry Detail",
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 28d7208..0190f09 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -46,19 +46,6 @@
 			"out_qty": min(sle.actual_qty, 0)
 		})
 
-		# get the name of the item that was produced using this item
-		if sle.voucher_type == "Stock Entry":
-			purpose, work_order, fg_completed_qty = frappe.db.get_value(sle.voucher_type, sle.voucher_no, ["purpose", "work_order", "fg_completed_qty"])
-
-			if purpose == "Manufacture" and work_order:
-				finished_product = frappe.db.get_value("Work Order", work_order, "item_name")
-				finished_qty = fg_completed_qty
-
-				sle.update({
-					"finished_product": finished_product,
-					"finished_qty": finished_qty,
-				})
-
 		data.append(sle)
 
 		if include_uom:
@@ -77,8 +64,6 @@
 		{"label": _("In Qty"), "fieldname": "in_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
 		{"label": _("Out Qty"), "fieldname": "out_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
 		{"label": _("Balance Qty"), "fieldname": "qty_after_transaction", "fieldtype": "Float", "width": 100, "convertible": "qty"},
-		{"label": _("Finished Product"), "fieldname": "finished_product", "width": 100},
-		{"label": _("Finished Qty"), "fieldname": "finished_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
 		{"label": _("Voucher #"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 150},
 		{"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 150},
 		{"label": _("Item Group"), "fieldname": "item_group", "fieldtype": "Link", "options": "Item Group", "width": 100},