Merge branch 'develop' of https://github.com/frappe/erpnext into leave-management
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 0d05cb1..eae937c 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -134,6 +134,12 @@
 					"name": "Employee Leave Balance",
 					"doctype": "Leave Application"
 				},
+				{
+					"type": "report",
+					"is_query_report": True,
+					"name": "Leave Ledger Entry",
+					"doctype": "Leave Ledger Entry"
+				},
 			]
 		},
 		{
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index be9a4fb..7e33a14 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -283,7 +283,9 @@
 		"erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status"
 	],
 	"daily_long": [
-		"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
+		"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
+		"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
+		"erpnext.hr.utils.generate_leave_encashment"
 	],
 	"monthly_long": [
 		"erpnext.accounts.deferred_revenue.convert_deferred_revenue_to_income",
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index 8dd0acf..a41c887 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -24,6 +24,7 @@
   "column_break_18",
   "leave_approver_mandatory_in_leave_application",
   "show_leaves_of_all_department_members_in_calendar",
+  "auto_leave_encashment",
   "hiring_settings",
   "check_vacancies"
  ],
@@ -153,12 +154,18 @@
    "fieldname": "check_vacancies",
    "fieldtype": "Check",
    "label": "Check Vacancies On Job Offer Creation"
+  },
+  {
+   "default": "0",
+   "fieldname": "auto_leave_encashment",
+   "fieldtype": "Check",
+   "label": "Auto Leave Encashment"
   }
  ],
  "icon": "fa fa-cog",
  "idx": 1,
  "issingle": 1,
- "modified": "2019-07-01 18:59:55.256878",
+ "modified": "2019-08-05 13:07:17.993968",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR Settings",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.js b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
index 4b4bfaf..210a73c 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.js
@@ -21,11 +21,41 @@
 		})
 	},
 
+	refresh: function(frm) {
+		if(frm.doc.docstatus === 1 && frm.doc.expired) {
+			var valid_expiry = moment(frappe.datetime.get_today()).isBetween(frm.doc.from_date, frm.doc.to_date);
+			if(valid_expiry) {
+				// expire current allocation
+				frm.add_custom_button(__('Expire Allocation'), function() {
+					frm.trigger("expire_allocation");
+				});
+			}
+		}
+	},
+
+	expire_allocation: function(frm) {
+		frappe.call({
+			method: 'erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.expire_allocation',
+			args: {
+				'allocation': frm.doc,
+				'expiry_date': frappe.datetime.get_today()
+			},
+			freeze: true,
+			callback: function(r){
+				if(!r.exc){
+					frappe.msgprint(__("Allocation Expired!"));
+				}
+				frm.refresh();
+			}
+		});
+	},
+
 	employee: function(frm) {
 		frm.trigger("calculate_total_leaves_allocated");
 	},
 
 	leave_type: function(frm) {
+		frm.trigger("leave_policy");
 		frm.trigger("calculate_total_leaves_allocated");
 	},
 
@@ -33,37 +63,38 @@
 		frm.trigger("calculate_total_leaves_allocated");
 	},
 
-	carry_forwarded_leaves: function(frm) {
+	unused_leaves: function(frm) {
 		frm.set_value("total_leaves_allocated",
-			flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
+			flt(frm.doc.unused_leaves) + flt(frm.doc.new_leaves_allocated));
 	},
 
 	new_leaves_allocated: function(frm) {
 		frm.set_value("total_leaves_allocated",
-			flt(frm.doc.carry_forwarded_leaves) + flt(frm.doc.new_leaves_allocated));
+			flt(frm.doc.unused_leaves) + flt(frm.doc.new_leaves_allocated));
 	},
 
+	leave_policy: function(frm) {
+		if(frm.doc.leave_policy && frm.doc.leave_type) {
+			frappe.db.get_value("Leave Policy Detail",{
+				'parent': frm.doc.leave_policy,
+				'leave_type': frm.doc.leave_type
+			}, 'annual_allocation', (r) => {
+				if (r && !r.exc) frm.set_value("new_leaves_allocated", flt(r.annual_allocation));
+			}, "Leave Policy");
+		}
+	},
 	calculate_total_leaves_allocated: function(frm) {
 		if (cint(frm.doc.carry_forward) == 1 && frm.doc.leave_type && frm.doc.employee) {
 			return frappe.call({
-				method: "erpnext.hr.doctype.leave_allocation.leave_allocation.get_carry_forwarded_leaves",
-				args: {
-					"employee": frm.doc.employee,
-					"date": frm.doc.from_date,
-					"leave_type": frm.doc.leave_type,
-					"carry_forward": frm.doc.carry_forward
-				},
+				method: "set_total_leaves_allocated",
+				doc: frm.doc,
 				callback: function(r) {
-					if (!r.exc && r.message) {
-						frm.set_value('carry_forwarded_leaves', r.message);
-						frm.set_value("total_leaves_allocated",
-							flt(r.message) + flt(frm.doc.new_leaves_allocated));
-					}
+					frm.refresh_fields();
 				}
 			})
 		} else if (cint(frm.doc.carry_forward) == 0) {
-			frm.set_value("carry_forwarded_leaves", 0);
+			frm.set_value("unused_leaves", 0);
 			frm.set_value("total_leaves_allocated", flt(frm.doc.new_leaves_allocated));
 		}
 	}
-})
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
index 6d61fe3..007497e 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json
@@ -1,683 +1,220 @@
 {
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
  "allow_import": 1,
- "allow_rename": 0,
  "autoname": "naming_series:",
- "beta": 0,
  "creation": "2013-02-20 19:10:38",
- "custom": 0,
- "docstatus": 0,
  "doctype": "DocType",
  "document_type": "Setup",
- "editable_grid": 0,
  "engine": "InnoDB",
+ "field_order": [
+  "naming_series",
+  "employee",
+  "employee_name",
+  "department",
+  "column_break1",
+  "leave_type",
+  "from_date",
+  "to_date",
+  "section_break_6",
+  "new_leaves_allocated",
+  "carry_forward",
+  "unused_leaves",
+  "total_leaves_allocated",
+  "total_leaves_encashed",
+  "column_break_10",
+  "compensatory_request",
+  "leave_period",
+  "leave_policy",
+  "carry_forwarded_leaves_count",
+  "expired",
+  "amended_from",
+  "notes",
+  "description"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "default": "",
    "fieldname": "naming_series",
    "fieldtype": "Select",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Series",
-   "length": 0,
    "no_copy": 1,
    "options": "HR-LAL-.YYYY.-",
-   "permlevel": 0,
-   "precision": "",
    "print_hide": 1,
-   "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": 1,
-   "translatable": 0,
-   "unique": 0
+   "set_only_once": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "employee",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
    "in_list_view": 1,
    "in_standard_filter": 1,
    "label": "Employee",
-   "length": 0,
-   "no_copy": 0,
    "oldfieldname": "employee",
    "oldfieldtype": "Link",
    "options": "Employee",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
    "reqd": 1,
-   "search_index": 1,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "search_index": 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",
    "fieldname": "employee_name",
    "fieldtype": "Data",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
    "in_list_view": 1,
-   "in_standard_filter": 0,
    "label": "Employee Name",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
    "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 1,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "search_index": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "employee.department",
    "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
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "column_break1",
    "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,
-   "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,
    "width": "50%"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "leave_type",
    "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": 1,
    "label": "Leave Type",
-   "length": 0,
-   "no_copy": 0,
    "oldfieldname": "leave_type",
    "oldfieldtype": "Link",
    "options": "Leave Type",
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
    "reqd": 1,
-   "search_index": 1,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "search_index": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "from_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": "From 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
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "to_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": "To 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
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "section_break_6",
    "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": "Allocation",
-   "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
+   "label": "Allocation"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 1,
    "bold": 1,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "new_leaves_allocated",
    "fieldtype": "Float",
-   "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": "New Leaves Allocated",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "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
+   "label": "New Leaves Allocated"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
-   "description": "",
+   "default": "0",
    "fieldname": "carry_forward",
    "fieldtype": "Check",
-   "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": "Add unused leaves from previous allocations",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "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
+   "label": "Add unused leaves from previous allocations"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "depends_on": "carry_forward",
-   "fieldname": "carry_forwarded_leaves",
+   "fieldname": "unused_leaves",
    "fieldtype": "Float",
-   "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": "Unused leaves",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "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
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
    "allow_on_submit": 1,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "total_leaves_allocated",
    "fieldtype": "Float",
-   "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 Leaves Allocated",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
    "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "depends_on": "eval:doc.total_leaves_encashed>0",
    "fieldname": "total_leaves_encashed",
    "fieldtype": "Float",
-   "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 Leaves Encashed",
-   "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
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "column_break_10",
-   "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
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "compensatory_request",
    "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": "Compensatory Leave Request",
-   "length": 0,
-   "no_copy": 0,
    "options": "Compensatory Leave Request",
-   "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
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "leave_period",
    "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": 1,
    "label": "Leave Period",
-   "length": 0,
-   "no_copy": 0,
    "options": "Leave Period",
-   "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
+   "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.leave_policy",
+   "fieldname": "leave_policy",
+   "fieldtype": "Link",
+   "in_standard_filter": 1,
+   "label": "Leave Policy",
+   "options": "Leave Policy",
+   "read_only": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "expired",
+   "fieldtype": "Check",
+   "hidden": 1,
+   "in_standard_filter": 1,
+   "label": "Expired",
+   "read_only": 1
+  },
+  {
    "fieldname": "amended_from",
    "fieldtype": "Link",
-   "hidden": 0,
    "ignore_user_permissions": 1,
-   "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,
    "oldfieldname": "amended_from",
    "oldfieldtype": "Data",
    "options": "Leave Allocation",
-   "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
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
    "collapsible": 1,
-   "columns": 0,
    "fieldname": "notes",
    "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": "Notes",
-   "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
+   "label": "Notes"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "description",
    "fieldtype": "Small Text",
-   "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": "Description",
-   "length": 0,
-   "no_copy": 0,
    "oldfieldname": "reason",
    "oldfieldtype": "Small Text",
-   "permlevel": 0,
-   "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,
    "width": "300px"
+  },
+  {
+   "depends_on": "carry_forwarded_leaves_count",
+   "fieldname": "carry_forwarded_leaves_count",
+   "fieldtype": "Float",
+   "label": "Carry Forwarded Leaves",
+   "read_only": 1
   }
  ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
  "icon": "fa fa-ok",
  "idx": 1,
- "image_view": 0,
- "in_create": 0,
  "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-30 11:28:09.360525",
+ "modified": "2019-08-08 15:08:42.440909",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Allocation",
@@ -689,15 +226,10 @@
    "create": 1,
    "delete": 1,
    "email": 1,
-   "export": 0,
-   "if_owner": 0,
-   "import": 0,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "HR User",
-   "set_user_permissions": 0,
    "share": 1,
    "submit": 1,
    "write": 1
@@ -709,28 +241,19 @@
    "delete": 1,
    "email": 1,
    "export": 1,
-   "if_owner": 0,
    "import": 1,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "HR Manager",
-   "set_user_permissions": 0,
    "share": 1,
    "submit": 1,
    "write": 1
   }
  ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
  "search_fields": "employee,employee_name,leave_type,total_leaves_allocated",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
- "timeline_field": "employee",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "timeline_field": "employee"
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index dc270db..296a52c 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -3,11 +3,11 @@
 
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import flt, date_diff, formatdate
+from frappe.utils import flt, date_diff, formatdate, add_days, today, getdate
 from frappe import _
 from frappe.model.document import Document
 from erpnext.hr.utils import set_employee_name, get_leave_period
-from erpnext.hr.doctype.leave_application.leave_application import get_approved_leaves_for_period
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation, create_leave_ledger_entry
 
 class OverlapError(frappe.ValidationError): pass
 class BackDatedAllocationError(frappe.ValidationError): pass
@@ -40,14 +40,18 @@
 				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))
 
-	def on_update_after_submit(self):
-		self.validate_new_leaves_allocated_value()
-		self.set_total_leaves_allocated()
+	def on_submit(self):
+		self.create_leave_ledger_entry()
 
-		frappe.db.set(self,'carry_forwarded_leaves', flt(self.carry_forwarded_leaves))
-		frappe.db.set(self,'total_leaves_allocated',flt(self.total_leaves_allocated))
+		# expire all unused leaves in the ledger on creation of carry forward allocation
+		allocation = get_previous_allocation(self.from_date, self.leave_type, self.employee)
+		if self.carry_forward and allocation:
+			expire_allocation(allocation)
 
-		self.validate_against_leave_applications()
+	def on_cancel(self):
+		self.create_leave_ledger_entry(submit=False)
+		if self.carry_forward:
+			self.set_carry_forwarded_leaves_in_previous_allocation(on_cancel=True)
 
 	def validate_period(self):
 		if date_diff(self.to_date, self.from_date) <= 0:
@@ -87,13 +91,32 @@
 					BackDatedAllocationError)
 
 	def set_total_leaves_allocated(self):
-		self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee,
+		self.unused_leaves = get_carry_forwarded_leaves(self.employee,
 			self.leave_type, self.from_date, self.carry_forward)
 
-		self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + flt(self.new_leaves_allocated)
+		self.total_leaves_allocated = flt(self.unused_leaves) + flt(self.new_leaves_allocated)
+
+		if self.carry_forward:
+			self.maintain_carry_forwarded_leaves()
+			self.set_carry_forwarded_leaves_in_previous_allocation()
 
 		if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
