Merge pull request #16306 from rohitwaghchaure/removed_duplicate_fields

[Fix] Duplicate fieldnames operation and allow_alternative_item in BOM Item
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 66d9bad..d518cd8 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -13,8 +13,8 @@
 from erpnext.utilities.transaction_base import delete_events
 from frappe.utils.nestedset import NestedSet
 
-class EmployeeUserDisabledError(frappe.ValidationError):
-	pass
+class EmployeeUserDisabledError(frappe.ValidationError): pass
+class EmployeeLeftValidationError(frappe.ValidationError): pass
 
 class Employee(NestedSet):
 	nsm_parent_field = 'reports_to'
@@ -147,8 +147,16 @@
 			validate_email_add(self.personal_email, True)
 
 	def validate_status(self):
-		if self.status == 'Left' and not self.relieving_date:
-			throw(_("Please enter relieving date."))
+		if self.status == 'Left':
+			reports_to = frappe.db.get_all('Employee',
+				filters={'reports_to': self.name}
+			)
+			if reports_to:
+				link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to]
+				throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ")
+					+ ', '.join(link_to_employees), EmployeeLeftValidationError)
+			if not self.relieving_date:
+				throw(_("Please enter relieving date."))
 
 	def validate_for_enabled_user_id(self, enabled):
 		if not self.status == 'Active':
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index 1afb8f4..5a63beb 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -7,6 +7,7 @@
 import erpnext
 import unittest
 import frappe.utils
+from erpnext.hr.doctype.employee.employee import EmployeeLeftValidationError
 
 test_records = frappe.get_test_records('Employee')
 
@@ -32,6 +33,18 @@
 		email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
 		self.assertTrue("Subject: Birthday Reminder" in email_queue[0].message)
 
+	def test_employee_status_left(self):
+		employee1 = make_employee("test_employee_1@company.com")
+		employee2 = make_employee("test_employee_2@company.com")
+		employee1_doc = frappe.get_doc("Employee", employee1)
+		employee2_doc = frappe.get_doc("Employee", employee2)
+		employee2_doc.reload()
+		employee2_doc.reports_to = employee1_doc.name
+		employee2_doc.save()
+		employee1_doc.reload()
+		employee1_doc.status = 'Left'
+		self.assertRaises(EmployeeLeftValidationError, employee1_doc.save)
+
 def make_employee(user):
 	if not frappe.db.get_value("User", user):
 		frappe.get_doc({
diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
new file mode 100644
index 0000000..5ab2847
--- /dev/null
+++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.utils import getdate
+from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
+from erpnext.hr.doctype.employee.test_employee import make_employee
+
+class TestUploadAttendance(unittest.TestCase):
+	def test_date_range(self):
+		employee = make_employee("test_employee@company.com")
+		employee_doc = frappe.get_doc("Employee", employee)
+		date_of_joining = "2018-01-02"
+		relieving_date = "2018-01-03"
+		from_date = "2018-01-01"
+		to_date = "2018-01-04"
+		employee_doc.date_of_joining = date_of_joining
+		employee_doc.relieving_date = relieving_date
+		employee_doc.save()
+		args = {
+			"from_date": from_date,
+			"to_date": to_date
+		}
+		data = get_data(args)
+		filtered_data = []
+		for row in data:
+			if row[1] == employee:
+				filtered_data.append(row)
+		print(filtered_data)
+		for row in filtered_data:
+			self.assertTrue(getdate(row[3]) >= getdate(date_of_joining) and getdate(row[3]) <= getdate(relieving_date))
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index 3d080a7..db74b10 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -41,16 +41,28 @@
 	return w
 
 def add_data(w, args):
+	data = get_data(args)
+	writedata(w, data)
+	return w
+
+def get_data(args):
 	dates = get_dates(args)
 	employees = get_active_employees()
 	existing_attendance_records = get_existing_attendance_records(args)
+	data = []
 	for date in dates:
 		for employee in employees:
+			if getdate(date) < getdate(employee.date_of_joining):
+				continue
+			if employee.relieving_date:
+				if getdate(date) > getdate(employee.relieving_date):
+					continue
 			existing_attendance = {}
 			if existing_attendance_records \
-				and tuple([getdate(date), employee.name]) in existing_attendance_records:
+				and tuple([getdate(date), employee.name]) in existing_attendance_records \
+				and getdate(employee.date_of_joining) >= getdate(date) \
+				and getdate(employee.relieving_date) <= getdate(date):
 					existing_attendance = existing_attendance_records[tuple([getdate(date), employee.name])]
-
 			row = [
 				existing_attendance and existing_attendance.name or "",
 				employee.name, employee.employee_name, date,
@@ -58,8 +70,12 @@
 				existing_attendance and existing_attendance.leave_type or "", employee.company,
 				existing_attendance and existing_attendance.naming_series or get_naming_series(),
 			]
-			w.writerow(row)
-	return w
+			data.append(row)
+	return data
+
+def writedata(w, data):
+	for row in data:
+		w.writerow(row)
 
 def get_dates(args):
 	"""get list of dates in between from date and to date"""
@@ -68,8 +84,13 @@
 	return dates
 
 def get_active_employees():
-	employees = frappe.db.sql("""select name, employee_name, company
-		from tabEmployee where docstatus < 2 and status = 'Active'""", as_dict=1)
+	employees = frappe.db.get_all('Employee',
+		fields=['name', 'employee_name', 'date_of_joining', 'company', 'relieving_date'],
+		filters={
+			'docstatus': ['<', 2],
+			'status': 'Active'
+		}
+	)
 	return employees
 
 def get_existing_attendance_records(args):