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 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)
|
||||
|
@ -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",
|
||||
|
@ -319,12 +319,12 @@ def get_holiday_list_for_employee(employee, raise_exception=True):
|
||||
|
||||
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()
|
||||
|
||||
|
@ -15,23 +15,24 @@ class EmployeeAttendanceLog(Document):
|
||||
|
||||
|
||||
@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 @@ def add_log_based_on_biometric_rf_id(biometric_rf_id, timestamp, device_id=None,
|
||||
doc.device_id = device_id
|
||||
doc.log_type = log_type
|
||||
doc.insert()
|
||||
frappe.db.commit()
|
||||
|
||||
return doc
|
||||
|
||||
|
@ -8,18 +8,18 @@ from frappe.utils import now_datetime, nowdate, to_timedelta
|
||||
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')
|
||||
|
@ -84,26 +84,3 @@ def get_events(start, end, filters=None):
|
||||
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)
|
@ -6,39 +6,27 @@ import frappe
|
||||
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
|
||||
|
@ -12,7 +12,7 @@ from frappe import _
|
||||
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 @@ def process_single_employee_logs(logs, hr_settings=None):
|
||||
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 @@ def mark_absent_for_days_with_no_attendance(employee, employee_last_sync, hr_set
|
||||
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 @@ def mark_absent_for_days_with_no_attendance(employee, employee_last_sync, hr_set
|
||||
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 get_filtered_date_list(employee, base_dates_set, start_date, end_date, filte
|
||||
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)
|
||||
|
@ -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
|
||||
}
|
@ -7,7 +7,7 @@ import frappe
|
||||
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 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
|
||||
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:
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user