-			frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}".format(self.leave_type)))
+			frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}").format(self.leave_type))
+
+	def maintain_carry_forwarded_leaves(self):
+		''' Reduce the carry forwarded leaves to be within the maximum allowed leaves '''
+		
+		max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
+		if self.new_leaves_allocated <= max_leaves_allowed <= self.total_leaves_allocated:
+			self.unused_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
+			self.total_leaves_allocated = flt(max_leaves_allowed)
+
+	def set_carry_forwarded_leaves_in_previous_allocation(self, on_cancel=False):
+		''' Set carry forwarded leaves in previous allocation '''
+		previous_allocation = get_previous_allocation(self.from_date, self.leave_type, self.employee)
+		if on_cancel:
+			self.unused_leaves = 0.0
+		frappe.db.set_value("Leave Allocation", previous_allocation.name, 'carry_forwarded_leaves_count', self.unused_leaves)
 
 	def validate_total_leaves_allocated(self):
 		# Adding a day to include To Date in the difference
@@ -101,15 +124,37 @@
 		if date_difference < self.total_leaves_allocated:
 			frappe.throw(_("Total allocated leaves are more than days in the period"), OverAllocationError)
 
-	def validate_against_leave_applications(self):
-		leaves_taken = get_approved_leaves_for_period(self.employee, self.leave_type,
-			self.from_date, self.to_date)
+	def create_leave_ledger_entry(self, submit=True):
+		if self.unused_leaves:
+			expiry_days = frappe.db.get_value("Leave Type", self.leave_type, "expire_carry_forwarded_leaves_after_days")
+			end_date = add_days(self.from_date, expiry_days - 1) if expiry_days else self.to_date
+			args = dict(
+				leaves=self.unused_leaves,
+				from_date=self.from_date,
+				to_date= min(getdate(end_date), getdate(self.to_date)),
+				is_carry_forward=1
+			)
+			create_leave_ledger_entry(self, args, submit)
 
-		if flt(leaves_taken) > flt(self.total_leaves_allocated):
-			if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
-				frappe.msgprint(_("Note: Total allocated leaves {0} shouldn't be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken))
-			else:
-				frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError)
+		args = dict(
+			leaves=self.new_leaves_allocated,
+			from_date=self.from_date,
+			to_date=self.to_date,
+			is_carry_forward=0
+		)
+		create_leave_ledger_entry(self, args, submit)
+
+def get_previous_allocation(from_date, leave_type, employee):
+	''' Returns document properties of previous allocation '''
+	return frappe.db.get_value("Leave Allocation",
+		filters={
+			'to_date': ("<", from_date),
+			'leave_type': leave_type,
+			'employee': employee,
+			'docstatus': 1
+		},
+		order_by='to_date DESC',
+		fieldname=['name', 'from_date', 'to_date', 'employee', 'leave_type'], as_dict=1)
 
 def get_leave_allocation_for_period(employee, leave_type, from_date, to_date):
 	leave_allocated = 0
@@ -136,25 +181,28 @@
 
 @frappe.whitelist()
 def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
-	carry_forwarded_leaves = 0
-
-	if carry_forward:
+	''' Returns carry forwarded leaves for the given employee '''
+	unused_leaves = 0.0
+	previous_allocation = get_previous_allocation(date, leave_type, employee)
+	if carry_forward and previous_allocation:
 		validate_carry_forward(leave_type)
+		unused_leaves = get_unused_leaves(employee, leave_type, previous_allocation.from_date, previous_allocation.to_date)
 
-		previous_allocation = frappe.db.sql("""
-			select name, from_date, to_date, total_leaves_allocated
-			from `tabLeave Allocation`
-			where employee=%s and leave_type=%s and docstatus=1 and to_date < %s
-			order by to_date desc limit 1
-		""", (employee, leave_type, date), as_dict=1)
-		if previous_allocation:
-			leaves_taken = get_approved_leaves_for_period(employee, leave_type,
-				previous_allocation[0].from_date, previous_allocation[0].to_date)
+	return unused_leaves
 
-			carry_forwarded_leaves = flt(previous_allocation[0].total_leaves_allocated) - flt(leaves_taken)
-
-	return carry_forwarded_leaves
+def get_unused_leaves(employee, leave_type, from_date, to_date):
+	''' Returns unused leaves between the given period while skipping leave allocation expiry '''
+	leaves = frappe.get_all("Leave Ledger Entry", filters={
+		'employee': employee,
+		'leave_type': leave_type,
+		'from_date': ('>=', from_date),
+		'to_date': ('<=', to_date)
+		}, or_filters={
+			'is_expired': 0,
+			'is_carry_forward': 1
+		}, fields=['sum(leaves) as leaves'])
+	return flt(leaves[0]['leaves'])
 
 def validate_carry_forward(leave_type):
 	if not frappe.db.get_value("Leave Type", leave_type, "is_carry_forward"):
-		frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
+		frappe.throw(_("Leave Type {0} cannot be carry-forwarded").format(leave_type))
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
index 72a1b7c..7456aeb 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_dashboard.py
@@ -12,4 +12,9 @@
                 'items': ['Leave Encashment']
             }
         ],
+        'reports': [
+			{
+				'items': ['Employee Leave Balance']
+			}
+		]
     }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
new file mode 100644
index 0000000..93f7b83
--- /dev/null
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation_list.js
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+// render
+frappe.listview_settings['Leave Allocation'] = {
+	get_indicator: function(doc) {
+		if(doc.status==="Expired") {
+			return [__("Expired"), "darkgrey", "expired, =, 1"];
+		}
+	},
+};
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
index b8f4faf..0ef78f2 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.js
@@ -34,7 +34,7 @@
 		() => assert.equal(today_date, cur_frm.doc.from_date,
 			"from date correctly set"),
 		// check for total leaves
-		() => assert.equal(cur_frm.doc.carry_forwarded_leaves + 2, cur_frm.doc.total_leaves_allocated,
+		() => assert.equal(cur_frm.doc.unused_leaves + 2, cur_frm.doc.total_leaves_allocated,
 			"total leave calculation is correctly set"),
 		() => done()
 	]);
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 3b22eb2..bdba8c9 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -1,12 +1,14 @@
 from __future__ import unicode_literals
 import frappe
 import unittest
-from frappe.utils import getdate
+from frappe.utils import nowdate, add_months, getdate, add_days
+from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation, expire_allocation
 
 class TestLeaveAllocation(unittest.TestCase):
 	def test_overlapping_allocation(self):
 		frappe.db.sql("delete from `tabLeave Allocation`")
-				
+
 		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
 		leaves = [
 			{
@@ -18,7 +20,7 @@
 				"from_date": getdate("2015-10-01"),
 				"to_date": getdate("2015-10-31"),
 				"new_leaves_allocated": 5,
-				"docstatus": 1			
+				"docstatus": 1
 			},
 			{
 				"doctype": "Leave Allocation",
@@ -28,17 +30,17 @@
 				"leave_type": "_Test Leave Type",
 				"from_date": getdate("2015-09-01"),
 				"to_date": getdate("2015-11-30"),
-				"new_leaves_allocated": 5			
+				"new_leaves_allocated": 5
 			}
 		]
 
 		frappe.get_doc(leaves[0]).save()
 		self.assertRaises(frappe.ValidationError, frappe.get_doc(leaves[1]).save)
-		
-	def test_invalid_period(self):		
+
+	def test_invalid_period(self):
 		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
