Merge pull request #13984 from manassolanki/employee-boarding

[feature] added the employee onboarding and separation doctype
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.js b/erpnext/accounts/doctype/accounting_period/accounting_period.js
index 1fb57ea..e3d805a 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.js
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.js
@@ -2,7 +2,23 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Accounting Period', {
-	refresh: function(frm) {
-
+	onload: function(frm) {
+		if(frm.doc.closed_documents.length === 0 || (frm.doc.closed_documents.length === 1 && frm.doc.closed_documents[0].document_type == undefined)) {
+			frappe.call({
+				method: "get_doctypes_for_closing",
+				doc:frm.doc,
+				callback: function(r) {
+					if(r.message) {
+						cur_frm.clear_table("closed_documents");
+						r.message.forEach(function(element) {
+							var c = frm.add_child("closed_documents");
+							c.document_type = element.document_type;
+							c.closed = element.closed;
+						});
+						refresh_field("closed_documents");
+					}
+				}
+			});
+		}
 	}
 });
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py
index 31f1849..32441db 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py
@@ -7,4 +7,48 @@
 from frappe.model.document import Document
 
 class AccountingPeriod(Document):
-	pass
+	def validate(self):
+		self.validate_overlap()
+
+	def before_insert(self):
+		self.bootstrap_doctypes_for_closing()
+
+	def autoname(self):
+		company_abbr = frappe.db.get_value("Company", self.company, "abbr")
+		self.name = " - ".join([self.period_name, company_abbr])
+	
+	def validate_overlap(self):
+		existing_accounting_period = frappe.db.sql("""select name from `tabAccounting Period`
+			where (
+				(%(start_date)s between start_date and end_date)
+				or (%(end_date)s between start_date and end_date)
+				or (start_date between %(start_date)s and %(end_date)s)
+				or (end_date between %(start_date)s and %(end_date)s)
+			) and name!=%(name)s and company=%(company)s""",
+			{
+				"start_date": self.start_date,
+				"end_date": self.end_date,
+				"name": self.name,
+				"company": self.company
+			}, as_dict=True)
+
+		if len(existing_accounting_period) > 0:
+			frappe.throw("Accounting Period overlaps with {0}".format(existing_accounting_period[0].get("name")))
+
+	def get_doctypes_for_closing(self):
+		docs_for_closing = []
+		#if not self.closed_documents or len(self.closed_documents) == 0:
+		doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation", "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
+		closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
+		for closed_doctype in closed_doctypes:
+			docs_for_closing.append(closed_doctype)
+
+		return docs_for_closing
+
+	def bootstrap_doctypes_for_closing(self):
+		if len(self.closed_documents) == 0:
+			for doctype_for_closing in self.get_doctypes_for_closing():
+				self.append('closed_documents', {
+					"document_type": doctype_for_closing.document_type,
+					"closed": doctype_for_closing.closed
+				})
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 99694d2..cc2e6a9 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -7,4 +7,21 @@
 import unittest
 
 class TestAccountingPeriod(unittest.TestCase):
-	pass
+	def test_overlap(self):
+		ap1 = create_accounting_period({"start_date":"2018-04-01", "end_date":"2018-06-30", "company":"Wind Power LLC"})
+		ap1.save()
+		ap2 = create_accounting_period({"start_date":"2018-06-30", "end_date":"2018-07-10", "company":"Wind Power LLC"})
+		self.assertRaises(frappe.OverlapError, accounting_period_2.save())	
+	
+	def tearDown(self):
+		pass
+
+
+def create_accounting_period(**args):
+	accounting_period = frappe.new_doc("Accounting Period")
+	accounting_period.start_date = args.start_date or frappe.utils.datetime.date(2018, 4, 1)
+	accounting_period.end_date = args.end_date or frappe.utils.datetime.date(2018, 6, 30)
+	accounting_period.company = args.company
+	accounting_period.period_name = "_Test_Period_Name_1"
+	
+	return accounting_period
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 242c987..76b5ae5 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -18,7 +18,7 @@
 					doctype: frm.doc.doctype
 				}
 			};
-		});
+		}); 
 
 		frm.set_query("employee", erpnext.queries.employee);
 	},
@@ -27,6 +27,33 @@
 		frm.toggle_reqd("half_day_date", frm.doc.half_day == 1);
 	},
 
