13615 - Leave Encashment, creating Additional Salary Component on submit and validations pending
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.js b/erpnext/hr/doctype/leave_encashment/leave_encashment.js
index 0556756..701c2f0 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.js
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.js
@@ -2,7 +2,39 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Leave Encashment', {
+	setup: function(frm) {
+		frm.set_query("leave_type", function() {
+			return {
+				filters: {
+					allow_encashment: 1
+				}
+			}
+		})
+	},
 	refresh: function(frm) {
-
+		cur_frm.set_intro("");
+		if(frm.doc.__islocal && !in_list(frappe.user_roles, "Employee")) {
+			frm.set_intro(__("Fill the form and save it"));
+		}
+	},
+	employee: function(frm) {
+		frm.trigger("get_leave_details_for_encashment");
+	},
+	leave_type: function(frm) {
+		frm.trigger("get_leave_details_for_encashment");
+	},
+	encashment_date: function(frm) {
+		frm.trigger("get_leave_details_for_encashment");
+	},
+	get_leave_details_for_encashment: function(frm) {
+		if(frm.doc.docstatus==0 && frm.doc.employee && frm.doc.leave_type) {
+			return frappe.call({
+				method: "get_leave_details_for_encashment",
+				doc: frm.doc,
+				callback: function(r) {
+					frm.refresh_fields();
+					}
+			});
+		}
 	}
 });
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.json b/erpnext/hr/doctype/leave_encashment/leave_encashment.json
index 22f0b20..3f04090 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.json
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.json
@@ -177,6 +177,38 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "leave_allocation", 
+   "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": "Leave Allocation", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Leave Allocation", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "leave_balance", 
    "fieldtype": "Float", 
    "hidden": 0, 
@@ -308,7 +340,7 @@
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_global_search": 0, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "in_standard_filter": 0, 
    "label": "Encashment Amount", 
    "length": 0, 
@@ -332,7 +364,8 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "fieldname": "payroll_date", 
+   "default": "Today", 
+   "fieldname": "encashment_date", 
    "fieldtype": "Date", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
@@ -341,7 +374,7 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
-   "label": "Payroll Date", 
+   "label": "Encashment Date", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
@@ -368,7 +401,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2018-04-14 15:35:51.428448", 
+ "modified": "2018-05-11 19:15:17.460624", 
  "modified_by": "Administrator", 
  "module": "HR", 
  "name": "Leave Encashment", 
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 5966a0b..1e2c3b9 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -4,7 +4,64 @@
 
 from __future__ import unicode_literals
 import frappe
+from frappe import _
 from frappe.model.document import Document
+from frappe.utils import getdate, nowdate, flt
+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
 
 class LeaveEncashment(Document):
-	pass
+	def validate(self):
+		set_employee_name(self)
+		self.get_leave_details_for_encashment()
+
+		if not self.encashment_date:
+			self.encashment_date = getdate(nowdate())
+
+	def before_submit(self):
+		if self.encashment_amount <= 0:
+			frappe.throw(_("You can only submit Leave Encashment for a valid encashment amount"))
+
+	def on_submit(self):
+		if not self.leave_allocation:
+			self.leave_allocation = self.get_leave_allocation()
+
+		#ToDo: Create Additional Salary Component
+
+		# Set encashed leaves in 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)
+
+	def on_cancel(self):
+		# ToDo: Cancel Additional Salary Component
+		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)
+
+	def get_leave_details_for_encashment(self):
+		salary_structure = get_assigned_salary_structure(self.employee, self.encashment_date or getdate(nowdate()))
+		if not salary_structure:
+			frappe.throw(_("No Salary Structure assigned for Employee {0} on given date {1}").format(self.employee, self.encashment_date))
+
+		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)
+
+		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
+
+		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()
+		return True
+
+	def get_leave_allocation(self):
+		leave_allocation = frappe.db.sql("""select name 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))
+
+		return leave_allocation[0][0] if leave_allocation else None