1252 lines
46 KiB
Python
1252 lines
46 KiB
Python
from datetime import date, datetime, timedelta
|
|
from django.shortcuts import render, redirect
|
|
from django.urls import reverse
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.http import HttpResponseRedirect, HttpResponse, JsonResponse
|
|
from horilla.decorators import permission_required, login_required, hx_request_required, manager_can_enter
|
|
from base.methods import filtersubordinates, choosesubordinates, sortby
|
|
from base.models import EmployeeShiftDay, EmployeeShift, EmployeeShiftSchedule, Department
|
|
from attendance.forms import AttendanceForm, AttendanceOverTimeForm, AttendanceActivityForm, AttendanceLateComeEarlyOutForm, AttendanceValidationConditionForm, AttendanceUpdateForm
|
|
from attendance.models import Attendance, AttendanceActivity, AttendanceOverTime, AttendanceLateComeEarlyOut, AttendanceValidationCondition
|
|
from attendance.filters import AttendanceReGroup, AttendanceOvertimeReGroup, LateComeEarlyOutReGroup, AttendanceActivityReGroup
|
|
from notifications.signals import notify
|
|
|
|
from django.db.models import Q
|
|
from django.core.paginator import Paginator
|
|
from attendance.filters import AttendanceFilters, AttendanceOverTimeFilter, LateComeEarlyOutFilter, AttendanceActivityFilter
|
|
from django.views.decorators.http import require_http_methods
|
|
from django.contrib import messages
|
|
from employee.models import Employee
|
|
import json
|
|
|
|
|
|
|
|
# Create your views here.
|
|
|
|
def intersection_list(list1, list2):
|
|
"""
|
|
This method is used to intersect two list
|
|
"""
|
|
return [value for value in list1 if value in list2]
|
|
|
|
|
|
def format_time(seconds):
|
|
"""
|
|
this method is used to formate seconds to H:M and return it
|
|
args:
|
|
seconds : seconds
|
|
"""
|
|
|
|
hour = int(seconds//3600)
|
|
minutes = int((seconds % 3600)//60)
|
|
seconds = int((seconds % 3600) % 60)
|
|
return "%02d:%02d" % (hour, minutes)
|
|
|
|
|
|
def strtime_seconds(time):
|
|
"""
|
|
this method is used reconvert time in H:M formate string back to seconds and return it
|
|
args:
|
|
time : time in H:M format
|
|
"""
|
|
|
|
ftr = [3600, 60, 1]
|
|
return sum(a*b for a, b in zip(ftr, map(int, time.split(':'))))
|
|
|
|
|
|
def is_reportingmanger(request, instance):
|
|
"""
|
|
if the instance have employee id field then you can use this method to know the request user employee is the reporting manager of the instance
|
|
args :
|
|
request : request
|
|
instance : an object or instance of any model contain employee_id foreign key field
|
|
"""
|
|
|
|
manager = request.user.employee_get
|
|
try:
|
|
employee_workinfo_manager = instance.employee_id.employee_work_info.reporting_manager_id
|
|
except Exception:
|
|
return HttpResponse('This Employee Dont Have any work information')
|
|
return manager == employee_workinfo_manager
|
|
|
|
|
|
def late_come_create(attendance):
|
|
"""
|
|
used to create late come report
|
|
args:
|
|
attendance : attendance object
|
|
"""
|
|
|
|
late_come = AttendanceLateComeEarlyOut()
|
|
late_come.type = 'late_come'
|
|
late_come.attendance_id = attendance
|
|
late_come.employee_id = attendance.employee_id
|
|
late_come.save()
|
|
return
|
|
|
|
|
|
def late_come(attendance, start_time, end_time):
|
|
"""
|
|
this method is used to mark the late check-in attendance after the shift starts
|
|
args:
|
|
attendance : attendance obj
|
|
start_time : attendance day shift start time
|
|
end_time : attendance day shift end time
|
|
|
|
"""
|
|
|
|
now_sec = strtime_seconds(datetime.now().strftime('%H:%M'))
|
|
mid_day_sec = strtime_seconds('12:00')
|
|
if start_time > end_time and start_time != end_time:
|
|
"""
|
|
night shift
|
|
"""
|
|
if now_sec < mid_day_sec:
|
|
"""
|
|
Here attendance or attendance activity for new day night shift
|
|
"""
|
|
|
|
late_come_create(attendance)
|
|
elif now_sec > start_time:
|
|
"""
|
|
Here attendance or attendance activity for previous day night shift
|
|
"""
|
|
|
|
late_come_create(attendance)
|
|
elif start_time < now_sec:
|
|
late_come_create(attendance)
|
|
return
|
|
|
|
|
|
def early_out_create(attendance):
|
|
"""
|
|
Used to create early out report
|
|
args:
|
|
attendance : attendance obj
|
|
"""
|
|
|
|
late_come = AttendanceLateComeEarlyOut()
|
|
late_come.type = 'early_out'
|
|
late_come.attendance_id = attendance
|
|
late_come.employee_id = attendance.employee_id
|
|
late_come.save()
|
|
return
|
|
|
|
|
|
def early_out(attendance, start_time, end_time):
|
|
"""
|
|
This method is used to mark the early check-out attendance before the shift ends
|
|
args:
|
|
attendance : attendance obj
|
|
start_time : attendance day shift start time
|
|
start_end : attendance day shift end time
|
|
"""
|
|
|
|
now_sec = strtime_seconds(datetime.now().strftime('%H:%M'))
|
|
mid_day_sec = strtime_seconds('12:00')
|
|
if start_time > end_time:
|
|
"""
|
|
Early out condition for night shift
|
|
"""
|
|
|
|
if now_sec < mid_day_sec:
|
|
if now_sec < end_time:
|
|
"""
|
|
Early out condition for general shift
|
|
"""
|
|
|
|
early_out_create(attendance)
|
|
else:
|
|
early_out_create(attendance)
|
|
return
|
|
if end_time > now_sec:
|
|
early_out_create(attendance)
|
|
return
|
|
|
|
|
|
def attendance_validate(attendance):
|
|
"""
|
|
This method is is used to check condition for at work in AttendanceValidationCondition
|
|
model instance it return true if at work is smaller than condition
|
|
args:
|
|
attendance : attendance object
|
|
"""
|
|
|
|
conditions = AttendanceValidationCondition.objects.all()
|
|
|
|
# Set the default condition for 'at work' to 9:00 AM
|
|
condition_for_at_work = strtime_seconds('09:00')
|
|
|
|
if conditions.exists():
|
|
condition_for_at_work = strtime_seconds(
|
|
conditions[0].validation_at_work)
|
|
at_work = strtime_seconds(attendance.attendance_worked_hour)
|
|
return condition_for_at_work >= at_work
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.add_attendance')
|
|
def attendance_create(request):
|
|
"""
|
|
This method is used to render attendance create form and save if it is valid
|
|
"""
|
|
form = AttendanceForm()
|
|
form = choosesubordinates(request, form, 'attendance.add_attendance')
|
|
if request.method == 'POST':
|
|
form = AttendanceForm(request.POST)
|
|
form = choosesubordinates(request, form, 'attendance.add_attendance')
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _('Attendance added.'))
|
|
response = render(
|
|
request, 'attendance/attendance/form.html', {'form': form})
|
|
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
|
|
return render(request, 'attendance/attendance/form.html', {'form': form})
|
|
|
|
|
|
def paginator_qry(qryset, page_number):
|
|
"""
|
|
This method is used to paginate queryset
|
|
"""
|
|
paginator = Paginator(qryset, 50)
|
|
qryset = paginator.get_page(page_number)
|
|
return qryset
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.view_attendance')
|
|
def attendance_view(request):
|
|
"""f
|
|
This method is used to view attendances.
|
|
"""
|
|
employee = Employee.objects.filter(employee_user_id=request.user).first()
|
|
previous_data = request.environ['QUERY_STRING']
|
|
form = AttendanceForm()
|
|
condition = AttendanceValidationCondition.objects.first()
|
|
minot = strtime_seconds('00:30')
|
|
if condition is not None:
|
|
minot = strtime_seconds(condition.minimum_overtime_to_approve)
|
|
validate_attendances = Attendance.objects.filter(
|
|
attendance_validated=False)
|
|
attendances = Attendance.objects.filter(attendance_validated=True)
|
|
ot_attendances = Attendance.objects.filter(
|
|
attendance_overtime_approve=False, overtime_second__gte=minot, attendance_validated=True)
|
|
f = AttendanceFilters(queryset=Attendance.objects.all())
|
|
|
|
attendances = filtersubordinates(
|
|
request, attendances, 'attendance.view_attendance')
|
|
validate_attendances = filtersubordinates(
|
|
request, validate_attendances, 'attendance.view_attendance')
|
|
ot_attendances = filtersubordinates(
|
|
request, ot_attendances, 'attendance.view_attendance')
|
|
|
|
return render(request, 'attendance/attendance/attendance_view.html', {
|
|
'form': form,
|
|
'validate_attendances': paginator_qry(validate_attendances, request.GET.get('vpage')),
|
|
'attendances': paginator_qry(attendances, request.GET.get('page')),
|
|
'overtime_attendances': paginator_qry(ot_attendances, request.GET.get('opage')),
|
|
'f': f,
|
|
'pd': previous_data,
|
|
'gp_fields': AttendanceReGroup.fields
|
|
})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.view_attendance')
|
|
def attendance_search(request):
|
|
"""
|
|
This method is used to search attendance by employee
|
|
"""
|
|
previous_data = request.environ['QUERY_STRING']
|
|
field = request.GET.get('field')
|
|
minot = strtime_seconds('00:30')
|
|
condition = AttendanceValidationCondition.objects.first()
|
|
if condition is not None:
|
|
minot = strtime_seconds(condition.minimum_overtime_to_approve)
|
|
|
|
validate_attendances = Attendance.objects.filter(attendance_validated=False)
|
|
attendances = Attendance.objects.filter(attendance_validated=True)
|
|
ot_attendances = Attendance.objects.filter(attendance_overtime_approve=False, overtime_second__gte=minot, attendance_validated=True,)
|
|
|
|
validate_attendances = AttendanceFilters(
|
|
request.GET, validate_attendances).qs
|
|
attendances = AttendanceFilters(request.GET, attendances).qs
|
|
ot_attendances = AttendanceFilters(request.GET, ot_attendances).qs
|
|
|
|
template = 'attendance/attendance/tab_content.html'
|
|
if field != '' and field is not None:
|
|
field_copy = field.replace('.', '__')
|
|
attendances = attendances.order_by(field_copy)
|
|
validate_attendances = validate_attendances.order_by(field_copy)
|
|
ot_attendances = ot_attendances.order_by(field_copy)
|
|
template = 'attendance/attendance/group_by.html'
|
|
|
|
attendances = filtersubordinates(
|
|
request, attendances, 'attendance.view_attendance')
|
|
validate_attendances = filtersubordinates(
|
|
request, validate_attendances, 'attendance.view_attendance')
|
|
ot_attendances = filtersubordinates(
|
|
request, ot_attendances, 'attendance.view_attendance')
|
|
|
|
attendances = sortby(request, attendances, 'sortby')
|
|
validate_attendances = sortby(request, validate_attendances, 'sortby')
|
|
ot_attendances = sortby(request, ot_attendances, 'sortby')
|
|
|
|
return render(request, template, {
|
|
'validate_attendances': paginator_qry(validate_attendances, request.GET.get('vpage')),
|
|
'attendances': paginator_qry(attendances, request.GET.get('page')),
|
|
'overtime_attendances': paginator_qry(ot_attendances, request.GET.get('opage')),
|
|
'pd': previous_data,
|
|
'field': field,
|
|
})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.change_attendance')
|
|
def attendance_update(request, id):
|
|
"""
|
|
This method render form to update attendance and save if the form is valid
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
attendance = Attendance.objects.get(id=id)
|
|
form = AttendanceUpdateForm(instance=attendance,)
|
|
form = choosesubordinates(request, form, 'attendance.change_attendance')
|
|
if request.method == 'POST':
|
|
form = AttendanceUpdateForm(request.POST, instance=attendance)
|
|
form = choosesubordinates(
|
|
request, form, 'attendance.change_attendance')
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _('Attendance Updated.'))
|
|
response = render(
|
|
request, 'attendance/attendance/update_form.html', {'form': form})
|
|
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
|
|
return render(request, 'attendance/attendance/update_form.html', {'form': form, })
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.delete_attendance')
|
|
@require_http_methods(['POST'])
|
|
def attendance_delete(request, id):
|
|
"""
|
|
This method is used to delete attendance.
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
attendance = Attendance.objects.get(id=id)
|
|
month = attendance.attendance_date
|
|
month = month.strftime('%B').lower()
|
|
overtime = attendance.employee_id.employee_overtime.filter(
|
|
month=month).last()
|
|
if overtime is not None:
|
|
if attendance.attendance_overtime_approve:
|
|
"""
|
|
Subtract overtime of this attendance
|
|
"""
|
|
total_overtime = strtime_seconds(overtime.overtime)
|
|
attendance_overtime_seconds = strtime_seconds(
|
|
attendance.attendance_overtime)
|
|
if total_overtime > attendance_overtime_seconds:
|
|
total_overtime = total_overtime - attendance_overtime_seconds
|
|
else:
|
|
total_overtime = attendance_overtime_seconds - total_overtime
|
|
overtime.overtime = format_time(total_overtime)
|
|
overtime.save()
|
|
try:
|
|
attendance.delete()
|
|
messages.success(request, _('Attendance deleted.'))
|
|
except Exception as e:
|
|
messages.error(request, e)
|
|
messages.error(request, _('You cannot delete this attendance'))
|
|
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def attendance_bulk_delete(request):
|
|
"""
|
|
This method is used to delete bulk of attendances
|
|
"""
|
|
ids = request.POST['ids']
|
|
ids = json.loads(ids)
|
|
for id in ids:
|
|
try:
|
|
attendance = Attendance.objects.get(id=id)
|
|
month = attendance.attendance_date
|
|
month = month.strftime('%B').lower()
|
|
overtime = attendance.employee_id.employee_overtime.filter(
|
|
month=month).last()
|
|
if overtime is not None:
|
|
if attendance.attendance_overtime_approve:
|
|
"""
|
|
Subtract overtime of this attendance
|
|
"""
|
|
total_overtime = strtime_seconds(overtime.overtime)
|
|
attendance_overtime_seconds = strtime_seconds(
|
|
attendance.attendance_overtime)
|
|
if total_overtime > attendance_overtime_seconds:
|
|
total_overtime = total_overtime - attendance_overtime_seconds
|
|
else:
|
|
total_overtime = attendance_overtime_seconds - total_overtime
|
|
overtime.overtime = format_time(total_overtime)
|
|
overtime.save()
|
|
try:
|
|
attendance.delete()
|
|
messages.success(request, _('Attendance Deleted'))
|
|
except:
|
|
messages.error(
|
|
request, _('You cannot delete this %(attendance)s' % {'attendance':attendance}))
|
|
except:
|
|
pass
|
|
|
|
return JsonResponse({'message': 'Success'})
|
|
|
|
|
|
@login_required
|
|
def view_my_attendance(request):
|
|
"""
|
|
This method is used to view self attendances of employee
|
|
"""
|
|
user = request.user
|
|
try:
|
|
employee = user.employee_get
|
|
except:
|
|
return redirect('/employee/employee-profile')
|
|
employee = user.employee_get
|
|
employee_attendances = employee.employee_attendances.all()
|
|
filter = AttendanceFilters()
|
|
return render(request, 'attendance/own_attendance/view_own_attendances.html', {'attendances': paginator_qry(employee_attendances, request.GET.get('page')), 'f': filter})
|
|
|
|
|
|
@login_required
|
|
@hx_request_required
|
|
def filter_own_attendance(request):
|
|
"""
|
|
This method is used to filter own attendances
|
|
"""
|
|
attendances = Attendance.objects.filter(
|
|
employee_id=request.user.employee_get)
|
|
attendances = AttendanceFilters(request.GET, queryset=attendances).qs
|
|
return render(request, 'attendance/own_attendance/attendances.html', {'attendances': paginator_qry(attendances, request.GET.get('page'))})
|
|
|
|
|
|
@login_required
|
|
def own_attendance_sort(request):
|
|
"""
|
|
This method is used to sort out attendances
|
|
"""
|
|
attendances = Attendance.objects.filter(
|
|
employee_id=request.user.employee_get)
|
|
previous_data = request.environ['QUERY_STRING']
|
|
attendances = sortby(request, attendances, 'orderby')
|
|
return render(request, 'attendance/own_attendance/attendances.html', {'attendances': paginator_qry(attendances, request.GET.get('page')), 'pd': previous_data})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.add_attendanceovertime')
|
|
def attendance_overtime_create(request):
|
|
"""
|
|
This method is used to render overtime creating form and save if the form is valid
|
|
"""
|
|
form = AttendanceOverTimeForm()
|
|
form = choosesubordinates(
|
|
request, form, 'attendance.add_attendanceovertime')
|
|
if request.method == 'POST':
|
|
form = AttendanceOverTimeForm(request.POST)
|
|
form = choosesubordinates(
|
|
request, form, 'attendance.add_attendanceovertime')
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(request, _('Attendance account added.'))
|
|
response = render(
|
|
request, 'attendance/attendance_account/form.html', {'form': form})
|
|
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
|
|
return render(request, 'attendance/attendance_account/form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.view_attendanceovertime')
|
|
def attendance_overtime_view(request):
|
|
"""
|
|
This method is used to view attendance account or overtime account.
|
|
"""
|
|
previous_data = request.environ['QUERY_STRING']
|
|
accounts = AttendanceOverTime.objects.all()
|
|
accounts = filtersubordinates(
|
|
request, accounts, 'attendance.view_attendanceovertime')
|
|
form = AttendanceOverTimeForm()
|
|
form = choosesubordinates(
|
|
request, form, 'attendance.add_attendanceovertime')
|
|
f = AttendanceOverTimeFilter()
|
|
return render(request, 'attendance/attendance_account/attendance_overtime_view.html', {
|
|
'accounts': paginator_qry(accounts, request.GET.get('page')),
|
|
'form': form,
|
|
'pd': previous_data,
|
|
'f': f,
|
|
'gp_fields': AttendanceOvertimeReGroup.fields
|
|
})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.view_attendanceovertime')
|
|
def attendance_overtime_search(request):
|
|
"""
|
|
This method is used to search attendance overtime account by employee.
|
|
"""
|
|
field = request.GET.get('field')
|
|
previous_data = request.environ['QUERY_STRING']
|
|
|
|
accounts = AttendanceOverTimeFilter(request.GET).qs
|
|
form = AttendanceOverTimeForm()
|
|
template = 'attendance/attendance_account/overtime_list.html'
|
|
if field != '' and field is not None:
|
|
field_copy = field.replace('.', '__')
|
|
accounts = accounts.order_by(field_copy)
|
|
template = 'attendance/attendance_account/group_by.html'
|
|
accounts = sortby(request, accounts, 'sortby')
|
|
accounts = filtersubordinates(
|
|
request, accounts, 'attendance.view_attendanceovertime')
|
|
return render(request, template, {
|
|
'accounts': paginator_qry(accounts, request.GET.get('page')),
|
|
'form': form,
|
|
'pd': previous_data,
|
|
'field': field,
|
|
})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.change_attendanceovertime')
|
|
@hx_request_required
|
|
def attendance_overtime_update(request, id):
|
|
"""
|
|
This method is used to update attendance overtime and save if the forms is valid
|
|
args:
|
|
id : attendance overtime id
|
|
"""
|
|
overtime = AttendanceOverTime.objects.get(id=id)
|
|
form = AttendanceOverTimeForm(instance=overtime)
|
|
form = choosesubordinates(
|
|
request, form, 'attendance.change_attendanceovertime')
|
|
if request.method == 'POST':
|
|
form = AttendanceOverTimeForm(request.POST, instance=overtime)
|
|
form = choosesubordinates(
|
|
request, form, 'attendance.change_attendanceovertime')
|
|
if form.is_valid():
|
|
form.save()
|
|
messages.success(
|
|
request, _('Attendance account updated successfully.'))
|
|
response = render(
|
|
request, 'attendance/attendance_account/update_form.html', {'form': form})
|
|
return HttpResponse(response.content.decode('utf-8') + '<script>location.reload();</script>')
|
|
return render(request, 'attendance/attendance_account/update_form.html', {'form': form})
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.delete_AttendanceOverTime')
|
|
@require_http_methods(['POST'])
|
|
def attendance_overtime_delete(request, id):
|
|
"""
|
|
This method is used to delete attendance overtime
|
|
args:
|
|
id : attendance overtime id
|
|
"""
|
|
try:
|
|
overtime = AttendanceOverTime.objects.get(id=id).delete()
|
|
messages.success(request, _('OT account deleted.'))
|
|
except Exception as e:
|
|
messages.error(request, e)
|
|
messages.error(request, _('You cannot delete this attendance OT'))
|
|
accounts = AttendanceOverTime.objects.all()
|
|
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.view_attendanceactivity')
|
|
def attendance_activity_view(request):
|
|
"""
|
|
This method will render a template to view all attendance activities
|
|
"""
|
|
attendance_activities = AttendanceActivity.objects.all()
|
|
previous_data = request.environ['QUERY_STRING']
|
|
filter = AttendanceActivityFilter()
|
|
return render(request, 'attendance/attendance_activity/attendance_activity_view.html', {
|
|
'data': paginator_qry(attendance_activities, request.GET.get('page')),
|
|
'pd': previous_data,
|
|
'f': filter,
|
|
'gp_fields': AttendanceActivityReGroup.fields}
|
|
)
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.view_attendanceactivity')
|
|
def attendance_activity_search(request):
|
|
"""
|
|
This method is used to search attendance activity
|
|
"""
|
|
previous_data = request.environ['QUERY_STRING']
|
|
field = request.GET.get('field')
|
|
attendance_activities = AttendanceActivityFilter(
|
|
request.GET,).qs
|
|
template = 'attendance/attendance_activity/activity_list.html'
|
|
if field != '' and field is not None:
|
|
field_copy = field.replace('.', '__')
|
|
attendance_activities = attendance_activities.order_by(field_copy)
|
|
template = 'attendance/attendance_activity/group_by.html'
|
|
attendance_activities = filtersubordinates(
|
|
request, attendance_activities, 'attendance.view_attendanceactivity')
|
|
|
|
attendance_activities = sortby(request, attendance_activities, 'orderby')
|
|
return render(request, template, {
|
|
'data': paginator_qry(attendance_activities, request.GET.get('page')),
|
|
'pd': previous_data,
|
|
'field': field
|
|
})
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.delete_attendanceactivity')
|
|
@require_http_methods(['POST', 'DELTE'])
|
|
def attendance_activity_delete(request, id):
|
|
"""
|
|
This method is used to delete attendance activity
|
|
args:
|
|
id : attendance activity id
|
|
"""
|
|
try:
|
|
attendance_activity = AttendanceActivity.objects.get(id=id).delete()
|
|
messages.success(request, _('Attendance activity deleted'))
|
|
except Exception as e:
|
|
messages.error(request, e)
|
|
messages.error(request, _('You cannot delete this activity'))
|
|
return redirect('/attendance/attendance-activity-view')
|
|
|
|
|
|
def employee_exists(request):
|
|
"""
|
|
This method return the employee instance and work info if not exists return None instead
|
|
"""
|
|
employee, employee_work_info = None, None
|
|
try:
|
|
employee = request.user.employee_get
|
|
employee_work_info = employee.employee_work_info
|
|
finally:
|
|
return (employee, employee_work_info)
|
|
|
|
|
|
def shift_schedule_today(day, shift):
|
|
"""
|
|
This function is used to find shift schedules for the day,
|
|
it will returns min hour,start time seconds end time seconds
|
|
args:
|
|
shift : shift instance
|
|
day : shift day object
|
|
"""
|
|
schedule_today = day.day_schedule.filter(shift_id=shift)
|
|
start_time_sec, end_time_sec, minimum_hour = 0, 0, '00:00'
|
|
if schedule_today.exists():
|
|
schedule_today = schedule_today[0]
|
|
minimum_hour = schedule_today.minimum_working_hour
|
|
start_time_sec = strtime_seconds(
|
|
schedule_today.start_time.strftime('%H:%M'))
|
|
end_time_sec = strtime_seconds(
|
|
schedule_today.end_time.strftime('%H:%M'))
|
|
return (minimum_hour, start_time_sec, end_time_sec)
|
|
|
|
|
|
def overtime_calculation(attendance):
|
|
"""
|
|
This method is used to calculate overtime of the attendance, it will
|
|
return difference between attendance worked hour and minimum hour if
|
|
and only worked hour greater than minimum hour, else return 00:00
|
|
args:
|
|
attendance : attendance instance
|
|
"""
|
|
|
|
minimum_hour = attendance.minimum_hour
|
|
at_work = attendance.attendance_worked_hour
|
|
at_work_sec = strtime_seconds(at_work)
|
|
minimum_hour_sec = strtime_seconds(minimum_hour)
|
|
if at_work_sec > minimum_hour_sec:
|
|
return format_time((at_work_sec - minimum_hour_sec))
|
|
return '00:00'
|
|
|
|
|
|
def clock_in_attendance_and_activity(employee, date_today, attendance_date, day, now, shift, minimum_hour, start_time, end_time):
|
|
"""
|
|
This method is used to create attendance activity or attendance when an employee clocks-in
|
|
args:
|
|
employee : employee instance
|
|
date_today : date
|
|
attendance_date : the date that attendance for
|
|
day : shift day
|
|
now : current time
|
|
shift : shift object
|
|
minimum_hour : minimum hour in shift schedule
|
|
start_time : start time in shift schedule
|
|
end_time : end time in shift schedule
|
|
"""
|
|
|
|
# attendance activity create
|
|
attendance_activity = AttendanceActivity(
|
|
employee_id=employee,
|
|
attendance_date=attendance_date,
|
|
clock_in_date=date_today,
|
|
shift_day=day,
|
|
clock_in=now,
|
|
).save()
|
|
|
|
# create attendance if not exist
|
|
attendance = Attendance.objects.filter(
|
|
employee_id=employee, attendance_date=attendance_date)
|
|
if not attendance.exists():
|
|
attendance = Attendance()
|
|
attendance.employee_id = employee
|
|
attendance.shift_id = shift
|
|
attendance.work_type_id = attendance.employee_id.employee_work_info.work_type_id
|
|
attendance.attendance_date = attendance_date
|
|
attendance.attendance_day = day
|
|
attendance.attendance_clock_in = now
|
|
attendance.attendance_clock_in_date = date_today
|
|
attendance.minimum_hour = minimum_hour
|
|
attendance.save()
|
|
"""
|
|
check here late come or not
|
|
"""
|
|
|
|
late_come(attendance=attendance,
|
|
start_time=start_time, end_time=end_time)
|
|
else:
|
|
attendance = attendance[0]
|
|
attendance.attendance_clock_out = None
|
|
attendance.attendance_clock_out_date = None
|
|
attendance.save()
|
|
"""
|
|
delete if the attendance marked the early out
|
|
"""
|
|
|
|
early_out_instance = attendance.late_come_early_out.filter(
|
|
type='early_out')
|
|
if early_out_instance.exists():
|
|
early_out_instance[0].delete()
|
|
return
|
|
|
|
|
|
@login_required
|
|
def clock_in(request):
|
|
"""
|
|
This method is used to mark the attendance once per a day and multiple attendance activities.
|
|
"""
|
|
employee, work_info = employee_exists(request)
|
|
if employee and work_info is not None:
|
|
shift = work_info.shift_id
|
|
date_today = date.today()
|
|
attendance_date = date_today
|
|
day = date_today.strftime('%A').lower()
|
|
day = EmployeeShiftDay.objects.get(day=day)
|
|
now = datetime.now().strftime('%H:%M')
|
|
now_sec = strtime_seconds(now)
|
|
mid_day_sec = strtime_seconds('12:00')
|
|
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
|
|
day=day, shift=shift)
|
|
if start_time_sec >= end_time_sec:
|
|
# night shift
|
|
"""
|
|
Night shift in open hrms consider a 24 hours from noon to next day noon,
|
|
the shift day taken today if the attendance clocked in after 12 O clock.
|
|
"""
|
|
|
|
if mid_day_sec > now_sec:
|
|
"""
|
|
Here you need to create attendance for yesterday
|
|
"""
|
|
|
|
date_yesterday = date_today - timedelta(days=1)
|
|
day_yesterday = date_yesterday.strftime('%A').lower()
|
|
day_yesterday = EmployeeShiftDay.objects.get(day=day_yesterday)
|
|
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
|
|
day=day_yesterday, shift=shift)
|
|
attendance_date = date_yesterday
|
|
day = day_yesterday
|
|
clock_in_attendance_and_activity(
|
|
employee=employee,
|
|
date_today=date_today,
|
|
attendance_date=attendance_date,
|
|
day=day,
|
|
now=now,
|
|
shift=shift,
|
|
minimum_hour=minimum_hour,
|
|
start_time=start_time_sec,
|
|
end_time=end_time_sec
|
|
)
|
|
return HttpResponse(
|
|
"""
|
|
<button class="oh-btn oh-btn--warning-outline " hx-get="/attendance/clock-out" hx-target='#attendance-activity-container' hx-swap='innerHTML'><ion-icon class="oh-navbar__clock-icon mr-2 text-warning" name="exit-outline"></ion-icon>{check_out}</button>
|
|
""".format(check_out=_('Check-Out'))
|
|
|
|
)
|
|
return HttpResponse("You Don't have work information filled or your employee detail neither entered ")
|
|
|
|
|
|
def activity_datetime(attendance_activity):
|
|
"""
|
|
This method is used to convert clock-in and clock-out of activity as datetime object
|
|
args:
|
|
attendance_activity : attendance activity instance
|
|
"""
|
|
|
|
# in
|
|
in_year = attendance_activity.clock_in_date.year
|
|
in_month = attendance_activity.clock_in_date.month
|
|
in_day = attendance_activity.clock_in_date.day
|
|
in_hour = attendance_activity.clock_in.hour
|
|
in_minute = attendance_activity.clock_in.minute
|
|
# out
|
|
out_year = attendance_activity.clock_out_date.year
|
|
out_month = attendance_activity.clock_out_date.month
|
|
out_day = attendance_activity.clock_out_date.day
|
|
out_hour = attendance_activity.clock_out.hour
|
|
out_minute = attendance_activity.clock_out.minute
|
|
return datetime(in_year, in_month, in_day, in_hour, in_minute), datetime(out_year, out_month, out_day, out_hour, out_minute)
|
|
|
|
|
|
def clock_out_attendance_and_activity(employee, date_today, now):
|
|
"""
|
|
Clock out the attendance and activity
|
|
args:
|
|
employee : employee instance
|
|
date_today : today date
|
|
now : now
|
|
"""
|
|
|
|
attendance_activities = AttendanceActivity.objects.filter(
|
|
employee_id=employee).order_by('attendance_date', 'id')
|
|
if attendance_activities.exists():
|
|
attendance_activity = attendance_activities.last()
|
|
attendance_activity.clock_out = now
|
|
attendance_activity.clock_out_date = date_today
|
|
attendance_activity.save()
|
|
attendance_activities = attendance_activities.filter(~Q(clock_out=None)).filter(
|
|
attendance_date=attendance_activity.attendance_date)
|
|
"""
|
|
Here calculate the total durations between the attendance activities
|
|
"""
|
|
|
|
duration = 0
|
|
for attendance_activity in attendance_activities:
|
|
in_datetime, out_datetime = activity_datetime(attendance_activity)
|
|
difference = out_datetime - in_datetime
|
|
days_second = difference.days * 24 * 3600
|
|
seconds = difference.seconds
|
|
total_seconds = days_second + seconds
|
|
duration = duration + total_seconds
|
|
duration = format_time(duration)
|
|
# update clock out of attendance
|
|
attendance = Attendance.objects.filter(
|
|
employee_id=employee).order_by('-attendance_date', '-id')[0]
|
|
attendance.attendance_clock_out = now
|
|
attendance.attendance_clock_out_date = date_today
|
|
attendance.attendance_worked_hour = duration
|
|
attendance.save()
|
|
"""
|
|
Overtime calculation
|
|
"""
|
|
|
|
attendance.attendance_overtime = overtime_calculation(attendance)
|
|
"""
|
|
Validate the attendance as per the condition
|
|
"""
|
|
|
|
attendance.attendance_validated = attendance_validate(attendance)
|
|
attendance.save()
|
|
|
|
return
|
|
|
|
|
|
@login_required
|
|
def clock_out(request):
|
|
"""
|
|
This method is used to set the out date and time for attendance and attendance activity
|
|
"""
|
|
employee, work_info = employee_exists(request)
|
|
shift = work_info.shift_id
|
|
date_today = date.today()
|
|
day = date_today.strftime('%A').lower()
|
|
day = EmployeeShiftDay.objects.get(day=day)
|
|
attendance = Attendance.objects.filter(
|
|
employee_id=employee).order_by('id', 'attendance_date').last()
|
|
if attendance is not None:
|
|
day = attendance.attendance_day
|
|
now = datetime.now().strftime('%H:%M')
|
|
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
|
|
day=day, shift=shift)
|
|
now_sec = strtime_seconds(now)
|
|
mid_day_sec = strtime_seconds('12:00')
|
|
if start_time_sec >= end_time_sec and mid_day_sec > now_sec:
|
|
# here the shift will be night shift
|
|
"""
|
|
Night shift in open hrms consider a 24 hours from noon to next day noon,
|
|
the shift day taken today if the attendance clocked-in before 12 O clock.
|
|
"""
|
|
|
|
# here can write night shift conditions
|
|
|
|
early_out_instance = attendance.late_come_early_out.filter(
|
|
type='early_out')
|
|
if not early_out_instance.exists():
|
|
early_out(attendance=attendance,
|
|
start_time=start_time_sec, end_time=end_time_sec)
|
|
|
|
clock_out_attendance_and_activity(
|
|
employee=employee, date_today=date_today, now=now)
|
|
return HttpResponse(
|
|
"""
|
|
<button class="oh-btn oh-btn--success-outline " hx-get="/attendance/clock-in" hx-target='#attendance-activity-container' hx-swap='innerHTML'><ion-icon class="oh-navbar__clock-icon mr-2 text-success" name="enter-outline"></ion-icon>{check_in}</button>
|
|
""".format(check_in=_('Check-In'))
|
|
|
|
)
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.view_attendancelatecomeearlyout')
|
|
def late_come_early_out_view(request):
|
|
"""
|
|
This method render template to view all late come early out entries
|
|
"""
|
|
reports = AttendanceLateComeEarlyOut.objects.all()
|
|
reports = filtersubordinates(
|
|
request, reports, 'attendance.view_attendancelatecomeearlyout')
|
|
f = LateComeEarlyOutFilter()
|
|
return render(request, 'attendance/late_come_early_out/reports.html', {
|
|
'data': paginator_qry(reports, request.GET.get('page')),
|
|
'f': f,
|
|
'gp_fields': LateComeEarlyOutReGroup.fields,
|
|
|
|
})
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.view_attendancelatecomeearlyout')
|
|
def late_come_early_out_search(request):
|
|
"""
|
|
This method is used to search late come early out by employee. Also include filter and pagination.
|
|
"""
|
|
field = request.GET.get('field')
|
|
previous_data = request.environ['QUERY_STRING']
|
|
|
|
reports = LateComeEarlyOutFilter(request.GET,).qs
|
|
template = 'attendance/late_come_early_out/report_list.html'
|
|
if field != '' and field is not None:
|
|
template = 'design\late_come_early_out\group_by.html'
|
|
field_copy = field.replace('.', '__')
|
|
reports = reports.order_by(field_copy)
|
|
reports = filtersubordinates(
|
|
request, reports, 'attendance.view_attendancelatecomeearlyout')
|
|
|
|
reports = sortby(request, reports, 'sortby')
|
|
|
|
return render(request, template, {
|
|
'data': paginator_qry(reports, request.GET.get('page')),
|
|
'pd': previous_data,
|
|
'field': field
|
|
})
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.delete_attendancelatecomeearlyout')
|
|
@require_http_methods(['POST'])
|
|
def late_come_early_out_delete(request, id):
|
|
"""
|
|
This method is used to delete the late come early out instance
|
|
args:
|
|
id : late come early out instance id
|
|
"""
|
|
try:
|
|
late_come_early_out = AttendanceLateComeEarlyOut.objects.get(
|
|
id=id).delete()
|
|
messages.success(request, _("Late-in early-out deleted"))
|
|
except Exception as e:
|
|
messages.error(request, e)
|
|
messages.error(request, _('You cannot delete this Late-in early-out'))
|
|
|
|
return redirect('/attendance/late-come-early-out-view')
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.add_attendancevalidationcondition')
|
|
def validation_condition_create(request):
|
|
"""
|
|
This method render a form to create attendance validation conditions, and create if the form is valid.
|
|
"""
|
|
form = AttendanceValidationConditionForm()
|
|
condition = AttendanceValidationCondition.objects.first()
|
|
if request.method == 'POST':
|
|
form = AttendanceValidationConditionForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
return render(request, 'attendance/break_point/condition.html', {'form': form, 'condition': condition})
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.change_attendancevalidationcondition')
|
|
def validation_condition_update(request, id):
|
|
"""
|
|
This method is used to update validation condition
|
|
args:
|
|
id : validation condition instance id
|
|
"""
|
|
condition = AttendanceValidationCondition.objects.get(id=id)
|
|
form = AttendanceValidationConditionForm(instance=condition)
|
|
if request.method == 'POST':
|
|
form = AttendanceValidationConditionForm(
|
|
request.POST, instance=condition)
|
|
if form.is_valid():
|
|
form.save()
|
|
return render(request, 'attendance/break_point/condition.html', {'form': form, 'condition': condition})
|
|
|
|
|
|
@login_required
|
|
@permission_required('attendance.change_attendancevalidationcondition')
|
|
@require_http_methods(['POST'])
|
|
def validation_condition_delete(request, id):
|
|
"""
|
|
This method is used to delete created validation condition
|
|
args:
|
|
id : validation condition id
|
|
"""
|
|
try:
|
|
condition = AttendanceValidationCondition.objects.get(id=id).delete()
|
|
messages.success(request, _('validation condition deleted.'))
|
|
except Exception as e:
|
|
messages.error(request, e)
|
|
messages.error(request, _('You cannot delete this validation condition.'))
|
|
return redirect('/attendance/validation-condition-view')
|
|
|
|
|
|
@login_required
|
|
@require_http_methods(['POST'])
|
|
@manager_can_enter('attendance.change_attendance')
|
|
def validate_bulk_attendance(request):
|
|
"""
|
|
This method is used to validate bulk of attendances
|
|
"""
|
|
ids = request.POST['ids']
|
|
ids = json.loads(ids)
|
|
for id in ids:
|
|
attendance = Attendance.objects.get(id=id)
|
|
attendance.attendance_validated = True
|
|
attendance.save()
|
|
messages.success(request, _('Attendance validated.'))
|
|
notify.send(request.user.employee_get, recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Your attendance for the date {attendance.attendance_date} is validated", redirect="/attendance/view-my-attendance", icon="checkmark")
|
|
return JsonResponse({'message': f'{attendance.employee_id} success'})
|
|
|
|
|
|
@login_required
|
|
def validate_this_attendance(request, id):
|
|
"""
|
|
This method is used to validate attendance
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
attendance = Attendance.objects.get(id=id)
|
|
if is_reportingmanger(request, attendance) or request.user.has_perm('attendance.change_attendance'):
|
|
attendance = Attendance.objects.get(id=id)
|
|
attendance.attendance_validated = True
|
|
attendance.save()
|
|
messages.success(request, _('Attendance validated.'))
|
|
notify.send(request.user.employee_get, recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Your attendance for the date {attendance.attendance_date} is validated", redirect="/attendance/view-my-attendance", icon="checkmark")
|
|
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
|
|
return HttpResponse('You Dont Have Permission')
|
|
|
|
|
|
@login_required
|
|
def revalidate_this_attendance(request, id):
|
|
"""
|
|
This method is used to not validate the attendance.
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
|
|
attendance = Attendance.objects.get(id=id)
|
|
if is_reportingmanger(request, attendance) or request.user.has_perm('attendance.change_attendance'):
|
|
attendance.attendance_validated = False
|
|
attendance.save()
|
|
try:
|
|
notify.send(request.user.employee_get, recipient=attendance.employee_id.employee_work_info.reporting_manager_id.employee_user_id,
|
|
verb=f"{attendance.employee_id} requested revalidation for {attendance.attendance_date} attendance", redirect="/attendance/view-my-attendance", icon="refresh")
|
|
except Exception:
|
|
pass
|
|
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
|
|
return HttpResponse('You Cannot Request for others attendance')
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.change_attendance')
|
|
def approve_overtime(request, id):
|
|
"""
|
|
This method is used to approve attendance overtime
|
|
args:
|
|
id : attendance id
|
|
"""
|
|
attendance = Attendance.objects.get(id=id)
|
|
attendance.attendance_overtime_approve = True
|
|
attendance.save()
|
|
notify.send(request.user.employee_get, recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Your {attendance.attendance_date}'s attendance overtime approved.", redirect="/attendance/attendance-overtime-view", icon="checkmark")
|
|
|
|
return HttpResponseRedirect(request. META. get('HTTP_REFERER', '/'))
|
|
|
|
|
|
@login_required
|
|
@manager_can_enter('attendance.change_attendance')
|
|
def approve_bulk_overtime(request):
|
|
ids = request.POST['ids']
|
|
ids = json.loads(ids)
|
|
for id in ids:
|
|
attendance = Attendance.objects.get(id=id)
|
|
attendance.attendance_overtime_approve = True
|
|
attendance.save()
|
|
messages.success(request, _('Overtime approved'))
|
|
notify.send(request.user.employee_get, recipient=attendance.employee_id.employee_user_id,
|
|
verb=f"Overtime approved for {attendance.attendance_date}'s attendance", redirect="/attendance/attendance-overtime-view", icon="checkmark")
|
|
|
|
return JsonResponse({'message': 'Success'})
|
|
|
|
|
|
def find_on_time(request, today, week_day, department=None):
|
|
"""
|
|
This method is used to find count for on time attendances
|
|
"""
|
|
on_time = 0
|
|
attendances = Attendance.objects.filter(attendance_date=today)
|
|
attendances = filtersubordinates(
|
|
request, attendances, 'attendance.view_attendance')
|
|
if department is not None:
|
|
attendances = attendances.filter(
|
|
employee_id__employee_work_info__department_id=department)
|
|
excepted_attendances = 0
|
|
for attendance in attendances:
|
|
shift = attendance.shift_id
|
|
schedules_today = shift.employeeshiftschedule_set.filter(
|
|
day__day=week_day)
|
|
if schedules_today.first() is not None:
|
|
excepted_attendances = excepted_attendances + 1
|
|
late_come = attendance.late_come_early_out.filter(
|
|
type='late_come').first()
|
|
if late_come is None:
|
|
on_time = on_time + 1
|
|
return on_time
|
|
|
|
|
|
def find_late_come(today, department=None):
|
|
"""
|
|
This method is used to find count of late comers
|
|
"""
|
|
late_come = AttendanceLateComeEarlyOut.objects.filter(
|
|
type='late_come', attendance_id__attendance_date=today)
|
|
if department is not None:
|
|
late_come = late_come.filter(
|
|
employee_id__employee_work_info__department_id=department)
|
|
return len(late_come)
|
|
|
|
|
|
def find_expected_attendances(week_day):
|
|
"""
|
|
This method is used to find count of expected attendances for the week day
|
|
"""
|
|
schedules_today = EmployeeShiftSchedule.objects.filter(day__day=week_day)
|
|
expected_attendances = 0
|
|
for schedule in schedules_today:
|
|
shift = schedule.shift_id
|
|
expected_attendances = expected_attendances + \
|
|
len(shift.employeeworkinformation_set.all())
|
|
return expected_attendances
|
|
|
|
|
|
def find_early_out(today, department=None):
|
|
"""
|
|
This method is used to find early out attendances and it returns query set
|
|
"""
|
|
if department is not None:
|
|
early_out = AttendanceLateComeEarlyOut.objects.filter(
|
|
type='early_out', employee_id__employee_work_info__department_id=department, attendance_id__attendance_date=today)
|
|
else:
|
|
early_out = AttendanceLateComeEarlyOut.objects.filter(
|
|
type='early_out', attendance_id__attendance_date=today)
|
|
return early_out
|
|
|
|
|
|
@login_required
|
|
def dashboard(request):
|
|
"""
|
|
This method is used to render individual dashboard for attendance module
|
|
"""
|
|
employees = Employee.objects.filter(is_active=True,).filter(
|
|
~Q(employee_work_info__shift_id=None))
|
|
total_employees = len(employees)
|
|
|
|
today = datetime.today()
|
|
week_day = today.strftime('%A').lower()
|
|
|
|
on_time = find_on_time(request, today=today, week_day=week_day)
|
|
late_come = find_late_come(today=today)
|
|
|
|
marked_attendances = late_come + on_time
|
|
|
|
expected_attendances = find_expected_attendances(week_day=week_day)
|
|
on_time_ratio = 0
|
|
late_come_ratio = 0
|
|
marked_attendances_ratio = 0
|
|
if expected_attendances != 0:
|
|
on_time_ratio = "%.1f" % ((on_time/expected_attendances)*100)
|
|
late_come_ratio = "%.1f" % ((late_come/expected_attendances)*100)
|
|
marked_attendances_ratio = "%.1f" % (
|
|
(marked_attendances/expected_attendances)*100)
|
|
early_outs = AttendanceLateComeEarlyOut.objects.filter(
|
|
type='early_out', attendance_id__attendance_date=today)
|
|
|
|
return render(request, 'attendance/dashboard/dashboard.html', {
|
|
'total_employees': total_employees,
|
|
'on_time': on_time,
|
|
'on_time_ratio': on_time_ratio,
|
|
'late_come': late_come,
|
|
'late_come_ratio': late_come_ratio,
|
|
'expected_attendances': expected_attendances,
|
|
'marked_attendances': marked_attendances,
|
|
'marked_attendances_ratio': marked_attendances_ratio,
|
|
'on_break': early_outs,
|
|
})
|
|
|
|
|
|
def generate_data_set(request, dept):
|
|
"""
|
|
This method is used to generate all the dashboard data
|
|
"""
|
|
today = datetime.today()
|
|
week_day = today.strftime('%A').lower()
|
|
# below method will find all the on-time attendance corresponding to the employee shift and shift schedule.
|
|
on_time = find_on_time(request, today=today,
|
|
week_day=week_day, department=dept)
|
|
|
|
# below method will find all the late-come attendance corresponding to the employee shift and schedule.
|
|
late_come = find_late_come(today=today, department=dept)
|
|
|
|
# below method will find all the early-out attendance corresponding to the employee shift and shift schedule
|
|
early_out = find_early_out(department=dept, today=today)
|
|
|
|
data = {'label': dept.department, 'data': [
|
|
on_time, late_come, len(early_out)]}
|
|
return data
|
|
|
|
|
|
@login_required
|
|
def dashboard_attendance(request):
|
|
|
|
labels = ['On Time', 'Late Come', 'On Break', ]
|
|
data_set = []
|
|
departments = Department.objects.all()
|
|
for dept in departments:
|
|
data_set.append(generate_data_set(request, dept))
|
|
return JsonResponse({'dataSet': data_set, 'labels': labels})
|