fix(hr): Auto Attendance

> fixing minor bug in shift calculation
> adding 'Mark Auto Attendance' button in shift and related fixes
> changed employee checkin naming series
> added aditional validation for employee checkin
> added/updated dashboard for Attendance, Employee, Shift Type
This commit is contained in:
karthikeyan5 2019-06-11 14:25:34 +05:30
parent 32197355ad
commit 82256bc58b
8 changed files with 47 additions and 20 deletions

View File

@ -0,0 +1,13 @@
from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'attendance',
'transactions': [
{
'label': '',
'items': ['Employee Checkin']
}
]
}

View File

@ -9,7 +9,7 @@ def get_data():
'transactions': [
{
'label': _('Leave and Attendance'),
'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation']
'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation', 'Employee Checkin']
},
{
'label': _('Lifecycle'),
@ -40,4 +40,4 @@ def get_data():
'items': ['Training Event', 'Training Result', 'Training Feedback', 'Employee Skill Map']
},
]
}
}

View File

@ -1,6 +1,6 @@
{
"allow_import": 1,
"autoname": "ATT-CKIN-.MM.-.YYYY.-.######",
"autoname": "EMP-CKIN-.MM.-.YYYY.-.######",
"creation": "2019-06-10 11:56:34.536413",
"doctype": "DocType",
"engine": "InnoDB",
@ -119,7 +119,7 @@
"label": "Shift Actual End"
}
],
"modified": "2019-06-10 11:56:34.536413",
"modified": "2019-06-10 15:33:22.731697",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Checkin",

View File

@ -28,6 +28,8 @@ class EmployeeCheckin(Document):
def fetch_shift(self):
shift_actual_timings = get_actual_start_end_datetime_of_shift(self.employee, get_datetime(self.time), True)
if shift_actual_timings[0] and shift_actual_timings[1]:
if shift_actual_timings[2].shift_type.determine_check_in_and_check_out == 'Strictly based on Log Type in Employee Checkin' and not self.log_type and not self.skip_auto_attendance:
frappe.throw(_('Log Type is required for check-ins falling in the shift: {0}.').format(shift_actual_timings[2].shift_type.name))
if not self.attendance:
self.shift = shift_actual_timings[2].shift_type.name
self.shift_actual_start = shift_actual_timings[0]

View File

@ -115,11 +115,12 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals
break
else:
direction = '<' if next_shift_direction == 'reverse' else '>'
sort_order = 'desc' if next_shift_direction == 'reverse' else 'asc'
dates = frappe.db.get_all('Shift Assignment',
'date',
{'employee':employee, 'date':(direction, for_date), 'docstatus': '1'},
as_list=True,
limit=MAX_DAYS)
limit=MAX_DAYS, order_by="date "+sort_order)
for date in dates:
shift_details = get_employee_shift(employee, date[0], consider_default_shift, None)
if shift_details:

View File

@ -3,6 +3,16 @@
frappe.ui.form.on('Shift Type', {
refresh: function(frm) {
frm.add_custom_button(
'Mark Auto Attendance',
() => frm.call({
doc: frm.doc,
method: 'process_auto_attendance',
freeze: true,
callback: () => {
frappe.msgprint(__("Attendance has been marked as per employee check-ins"));
}
})
);
}
});

View File

@ -8,7 +8,7 @@ from datetime import timedelta
import frappe
from frappe.model.document import Document
from frappe.utils import cint, getdate
from frappe.utils import cint, getdate, get_datetime
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift, get_employee_shift
from erpnext.hr.doctype.employee_checkin.employee_checkin import mark_attendance_and_link_log, calculate_working_hours
from erpnext.hr.doctype.attendance.attendance import mark_absent
@ -53,9 +53,9 @@ class ShiftType(Document):
date_of_joining, relieving_date, employee_creation = frappe.db.get_value("Employee", employee, ["date_of_joining", "relieving_date", "creation"])
if not date_of_joining:
date_of_joining = employee_creation.date()
start_date = max(self.process_attendance_after, date_of_joining)
actual_shift_datetime = get_actual_start_end_datetime_of_shift(employee, self.last_sync_of_checkin, True)
last_shift_time = actual_shift_datetime[0] if actual_shift_datetime[0] else self.last_sync_of_checkin
start_date = max(getdate(self.process_attendance_after), date_of_joining)
actual_shift_datetime = get_actual_start_end_datetime_of_shift(employee, get_datetime(self.last_sync_of_checkin), True)
last_shift_time = actual_shift_datetime[0] if actual_shift_datetime[0] else get_datetime(self.last_sync_of_checkin)
prev_shift = get_employee_shift(employee, last_shift_time.date()-timedelta(days=1), True, 'reverse')
if prev_shift:
end_date = min(prev_shift.start_datetime.date(), relieving_date) if relieving_date else prev_shift.start_datetime.date()
@ -64,10 +64,11 @@ class ShiftType(Document):
holiday_list_name = self.holiday_list
if not holiday_list_name:
holiday_list_name = get_holiday_list_for_employee(employee, False)
for date in get_filtered_date_list(employee, start_date, end_date, holiday_list=holiday_list_name):
dates = get_filtered_date_list(employee, start_date, end_date, holiday_list=holiday_list_name)
for date in dates:
shift_details = get_employee_shift(employee, date, True)
if shift_details and shift_details.shift_type.name == self.name:
mark_absent(employee, date)
mark_absent(employee, date, self.name)
def get_assigned_employee(self, from_date=None, consider_default_shift=False):
filters = {'date':('>=', from_date), 'shift_type': self.name, 'docstatus': '1'}

View File

@ -2,11 +2,11 @@ from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'shift_type',
'transactions': [
{
'items': ['Shift Request', 'Shift Assignment']
}
],
}
return {
'fieldname': 'shift',
'transactions': [
{
'items': ['Attendance', 'Employee Checkin', 'Shift Request', 'Shift Assignment']
}
]
}