Employee Promotion, Transfer - validate, submit, cancel workflow
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 0f11639..4cf28a1 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -156,6 +156,9 @@
 	def on_trash(self):
 		self.update_nsm_model()
 		delete_events(self.doctype, self.name)
+		if frappe.db.exists("Employee Transfer", {'new_employee_id': self.name, 'docstatus': 1}):
+			emp_transfer = frappe.get_doc("Employee Transfer", {'new_employee_id': self.name, 'docstatus': 1})
+			emp_transfer.db_set("new_employee_id", '')
 
 	def validate_preferred_email(self):
 		if self.prefered_contact_email and not self.get(scrub(self.prefered_contact_email)):
diff --git a/erpnext/hr/doctype/employee_promotion/employee_promotion.py b/erpnext/hr/doctype/employee_promotion/employee_promotion.py
index 564f1ad..5fcceed 100644
--- a/erpnext/hr/doctype/employee_promotion/employee_promotion.py
+++ b/erpnext/hr/doctype/employee_promotion/employee_promotion.py
@@ -4,7 +4,27 @@
 
 from __future__ import unicode_literals
 import frappe
+from frappe import _
 from frappe.model.document import Document
+from frappe.utils import getdate
+from erpnext.hr.utils import update_employee
 
 class EmployeePromotion(Document):
-	pass
+	def validate(self):
+		if frappe.get_value("Employee", self.employee, "status") == "Left":
+			frappe.throw(_("Cannot promote Employee with status Left"))
+
+	def before_submit(self):
+		if getdate(self.promotion_date) > getdate():
+			frappe.throw(_("Employee Promotion cannot be submitted before Promotion Date "),
+				frappe.DocstatusTransitionError)
+
+	def on_submit(self):
+		employee = frappe.get_doc("Employee", self.employee)
+		employee = update_employee(employee, self.promotion_details)
+		employee.save()
+
+	def on_cancel(self):
+		employee = frappe.get_doc("Employee", self.employee)
+		employee = update_employee(employee, self.promotion_details, True)
+		employee.save()
diff --git a/erpnext/hr/doctype/employee_transfer/employee_transfer.py b/erpnext/hr/doctype/employee_transfer/employee_transfer.py
index 96645c4..d80e293 100644
--- a/erpnext/hr/doctype/employee_transfer/employee_transfer.py
+++ b/erpnext/hr/doctype/employee_transfer/employee_transfer.py
@@ -4,7 +4,59 @@
 
 from __future__ import unicode_literals
 import frappe
+from frappe import _
 from frappe.model.document import Document
+from frappe.utils import getdate
+from erpnext.hr.utils import update_employee
 
 class EmployeeTransfer(Document):
-	pass
+	def validate(self):
+		if frappe.get_value("Employee", self.employee, "status") == "Left":
+			frappe.throw(_("Cannot transfer Employee with status Left"))
+
+	def before_submit(self):
+		if getdate(self.transfer_date) > getdate():
+			frappe.throw(_("Employee Transfer cannot be submitted before Transfer Date "),
+				frappe.DocstatusTransitionError)
+
+	def on_submit(self):
+		employee = frappe.get_doc("Employee", self.employee)
+		if self.create_new_employee_id:
+			new_employee = frappe.copy_doc(employee)
+			new_employee = update_employee(new_employee, self.transfer_details)
+			if self.new_company:
+				new_employee.company = self.new_company
+			#move user_id to new employee before insert
+			if employee.user_id and not self.validate_user_in_details():
+				new_employee.user_id = employee.user_id
+				employee.db_set("user_id", "")
+			new_employee.insert()
+			self.db_set("new_employee_id", new_employee.name)
+			#relieve the old employee
+			employee.db_set("relieving_date", self.transfer_date)
+			employee.db_set("status", "Left")
+		else:
+			employee = update_employee(employee, self.transfer_details)
+			if self.new_company:
+				employee.company = self.new_company
+			employee.save()
+
+	def on_cancel(self):
+		employee = frappe.get_doc("Employee", self.employee)
+		if self.create_new_employee_id:
+			if self.new_employee_id:
+				frappe.throw(_("Please delete the Employee <a href='#Form/Employee/{0}'>{0}</a>\
+					to cancel this document").format(self.new_employee_id))
+			#mark the employee as active
+			employee.status = "Active"
+			employee.relieving_date = ''
+			employee.save()
+		else:
+			employee = update_employee(employee, self.transfer_details, True)
+			employee.save()
+
+	def validate_user_in_details(self):
+		for item in self.transfer_details:
+			if item.fieldname == "user_id" and item.new != item.current:
+				return True
+		return False