-		
-		d = frappe.get_doc({
+
+		doc = frappe.get_doc({
 			"doctype": "Leave Allocation",
 			"__islocal": 1,
 			"employee": employee.name,
@@ -46,15 +48,15 @@
 			"leave_type": "_Test Leave Type",
 			"from_date": getdate("2015-09-30"),
 			"to_date": getdate("2015-09-1"),
-			"new_leaves_allocated": 5			
+			"new_leaves_allocated": 5
 		})
-		
+
 		#invalid period
-		self.assertRaises(frappe.ValidationError, d.save)
-	
+		self.assertRaises(frappe.ValidationError, doc.save)
+
 	def test_allocated_leave_days_over_period(self):
 		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
-		d = frappe.get_doc({
+		doc = frappe.get_doc({
 			"doctype": "Leave Allocation",
 			"__islocal": 1,
 			"employee": employee.name,
@@ -62,10 +64,102 @@
 			"leave_type": "_Test Leave Type",
 			"from_date": getdate("2015-09-1"),
 			"to_date": getdate("2015-09-30"),
-			"new_leaves_allocated": 35			
+			"new_leaves_allocated": 35
 		})
-		
-		#allocated leave more than period 
-		self.assertRaises(frappe.ValidationError, d.save)
-		
+		#allocated leave more than period
+		self.assertRaises(frappe.ValidationError, doc.save)
+
+	def test_carry_forward_calculation(self):
+		frappe.db.sql("delete from `tabLeave Allocation`")
+		frappe.db.sql("delete from `tabLeave Ledger Entry`")
+		leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
+		leave_type.submit()
+
+		# initial leave allocation
+		leave_allocation = create_leave_allocation(
+			leave_type="_Test_CF_leave",
+			from_date=add_months(nowdate(), -12),
+			to_date=add_months(nowdate(), -1),
+			carry_forward=0)
+		leave_allocation.submit()
+
+		# leave allocation with carry forward from previous allocation
+		leave_allocation_1 = create_leave_allocation(
+			leave_type="_Test_CF_leave",
+			carry_forward=1)
+		leave_allocation_1.submit()
+
+		self.assertEquals(leave_allocation.total_leaves_allocated, leave_allocation_1.unused_leaves)
+
+	def test_carry_forward_leaves_expiry(self):
+		frappe.db.sql("delete from `tabLeave Allocation`")
+		frappe.db.sql("delete from `tabLeave Ledger Entry`")
+		leave_type = create_leave_type(
+			leave_type_name="_Test_CF_leave_expiry",
+			is_carry_forward=1,
+			expire_carry_forwarded_leaves_after_days=90)
+		leave_type.submit()
+
+		# initial leave allocation
+		leave_allocation = create_leave_allocation(
+			leave_type="_Test_CF_leave_expiry",
+			from_date=add_months(nowdate(), -24),
+			to_date=add_months(nowdate(), -12),
+			carry_forward=0)
+		leave_allocation.submit()
+
+		leave_allocation = create_leave_allocation(
+			leave_type="_Test_CF_leave_expiry",
+			from_date=add_days(nowdate(), -90),
+			to_date=add_days(nowdate(), 100),
+			carry_forward=1)
+		leave_allocation.submit()
+
+		# expires all the carry forwarded leaves after 90 days
+		process_expired_allocation()
+
+		# leave allocation with carry forward of only new leaves allocated
+		leave_allocation_1 = create_leave_allocation(
+			leave_type="_Test_CF_leave_expiry",
+			carry_forward=1,
+			from_date=add_months(nowdate(), 6),
+			to_date=add_months(nowdate(), 12))
+		leave_allocation_1.submit()
+
+		self.assertEquals(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
+
+	def test_creation_of_leave_ledger_entry_on_submit(self):
+		frappe.db.sql("delete from `tabLeave Allocation`")
+
+		leave_allocation = create_leave_allocation()
+		leave_allocation.submit()
+
+		leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_allocation.name))
+
+		self.assertEquals(len(leave_ledger_entry), 1)
+		self.assertEquals(leave_ledger_entry[0].employee, leave_allocation.employee)
+		self.assertEquals(leave_ledger_entry[0].leave_type, leave_allocation.leave_type)
+		self.assertEquals(leave_ledger_entry[0].leaves, leave_allocation.new_leaves_allocated)
+
+		# check if leave ledger entry is deleted on cancellation
+		leave_allocation.cancel()
+		self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
+
+def create_leave_allocation(**args):
+	args = frappe._dict(args)
+
+	employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
+	leave_allocation = frappe.get_doc({
+		"doctype": "Leave Allocation",
+		"__islocal": 1,
+		"employee": args.employee or employee.name,
+		"employee_name": args.employee_name or employee.employee_name,
+		"leave_type": args.leave_type or "_Test Leave Type",
+		"from_date": args.from_date or nowdate(),
+		"new_leaves_allocated": args.new_leaves_created or 15,
+		"carry_forward": args.carry_forward or 0,
+		"to_date": args.to_date or add_months(nowdate(), 12)
+	})
+	return leave_allocation
+
 test_dependencies = ["Employee", "Leave Type"]
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 5bce348..1746410 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -49,7 +49,7 @@
 				async: false,
 				args: {
 					employee: frm.doc.employee,
-					date: frm.doc.posting_date
+					date: frm.doc.from_date || frm.doc.posting_date
 				},
 				callback: function(r) {
 					if (!r.exc && r.message['leave_allocation']) {
@@ -60,9 +60,8 @@
 					}
 				}
 			});
-
 			$("div").remove(".form-dashboard-section");
-			let section = frm.dashboard.add_section(
+			frm.dashboard.add_section(
 				frappe.render_template('leave_application_dashboard', {
 					data: leave_details
 				})
@@ -115,6 +114,7 @@
 	},
 
 	from_date: function(frm) {
+		frm.trigger("make_dashboard");
 		frm.trigger("half_day_datepicker");
 		frm.trigger("calculate_total_days");
 	},
@@ -138,12 +138,13 @@
 	},
 
 	get_leave_balance: function(frm) {
-		if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date) {
+		if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type && frm.doc.from_date && frm.doc.to_date) {
 			return frappe.call({
 				method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_balance_on",
 				args: {
 					employee: frm.doc.employee,
 					date: frm.doc.from_date,
+					to_date: frm.doc.to_date,
 					leave_type: frm.doc.leave_type,
 					consider_all_leaves_in_the_allocation_period: true
 				},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json
index b3800e0..cdb1add 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -1,332 +1,332 @@
 {
- "allow_import": 1,
- "autoname": "naming_series:",
- "creation": "2013-02-20 11:18:11",
- "description": "Apply / Approve Leaves",
- "doctype": "DocType",
- "document_type": "Document",
- "engine": "InnoDB",
- "field_order": [
-  "naming_series",
-  "employee",
-  "employee_name",
-  "column_break_4",
-  "leave_type",
-  "department",
-  "leave_balance",
-  "section_break_5",
-  "from_date",
-  "to_date",
-  "half_day",
-  "half_day_date",
-  "total_leave_days",
-  "column_break1",
-  "description",
-  "section_break_7",
-  "leave_approver",
-  "leave_approver_name",
-  "column_break_18",
-  "status",
-  "salary_slip",
-  "sb10",
-  "posting_date",
-  "follow_via_email",
-  "color",
-  "column_break_17",
-  "company",
-  "letter_head",
-  "amended_from"
- ],
- "fields": [
-  {
-   "fieldname": "naming_series",
-   "fieldtype": "Select",
-   "label": "Series",
-   "no_copy": 1,
-   "options": "HR-LAP-.YYYY.-",
-   "print_hide": 1,
-   "reqd": 1,
-   "set_only_once": 1
-  },
-  {
-   "fieldname": "employee",
-   "fieldtype": "Link",
-   "in_global_search": 1,
-   "in_standard_filter": 1,
-   "label": "Employee",
-   "options": "Employee",
-   "reqd": 1,
-   "search_index": 1
-  },
-  {
-   "fieldname": "employee_name",
-   "fieldtype": "Data",
-   "in_global_search": 1,
-   "label": "Employee Name",
-   "read_only": 1
-  },
-  {
-   "fieldname": "column_break_4",
-   "fieldtype": "Column Break"
-  },
-  {
-   "fieldname": "leave_type",
-   "fieldtype": "Link",
-   "ignore_user_permissions": 1,
-   "in_standard_filter": 1,
-   "label": "Leave Type",
-   "options": "Leave Type",
-   "reqd": 1,
-   "search_index": 1
-  },
-  {
-   "fetch_from": "employee.department",
-   "fieldname": "department",
-   "fieldtype": "Link",
-   "label": "Department",
-   "options": "Department",
-   "read_only": 1
-  },
-  {
-   "fieldname": "leave_balance",
-   "fieldtype": "Float",
-   "label": "Leave Balance Before Application",
-   "no_copy": 1,
-   "read_only": 1
-  },
-  {
-   "fieldname": "section_break_5",
-   "fieldtype": "Section Break"
-  },
-  {
-   "fieldname": "from_date",
-   "fieldtype": "Date",
-   "in_list_view": 1,
-   "label": "From Date",
-   "reqd": 1,
-   "search_index": 1
-  },
-  {
-   "fieldname": "to_date",
-   "fieldtype": "Date",
-   "label": "To Date",
-   "reqd": 1,
-   "search_index": 1
-  },
-  {
-   "default": "0",
-   "fieldname": "half_day",
-   "fieldtype": "Check",
-   "label": "Half Day"
-  },
-  {
-   "depends_on": "eval:doc.half_day && (doc.from_date != doc.to_date)",
-   "fieldname": "half_day_date",
-   "fieldtype": "Date",
-   "label": "Half Day Date"
-  },
-  {
-   "fieldname": "total_leave_days",
-   "fieldtype": "Float",
-   "in_list_view": 1,
-   "label": "Total Leave Days",
-   "no_copy": 1,
-   "precision": "1",
-   "read_only": 1
-  },
-  {
-   "fieldname": "column_break1",
-   "fieldtype": "Column Break",
-   "print_width": "50%",
-   "width": "50%"
-  },
-  {
-   "fieldname": "description",
-   "fieldtype": "Small Text",
-   "label": "Reason"
-  },
-  {
-   "fieldname": "section_break_7",
-   "fieldtype": "Section Break"
-  },
-  {
-   "fieldname": "leave_approver",
-   "fieldtype": "Link",
-   "label": "Leave Approver",
-   "options": "User"
-  },
-  {
-   "fieldname": "leave_approver_name",
-   "fieldtype": "Data",
-   "label": "Leave Approver Name",
-   "read_only": 1
-  },
-  {
-   "fieldname": "column_break_18",
-   "fieldtype": "Column Break"
-  },
-  {
-   "default": "Open",
-   "fieldname": "status",
-   "fieldtype": "Select",
-   "in_standard_filter": 1,
-   "label": "Status",
-   "no_copy": 1,
-   "options": "Open\nApproved\nRejected\nCancelled"
-  },
-  {
-   "fieldname": "salary_slip",
-   "fieldtype": "Link",
-   "label": "Salary Slip",
-   "options": "Salary Slip",
-   "print_hide": 1
-  },
-  {
-   "fieldname": "sb10",
-   "fieldtype": "Section Break"
-  },
-  {
-   "default": "Today",
-   "fieldname": "posting_date",
-   "fieldtype": "Date",
-   "label": "Posting Date",
-   "no_copy": 1,
-   "reqd": 1
-  },
-  {
-   "allow_on_submit": 1,
-   "default": "1",
-   "fieldname": "follow_via_email",
-   "fieldtype": "Check",
-   "label": "Follow via Email",
-   "print_hide": 1
-  },
-  {
-   "allow_on_submit": 1,
-   "fieldname": "color",
-   "fieldtype": "Color",
-   "label": "Color",
-   "print_hide": 1
-  },
-  {
-   "fieldname": "column_break_17",
-   "fieldtype": "Column Break"
-  },
-  {
-   "fieldname": "company",
-   "fieldtype": "Link",
-   "label": "Company",
-   "options": "Company",
-   "remember_last_selected_value": 1,
-   "reqd": 1
-  },
-  {
-   "allow_on_submit": 1,
-   "fieldname": "letter_head",
-   "fieldtype": "Link",
-   "ignore_user_permissions": 1,
-   "label": "Letter Head",
-   "options": "Letter Head",
-   "print_hide": 1
-  },
-  {
-   "fieldname": "amended_from",
-   "fieldtype": "Link",
-   "ignore_user_permissions": 1,
-   "label": "Amended From",
-   "no_copy": 1,
-   "options": "Leave Application",
-   "print_hide": 1,
-   "read_only": 1
-  }
- ],
- "icon": "fa fa-calendar",
- "idx": 1,
- "is_submittable": 1,
- "max_attachments": 3,
- "modified": "2019-08-11 19:13:53.603011",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Leave Application",
- "owner": "Administrator",
- "permissions": [
-  {
-   "create": 1,
-   "email": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Employee",
-   "share": 1,
-   "write": 1
-  },
-  {
-   "amend": 1,
-   "cancel": 1,
-   "create": 1,
-   "delete": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "HR Manager",
-   "set_user_permissions": 1,
-   "share": 1,
-   "submit": 1,
-   "write": 1
-  },
-  {
-   "permlevel": 1,
-   "read": 1,
-   "role": "All"
-  },
-  {
-   "amend": 1,
-   "cancel": 1,
-   "create": 1,
-   "delete": 1,
-   "email": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "HR User",
-   "set_user_permissions": 1,
-   "share": 1,
-   "submit": 1,
-   "write": 1
-  },
-  {
-   "amend": 1,
-   "cancel": 1,
-   "delete": 1,
-   "email": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Leave Approver",
-   "share": 1,
-   "submit": 1,
-   "write": 1
-  },
-  {
-   "permlevel": 1,
-   "read": 1,
-   "report": 1,
-   "role": "HR User",
-   "write": 1
-  },
-  {
-   "permlevel": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Leave Approver",
-   "write": 1
-  }
- ],
- "search_fields": "employee,employee_name,leave_type,from_date,to_date,total_leave_days",
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "employee",
- "title_field": "employee_name"
-}
\ No newline at end of file
+   "allow_import": 1,
+   "autoname": "naming_series:",
+   "creation": "2013-02-20 11:18:11",
+   "description": "Apply / Approve Leaves",
+   "doctype": "DocType",
+   "document_type": "Document",
+   "engine": "InnoDB",
+   "field_order": [
+    "naming_series",
+    "employee",
+    "employee_name",
+    "column_break_4",
+    "leave_type",
+    "department",
+    "leave_balance",
+    "section_break_5",
+    "from_date",
+    "to_date",
+    "half_day",
+    "half_day_date",
+    "total_leave_days",
+    "column_break1",
+    "description",
+    "section_break_7",
+    "leave_approver",
+    "leave_approver_name",
+    "column_break_18",
+    "status",
+    "salary_slip",
+    "sb10",
+    "posting_date",
+    "follow_via_email",
+    "color",
+    "column_break_17",
+    "company",
+    "letter_head",
+    "amended_from"
+   ],
+   "fields": [
+    {
+     "fieldname": "naming_series",
+     "fieldtype": "Select",
+     "label": "Series",
+     "no_copy": 1,
+     "options": "HR-LAP-.YYYY.-",
+     "print_hide": 1,
+     "reqd": 1,
+     "set_only_once": 1
+    },
+    {
+     "fieldname": "employee",
+     "fieldtype": "Link",
+     "in_global_search": 1,
+     "in_standard_filter": 1,
+     "label": "Employee",
+     "options": "Employee",
+     "reqd": 1,
+     "search_index": 1
+    },
+    {
+     "fieldname": "employee_name",
+     "fieldtype": "Data",
+     "in_global_search": 1,
+     "label": "Employee Name",
+     "read_only": 1
+    },
+    {
+     "fieldname": "column_break_4",
+     "fieldtype": "Column Break"
+    },
+    {
+     "fieldname": "leave_type",
+     "fieldtype": "Link",
+     "ignore_user_permissions": 1,
+     "in_standard_filter": 1,
+     "label": "Leave Type",
+     "options": "Leave Type",
+     "reqd": 1,
+     "search_index": 1
+    },
+    {
+     "fetch_from": "employee.department",
+     "fieldname": "department",
+     "fieldtype": "Link",
+     "label": "Department",
+     "options": "Department",
+     "read_only": 1
+    },
+    {
+     "fieldname": "leave_balance",
+     "fieldtype": "Float",
+     "label": "Leave Balance Before Application",
+     "no_copy": 1,
+     "read_only": 1
+    },
+    {
+     "fieldname": "section_break_5",
+     "fieldtype": "Section Break"
+    },
+    {
+     "fieldname": "from_date",
+     "fieldtype": "Date",
+     "in_list_view": 1,
+     "label": "From Date",
+     "reqd": 1,
+     "search_index": 1
+    },
+    {
+     "fieldname": "to_date",
+     "fieldtype": "Date",
+     "label": "To Date",
+     "reqd": 1,
+     "search_index": 1
+    },
+    {
+     "default": "0",
+     "fieldname": "half_day",
+     "fieldtype": "Check",
+     "label": "Half Day"
+    },
+    {
+     "depends_on": "eval:doc.half_day && (doc.from_date != doc.to_date)",
+     "fieldname": "half_day_date",
+     "fieldtype": "Date",
+     "label": "Half Day Date"
+    },
+    {
+     "fieldname": "total_leave_days",
+     "fieldtype": "Float",
+     "in_list_view": 1,
+     "label": "Total Leave Days",
+     "no_copy": 1,
+     "precision": "1",
+     "read_only": 1
+    },
+    {
+     "fieldname": "column_break1",
+     "fieldtype": "Column Break",
+     "print_width": "50%",
+     "width": "50%"
+    },
+    {
+     "fieldname": "description",
+     "fieldtype": "Small Text",
+     "label": "Reason"
+    },
+    {
+     "fieldname": "section_break_7",
+     "fieldtype": "Section Break"
+    },
+    {
+     "fieldname": "leave_approver",
+     "fieldtype": "Link",
+     "label": "Leave Approver",
+     "options": "User"
+    },
+    {
+     "fieldname": "leave_approver_name",
+     "fieldtype": "Data",
+     "label": "Leave Approver Name",
+     "read_only": 1
+    },
+    {
+     "fieldname": "column_break_18",
+     "fieldtype": "Column Break"
+    },
+    {
+     "default": "Open",
+     "fieldname": "status",
+     "fieldtype": "Select",
+     "in_standard_filter": 1,
+     "label": "Status",
+     "no_copy": 1,
+     "options": "Open\nApproved\nRejected\nCancelled"
+    },
+    {
+     "fieldname": "sb10",
+     "fieldtype": "Section Break"
+    },
+    {
+     "default": "Today",
+     "fieldname": "posting_date",
+     "fieldtype": "Date",
+     "label": "Posting Date",
+     "no_copy": 1,
+     "reqd": 1
+    },
+    {
+     "fieldname": "company",
+     "fieldtype": "Link",
+     "label": "Company",
+     "options": "Company",
+     "remember_last_selected_value": 1,
+     "reqd": 1
+    },
+    {
+     "allow_on_submit": 1,
+     "default": "1",
+     "fieldname": "follow_via_email",
+     "fieldtype": "Check",
+     "label": "Follow via Email",
+     "print_hide": 1
+    },
+    {
+     "fieldname": "column_break_17",
+     "fieldtype": "Column Break"
+    },
+    {
+     "fieldname": "salary_slip",
+     "fieldtype": "Link",
+     "label": "Salary Slip",
+     "options": "Salary Slip",
+     "print_hide": 1
+    },
+    {
+     "allow_on_submit": 1,
+     "fieldname": "letter_head",
+     "fieldtype": "Link",
+     "ignore_user_permissions": 1,
+     "label": "Letter Head",
+     "options": "Letter Head",
+     "print_hide": 1
+    },
+    {
+     "allow_on_submit": 1,
+     "fieldname": "color",
+     "fieldtype": "Color",
+     "label": "Color",
+     "print_hide": 1
+    },
+    {
+     "fieldname": "amended_from",
+     "fieldtype": "Link",
+     "ignore_user_permissions": 1,
+     "label": "Amended From",
+     "no_copy": 1,
+     "options": "Leave Application",
+     "print_hide": 1,
+     "read_only": 1
+    }
+   ],
+   "icon": "fa fa-calendar",
+   "idx": 1,
+   "is_submittable": 1,
+   "max_attachments": 3,
+   "modified": "2019-08-13 13:32:04.860848",
+   "modified_by": "Administrator",
+   "module": "HR",
+   "name": "Leave Application",
+   "owner": "Administrator",
+   "permissions": [
+    {
+     "create": 1,
+     "email": 1,
+     "print": 1,
+     "read": 1,
+     "report": 1,
+     "role": "Employee",
+     "share": 1,
+     "write": 1
+    },
+    {
+     "amend": 1,
+     "cancel": 1,
+     "create": 1,
+     "delete": 1,
+     "email": 1,
+     "export": 1,
+     "print": 1,
+     "read": 1,
+     "report": 1,
+     "role": "HR Manager",
+     "set_user_permissions": 1,
+     "share": 1,
+     "submit": 1,
+     "write": 1
+    },
+    {
+     "permlevel": 1,
+     "read": 1,
+     "role": "All"
+    },
+    {
+     "amend": 1,
+     "cancel": 1,
+     "create": 1,
+     "delete": 1,
+     "email": 1,
+     "print": 1,
+     "read": 1,
+     "report": 1,
+     "role": "HR User",
+     "set_user_permissions": 1,
+     "share": 1,
+     "submit": 1,
+     "write": 1
+    },
+    {
+     "amend": 1,
+     "cancel": 1,
+     "delete": 1,
+     "email": 1,
+     "print": 1,
+     "read": 1,
+     "report": 1,
+     "role": "Leave Approver",
+     "share": 1,
+     "submit": 1,
+     "write": 1
+    },
+    {
+     "permlevel": 1,
+     "read": 1,
+     "report": 1,
+     "role": "HR User",
+     "write": 1
+    },
+    {
+     "permlevel": 1,
+     "read": 1,
+     "report": 1,
+     "role": "Leave Approver",
+     "write": 1
+    }
+   ],
+   "search_fields": "employee,employee_name,leave_type,from_date,to_date,total_leave_days",
+   "sort_field": "modified",
+   "sort_order": "DESC",
+   "timeline_field": "employee",
+   "title_field": "employee_name"
+  }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 1ef8ee0..0aa8849 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -5,11 +5,12 @@
 import frappe
 from frappe import _
 from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
-	comma_or, get_fullname, add_days, nowdate
+	comma_or, get_fullname, add_days, nowdate, get_datetime_str
 from erpnext.hr.utils import set_employee_name, get_leave_period
 from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
 from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
 
 class LeaveDayBlockedError(frappe.ValidationError): pass
 class OverlapError(frappe.ValidationError): pass
@@ -50,6 +51,7 @@
 
 		# notify leave applier about approval
 		self.notify_employee()
+		self.create_leave_ledger_entry()
 		self.reload()
 
 	def on_cancel(self):
@@ -57,6 +59,7 @@
 		# notify leave applier about cancellation
 		self.notify_employee()
 		self.cancel_attendance()
+		self.create_leave_ledger_entry(submit=False)
 
 	def validate_applicable_after(self):
 		if self.leave_type:
@@ -193,9 +196,9 @@
 				frappe.throw(_("The day(s) on which you are applying for leave are holidays. You need not apply for leave."))
 
 			if not is_lwp(self.leave_type):
-				self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, docname=self.name,
+				self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, self.to_date,
 					consider_all_leaves_in_the_allocation_period=True)
-				if self.status != "Rejected" and self.leave_balance < self.total_leave_days:
+				if self.status != "Rejected" and (self.leave_balance < self.total_leave_days or not self.leave_balance):
 					if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
 						frappe.msgprint(_("Note: There is not enough leave balance for Leave Type {0}")
 							.format(self.leave_type))
@@ -347,6 +350,54 @@
 			except frappe.OutgoingEmailError:
 				pass
 
+	def create_leave_ledger_entry(self, submit=True):
+		expiry_date = get_allocation_expiry(self.employee, self.leave_type,
+			self.to_date, self.from_date)
+
+		lwp = frappe.db.get_value("Leave Type", self.leave_type, "is_lwp")
+
+		if expiry_date:
+			self.create_ledger_entry_for_intermediate_allocation_expiry(expiry_date, submit, lwp)
+		else:
+			args = dict(
+				leaves=self.total_leave_days * -1,
+				from_date=self.from_date,
+				to_date=self.to_date,
+				is_lwp=lwp
+			)
+			create_leave_ledger_entry(self, args, submit)
+
+	def create_ledger_entry_for_intermediate_allocation_expiry(self, expiry_date, submit, lwp):
+		''' splits leave application into two ledger entries to consider expiry of allocation '''
+		args = dict(
+			from_date=self.from_date,
+			to_date=expiry_date,
+			leaves=(date_diff(expiry_date, self.from_date) + 1) * -1,
+			is_lwp=lwp
+		)
+		create_leave_ledger_entry(self, args, submit)
+
+		if getdate(expiry_date) != getdate(self.to_date):
+			start_date = add_days(expiry_date, 1)
+			args.update(dict(
+				from_date=start_date,
+				to_date=self.to_date,
+				leaves=date_diff(self.to_date, expiry_date) * -1
+			))
+			create_leave_ledger_entry(self, args, submit)
+
+def get_allocation_expiry(employee, leave_type, to_date, from_date):
+	''' Returns expiry of carry forward allocation in leave ledger entry '''
+	expiry =  frappe.get_all("Leave Ledger Entry",
+		filters={
+			'employee': employee,
+			'leave_type': leave_type,
+			'is_carry_forward': 1,
+			'transaction_type': 'Leave Allocation',
+			'to_date': ['between', (from_date, to_date)]
+		},fields=['to_date'])
+	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):
 	number_of_days = 0
@@ -364,14 +415,16 @@
 
 @frappe.whitelist()
 def get_leave_details(employee, date):
-	allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+	allocation_records = get_leave_allocation_records(employee, date)
 	leave_allocation = {}
 	for d in allocation_records:
 		allocation = allocation_records.get(d, frappe._dict())
-		date = allocation.to_date
-		leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, date, status="Approved")
-		leaves_pending = get_leaves_for_period(employee, d, allocation.from_date, date, status="Open")
-		remaining_leaves = allocation.total_leaves_allocated - leaves_taken - leaves_pending
+		remaining_leaves = get_leave_balance_on(employee, d, date, to_date = allocation.to_date,
+			consider_all_leaves_in_the_allocation_period=True)
+		end_date = allocation.to_date
+		leaves_taken = get_leaves_for_period(employee, d, allocation.from_date, end_date) * -1
+		leaves_pending = get_pending_leaves_for_period(employee, d, allocation.from_date, end_date)
+
 		leave_allocation[d] = {
 			"total_leaves": allocation.total_leaves_allocated,
 			"leaves_taken": leaves_taken,
@@ -386,27 +439,131 @@
 	return ret
 
 @frappe.whitelist()
-def get_leave_balance_on(employee, leave_type, date, allocation_records=None, docname=None,
-		consider_all_leaves_in_the_allocation_period=False, consider_encashed_leaves=True):
+def get_leave_balance_on(employee, leave_type, date, to_date=nowdate(), consider_all_leaves_in_the_allocation_period=False):
+	'''
+		Returns leave balance till date
+		:param employee: employee name
+		:param leave_type: leave type
+		:param date: date to check balance on
+		:param to_date: future date to check for allocation expiry
+		:param consider_all_leaves_in_the_allocation_period: consider all leaves taken till the allocation end date
+	'''
 
-	if allocation_records == None:
-		allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+	allocation_records = get_leave_allocation_records(employee, date, leave_type)
 	allocation = allocation_records.get(leave_type, frappe._dict())
-	if consider_all_leaves_in_the_allocation_period:
-		date = allocation.to_date
-	leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, date, status="Approved", docname=docname)
-	leaves_encashed = 0
-	if frappe.db.get_value("Leave Type", leave_type, 'allow_encashment') and consider_encashed_leaves:
-		leaves_encashed = flt(allocation.total_leaves_encashed)
 