+	make_dashboard: function(frm) {
+		var leave_details;
+		if (frm.doc.employee) {
+			frappe.call({
+				method: "erpnext.hr.doctype.leave_application.leave_application.get_leave_details",
+				async: false,
+				args: {
+					employee: frm.doc.employee,
+					date: frm.doc.posting_date
+				},
+				callback: function(r) {
+					if (!r.exc && r.message) {
+						leave_details = r.message;
+					}
+				}
+			});
+
+			$("div").remove(".form-dashboard-section");
+			let section = frm.dashboard.add_section(
+				frappe.render_template('leave_application_dashboard', {
+					data: leave_details
+				})
+			);
+			frm.dashboard.show();
+		}
+	},
+
 	refresh: function(frm) {
 		if (frm.is_new()) {
 			frm.trigger("calculate_total_days");
@@ -43,6 +70,7 @@
 	},
 
 	employee: function(frm) {
+		frm.trigger("make_dashboard");
 		frm.trigger("get_leave_balance");
 	},
 
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 23514e1..304afdd 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -19,6 +19,7 @@
 
 from frappe.model.document import Document
 class LeaveApplication(Document):
+
 	def get_feed(self):
 		return _("{0}: From {0} of type {1}").format(self.employee_name, self.leave_type)
 
@@ -307,6 +308,24 @@
 	return number_of_days
 
 @frappe.whitelist()
+def get_leave_details(employee, date):
+	allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
+	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
+		leave_allocation[d] = {
+			"total_leaves": allocation.total_leaves_allocated,
+			"leaves_taken": leaves_taken,
+			"pending_leaves": leaves_pending,
+			"remaining_leaves": remaining_leaves}
+
+	return leave_allocation
+
+@frappe.whitelist()
 def get_leave_balance_on(employee, leave_type, date, allocation_records=None,
 		consider_all_leaves_in_the_allocation_period=False):
 	if allocation_records == None:
@@ -316,16 +335,16 @@
 
 	if consider_all_leaves_in_the_allocation_period:
 		date = allocation.to_date
-	leaves_taken = get_approved_leaves_for_period(employee, leave_type, allocation.from_date, date)
+	leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, date, status=Approved)
 
 	return flt(allocation.total_leaves_allocated) - flt(leaves_taken)
 
-def get_approved_leaves_for_period(employee, leave_type, from_date, to_date):
+def get_leaves_for_period(employee, leave_type, from_date, to_date, status):
 	leave_applications = frappe.db.sql("""
 		select employee, leave_type, from_date, to_date, total_leave_days
 		from `tabLeave Application`
 		where employee=%(employee)s and leave_type=%(leave_type)s
-			and docstatus=1
+			and status = %(status)s and docstatus=1
 			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))
@@ -333,6 +352,7 @@
 		"from_date": from_date,
 		"to_date": to_date,
 		"employee": employee,
+		"status": status,
 		"leave_type": leave_type
 	}, as_dict=1)
 
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.html b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
new file mode 100644
index 0000000..95e74a6
--- /dev/null
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.html
@@ -0,0 +1,30 @@
+
+{% if data %}
+<h5 style="margin-top: 20px;"> {{ __("Allocated Leaves") }} </h5>
+<table class="table table-bordered small">
+	<thead>
+		<tr>
+			<th style="width: 20%">{{ __("Leave Type") }}</th>
+			<th style="width: 20%" class="text-right">{{ __("Total Allocated Leaves") }}</th>
+			<th style="width: 20%" class="text-right">{{ __("Used Leaves") }}</th>
+			<th style="width: 20%" class="text-right">{{ __("Pending Leaves") }}</th>
+			<th style="width: 20%" class="text-right">{{ __("Available Leaves") }}</th>
+		</tr>
+		<!-- <p> {{data["Sick Leave"][0]["leaves_taken"]}}</p> -->
+		
+	</thead>
+	<tbody>
+		{% for(const [key, value] of Object.entries(data)) { %}
+			<tr>
+				<td> {%= key %} </td>
+				<td> {%= value["total_leaves"] %} </td>
+				<td> {%= value["leaves_taken"] %} </td>
+				<td> {%= value["pending_leaves"] %} </td>
+				<td> {%= value["remaining_leaves"] %} </td>
+			</tr>
+		{% } %}
+	</tbody>
+</table>
+{% } else { %}
+<p style="margin-top: 30px;"> No Leaves have been allocated. </p>
+{% } %}
\ No newline at end of file