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
This commit is contained in:
parent
23cedfd6c8
commit
66e459b35d
@ -4,8 +4,17 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
from frappe.utils import nowdate
|
||||||
|
|
||||||
test_records = frappe.get_test_records('Attendance')
|
test_records = frappe.get_test_records('Attendance')
|
||||||
|
|
||||||
class TestAttendance(unittest.TestCase):
|
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)
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
"middle_name",
|
"middle_name",
|
||||||
"last_name",
|
"last_name",
|
||||||
"employee_name",
|
"employee_name",
|
||||||
"biometric_rf_id",
|
"attendance_device_id",
|
||||||
"image",
|
"image",
|
||||||
"column_break1",
|
"column_break1",
|
||||||
"company",
|
"company",
|
||||||
@ -511,6 +511,7 @@
|
|||||||
"options": "Email"
|
"options": "Email"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"fieldname": "unsubscribed",
|
"fieldname": "unsubscribed",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Unsubscribed"
|
"label": "Unsubscribed"
|
||||||
@ -749,9 +750,9 @@
|
|||||||
"label": "Old Parent"
|
"label": "Old Parent"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "biometric_rf_id",
|
"fieldname": "attendance_device_id",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "Biometric/RF tag ID ",
|
"label": "Attendance Device ID (Biometric/RF tag ID)",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"unique": 1
|
"unique": 1
|
||||||
}
|
}
|
||||||
@ -759,7 +760,7 @@
|
|||||||
"icon": "fa fa-user",
|
"icon": "fa fa-user",
|
||||||
"idx": 24,
|
"idx": 24,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"modified": "2019-05-08 14:32:06.443825",
|
"modified": "2019-05-29 17:33:11.988538",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Employee",
|
"name": "Employee",
|
||||||
|
|||||||
@ -319,12 +319,12 @@ def get_holiday_list_for_employee(employee, raise_exception=True):
|
|||||||
|
|
||||||
return holiday_list
|
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
|
'''Returns True if given Employee has an holiday on the given date
|
||||||
:param employee: Employee `name`
|
:param employee: Employee `name`
|
||||||
:param date: Date to check. Will check for today if None'''
|
: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:
|
if not date:
|
||||||
date = today()
|
date = today()
|
||||||
|
|
||||||
|
|||||||
@ -15,23 +15,24 @@ class EmployeeAttendanceLog(Document):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def add_log_based_on_biometric_rf_id(biometric_rf_id, timestamp, device_id=None, log_type=None):
|
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 biometric_rf_id and creates a Employee Attendance Log.
|
"""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 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 device_id: (optional)Location / Device ID. A short string is expected.
|
||||||
:param log_type: (optional)Direction of the Punch if available (IN/OUT).
|
: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:
|
if not employee_field_value or not timestamp:
|
||||||
frappe.throw(_("'biometric_rf_id' and 'timestamp' are required."))
|
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:
|
if employee:
|
||||||
employee = employee[0]
|
employee = employee[0]
|
||||||
else:
|
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 = frappe.new_doc("Employee Attendance Log")
|
||||||
doc.employee = employee.name
|
doc.employee = employee.name
|
||||||
@ -40,7 +41,6 @@ def add_log_based_on_biometric_rf_id(biometric_rf_id, timestamp, device_id=None,
|
|||||||
doc.device_id = device_id
|
doc.device_id = device_id
|
||||||
doc.log_type = log_type
|
doc.log_type = log_type
|
||||||
doc.insert()
|
doc.insert()
|
||||||
frappe.db.commit()
|
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|||||||
@ -8,18 +8,18 @@ from frappe.utils import now_datetime, nowdate, to_timedelta
|
|||||||
import unittest
|
import unittest
|
||||||
from datetime import timedelta
|
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
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
|
||||||
class TestEmployeeAttendanceLog(unittest.TestCase):
|
class TestEmployeeAttendanceLog(unittest.TestCase):
|
||||||
def test_add_log_based_on_biometric_rf_id(self):
|
def test_add_log_based_on_employee_field(self):
|
||||||
employee = make_employee("test_add_log_based_on_biometric_rf_id@example.com")
|
employee = make_employee("test_add_log_based_on_employee_field@example.com")
|
||||||
employee = frappe.get_doc("Employee", employee)
|
employee = frappe.get_doc("Employee", employee)
|
||||||
employee.biometric_rf_id = '3344'
|
employee.attendance_device_id = '3344'
|
||||||
employee.save()
|
employee.save()
|
||||||
|
|
||||||
time_now = now_datetime().__str__()[:-7]
|
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.employee, employee.name)
|
||||||
self.assertEqual(employee_attendance_log.time, time_now)
|
self.assertEqual(employee_attendance_log.time, time_now)
|
||||||
self.assertEqual(employee_attendance_log.device_id, 'mumbai_first_floor')
|
self.assertEqual(employee_attendance_log.device_id, 'mumbai_first_floor')
|
||||||
|
|||||||
@ -84,26 +84,3 @@ def get_events(start, end, filters=None):
|
|||||||
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description', '`tabHoliday List`.color'],
|
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description', '`tabHoliday List`.color'],
|
||||||
filters = filters,
|
filters = filters,
|
||||||
update={"allDay": 1})
|
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)
|
|
||||||
@ -6,39 +6,27 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from erpnext.hr.doctype.employee.test_employee import make_employee
|
|
||||||
|
|
||||||
|
|
||||||
class TestHolidayList(unittest.TestCase):
|
class TestHolidayList(unittest.TestCase):
|
||||||
def test_get_holiday_list(self):
|
def test_holiday_list(self):
|
||||||
holiday_list = make_holiday_list("test_get_holiday_list")
|
today_date = getdate()
|
||||||
employee = make_employee("test_get_holiday_list@example.com")
|
test_holiday_dates = [today_date-timedelta(days=5), today_date-timedelta(days=4)]
|
||||||
employee = frappe.get_doc("Employee", employee)
|
holiday_list = make_holiday_list("test_is_holiday",
|
||||||
employee.holiday_list = None
|
holiday_dates=[
|
||||||
employee.save()
|
{'holiday_date': test_holiday_dates[0], 'description': 'test holiday'},
|
||||||
company = frappe.get_doc("Company", employee.company)
|
{'holiday_date': test_holiday_dates[1], 'description': 'test holiday2'}
|
||||||
company_default_holiday_list = company.default_holiday_list
|
])
|
||||||
|
fetched_holiday_list = frappe.get_value('Holiday List', holiday_list.name)
|
||||||
from erpnext.hr.doctype.holiday_list.holiday_list import get_holiday_list
|
self.assertEqual(holiday_list.name, fetched_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 make_holiday_list(name, from_date=getdate()-timedelta(days=10), to_date=getdate(), holiday_dates=None):
|
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):
|
frappe.delete_doc_if_exists("Holiday List", name, force=1)
|
||||||
doc = frappe.get_doc({
|
doc = frappe.get_doc({
|
||||||
"doctype": "Holiday List",
|
"doctype": "Holiday List",
|
||||||
"holiday_list_name": name,
|
"holiday_list_name": name,
|
||||||
"from_date" : from_date,
|
"from_date" : from_date,
|
||||||
"to_date" : to_date
|
"to_date" : to_date,
|
||||||
}).insert()
|
"holidays" : holiday_dates
|
||||||
doc.holidays = holiday_dates
|
}).insert()
|
||||||
doc.save()
|
|
||||||
else:
|
|
||||||
doc = frappe.get_doc("Holiday List", name)
|
|
||||||
return doc
|
return doc
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
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.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.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
|
from erpnext.hr.doctype.attendance.attendance import mark_absent
|
||||||
|
|
||||||
class HRSettings(Document):
|
class HRSettings(Document):
|
||||||
@ -79,9 +79,9 @@ def process_single_employee_logs(logs, hr_settings=None):
|
|||||||
while logs and logs[0].time <= actual_shift_end:
|
while logs and logs[0].time <= actual_shift_end:
|
||||||
single_shift_logs.append(logs.pop(0))
|
single_shift_logs.append(logs.pop(0))
|
||||||
process_single_employee_shift_logs(single_shift_logs, shift_details)
|
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.
|
"""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
|
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.
|
going back to 'hr_settings.process_attendance_after' or employee creation date.
|
||||||
@ -100,7 +100,7 @@ def mark_absent_for_days_with_no_attendance(employee, employee_last_sync, hr_set
|
|||||||
if prev_shift:
|
if prev_shift:
|
||||||
end_date = prev_shift.start_datetime.date()
|
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':
|
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)
|
mark_absent(employee, date)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@ -111,7 +111,7 @@ def mark_absent_for_days_with_no_attendance(employee, employee_last_sync, hr_set
|
|||||||
if get_employee_shift(employee, date, consider_default_shift):
|
if get_employee_shift(employee, date, consider_default_shift):
|
||||||
mark_absent(employee, date)
|
mark_absent(employee, date)
|
||||||
elif hr_settings.attendance_for_employee_without_shift == 'At least one Employee Attendance Log per day as present':
|
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)
|
mark_absent(employee, date)
|
||||||
else:
|
else:
|
||||||
for date in get_filtered_date_list(employee, "Assigned Shifts", start_date, end_date):
|
for date in get_filtered_date_list(employee, "Assigned Shifts", start_date, end_date):
|
||||||
@ -155,9 +155,12 @@ def get_filtered_date_list(employee, base_dates_set, start_date, end_date, filte
|
|||||||
def process_single_employee_shift_logs(logs, shift_details):
|
def process_single_employee_shift_logs(logs, shift_details):
|
||||||
"""Mark Attendance for a set of logs belonging to a single shift.
|
"""Mark Attendance for a set of logs belonging to a single shift.
|
||||||
Assumtion:
|
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
|
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
|
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
|
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)
|
total_working_hours = calculate_working_hours(logs, check_in_out_type, working_hours_calc_type)
|
||||||
|
|||||||
@ -1,381 +1,101 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "HR-SHA-.YY.-.MM.-.#####",
|
"autoname": "HR-SHA-.YY.-.MM.-.#####",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2018-04-13 16:25:04.562730",
|
"creation": "2018-04-13 16:25:04.562730",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"employee",
|
||||||
|
"employee_name",
|
||||||
|
"department",
|
||||||
|
"shift_type",
|
||||||
|
"column_break_3",
|
||||||
|
"company",
|
||||||
|
"date",
|
||||||
|
"shift_request",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Employee",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee",
|
"options": "Employee",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.employee_name",
|
"fetch_from": "employee.employee_name",
|
||||||
"fieldname": "employee_name",
|
"fieldname": "employee_name",
|
||||||
"fieldtype": "Data",
|
"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",
|
"label": "Employee Name",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Department",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
"options": "Department",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"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": "shift_type",
|
"fieldname": "shift_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Shift Type",
|
"label": "Shift Type",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shift Type",
|
"options": "Shift Type",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break",
|
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "date",
|
"fieldname": "date",
|
||||||
"fieldtype": "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_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"label": "Date"
|
||||||
"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
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "shift_request",
|
"fieldname": "shift_request",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Shift Request",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shift Request",
|
"options": "Shift Request",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"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",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Shift Assignment",
|
"options": "Shift Assignment",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"modified": "2019-05-30 15:40:54.418427",
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-08-21 16:15:41.155464",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Shift Assignment",
|
"name": "Shift Assignment",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 0,
|
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Employee",
|
"role": "Employee",
|
||||||
"set_user_permissions": 0,
|
"share": 1
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
@ -384,46 +104,29 @@
|
|||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR Manager",
|
"role": "HR Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 0,
|
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 0,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR User",
|
"role": "HR User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "employee_name",
|
"title_field": "employee_name",
|
||||||
"track_changes": 1,
|
"track_changes": 1
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
||||||
@ -7,7 +7,7 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, now_datetime, nowdate
|
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
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
class OverlapError(frappe.ValidationError): pass
|
||||||
@ -97,8 +97,8 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
|
|||||||
if shift_type_name:
|
if shift_type_name:
|
||||||
holiday_list_name = frappe.db.get_value('Shift Type', shift_type_name, 'holiday_list')
|
holiday_list_name = frappe.db.get_value('Shift Type', shift_type_name, 'holiday_list')
|
||||||
if not holiday_list_name:
|
if not holiday_list_name:
|
||||||
holiday_list_name = get_holiday_list(employee)
|
holiday_list_name = get_holiday_list_for_employee(employee, False)
|
||||||
if holiday_list_name and is_holiday(holiday_list_name, for_date):
|
if holiday_list_name and is_holiday(holiday_list_name, for_date, False):
|
||||||
shift_type_name = None
|
shift_type_name = None
|
||||||
|
|
||||||
if not shift_type_name and next_shift_direction:
|
if not shift_type_name and next_shift_direction:
|
||||||
|
|||||||
@ -7,10 +7,10 @@
|
|||||||
"field_order": [
|
"field_order": [
|
||||||
"start_time",
|
"start_time",
|
||||||
"end_time",
|
"end_time",
|
||||||
"disable_auto_attendance_for_this_shift",
|
|
||||||
"column_break_3",
|
"column_break_3",
|
||||||
"holiday_list",
|
"holiday_list",
|
||||||
"auto_attendance_configurations_section",
|
"enable_auto_attendance",
|
||||||
|
"auto_attendance_settings_section",
|
||||||
"determine_check_in_and_check_out",
|
"determine_check_in_and_check_out",
|
||||||
"working_hours_calculation_based_on",
|
"working_hours_calculation_based_on",
|
||||||
"begin_check_in_before_shift_start_time",
|
"begin_check_in_before_shift_start_time",
|
||||||
@ -18,7 +18,7 @@
|
|||||||
"column_break_10",
|
"column_break_10",
|
||||||
"working_hours_threshold_for_half_day",
|
"working_hours_threshold_for_half_day",
|
||||||
"working_hours_threshold_for_absent",
|
"working_hours_threshold_for_absent",
|
||||||
"grace_period_configuration_auto_attendance_section",
|
"grace_period_settings_auto_attendance_section",
|
||||||
"enable_entry_grace_period",
|
"enable_entry_grace_period",
|
||||||
"late_entry_grace_period",
|
"late_entry_grace_period",
|
||||||
"consequence_after",
|
"consequence_after",
|
||||||
@ -86,33 +86,14 @@
|
|||||||
"precision": "1"
|
"precision": "1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval:!doc.disable_auto_attendance_for_this_shift",
|
"default": "60",
|
||||||
"fieldname": "auto_attendance_configurations_section",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"label": "Auto Attendance Configurations"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"default": "45",
|
|
||||||
"description": "The time before the shift start time during which Employee Check-in is considered for attendance.",
|
"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",
|
"fieldname": "begin_check_in_before_shift_start_time",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Begin check-in before shift start time (in minutes)"
|
"label": "Begin check-in before shift start time (in minutes)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "1",
|
"default": "0",
|
||||||
"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"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldname": "enable_entry_grace_period",
|
"fieldname": "enable_entry_grace_period",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enable Entry Grace Period"
|
"label": "Enable Entry Grace Period"
|
||||||
@ -144,11 +125,13 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"fieldname": "enable_exit_grace_period",
|
"fieldname": "enable_exit_grace_period",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enable Exit Grace Period"
|
"label": "Enable Exit Grace Period"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"depends_on": "enable_exit_grace_period",
|
"depends_on": "enable_exit_grace_period",
|
||||||
"fieldname": "enable_different_consequence_for_early_exit",
|
"fieldname": "enable_different_consequence_for_early_exit",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -177,13 +160,34 @@
|
|||||||
"options": "Half Day\nAbsent"
|
"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",
|
"fieldname": "allow_check_out_after_shift_end_time",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"label": "Allow check-out after shift end time (in minutes)"
|
"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",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Shift Type",
|
"name": "Shift Type",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user