-	return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
+	end_date = allocation.to_date if consider_all_leaves_in_the_allocation_period else date
+	expiry = get_allocation_expiry(employee, leave_type, to_date, date)
 
-def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
-	leave_applications = frappe.db.sql("""
-		select name, employee, leave_type, from_date, to_date, total_leave_days
-		from `tabLeave Application`
+	leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, end_date)
+
+	return get_remaining_leaves(allocation, leaves_taken, date, expiry)
+
+def get_leave_allocation_records(employee, date, leave_type=None):
+	''' returns the total allocated leaves and carry forwarded leaves based on ledger entries '''
+
+	conditions = ("and leave_type='%s'" % leave_type) if leave_type else ""
+	allocation_details = frappe.db.sql("""
+		SELECT
+			SUM(CASE WHEN is_carry_forward = 1 THEN leaves ELSE 0 END) as cf_leaves,
+			SUM(CASE WHEN is_carry_forward = 0 THEN leaves ELSE 0 END) as new_leaves,
+			MIN(from_date) as from_date,
+			MAX(to_date) as to_date,
+			leave_type
+		FROM `tabLeave Ledger Entry`
+		WHERE
+			from_date <= %(date)s
+			AND to_date >= %(date)s
+			AND docstatus=1
+			AND transaction_type="Leave Allocation"
+			AND employee=%(employee)s
+			AND is_expired=0
+			AND is_lwp=0
+			{0}
+		GROUP BY employee, leave_type
+	""".format(conditions), dict(date=date, employee=employee), as_dict=1) #nosec
+
+	allocated_leaves = frappe._dict()
+	for d in allocation_details:
+		allocated_leaves.setdefault(d.leave_type, frappe._dict({
+			"from_date": d.from_date,
+			"to_date": d.to_date,
+			"total_leaves_allocated": flt(d.cf_leaves) + flt(d.new_leaves),
+			"unused_leaves": d.cf_leaves,
+			"new_leaves_allocated": d.new_leaves,
+			"leave_type": d.leave_type
+		}))
+	return allocated_leaves
+
+def get_pending_leaves_for_period(employee, leave_type, from_date, to_date):
+	''' Returns leaves that are pending approval '''
+	return frappe.db.get_value("Leave Application",
+		filters={
+			"employee": employee,
+			"leave_type": leave_type,
+			"from_date": ("<=", from_date),
+			"to_date": (">=", to_date),
+			"status": "Open"
+		}, fieldname=['SUM(total_leave_days)']) or flt(0)
+
+def get_remaining_leaves(allocation, leaves_taken, date, expiry):
+	''' Returns minimum leaves remaining after comparing with remaining days for allocation expiry '''
+	def _get_remaining_leaves(allocated_leaves, end_date):
+		remaining_leaves = flt(allocated_leaves) + flt(leaves_taken)
+
+		if remaining_leaves > 0:
+			remaining_days = date_diff(end_date, date) + 1
+			remaining_leaves = min(remaining_days, remaining_leaves)
+
+		return remaining_leaves
+
+	total_leaves = allocation.total_leaves_allocated
+
+	if expiry and allocation.unused_leaves:
+		remaining_leaves = _get_remaining_leaves(allocation.unused_leaves, expiry)
+
+		total_leaves = flt(allocation.new_leaves_allocated) + flt(remaining_leaves)
+
+	return _get_remaining_leaves(total_leaves, allocation.to_date)
+
+def get_leaves_for_period(employee, leave_type, from_date, to_date):
+	leave_entries = get_leave_entries(employee, leave_type, from_date, to_date)
+	leave_days = 0
+
+	for leave_entry in leave_entries:
+		inclusive_period = leave_entry.from_date >= getdate(from_date) and leave_entry.to_date <= getdate(to_date)
+
+		if  inclusive_period and leave_entry.transaction_type == 'Leave Encashment':
+			leave_days += leave_entry.leaves
+
+		elif inclusive_period and leave_entry.transaction_type == 'Leave Allocation' \
+			and not skip_expiry_leaves(leave_entry, to_date):
+			leave_days += leave_entry.leaves
+
+		else:
+			if leave_entry.from_date < getdate(from_date):
+				leave_entry.from_date = from_date
+			if leave_entry.to_date > getdate(to_date):
+				leave_entry.to_date = to_date
+
+			leave_days += get_number_of_leave_days(employee, leave_type,
+				leave_entry.from_date, leave_entry.to_date) * -1
+
+	return leave_days
+
+def skip_expiry_leaves(leave_entry, date):
+	''' Checks whether the expired leaves coincide with the to_date of leave balance check '''
+	end_date = frappe.db.get_value("Leave Allocation", {'name': leave_entry.transaction_name}, ['to_date'])
+	return True if end_date == date and not leave_entry.is_carry_forward else False
+
+def get_leave_entries(employee, leave_type, from_date, to_date):
+	''' Returns leave entries between from_date and to_date '''
+	return frappe.db.sql("""
+		select employee, leave_type, from_date, to_date, leaves, transaction_type, is_carry_forward
+		from `tabLeave Ledger Entry`
 		where employee=%(employee)s and leave_type=%(leave_type)s
-			and status = %(status)s and docstatus != 2
+			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))
@@ -414,43 +571,8 @@
 		"from_date": from_date,
 		"to_date": to_date,
 		"employee": employee,
-		"status": status,
 		"leave_type": leave_type
 	}, as_dict=1)
-	leave_days = 0
-	for leave_app in leave_applications:
-		if docname and leave_app.name == docname:
-			continue
-		if leave_app.from_date >= getdate(from_date) and leave_app.to_date <= getdate(to_date):
-			leave_days += leave_app.total_leave_days
-		else:
-			if leave_app.from_date < getdate(from_date):
-				leave_app.from_date = from_date
-			if leave_app.to_date > getdate(to_date):
-				leave_app.to_date = to_date
-
-			leave_days += get_number_of_leave_days(employee, leave_type,
-				leave_app.from_date, leave_app.to_date)
-
-	return leave_days
-
-def get_leave_allocation_records(date, employee=None):
-	conditions = (" and employee='%s'" % employee) if employee else ""
-
-	leave_allocation_records = frappe.db.sql("""
-		select employee, leave_type, total_leaves_allocated, total_leaves_encashed, from_date, to_date
-		from `tabLeave Allocation`
-		where %s between from_date and to_date and docstatus=1 {0}""".format(conditions), (date), as_dict=1)
-
-	allocated_leaves = frappe._dict()
-	for d in leave_allocation_records:
-		allocated_leaves.setdefault(d.employee, frappe._dict()).setdefault(d.leave_type, frappe._dict({
-			"from_date": d.from_date,
-			"to_date": d.to_date,
-			"total_leaves_allocated": d.total_leaves_allocated,
-			"total_leaves_encashed":d.total_leaves_encashed
-		}))
-	return allocated_leaves
 
 @frappe.whitelist()
 def get_holidays(employee, from_date, to_date):
