fix(auto attendance): changes as requested in review
> removed unused field from shift assignment
> renamed 'biometric_rf_id' to 'attendance_device_id'
> added more test cases
> few other minor changes after demo
diff --git a/erpnext/hr/doctype/attendance/test_attendance.py b/erpnext/hr/doctype/attendance/test_attendance.py
index 7fe020a..35d1126 100644
--- a/erpnext/hr/doctype/attendance/test_attendance.py
+++ b/erpnext/hr/doctype/attendance/test_attendance.py
@@ -4,8 +4,17 @@
import frappe
import unittest
+from frappe.utils import nowdate
test_records = frappe.get_test_records('Attendance')
class TestAttendance(unittest.TestCase):
- pass
+ def test_mark_absent(self):
+ from erpnext.hr.doctype.employee.test_employee import make_employee
+ employee = make_employee("test_mark_absent@example.com")
+ date = nowdate()
+ frappe.db.delete('Attendance', {'employee':employee, 'attendance_date':date})
+ from erpnext.hr.doctype.attendance.attendance import mark_absent
+ attendance = mark_absent(employee, date)
+ fetch_attendance = frappe.get_value('Attendance', {'employee':employee, 'attendance_date':date, 'status':'Absent'})
+ self.assertEqual(attendance, fetch_attendance)
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index d138418..188d460 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -16,7 +16,7 @@
"middle_name",
"last_name",
"employee_name",
- "biometric_rf_id",
+ "attendance_device_id",
"image",
"column_break1",
"company",
@@ -511,6 +511,7 @@
"options": "Email"
},
{
+ "default": "0",
"fieldname": "unsubscribed",
"fieldtype": "Check",
"label": "Unsubscribed"
@@ -749,9 +750,9 @@
"label": "Old Parent"
},
{
- "fieldname": "biometric_rf_id",
+ "fieldname": "attendance_device_id",
"fieldtype": "Data",
- "label": "Biometric/RF tag ID ",
+ "label": "Attendance Device ID (Biometric/RF tag ID)",
"no_copy": 1,
"unique": 1
}
@@ -759,7 +760,7 @@
"icon": "fa fa-user",
"idx": 24,
"image_field": "image",
- "modified": "2019-05-08 14:32:06.443825",
+ "modified": "2019-05-29 17:33:11.988538",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 48957e5..63ba573 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -319,12 +319,12 @@
return holiday_list
-def is_holiday(employee, date=None):
+def is_holiday(employee, date=None, raise_exception=True):
'''Returns True if given Employee has an holiday on the given date
:param employee: Employee `name`
:param date: Date to check. Will check for today if None'''
- holiday_list = get_holiday_list_for_employee(employee)
+ holiday_list = get_holiday_list_for_employee(employee, raise_exception)
if not date:
date = today()
diff --git a/erpnext/hr/doctype/employee_attendance_log/employee_attendance_log.py b/erpnext/hr/doctype/employee_attendance_log/employee_attendance_log.py
index 3932f82..b25f9b9 100644
--- a/erpnext/hr/doctype/employee_attendance_log/employee_attendance_log.py
+++ b/erpnext/hr/doctype/employee_attendance_log/employee_attendance_log.py
@@ -15,23 +15,24 @@
@frappe.whitelist()
-def add_log_based_on_biometric_rf_id(biometric_rf_id, timestamp, device_id=None, log_type=None):
- """Finds the relevant Employee using the biometric_rf_id and creates a Employee Attendance Log.
+def add_log_based_on_employee_field(employee_field_value, timestamp, device_id=None, log_type=None, employee_fieldname='attendance_device_id'):
+ """Finds the relevant Employee using the employee field value and creates a Employee Attendance Log.
- :param biometric_rf_id: The Biometric/RF tag ID as set up in Employee DocType.
+ :param employee_field_value: The value to look for in employee field.
:param timestamp: The timestamp of the Log. Currently expected in the following format as string: '2019-05-08 10:48:08.000000'
:param device_id: (optional)Location / Device ID. A short string is expected.
:param log_type: (optional)Direction of the Punch if available (IN/OUT).
+ :param employee_fieldname: (Default: attendance_device_id)Name of the field in Employee DocType based on which employee lookup will happen.
"""
- if not biometric_rf_id or not timestamp:
- frappe.throw(_("'biometric_rf_id' and 'timestamp' are required."))
+ if not employee_field_value or not timestamp:
+ frappe.throw(_("'employee_field_value' and 'timestamp' are required."))
- employee = frappe.db.get_values("Employee", {"biometric_rf_id": biometric_rf_id}, ["name", "employee_name", "biometric_rf_id"], as_dict=True)
+ employee = frappe.db.get_values("Employee", {employee_fieldname: employee_field_value}, ["name", "employee_name", employee_fieldname], as_dict=True)
if employee:
employee = employee[0]
else:
- frappe.throw(_("No Employee found for the given 'biometric_rf_id':{}.").format(biometric_rf_id))
+ frappe.throw(_("No Employee found for the given employee field value. '{}': {}").format(employee_fieldname,employee_field_value))
doc = frappe.new_doc("Employee Attendance Log")
doc.employee = employee.name
@@ -40,7 +41,6 @@
doc.device_id = device_id
doc.log_type = log_type
doc.insert()
- frappe.db.commit()
return doc
diff --git a/erpnext/hr/doctype/employee_attendance_log/test_employee_attendance_log.py b/erpnext/hr/doctype/employee_attendance_log/test_employee_attendance_log.py
index fdc63d6..d1fcf0c 100644
--- a/erpnext/hr/doctype/employee_attendance_log/test_employee_attendance_log.py
+++ b/erpnext/hr/doctype/employee_attendance_log/test_employee_attendance_log.py
@@ -8,18 +8,18 @@
import unittest
from datetime import timedelta
-from erpnext.hr.doctype.employee_attendance_log.employee_attendance_log import add_log_based_on_biometric_rf_id, mark_attendance_and_link_log
+from erpnext.hr.doctype.employee_attendance_log.employee_attendance_log import add_log_based_on_employee_field, mark_attendance_and_link_log
from erpnext.hr.doctype.employee.test_employee import make_employee
class TestEmployeeAttendanceLog(unittest.TestCase):
- def test_add_log_based_on_biometric_rf_id(self):
- employee = make_employee("test_add_log_based_on_biometric_rf_id@example.com")
+ def test_add_log_based_on_employee_field(self):
+ employee = make_employee("test_add_log_based_on_employee_field@example.com")
employee = frappe.get_doc("Employee", employee)
- employee.biometric_rf_id = '3344'
+ employee.attendance_device_id = '3344'
employee.save()
time_now = now_datetime().__str__()[:-7]
- employee_attendance_log = add_log_based_on_biometric_rf_id('3344', time_now, 'mumbai_first_floor', 'IN')
+ employee_attendance_log = add_log_based_on_employee_field('3344', time_now, 'mumbai_first_floor', 'IN')
self.assertEqual(employee_attendance_log.employee, employee.name)
self.assertEqual(employee_attendance_log.time, time_now)
self.assertEqual(employee_attendance_log.device_id, 'mumbai_first_floor')
diff --git a/erpnext/hr/doctype/holiday_list/holiday_list.py b/erpnext/hr/doctype/holiday_list/holiday_list.py
index 453320f..e475e6e 100644
--- a/erpnext/hr/doctype/holiday_list/holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/holiday_list.py
@@ -84,26 +84,3 @@
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description', '`tabHoliday List`.color'],
filters = filters,
update={"allDay": 1})
-
-def get_holiday_list(employee):
- employee_holiday = frappe.db.get_all('Employee', fields=['name', 'holiday_list', 'company'], filters={'name':employee})
- if not employee_holiday:
- frappe.throw(_("Employee not found."))
- if employee_holiday[0].holiday_list:
- return employee_holiday[0].holiday_list
- else:
- company_holiday = frappe.db.get_all('Company', fields=['name', 'default_holiday_list'], filters={'name':employee_holiday[0].company})
- if company_holiday[0].default_holiday_list:
- return company_holiday[0].default_holiday_list
- return None
-
-def is_holiday(holiday_list, for_date):
- """Returns true if the given date is a holiday in the given holiday list
- """
- holiday = frappe.get_value('Holiday', {
- 'parent': holiday_list,
- 'parentfield': 'holidays',
- 'parenttype': 'Holiday List',
- 'holiday_date': for_date
- }, 'name')
- return bool(holiday)
\ No newline at end of file
diff --git a/erpnext/hr/doctype/holiday_list/test_holiday_list.py b/erpnext/hr/doctype/holiday_list/test_holiday_list.py
index 33a24d1..2d2cc0b 100644
--- a/erpnext/hr/doctype/holiday_list/test_holiday_list.py
+++ b/erpnext/hr/doctype/holiday_list/test_holiday_list.py
@@ -6,39 +6,27 @@
import unittest
from frappe.utils import getdate
from datetime import timedelta
-from erpnext.hr.doctype.employee.test_employee import make_employee
class TestHolidayList(unittest.TestCase):
- def test_get_holiday_list(self):
- holiday_list = make_holiday_list("test_get_holiday_list")
- employee = make_employee("test_get_holiday_list@example.com")
- employee = frappe.get_doc("Employee", employee)
- employee.holiday_list = None
- employee.save()
- company = frappe.get_doc("Company", employee.company)
- company_default_holiday_list = company.default_holiday_list
-
- from erpnext.hr.doctype.holiday_list.holiday_list import get_holiday_list
- holiday_list_name = get_holiday_list(employee.name)
- self.assertEqual(holiday_list_name, company_default_holiday_list)
-
- employee.holiday_list = holiday_list.name
- employee.save()
- holiday_list_name = get_holiday_list(employee.name)
- self.assertEqual(holiday_list_name, holiday_list.name)
-
+ def test_holiday_list(self):
+ today_date = getdate()
+ test_holiday_dates = [today_date-timedelta(days=5), today_date-timedelta(days=4)]
+ holiday_list = make_holiday_list("test_is_holiday",
+ holiday_dates=[
+ {'holiday_date': test_holiday_dates[0], 'description': 'test holiday'},
+ {'holiday_date': test_holiday_dates[1], 'description': 'test holiday2'}
+ ])
+ fetched_holiday_list = frappe.get_value('Holiday List', holiday_list.name)
+ self.assertEqual(holiday_list.name, fetched_holiday_list)
def make_holiday_list(name, from_date=getdate()-timedelta(days=10), to_date=getdate(), holiday_dates=None):
- if not frappe.db.get_value("Holiday List", name):
- doc = frappe.get_doc({
- "doctype": "Holiday List",
- "holiday_list_name": name,
- "from_date" : from_date,
- "to_date" : to_date
- }).insert()
- doc.holidays = holiday_dates
- doc.save()
- else:
- doc = frappe.get_doc("Holiday List", name)
+ frappe.delete_doc_if_exists("Holiday List", name, force=1)
+ doc = frappe.get_doc({
+ "doctype": "Holiday List",
+ "holiday_list_name": name,
+ "from_date" : from_date,
+ "to_date" : to_date,
+ "holidays" : holiday_dates
+ }).insert()
return doc
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.py b/erpnext/hr/doctype/hr_settings/hr_settings.py
index afd90f7..9511ff1 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.py
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.py
@@ -12,7 +12,7 @@
from frappe.model.document import Document
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_employee_shift_timings, get_employee_shift
from erpnext.hr.doctype.employee_attendance_log.employee_attendance_log import mark_attendance_and_link_log
-from erpnext.hr.doctype.holiday_list.holiday_list import get_holiday_list
+from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.hr.doctype.attendance.attendance import mark_absent
class HRSettings(Document):
@@ -79,9 +79,9 @@
while logs and logs[0].time <= actual_shift_end:
single_shift_logs.append(logs.pop(0))
process_single_employee_shift_logs(single_shift_logs, shift_details)
- mark_absent_for_days_with_no_attendance(last_log.employee, employee_last_sync, hr_settings)
+ mark_absent_for_dates_with_no_attendance(last_log.employee, employee_last_sync, hr_settings)
-def mark_absent_for_days_with_no_attendance(employee, employee_last_sync, hr_settings=None):
+def mark_absent_for_dates_with_no_attendance(employee, employee_last_sync, hr_settings=None):
"""Marks Absents for the given employee on working days which have no attendance marked.
The Absent is marked starting from one shift before the employee_last_sync
going back to 'hr_settings.process_attendance_after' or employee creation date.
@@ -100,7 +100,7 @@
if prev_shift:
end_date = prev_shift.start_datetime.date()
elif hr_settings.attendance_for_employee_without_shift == 'At least one Employee Attendance Log per day as present':
- for date in get_filtered_date_list(employee, "All Dates", start_date, employee_last_sync.date(), True, get_holiday_list(employee)):
+ for date in get_filtered_date_list(employee, "All Dates", start_date, employee_last_sync.date(), True, get_holiday_list_for_employee(employee, False)):
mark_absent(employee, date)
return
else:
@@ -111,7 +111,7 @@
if get_employee_shift(employee, date, consider_default_shift):
mark_absent(employee, date)
elif hr_settings.attendance_for_employee_without_shift == 'At least one Employee Attendance Log per day as present':
- for date in get_filtered_date_list(employee, "All Dates", start_date, employee_last_sync.date(), True, get_holiday_list(employee)):
+ for date in get_filtered_date_list(employee, "All Dates", start_date, employee_last_sync.date(), True, get_holiday_list_for_employee(employee, False)):
mark_absent(employee, date)
else:
for date in get_filtered_date_list(employee, "Assigned Shifts", start_date, end_date):
@@ -155,9 +155,12 @@
def process_single_employee_shift_logs(logs, shift_details):
"""Mark Attendance for a set of logs belonging to a single shift.
Assumtion:
- 1. These logs belongs to an single shift, single employee and is not in a holiday shift.
+ 1. These logs belongs to an single shift, single employee and is not in a holiday date.
2. Logs are in chronological order
"""
+ if shift_details.shift_type.enable_auto_attendance:
+ mark_attendance_and_link_log(logs, 'Skip', None)
+ return
check_in_out_type = shift_details.shift_type.determine_check_in_and_check_out
working_hours_calc_type = shift_details.shift_type.working_hours_calculation_based_on
total_working_hours = calculate_working_hours(logs, check_in_out_type, working_hours_calc_type)
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.json b/erpnext/hr/doctype/shift_assignment/shift_assignment.json
index 437e4d7..d4cd1c4 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.json
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.json
@@ -1,429 +1,132 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "HR-SHA-.YY.-.MM.-.#####",
- "beta": 0,
- "creation": "2018-04-13 16:25:04.562730",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_import": 1,
+ "autoname": "HR-SHA-.YY.-.MM.-.#####",
+ "creation": "2018-04-13 16:25:04.562730",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "department",
+ "shift_type",
+ "column_break_3",
+ "company",
+ "date",
+ "shift_request",
+ "amended_from"
+ ],
"fields": [
{
- "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": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "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
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 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": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "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
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "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.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
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shift_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": 0,
- "label": "Shift Type",
- "length": 0,
- "no_copy": 0,
- "options": "Shift Type",
- "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
- },
+ "fieldname": "shift_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Shift Type",
+ "options": "Shift Type",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "present",
- "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": "Present",
- "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
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "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
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "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": 0,
- "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
- },
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "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": "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": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "shift_request",
+ "fieldtype": "Link",
+ "label": "Shift Request",
+ "options": "Shift Request",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shift_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": "Shift Request",
- "length": 0,
- "no_copy": 0,
- "options": "Shift 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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Shift Assignment",
- "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
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Shift Assignment",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:41.155464",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Shift Assignment",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "modified": "2019-05-30 15:40:54.418427",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Shift Assignment",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1
+ },
{
- "amend": 1,
- "cancel": 1,
- "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": 1,
+ "amend": 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
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "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": 1,
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "employee_name",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
index c90894e..ac8c8f2 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py
@@ -7,7 +7,7 @@
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, now_datetime, nowdate
-from erpnext.hr.doctype.holiday_list.holiday_list import get_holiday_list, is_holiday
+from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee, is_holiday
from datetime import timedelta, datetime
class OverlapError(frappe.ValidationError): pass
@@ -97,8 +97,8 @@
if shift_type_name:
holiday_list_name = frappe.db.get_value('Shift Type', shift_type_name, 'holiday_list')
if not holiday_list_name:
- holiday_list_name = get_holiday_list(employee)
- if holiday_list_name and is_holiday(holiday_list_name, for_date):
+ holiday_list_name = get_holiday_list_for_employee(employee, False)
+ if holiday_list_name and is_holiday(holiday_list_name, for_date, False):
shift_type_name = None
if not shift_type_name and next_shift_direction:
diff --git a/erpnext/hr/doctype/shift_type/shift_type.json b/erpnext/hr/doctype/shift_type/shift_type.json
index 1ee30b2..0c295c6 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.json
+++ b/erpnext/hr/doctype/shift_type/shift_type.json
@@ -7,10 +7,10 @@
"field_order": [
"start_time",
"end_time",
- "disable_auto_attendance_for_this_shift",
"column_break_3",
"holiday_list",
- "auto_attendance_configurations_section",
+ "enable_auto_attendance",
+ "auto_attendance_settings_section",
"determine_check_in_and_check_out",
"working_hours_calculation_based_on",
"begin_check_in_before_shift_start_time",
@@ -18,7 +18,7 @@
"column_break_10",
"working_hours_threshold_for_half_day",
"working_hours_threshold_for_absent",
- "grace_period_configuration_auto_attendance_section",
+ "grace_period_settings_auto_attendance_section",
"enable_entry_grace_period",
"late_entry_grace_period",
"consequence_after",
@@ -86,33 +86,14 @@
"precision": "1"
},
{
- "depends_on": "eval:!doc.disable_auto_attendance_for_this_shift",
- "fieldname": "auto_attendance_configurations_section",
- "fieldtype": "Section Break",
- "label": "Auto Attendance Configurations"
- },
- {
- "default": "45",
+ "default": "60",
"description": "The time before the shift start time during which Employee Check-in is considered for attendance.",
"fieldname": "begin_check_in_before_shift_start_time",
"fieldtype": "Int",
"label": "Begin check-in before shift start time (in minutes)"
},
{
- "default": "1",
- "description": "Don't mark attendance based on Employee Attendance Log.",
- "fieldname": "disable_auto_attendance_for_this_shift",
- "fieldtype": "Check",
- "label": "Disable Auto Attendance for this shift"
- },
- {
- "depends_on": "eval:!doc.disable_auto_attendance_for_this_shift",
- "fieldname": "grace_period_configuration_auto_attendance_section",
- "fieldtype": "Section Break",
- "hidden": 1,
- "label": "Grace Period Configuration For Auto Attendance"
- },
- {
+ "default": "0",
"fieldname": "enable_entry_grace_period",
"fieldtype": "Check",
"label": "Enable Entry Grace Period"
@@ -144,11 +125,13 @@
"fieldtype": "Column Break"
},
{
+ "default": "0",
"fieldname": "enable_exit_grace_period",
"fieldtype": "Check",
"label": "Enable Exit Grace Period"
},
{
+ "default": "0",
"depends_on": "enable_exit_grace_period",
"fieldname": "enable_different_consequence_for_early_exit",
"fieldtype": "Check",
@@ -177,13 +160,34 @@
"options": "Half Day\nAbsent"
},
{
- "description": "Time after the end of shift during which check-out is considered for attendance. (Zero to allow till next shift begins)",
+ "default": "60",
+ "description": "Time after the end of shift during which check-out is considered for attendance.",
"fieldname": "allow_check_out_after_shift_end_time",
"fieldtype": "Int",
"label": "Allow check-out after shift end time (in minutes)"
+ },
+ {
+ "depends_on": "enable_auto_attendance",
+ "fieldname": "auto_attendance_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Auto Attendance Settings"
+ },
+ {
+ "depends_on": "enable_auto_attendance",
+ "fieldname": "grace_period_settings_auto_attendance_section",
+ "fieldtype": "Section Break",
+ "hidden": 1,
+ "label": "Grace Period Settings For Auto Attendance"
+ },
+ {
+ "default": "0",
+ "description": "Mark attendance based on 'Employee Attendance Log' for Employees assigned to this shift.",
+ "fieldname": "enable_auto_attendance",
+ "fieldtype": "Check",
+ "label": "Enable Auto Attendance"
}
],
- "modified": "2019-05-16 18:57:00.150899",
+ "modified": "2019-05-30 15:31:35.594990",
"modified_by": "Administrator",
"module": "HR",
"name": "Shift Type",