@@ -629,4 +751,4 @@
 
 	if department:
 		return frappe.db.get_value('Department Approver', {'parent': department,
-			'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
+			'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
new file mode 100644
index 0000000..8075b7b
--- /dev/null
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
@@ -0,0 +1,14 @@
+from __future__ import unicode_literals
+
+from frappe import _
+
+
+def get_data():
+	return {
+        'reports': [
+			{
+                'label': _('Reports'),
+				'items': ['Employee Leave Balance']
+			}
+		]
+    }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index d3dcca1..ad141a5 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -7,7 +7,9 @@
 
 from erpnext.hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError, NotAnOptionalHoliday, get_leave_balance_on
 from frappe.permissions import clear_user_permissions_for_doctype
-from frappe.utils import add_days, nowdate, now_datetime, getdate
+from frappe.utils import add_days, nowdate, now_datetime, getdate, add_months
+from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
+from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
 
 test_dependencies = ["Leave Allocation", "Leave Block List"]
 
@@ -17,6 +19,7 @@
   "doctype": "Leave Application",
   "employee": "_T-Employee-00001",
   "from_date": "2013-05-01",
+  "description": "_Test Reason",
   "leave_type": "_Test Leave Type",
   "posting_date": "2013-01-02",
   "to_date": "2013-05-05"
@@ -26,6 +29,7 @@
   "doctype": "Leave Application",
   "employee": "_T-Employee-00002",
   "from_date": "2013-05-01",
+  "description": "_Test Reason",
   "leave_type": "_Test Leave Type",
   "posting_date": "2013-01-02",
   "to_date": "2013-05-05"
@@ -35,6 +39,7 @@
   "doctype": "Leave Application",
   "employee": "_T-Employee-00001",
   "from_date": "2013-01-15",
+  "description": "_Test Reason",
   "leave_type": "_Test Leave Type LWP",
   "posting_date": "2013-01-02",
   "to_date": "2013-01-15"
@@ -44,8 +49,8 @@
 
 class TestLeaveApplication(unittest.TestCase):
 	def setUp(self):
-		for dt in ["Leave Application", "Leave Allocation", "Salary Slip"]:
-			frappe.db.sql("delete from `tab%s`" % dt)
+		for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Leave Ledger Entry"]:
+			frappe.db.sql("DELETE FROM `tab%s`" % dt) #nosec
 
 	@classmethod
 	def setUpClass(cls):
@@ -268,13 +273,14 @@
 			doctype = 'Leave Application',
 			employee = employee.name,
 			company = '_Test Company',
+			description = "_Test Reason",
 			leave_type = leave_type,
 			from_date = date,
 			to_date = date,
 		))
 
 		# can only apply on optional holidays
-		self.assertTrue(NotAnOptionalHoliday, leave_application.insert)
+		self.assertRaises(NotAnOptionalHoliday, leave_application.insert)
 
 		leave_application.from_date = today
 		leave_application.to_date = today
@@ -285,7 +291,6 @@
 		# check leave balance is reduced
 		self.assertEqual(get_leave_balance_on(employee.name, leave_type, today), 9)
 
-
 	def test_leaves_allowed(self):
 		employee = get_employee()
 		leave_period = get_leave_period()
@@ -301,24 +306,25 @@
 		allocate_leaves(employee, leave_period, leave_type.name, 5)
 
 		leave_application = frappe.get_doc(dict(
-		doctype = 'Leave Application',
+			doctype = 'Leave Application',
 			employee = employee.name,
 			leave_type = leave_type.name,
+			description = "_Test Reason",
 			from_date = date,
 			to_date = add_days(date, 2),
 			company = "_Test Company",
 			docstatus = 1,
             status = "Approved"
 		))
-
-		self.assertTrue(leave_application.insert())
+		leave_application.submit()
 
 		leave_application = frappe.get_doc(dict(
 			doctype = 'Leave Application',
 			employee = employee.name,
 			leave_type = leave_type.name,
+			description = "_Test Reason",
 			from_date = add_days(date, 4),
-			to_date = add_days(date, 7),
+			to_date = add_days(date, 8),
 			company = "_Test Company",
 			docstatus = 1,
             status = "Approved"
@@ -342,6 +348,7 @@
 			doctype = 'Leave Application',
 			employee = employee.name,
 			leave_type = leave_type.name,
+			description = "_Test Reason",
 			from_date = date,
 			to_date = add_days(date, 4),
 			company = "_Test Company",
@@ -363,6 +370,7 @@
 		doctype = 'Leave Application',
 			employee = employee.name,
 			leave_type = leave_type_1.name,
+			description = "_Test Reason",
 			from_date = date,
 			to_date = add_days(date, 4),
 			company = "_Test Company",
@@ -392,6 +400,7 @@
 			doctype = 'Leave Application',
 			employee = employee.name,
 			leave_type = leave_type.name,
+			description = "_Test Reason",
 			from_date = date,
 			to_date = add_days(date, 4),
 			company = "_Test Company",
@@ -401,6 +410,18 @@
 
 		self.assertRaises(frappe.ValidationError, leave_application.insert)
 
+	def test_leave_balance_near_allocaton_expiry(self):
+		employee = get_employee()
+		leave_type = create_leave_type(
+			leave_type_name="_Test_CF_leave_expiry",
+			is_carry_forward=1,
+			expire_carry_forwarded_leaves_after_days=90)
+		leave_type.submit()
+
+		create_carry_forwarded_allocation(employee, leave_type)
+
+		self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, nowdate(), add_days(nowdate(), 8)), 21)
+
 	def test_earned_leave(self):
 		leave_period = get_leave_period()
 		employee = get_employee()
@@ -444,9 +465,10 @@
 		allocation.insert(ignore_permissions=True)
 		allocation.submit()
 		leave_application = frappe.get_doc(dict(
-		doctype = 'Leave Application',
+			doctype = 'Leave Application',
 			employee = employee.name,
 			leave_type = leave_type,
+			description = "_Test Reason",
 			from_date = '2018-10-02',
 			to_date = '2018-10-02',
 			company = '_Test Company',
@@ -457,9 +479,103 @@
 		leave_application.submit()
 		self.assertEqual(leave_application.docstatus, 1)
 
-def make_allocation_record(employee=None, leave_type=None):
-	frappe.db.sql("delete from `tabLeave Allocation`")
+	def test_creation_of_leave_ledger_entry_on_submit(self):
+		employee = get_employee()
 
+		leave_type = create_leave_type(leave_type_name = 'Test Leave Type 1')
+		leave_type.save()
+
+		leave_allocation = create_leave_allocation(employee=employee.name, employee_name=employee.employee_name,
+			leave_type=leave_type.name)
+		leave_allocation.submit()
+
+		leave_application = frappe.get_doc(dict(
+			doctype = 'Leave Application',
+			employee = employee.name,
+			leave_type = leave_type.name,
+			from_date = add_days(nowdate(), 1),
+			to_date = add_days(nowdate(), 4),
+			description = "_Test Reason",
+			company = "_Test Company",
+			docstatus = 1,
+            status = "Approved"
+		))
+		leave_application.submit()
+		leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_application.name))
+
+		self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
+		self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+		self.assertEquals(leave_ledger_entry[0].leaves, leave_application.total_leave_days * -1)
+
+		# check if leave ledger entry is deleted on cancellation
+		leave_application.cancel()
+		self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_application.name}))
+
+	def test_ledger_entry_creation_on_intermediate_allocation_expiry(self):
+		employee = get_employee()
+		leave_type = create_leave_type(
+			leave_type_name="_Test_CF_leave_expiry",
+			is_carry_forward=1,
+			expire_carry_forwarded_leaves_after_days=90)
+		leave_type.submit()
+
+		create_carry_forwarded_allocation(employee, leave_type)
+
+		leave_application = frappe.get_doc(dict(
+			doctype = 'Leave Application',
+			employee = employee.name,
+			leave_type = leave_type.name,
+			from_date = add_days(nowdate(), -3),
+			to_date = add_days(nowdate(), 7),
+			description = "_Test Reason",
+			company = "_Test Company",
+			docstatus = 1,
+            status = "Approved"
+		))
+		leave_application.submit()
+
+		leave_ledger_entry = frappe.get_all('Leave Ledger Entry', '*', filters=dict(transaction_name=leave_application.name))
+
+		self.assertEquals(len(leave_ledger_entry), 2)
+		self.assertEquals(leave_ledger_entry[0].employee, leave_application.employee)
+		self.assertEquals(leave_ledger_entry[0].leave_type, leave_application.leave_type)
+		self.assertEquals(leave_ledger_entry[0].leaves, -9)
+		self.assertEquals(leave_ledger_entry[1].leaves, -2)
+
+	def test_leave_application_creation_after_expiry(self):
+		# test leave balance for carry forwarded allocation
+		employee = get_employee()
+		leave_type = create_leave_type(
+			leave_type_name="_Test_CF_leave_expiry",
+			is_carry_forward=1,
+			expire_carry_forwarded_leaves_after_days=90)
+		leave_type.submit()
+
+		create_carry_forwarded_allocation(employee, leave_type)
+
+		self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
+
+def create_carry_forwarded_allocation(employee, leave_type):
+		# initial leave allocation
+		leave_allocation = create_leave_allocation(
+			leave_type="_Test_CF_leave_expiry",
+			employee=employee.name,
+			employee_name=employee.employee_name,
+			from_date=add_months(nowdate(), -24),
+			to_date=add_months(nowdate(), -12),
+			carry_forward=0)
+		leave_allocation.submit()
+
+		leave_allocation = create_leave_allocation(
+			leave_type="_Test_CF_leave_expiry",
+			employee=employee.name,
+			employee_name=employee.employee_name,
+			from_date=add_days(nowdate(), -84),
+			to_date=add_days(nowdate(), 100),
+			carry_forward=1)
+		leave_allocation.submit()
+
+def make_allocation_record(employee=None, leave_type=None):
 	allocation = frappe.get_doc({
 		"doctype": "Leave Allocation",
 		"employee": employee or "_T-Employee-00001",
@@ -513,4 +629,4 @@
 		"docstatus": 1
 	}).insert()
 
-	allocate_leave.submit()
+	allocate_leave.submit()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 9944bc5..42f0179 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -10,6 +10,8 @@
 from erpnext.hr.utils import set_employee_name
 from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
 from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
+from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
+from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves
 
 class LeaveEncashment(Document):
 	def validate(self):
@@ -25,7 +27,7 @@
 
 	def on_submit(self):
 		if not self.leave_allocation:
-			self.leave_allocation = self.get_leave_allocation()
+			self.leave_allocation = self.get_leave_allocation().get('name')
 		additional_salary = frappe.new_doc("Additional Salary")
 		additional_salary.company = frappe.get_value("Employee", self.employee, "company")
 		additional_salary.employee = self.employee
@@ -40,6 +42,8 @@
 		frappe.db.set_value("Leave Allocation", self.leave_allocation, "total_leaves_encashed",
 				frappe.db.get_value('Leave Allocation', self.leave_allocation, 'total_leaves_encashed') + self.encashable_days)
 
+		self.create_leave_ledger_entry()
+
 	def on_cancel(self):
 		if self.additional_salary:
 			frappe.get_doc("Additional Salary", self.additional_salary).cancel()
@@ -48,6 +52,7 @@
 		if self.leave_allocation:
 			frappe.db.set_value("Leave Allocation", self.leave_allocation, "total_leaves_encashed",
 				frappe.db.get_value('Leave Allocation', self.leave_allocation, 'total_leaves_encashed') - self.encashable_days)
+		self.create_leave_ledger_entry(submit=False)
 
 	def get_leave_details_for_encashment(self):
 		salary_structure = get_assigned_salary_structure(self.employee, self.encashment_date or getdate(nowdate()))
@@ -57,8 +62,10 @@
 		if not frappe.db.get_value("Leave Type", self.leave_type, 'allow_encashment'):
 			frappe.throw(_("Leave Type {0} is not encashable").format(self.leave_type))
 
-		self.leave_balance = get_leave_balance_on(self.employee, self.leave_type,
-			self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True)
+		allocation = self.get_leave_allocation()
+
+		self.leave_balance = allocation.total_leaves_allocated - allocation.carry_forwarded_leaves_count\
+			- get_unused_leaves(self.employee, self.leave_type, allocation.from_date, self.encashment_date)
 
 		encashable_days = self.leave_balance - frappe.db.get_value('Leave Type', self.leave_type, 'encashment_threshold_days')
 		self.encashable_days = encashable_days if encashable_days > 0 else 0
@@ -66,12 +73,47 @@
 		per_day_encashment = frappe.db.get_value('Salary Structure', salary_structure , 'leave_encashment_amount_per_day')
 		self.encashment_amount = self.encashable_days * per_day_encashment if per_day_encashment > 0 else 0
 
-		self.leave_allocation = self.get_leave_allocation()
+		self.leave_allocation = allocation.name
 		return True
 
 	def get_leave_allocation(self):
-		leave_allocation = frappe.db.sql("""select name from `tabLeave Allocation` where '{0}'
+		leave_allocation = frappe.db.sql("""select name, to_date, total_leaves_allocated, carry_forwarded_leaves_count from `tabLeave Allocation` where '{0}'
 		between from_date and to_date and docstatus=1 and leave_type='{1}'
-		and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee))
+		and employee= '{2}'""".format(self.encashment_date or getdate(nowdate()), self.leave_type, self.employee), as_dict=1) #nosec
 
-		return leave_allocation[0][0] if leave_allocation else None
+		return leave_allocation[0] if leave_allocation else None
+
+	def create_leave_ledger_entry(self, submit=True):
+		args = frappe._dict(
+			leaves=self.encashable_days * -1,
+			from_date=self.encashment_date,
+			to_date=self.encashment_date,
+			is_carry_forward=0
+		)
+		create_leave_ledger_entry(self, args, submit)
+
+		# create reverse entry for expired leaves
+		to_date = self.get_leave_allocation().get('to_date')
+		if to_date < getdate(nowdate()):
+			args = frappe._dict(
+				leaves=self.encashable_days,
+				from_date=to_date,
+				to_date=to_date,
+				is_carry_forward=0
+			)
+			create_leave_ledger_entry(self, args, submit)
+
+
+def create_leave_encashment(leave_allocation):
+	''' Creates leave encashment for the given allocations '''
+	for allocation in leave_allocation:
+		if not get_assigned_salary_structure(allocation.employee, allocation.to_date):
+			continue
+		leave_encashment = frappe.get_doc(dict(
+			doctype="Leave Encashment",
+			leave_period=allocation.leave_period,
+			employee=allocation.employee,
+			leave_type=allocation.leave_type,
+			encashment_date=allocation.to_date
+		))
+		leave_encashment.insert(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
index ef5c2aa..e5bd170 100644
--- a/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/test_leave_encashment.py
@@ -9,42 +9,43 @@
 from erpnext.hr.doctype.employee.test_employee import make_employee
 from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure
 from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
+from erpnext.hr.doctype.leave_policy.test_leave_policy import create_leave_policy\
 
 test_dependencies = ["Leave Type"]
 
 class TestLeaveEncashment(unittest.TestCase):
 	def setUp(self):
 		frappe.db.sql('''delete from `tabLeave Period`''')
-	def test_leave_balance_value_and_amount(self):
-		employee = "test_employee_encashment@salary.com"
-		leave_type = "_Test Leave Type Encashment"
+		frappe.db.sql('''delete from `tabLeave Allocation`''')
+		frappe.db.sql('''delete from `tabLeave Ledger Entry`''')
+		frappe.db.sql('''delete from `tabAdditional Salary`''')
 
 		# create the leave policy
-		leave_policy = frappe.get_doc({
-			"doctype": "Leave Policy",
-			"leave_policy_details": [{
-				"leave_type": leave_type,
-				"annual_allocation": 10
-			}]
-		}).insert()
+		leave_policy = create_leave_policy(
+			leave_type="_Test Leave Type Encashment",
+			annual_allocation=10)
 		leave_policy.submit()
 
 		# create employee, salary structure and assignment
-		employee = make_employee(employee)
-		frappe.db.set_value("Employee", employee, "leave_policy", leave_policy.name) 
-		salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", employee,
+		self.employee = make_employee("test_employee_encashment@example.com")
+
+		frappe.db.set_value("Employee", self.employee, "leave_policy", leave_policy.name)
+
+		salary_structure = make_salary_structure("Salary Structure for Encashment", "Monthly", self.employee,
 			other_details={"leave_encashment_amount_per_day": 50})
 
 		# create the leave period and assign the leaves
-		leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
-		leave_period.grant_leave_allocation(employee=employee)
+		self.leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3))
+		self.leave_period.grant_leave_allocation(employee=self.employee)
 
+	def test_leave_balance_value_and_amount(self):
+		frappe.db.sql('''delete from `tabLeave Encashment`''')
 		leave_encashment = frappe.get_doc(dict(
-			doctype = 'Leave Encashment',
-			employee = employee,
-			leave_type = leave_type,
-			leave_period = leave_period.name,
-			payroll_date = today()
+			doctype='Leave Encashment',
+			employee=self.employee,
+			leave_type="_Test Leave Type Encashment",
+			leave_period=self.leave_period.name,
+			payroll_date=today()
 		)).insert()
 
 		self.assertEqual(leave_encashment.leave_balance, 10)
@@ -53,3 +54,26 @@
 
 		leave_encashment.submit()
 		self.assertTrue(frappe.db.get_value("Leave Encashment", leave_encashment.name, "additional_salary"))
+
+	def test_creation_of_leave_ledger_entry_on_submit(self):
+		frappe.db.sql('''delete from `tabLeave Encashment`''')
+		leave_encashment = frappe.get_doc(dict(
+			doctype='Leave Encashment',
+			employee=self.employee,
+			leave_type="_Test Leave Type Encashment",
+			leave_period=self.leave_period.name,
+			payroll_date=today()
+		)).insert()
+
+		leave_encashment.submit()
+
+		leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=dict(transaction_name=leave_encashment.name))
+
+		self.assertEquals(len(leave_ledger_entry), 1)
+		self.assertEquals(leave_ledger_entry[0].employee, leave_encashment.employee)
+		self.assertEquals(leave_ledger_entry[0].leave_type, leave_encashment.leave_type)
+		self.assertEquals(leave_ledger_entry[0].leaves, leave_encashment.encashable_days *  -1)
+
+		# check if leave ledger entry is deleted on cancellation
+		leave_encashment.cancel()
+		self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_encashment.name}))
diff --git a/erpnext/hr/doctype/leave_ledger_entry/__init__.py b/erpnext/hr/doctype/leave_ledger_entry/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/__init__.py
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js
new file mode 100644
index 0000000..c68d518
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Leave Ledger Entry', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
new file mode 100644
index 0000000..c114222
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.json
@@ -0,0 +1,168 @@
+{
+ "creation": "2019-05-09 15:47:39.760406",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "employee_name",
+  "leave_type",
+  "transaction_type",
+  "transaction_name",
+  "leaves",
+  "column_break_7",
+  "from_date",
+  "to_date",
+  "is_carry_forward",
+  "is_expired",
+  "is_lwp",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Employee",
+   "options": "Employee"
+  },
+  {
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name"
+  },
+  {
+   "fieldname": "leave_type",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Leave Type",
+   "options": "Leave Type"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Leave Ledger Entry",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "transaction_type",
+   "fieldtype": "Link",
+   "label": "Transaction Type",
+   "options": "DocType"
+  },
+  {
+   "fieldname": "transaction_name",
+   "fieldtype": "Dynamic Link",
+   "label": "Transaction Name",
+   "options": "transaction_type"
+  },
+  {
+   "fieldname": "leaves",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Leaves"
+  },
+  {
+   "fieldname": "from_date",
+   "fieldtype": "Date",
+   "label": "From Date"
+  },
+  {
+   "fieldname": "to_date",
+   "fieldtype": "Date",
+   "label": "To Date"
+  },
+  {
+   "default": "0",
+   "fieldname": "is_carry_forward",
+   "fieldtype": "Check",
+   "label": "Is Carry Forward"
+  },
+  {
+   "default": "0",
+   "fieldname": "is_expired",
+   "fieldtype": "Check",
+   "label": "Is Expired"
+  },
+  {
+   "fieldname": "column_break_7",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "fieldname": "is_lwp",
+   "fieldtype": "Check",
+   "label": "Is Leave Without Pay"
+  }
+ ],
+ "in_create": 1,
+ "is_submittable": 1,
+ "modified": "2019-06-21 00:37:07.782810",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Ledger Entry",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System 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 Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "if_owner": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "All",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "title_field": "employee"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
new file mode 100644
index 0000000..c82114e
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, 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
+from frappe import _
+from frappe.utils import add_days, today, flt, DATE_FORMAT, getdate
+
+class LeaveLedgerEntry(Document):
+	def validate(self):
+		if getdate(self.from_date) > getdate(self.to_date):
+			frappe.throw(_("To date needs to be before from date"))
+
+	def on_cancel(self):
+		# allow cancellation of expiry leaves
+		if self.is_expired:
+			frappe.db.set_value("Leave Allocation", self.transaction_name, "expired", 0)
+		else:
+			frappe.throw(_("Only expired allocation can be cancelled"))
+
+def validate_leave_allocation_against_leave_application(ledger):
+	''' Checks that leave allocation has no leave application against it '''
+	leave_application_records = frappe.db.sql_list("""
+		SELECT transaction_name
+		FROM `tabLeave Ledger Entry`
+		WHERE
+			employee=%s
+			AND leave_type=%s
+			AND transaction_type='Leave Application'
+			AND from_date>=%s
+			AND to_date<=%s
+	""", (ledger.employee, ledger.leave_type, ledger.from_date, ledger.to_date))
+
+	if leave_application_records:
+		frappe.throw(_("Leave allocation %s is linked with leave application %s"
+			% (ledger.transaction_name, ', '.join(leave_application_records))))
+
+def create_leave_ledger_entry(ref_doc, args, submit=True):
+	ledger = frappe._dict(
+		doctype='Leave Ledger Entry',
+		employee=ref_doc.employee,
+		employee_name=ref_doc.employee_name,
+		leave_type=ref_doc.leave_type,
+		transaction_type=ref_doc.doctype,
+		transaction_name=ref_doc.name,
+		is_carry_forward=0,
+		is_expired=0,
+		is_lwp=0
+	)
+	ledger.update(args)
+
+	if submit:
+		frappe.get_doc(ledger).submit()
+	else:
+		delete_ledger_entry(ledger)
+
+def delete_ledger_entry(ledger):
+	''' Delete ledger entry on cancel of leave application/allocation/encashment '''
+	if ledger.transaction_type == "Leave Allocation":
+		validate_leave_allocation_against_leave_application(ledger)
+
+	expired_entry = get_previous_expiry_ledger_entry(ledger)
+	frappe.db.sql("""DELETE
+		FROM `tabLeave Ledger Entry`
+		WHERE
+			`transaction_name`=%s
+			OR `name`=%s""", (ledger.transaction_name, expired_entry))
+
+def get_previous_expiry_ledger_entry(ledger):
+	''' Returns the expiry ledger entry having same creation date as the ledger entry to be cancelled '''
+	creation_date = frappe.db.get_value("Leave Ledger Entry", filters={
+			'transaction_name': ledger.transaction_name,
+			'is_expired': 0,
+			'transaction_type': 'Leave Allocation'
+		}, fieldname=['creation'])
+
+	creation_date = creation_date.strftime(DATE_FORMAT) if creation_date else ''
+
+	return frappe.db.get_value("Leave Ledger Entry", filters={
+		'creation': ('like', creation_date+"%"),
+		'employee': ledger.employee,
+		'leave_type': ledger.leave_type,
+		'is_expired': 1,
+		'docstatus': 1,
+		'is_carry_forward': 0
+	}, fieldname=['name'])
+
+def process_expired_allocation():
+	''' Check if a carry forwarded allocation has expired and create a expiry ledger entry '''
+
+	# fetch leave type records that has carry forwarded leaves expiry
+	leave_type_records = frappe.db.get_values("Leave Type", filters={
+			'expire_carry_forwarded_leaves_after_days': (">", 0)
+		}, fieldname=['name'])
+
+	if leave_type_records:
+		leave_type = [record[0] for record in leave_type_records]
+
+		expired_allocation = frappe.db.sql_list("""SELECT name
+			FROM `tabLeave Ledger Entry`
+			WHERE
+				`transaction_type`='Leave Allocation'
+				AND `is_expired`=1""")
+
+		expire_allocation = frappe.get_all("Leave Ledger Entry",
+			fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
+			filters={
+				'to_date': ("<", today()),
+				'transaction_type': 'Leave Allocation',
+				'transaction_name': ('not in', expired_allocation)
+			},
+			or_filters={
+				'is_carry_forward': 0,
+				'leave_type': ('in', leave_type)
+			})
+
+	if expire_allocation:
+		create_expiry_ledger_entry(expire_allocation)
+
+def create_expiry_ledger_entry(allocations):
+	''' Create ledger entry for expired allocation '''
+	for allocation in allocations:
+		if allocation.is_carry_forward:
+			expire_carried_forward_allocation(allocation)
+		else:
+			expire_allocation(allocation)
+
+def get_remaining_leaves(allocation):
+	''' Returns remaining leaves from the given allocation '''
+	return frappe.db.get_value("Leave Ledger Entry",
+		filters={
+			'employee': allocation.employee,
+			'leave_type': allocation.leave_type,
+			'to_date': ('<=', allocation.to_date),
+		}, fieldname=['SUM(leaves)'])
+
+@frappe.whitelist()
+def expire_allocation(allocation, expiry_date=None):
+	''' expires non-carry forwarded allocation '''
+	leaves = get_remaining_leaves(allocation)
+	expiry_date = expiry_date if expiry_date else allocation.to_date
+
+	if leaves:
+		args = dict(
+			leaves=flt(leaves) * -1,
+			transaction_name=allocation.name,
+			transaction_type='Leave Allocation',
+			from_date=expiry_date,
+			to_date=expiry_date,
+			is_carry_forward=0,
+			is_expired=1
+		)
+		create_leave_ledger_entry(allocation, args)
+
+	frappe.db.set_value("Leave Allocation", allocation.name, "expired", 1)
+
+def expire_carried_forward_allocation(allocation):
+	''' Expires remaining leaves in the on carried forward allocation '''
+	from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
+	leaves_taken = get_leaves_for_period(allocation.employee, allocation.leave_type, allocation.from_date, allocation.to_date)
+	leaves = flt(allocation.leaves) + flt(leaves_taken)
+	if leaves > 0:
+		args = frappe._dict(
+			transaction_name=allocation.name,
+			transaction_type="Leave Allocation",
+			leaves=allocation.leaves * -1,
+			is_carry_forward=allocation.is_carry_forward,
+			is_expired=1,
+			from_date=allocation.to_date,
+			to_date=allocation.to_date
+		)
+		create_leave_ledger_entry(allocation, args)
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
new file mode 100644
index 0000000..6f7725c
--- /dev/null
+++ b/erpnext/hr/doctype/leave_ledger_entry/test_leave_ledger_entry.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestLeaveLedgerEntry(unittest.TestCase):
+	pass
diff --git a/erpnext/hr/doctype/leave_period/leave_period.js b/erpnext/hr/doctype/leave_period/leave_period.js
index b8c5f71..bad2b87 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.js
+++ b/erpnext/hr/doctype/leave_period/leave_period.js
@@ -68,7 +68,7 @@
 				},
 				{
 					"label": "Add unused leaves from previous allocations",
-					"fieldname": "carry_forward_leaves",
+					"fieldname": "carry_forward",
 					"fieldtype": "Check"
 				}
 			],
diff --git a/erpnext/hr/doctype/leave_period/leave_period.json b/erpnext/hr/doctype/leave_period/leave_period.json
index df28763..9e895c3 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.json
+++ b/erpnext/hr/doctype/leave_period/leave_period.json
@@ -1,294 +1,294 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "HR-LPR-.YYYY.-.#####", 
- "beta": 0, 
- "creation": "2018-04-13 15:20:52.864288", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-LPR-.YYYY.-.#####",
+ "beta": 0,
+ "creation": "2018-04-13 15:20:52.864288",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "from_date", 
-   "fieldtype": "Date", 
-   "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": "From 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, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "from_date",
+   "fieldtype": "Date",
+   "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": "From 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
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "to_date", 
-   "fieldtype": "Date", 
-   "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": "To 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, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "to_date",
+   "fieldtype": "Date",
+   "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": "To 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
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_3", 
-   "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, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "is_active",
+   "fieldtype": "Check",
+   "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": "Is Active",
+   "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, 
-   "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, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "column_break_3",
+   "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
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "is_active", 
-   "fieldtype": "Check", 
-   "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": "Is Active", 
-   "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, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 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
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "optional_holiday_list", 
-   "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": "Holiday List for Optional Leave", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Holiday List", 
-   "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, 
+   "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
+   "allow_on_submit": 0,
+   "bold": 0,
+   "collapsible": 0,
+   "columns": 0,
+   "fieldname": "optional_holiday_list",
+   "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": "Holiday List for Optional Leave",
+   "length": 0,
+   "no_copy": 0,
+   "options": "Holiday List",
+   "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
   }
- ], 
- "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-08-21 16:15:43.305502", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Leave Period", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "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-05-30 16:15:43.305502",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Period",
+ "name_case": "",
+ "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, 
+   "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,
    "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, 
+   "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,
    "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, 
+   "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,
    "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, 
+ ],
+ "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
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py
index 15fa8d6..a8566c4 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.py
+++ b/erpnext/hr/doctype/leave_period/leave_period.py
@@ -5,9 +5,10 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import getdate, cstr
+from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil
 from frappe.model.document import Document
 from erpnext.hr.utils import validate_overlap, get_employee_leave_policy
+from erpnext.hr.doctype.leave_allocation.leave_allocation import get_carry_forwarded_leaves
 from frappe.utils.background_jobs import enqueue
 from six import iteritems
 
@@ -21,8 +22,8 @@
 
 		condition_str = " and " + " and ".join(conditions) if len(conditions) else ""
 
-		employees = frappe.db.sql_list("select name from tabEmployee where status='Active' {condition}"
-			.format(condition=condition_str), tuple(values))
+		employees = frappe._dict(frappe.db.sql("select name, date_of_joining from tabEmployee where status='Active' {condition}" #nosec
+			.format(condition=condition_str), tuple(values)))
 
 		return employees
 
@@ -36,29 +37,29 @@
 
 
 	def grant_leave_allocation(self, grade=None, department=None, designation=None,
-			employee=None, carry_forward_leaves=0):
-		employees = self.get_employees({
+			employee=None, carry_forward=0):
+		employee_records = self.get_employees({
 			"grade": grade,
-			"department": department, 
-			"designation": designation, 
+			"department": department,
+			"designation": designation,
 			"name": employee
 		})
 
-		if employees:
-			if len(employees) > 20:
+		if employee_records:
+			if len(employee_records) > 20:
 				frappe.enqueue(grant_leave_alloc_for_employees, timeout=600,
-					employees=employees, leave_period=self, carry_forward_leaves=carry_forward_leaves)
+					employee_records=employee_records, leave_period=self, carry_forward=carry_forward)
 			else:
-				grant_leave_alloc_for_employees(employees, self, carry_forward_leaves)
+				grant_leave_alloc_for_employees(employee_records, self, carry_forward)
 		else:
 			frappe.msgprint(_("No Employee Found"))
 
-def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leaves=0):
+def grant_leave_alloc_for_employees(employee_records, leave_period, carry_forward=0):
 	leave_allocations = []
-	existing_allocations_for = get_existing_allocations(employees, leave_period.name)
+	existing_allocations_for = get_existing_allocations(list(employee_records.keys()), leave_period.name)
 	leave_type_details = get_leave_type_details()
-	count=0
-	for employee in employees:
+	count = 0
+	for employee in employee_records.keys():
 		if employee in existing_allocations_for:
 			continue
 		count +=1
@@ -67,18 +68,24 @@
 			for leave_policy_detail in leave_policy.leave_policy_details:
 				if not leave_type_details.get(leave_policy_detail.leave_type).is_lwp:
 					leave_allocation = create_leave_allocation(employee, leave_policy_detail.leave_type,
-						leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward_leaves)
+						leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward, employee_records.get(employee))
 					leave_allocations.append(leave_allocation)
 		frappe.db.commit()
-		frappe.publish_progress(count*100/len(set(employees) - set(existing_allocations_for)), title = _("Allocating leaves..."))
+		frappe.publish_progress(count*100/len(set(employee_records.keys()) - set(existing_allocations_for)), title = _("Allocating leaves..."))
 
 	if leave_allocations:
 		frappe.msgprint(_("Leaves has been granted sucessfully"))
 
 def get_existing_allocations(employees, leave_period):
 	leave_allocations = frappe.db.sql_list("""
-		select distinct employee from `tabLeave Allocation` 
-		where leave_period=%s and employee in (%s) and docstatus=1
+		SELECT DISTINCT
+			employee
+		FROM `tabLeave Allocation`
+		WHERE
+			leave_period=%s
+			AND employee in (%s)
+			AND carry_forward=0
+			AND docstatus=1
 	""" % ('%s', ', '.join(['%s']*len(employees))), [leave_period] + employees)
 	if leave_allocations:
 		frappe.msgprint(_("Skipping Leave Allocation for the following employees, as Leave Allocation records already exists against them. {0}")
@@ -87,28 +94,36 @@
 
 def get_leave_type_details():
 	leave_type_details = frappe._dict()
-	leave_types = frappe.get_all("Leave Type", fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward"])
+	leave_types = frappe.get_all("Leave Type",
+		fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carry_forwarded_leaves_after_days"])
 	for d in leave_types:
 		leave_type_details.setdefault(d.name, d)
 	return leave_type_details
 
-def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward_leaves):
-	allocation = frappe.new_doc("Leave Allocation")
-	allocation.employee = employee
-	allocation.leave_type = leave_type
-	allocation.from_date = leave_period.from_date
-	allocation.to_date = leave_period.to_date
+def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward, date_of_joining):
+	''' Creates leave allocation for the given employee in the provided leave period '''
+	if carry_forward and not leave_type_details.get(leave_type).is_carry_forward:
+		carry_forward = 0
+
+	# Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
+	if getdate(date_of_joining) > getdate(leave_period.from_date):
+		remaining_period = ((date_diff(leave_period.to_date, date_of_joining) + 1) / (date_diff(leave_period.to_date, leave_period.from_date) + 1))
+		new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
+
 	# Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
 	if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1:
 		new_leaves_allocated = 0
 
-	allocation.new_leaves_allocated = new_leaves_allocated
-	allocation.leave_period = leave_period.name
-	if carry_forward_leaves:
-		if leave_type_details.get(leave_type).is_carry_forward:
-			allocation.carry_forward = carry_forward_leaves
+	allocation = frappe.get_doc(dict(
+		doctype="Leave Allocation",
+		employee=employee,
+		leave_type=leave_type,
+		from_date=leave_period.from_date,
+		to_date=leave_period.to_date,
+		new_leaves_allocated=new_leaves_allocated,
+		leave_period=leave_period.name,
+		carry_forward=carry_forward
+		))
 	allocation.save(ignore_permissions = True)
 	allocation.submit()
-	return allocation.name
-
-
+	return allocation.name
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
index f97d285..48a2045 100644
--- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
+++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py
@@ -12,6 +12,9 @@
 			},
 			{
 				'items': ['Employee Grade']
-			}
+			},
+			{
+				'items': ['Leave Allocation']
+			},
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy/test_leave_policy.py b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
index 2c6f1d0..fc868ea 100644
--- a/erpnext/hr/doctype/leave_policy/test_leave_policy.py
+++ b/erpnext/hr/doctype/leave_policy/test_leave_policy.py
@@ -12,16 +12,20 @@
 		if random_leave_type:
 			random_leave_type = random_leave_type[0]
 			leave_type = frappe.get_doc("Leave Type", random_leave_type.name)
-			old_max_leaves_allowed = leave_type.max_leaves_allowed
 			leave_type.max_leaves_allowed = 2
 			leave_type.save()
 
-			leave_policy_details = {
-				"doctype": "Leave Policy",
-				"leave_policy_details": [{
-					"leave_type": leave_type.name,
-					"annual_allocation": leave_type.max_leaves_allowed + 1
-				}]
-			}
+		leave_policy = create_leave_policy(leave_type=leave_type.name, annual_allocation=leave_type.max_leaves_allowed + 1)
 
-			self.assertRaises(frappe.ValidationError, frappe.get_doc(leave_policy_details).insert)
+		self.assertRaises(frappe.ValidationError, leave_policy.insert)
+
+def create_leave_policy(**args):
+	''' Returns an object of leave policy '''
+	args = frappe._dict(args)
+	return frappe.get_doc({
+		"doctype": "Leave Policy",
+		"leave_policy_details": [{
+			"leave_type": args.leave_type or "_Test Leave Type",
+			"annual_allocation": args.annual_allocation or 10
+		}]
+	})
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 6a7a80a..2f15e3b 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0,
+ "allow_events_in_timeline": 0,
  "allow_guest_to_view": 0,
  "allow_import": 1,
  "allow_rename": 1,
@@ -14,10 +15,12 @@
  "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": "leave_type_name",
    "fieldtype": "Data",
    "hidden": 0,
@@ -42,15 +45,17 @@
    "search_index": 0,
    "set_only_once": 0,
    "translatable": 0,
-   "unique": 0
+   "unique": 1
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
    "depends_on": "",
+   "fetch_if_empty": 0,
    "fieldname": "max_leaves_allowed",
    "fieldtype": "Int",
    "hidden": 0,
@@ -78,10 +83,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "applicable_after",
    "fieldtype": "Int",
    "hidden": 0,
@@ -109,10 +116,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "max_continuous_days_allowed",
    "fieldtype": "Int",
    "hidden": 0,
@@ -141,10 +150,12 @@
   },
   {
    "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_3",
    "fieldtype": "Column Break",
    "hidden": 0,
@@ -171,10 +182,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "is_carry_forward",
    "fieldtype": "Check",
    "hidden": 0,
@@ -203,10 +216,13 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "depends_on": "",
+   "fetch_if_empty": 0,
    "fieldname": "is_lwp",
    "fieldtype": "Check",
    "hidden": 0,
@@ -233,10 +249,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "is_optional_leave",
    "fieldtype": "Check",
    "hidden": 0,
@@ -264,10 +282,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "allow_negative",
    "fieldtype": "Check",
    "hidden": 0,
@@ -294,10 +314,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "include_holiday",
    "fieldtype": "Check",
    "hidden": 0,
@@ -324,10 +346,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "is_compensatory",
    "fieldtype": "Check",
    "hidden": 0,
@@ -355,10 +379,81 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 1,
    "columns": 0,
+   "depends_on": "eval: doc.is_carry_forward == 1",
+   "fetch_if_empty": 0,
+   "fieldname": "carry_forward_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": "Carry Forward",
+   "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,
+   "depends_on": "",
+   "description": "Calculated in days",
+   "fetch_if_empty": 0,
+   "fieldname": "expire_carry_forwarded_leaves_after_days",
+   "fieldtype": "Int",
+   "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": "Expire Carry Forwarded Leaves (Days)",
+   "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": 1,
+   "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "encashment",
    "fieldtype": "Section Break",
    "hidden": 0,
@@ -386,10 +481,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "allow_encashment",
    "fieldtype": "Check",
    "hidden": 0,
@@ -417,11 +514,13 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
    "depends_on": "allow_encashment",
+   "fetch_if_empty": 0,
    "fieldname": "encashment_threshold_days",
    "fieldtype": "Int",
    "hidden": 0,
@@ -449,11 +548,13 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
    "depends_on": "allow_encashment",
+   "fetch_if_empty": 0,
    "fieldname": "earning_component",
    "fieldtype": "Link",
    "hidden": 0,
@@ -482,10 +583,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 1,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "earned_leave",
    "fieldtype": "Section Break",
    "hidden": 0,
@@ -513,10 +616,12 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
+   "fetch_if_empty": 0,
    "fieldname": "is_earned_leave",
    "fieldtype": "Check",
    "hidden": 0,
@@ -544,11 +649,13 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
    "depends_on": "is_earned_leave",
+   "fetch_if_empty": 0,
    "fieldname": "earned_leave_frequency",
    "fieldtype": "Select",
    "hidden": 0,
@@ -577,12 +684,14 @@
   },
   {
    "allow_bulk_edit": 0,
+   "allow_in_quick_entry": 0,
    "allow_on_submit": 0,
    "bold": 0,
    "collapsible": 0,
    "columns": 0,
    "default": "0.5",
    "depends_on": "is_earned_leave",
+   "fetch_if_empty": 0,
    "fieldname": "rounding",
    "fieldtype": "Select",
    "hidden": 0,
@@ -611,17 +720,15 @@
   }
  ],
  "has_web_view": 0,
- "hide_heading": 0,
  "hide_toolbar": 0,
  "icon": "fa fa-flag",
  "idx": 1,
- "image_view": 0,
  "in_create": 0,
  "is_submittable": 0,
  "issingle": 0,
  "istable": 0,
  "max_attachments": 0,
- "modified": "2018-06-03 18:32:51.803472",
+ "modified": "2019-08-02 15:38:39.334283",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Type",
@@ -687,8 +794,8 @@
  ],
  "quick_entry": 0,
  "read_only": 0,
- "read_only_onload": 0,
  "show_name_in_global_search": 0,
  "track_changes": 0,
- "track_seen": 0
-}
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_type/leave_type.py b/erpnext/hr/doctype/leave_type/leave_type.py
index e0127e5..3a19fa9 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.py
+++ b/erpnext/hr/doctype/leave_type/leave_type.py
@@ -2,9 +2,16 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
+import calendar
 import frappe
+from datetime import datetime
+from frappe import _
 
 from frappe.model.document import Document
 
 class LeaveType(Document):
-	pass
\ No newline at end of file
+	def validate(self):
+		if self.is_lwp:
+			leave_allocation = frappe.db.sql_list("""select name from `tabLeave Allocation` where leave_type=%s""", (self.name))
+			if leave_allocation:
+				frappe.throw(_('Leave application is linked with leave allocations {0}. Leave application cannot be set as leave without pay').format(", ".join(leave_allocation))) #nosec
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_type/test_leave_type.py b/erpnext/hr/doctype/leave_type/test_leave_type.py
index b844e49..0c4f435 100644
--- a/erpnext/hr/doctype/leave_type/test_leave_type.py
+++ b/erpnext/hr/doctype/leave_type/test_leave_type.py
@@ -2,6 +2,25 @@
 # License: GNU General Public License v3. See license.txt
 from __future__ import unicode_literals
 
-
 import frappe
-test_records = frappe.get_test_records('Leave Type')
\ No newline at end of file
+from frappe import _
+
+test_records = frappe.get_test_records('Leave Type')
+
+def create_leave_type(**args):
+    args = frappe._dict(args)
+    if frappe.db.exists("Leave Type", args.leave_type_name):
+        return frappe.get_doc("Leave Type", args.leave_type_name)
+    leave_type = frappe.get_doc({
+        "doctype": "Leave Type",
+        "leave_type_name": args.leave_type_name or "_Test Leave Type",
+        "include_holiday": args.include_holidays or 1,
+        "allow_encashment": args.allow_encashment or 0,
+        "is_earned_leave": args.is_earned_leave or 0,
+        "is_lwp": args.is_lwp or 0,
+        "is_carry_forward": args.is_carry_forward or 0,
+        "expire_carry_forwarded_leaves_after_days": args.expire_carry_forwarded_leaves_after_days or 0,
+        "encashment_threshold_days": args.encashment_threshold_days or 5,
+        "earning_component": "Leave Encashment"
+    })
+    return leave_type
\ No newline at end of file
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
index 59c2560..05728a2 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
@@ -24,6 +24,18 @@
 			"options": "Company",
 			"reqd": 1,
 			"default": frappe.defaults.get_user_default("Company")
+		},
+		{
+			"fieldname":"department",
+			"label": __("Department"),
+			"fieldtype": "Link",
+			"options": "Department",
+		},
+		{
+			"fieldname":"employee",
+			"label": __("Employee"),
+			"fieldtype": "Link",
+			"options": "Employee",
 		}
 	]
 }
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 1843176..66e3614 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -4,8 +4,9 @@
 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_allocation_records, get_leave_balance_on, get_approved_leaves_for_period
+	import get_leave_balance_on, get_leaves_for_period
 
 
 def execute(filters=None):
@@ -30,17 +31,28 @@
 
 	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")})
+
+	return conditions
+
 def get_data(filters, leave_types):
 	user = frappe.session.user
-	allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
-	allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
+	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 = { "status": "Active", "company": filters.company},
-		fields = ["name", "employee_name", "department", "user_id"])
+		filters=conditions,
+		fields=["name", "employee_name", "department", "user_id"])
 
 	data = []
 	for employee in active_employees:
@@ -50,16 +62,14 @@
 
 			for leave_type in leave_types:
 				# leaves taken
-				leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
-					filters.from_date, filters.to_date)
+				leaves_taken = get_leaves_for_period(employee.name, leave_type,
+					filters.from_date, filters.to_date) * -1
 
 				# opening balance
-				opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
-					allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
+				opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
 
 				# closing balance
-				closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
-					allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
+				closing = flt(opening) - flt(leaves_taken)
 
 				row += [opening, leaves_taken, closing]
 
@@ -84,3 +94,19 @@
 			where parent = %s and parentfield = 'leave_approvers'""", (d), as_dict=True)])
 
 	return approvers
+
+def get_total_allocated_leaves(employee, leave_type, from_date, to_date):
+	''' Returns leave allocation between from date and to date '''
+	filters= {
+		'from_date': ['between', (from_date, to_date)],
+		'to_date': ['between', (from_date, to_date)],
+		'docstatus': 1,
+		'is_expired': 0,
+		'leave_type': leave_type,
+		'employee': employee,
+		'transaction_type': 'Leave Allocation'
+	}
+
+	leave_allocation_records = frappe.db.get_all('Leave Ledger Entry', filters=filters, fields=['SUM(leaves) as leaves'])
+
+	return flt(leave_allocation_records[0].get('leaves')) if leave_allocation_records else flt(0)
\ No newline at end of file
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index de2b090..2183c5e 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe, erpnext
 from frappe import _
-from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate, flt, cstr
+from frappe.utils import formatdate, format_datetime, getdate, get_datetime, nowdate, flt, cstr, add_days, today
 from frappe.model.document import Document
 from frappe.desk.form import assign_to
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@@ -270,6 +270,21 @@
 	if leave_period:
 		return leave_period
 
+def generate_leave_encashment():
+	''' Generates a draft leave encashment on allocation expiry '''
+	from erpnext.hr.doctype.leave_encashment.leave_encashment import create_leave_encashment
+
+	if frappe.db.get_single_value('HR Settings', 'auto_leave_encashment'):
+		leave_type = frappe.get_all('Leave Type', filters={'allow_encashment': 1}, fields=['name'])
+		leave_type=[l['name'] for l in leave_type]
+
+		leave_allocation = frappe.get_all("Leave Allocation", filters={
+			'to_date': add_days(today(), -1),
+			'leave_type': ('in', leave_type)
+		}, fields=['employee', 'leave_period', 'leave_type', 'to_date', 'total_leaves_allocated', 'new_leaves_allocated'])
+
+		create_leave_encashment(leave_allocation=leave_allocation)
+
 def allocate_earned_leaves():
 	'''Allocate earned leaves to Employees'''
 	e_leave_types = frappe.get_all("Leave Type",
@@ -277,31 +292,44 @@
 		filters={'is_earned_leave' : 1})
 	today = getdate()
 	divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
-	if e_leave_types:
-		for e_leave_type in e_leave_types:
-			leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where '{0}'
-				between from_date and to_date and docstatus=1 and leave_type='{1}'"""
-				.format(today, e_leave_type.name), as_dict=1)
-			for allocation in leave_allocations:
-				leave_policy = get_employee_leave_policy(allocation.employee)
-				if not leave_policy:
-					continue
-				if not e_leave_type.earned_leave_frequency == "Monthly":
-					if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
-						continue
-				annual_allocation = frappe.db.sql("""select annual_allocation from `tabLeave Policy Detail`
-					where parent=%s and leave_type=%s""", (leave_policy.name, e_leave_type.name))
-				if annual_allocation and annual_allocation[0]:
-					earned_leaves = flt(annual_allocation[0][0]) / divide_by_frequency[e_leave_type.earned_leave_frequency]
-					if e_leave_type.rounding == "0.5":
-						earned_leaves = round(earned_leaves * 2) / 2
-					else:
-						earned_leaves = round(earned_leaves)
 
-					allocated_leaves = frappe.db.get_value('Leave Allocation', allocation.name, 'total_leaves_allocated')
-					new_allocation = flt(allocated_leaves) + flt(earned_leaves)
-					new_allocation = new_allocation if new_allocation <= e_leave_type.max_leaves_allowed else e_leave_type.max_leaves_allowed
-					frappe.db.set_value('Leave Allocation', allocation.name, 'total_leaves_allocated', new_allocation)
+	for e_leave_type in e_leave_types:
+		leave_allocations = frappe.db.sql("""select name, employee, from_date, to_date from `tabLeave Allocation` where %s
+			between from_date and to_date and docstatus=1 and leave_type=%s""", (today, e_leave_type.name), as_dict=1)
+		for allocation in leave_allocations:
+			leave_policy = get_employee_leave_policy(allocation.employee)
+			if not leave_policy:
+				continue
+			if not e_leave_type.earned_leave_frequency == "Monthly":
+				if not check_frequency_hit(allocation.from_date, today, e_leave_type.earned_leave_frequency):
+					continue
+			annual_allocation = frappe.db.get_value("Leave Policy Detail", filters={
+				'parent': leave_policy.name,
+				'leave_type': e_leave_type.name
+			}, fieldname=['annual_allocation'])
+			if annual_allocation:
+				earned_leaves = flt(annual_allocation) / divide_by_frequency[e_leave_type.earned_leave_frequency]
+				if e_leave_type.rounding == "0.5":
+					earned_leaves = round(earned_leaves * 2) / 2
+				else:
+					earned_leaves = round(earned_leaves)
+
+				allocation = frappe.get_doc('Leave Allocation', allocation.name)
+				new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
+				new_allocation = new_allocation if new_allocation <= e_leave_type.max_leaves_allowed else e_leave_type.max_leaves_allowed
+
+				if new_allocation == allocation.total_leaves_allocated:
+					continue
+				allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False)
+				create_earned_leave_ledger_entry(allocation, earned_leaves, today)
+
+
+def create_earned_leave_ledger_entry(allocation, earned_leaves, date):
+	''' Create leave ledger entry based on the earned leave frequency '''
+	allocation.new_leaves_allocated = earned_leaves
+	allocation.from_date = date
+	allocation.unused_leaves = 0
+	allocation.create_leave_ledger_entry()
 
 def check_frequency_hit(from_date, to_date, frequency):
 	'''Return True if current date matches frequency'''
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 33d4f55..ac9b01f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -626,3 +626,4 @@
 erpnext.patches.v12_0.update_ewaybill_field_position
 erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
 erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
+erpnext.patches.v12_0.generate_leave_ledger_entries
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
new file mode 100644
index 0000000..44b59bf
--- /dev/null
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -0,0 +1,86 @@
+# Copyright (c) 2018, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import getdate
+
+def execute():
+	""" Generates leave ledger entries for leave allocation/application/encashment
+		for last allocation """
+	frappe.reload_doc("HR", "doctype", "Leave Ledger Entry")
+	frappe.reload_doc("HR", "doctype", "Leave Encashment")
+	if frappe.db.a_row_exists("Leave Ledger Entry"):
+		return
+
+	if not frappe.get_meta("Leave Allocation").has_field("unused_leaves"):
+		frappe.reload_doc("HR", "doctype", "Leave Allocation")
+		update_leave_allocation_fieldname()
+
+	generate_allocation_ledger_entries()
+	generate_application_leave_ledger_entries()
+	generate_encashment_leave_ledger_entries()
+	generate_expiry_allocation_ledger_entries()
+
+def update_leave_allocation_fieldname():
+	''' maps data from old field to the new field '''
+	frappe.db.sql("""
+		UPDATE `tabLeave Allocation`
+		SET `unused_leaves` = `carry_forwarded_leaves`
+	""")
+
+def generate_allocation_ledger_entries():
+	''' fix ledger entries for missing leave allocation transaction '''
+	allocation_list = get_allocation_records()
+
+	for allocation in allocation_list:
+		if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name}):
+			allocation.update(dict(doctype="Leave Allocation"))
+			allocation_obj = frappe.get_doc(allocation)
+			allocation_obj.create_leave_ledger_entry()
+
+def generate_application_leave_ledger_entries():
+	''' fix ledger entries for missing leave application transaction '''
+	leave_applications = get_leaves_application_records()
+
+	for application in leave_applications:
+		if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Application', 'transaction_name': application.name}):
+			application.update(dict(doctype="Leave Application"))
+			frappe.get_doc(application).create_leave_ledger_entry()
+
+def generate_encashment_leave_ledger_entries():
+	''' fix ledger entries for missing leave encashment transaction '''
+	leave_encashments = get_leave_encashment_records()
+
+	for encashment in leave_encashments:
+		if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
+			encashment.update(dict(doctype="Leave Encashment"))
+			frappe.get_doc(encashment).create_leave_ledger_entry()
+
+def generate_expiry_allocation_ledger_entries():
+	''' fix ledger entries for missing leave allocation transaction '''
+	from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import expire_allocation
+	allocation_list = get_allocation_records()
+
+	for allocation in allocation_list:
+		if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Allocation', 'transaction_name': allocation.name, 'is_expired': 1}):
+			allocation.update(dict(doctype="Leave Allocation"))
+			allocation_obj = frappe.get_doc(allocation)
+			expire_allocation(allocation_obj)
+
+def get_allocation_records():
+	return frappe.get_all("Leave Allocation", filters={
+		"docstatus": 1
+		}, fields=['name', 'employee', 'leave_type', 'new_leaves_allocated',
+			'unused_leaves', 'from_date', 'to_date', 'carry_forward'
+		], order_by='to_date ASC')
+
+def get_leaves_application_records():
+	return frappe.get_all("Leave Application", filters={
+		"docstatus": 1
+		}, fields=['name', 'employee', 'leave_type', 'total_leave_days', 'from_date', 'to_date'])
+
+def get_leave_encashment_records():
+	return frappe.get_all("Leave Encashment", filters={
+		"docstatus": 1
+		}, fields=['name', 'employee', 'leave_type', 'encashable_days', 'encashment_date'])
\ No newline at end of file