[ADD] ATTENDANCE: Check in check out enable disable feature added
This commit is contained in:
@@ -10,6 +10,7 @@ import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
from datetime import date, datetime, timedelta
|
||||
|
||||
from django.contrib import messages
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -25,6 +26,7 @@ from attendance.methods.utils import (
|
||||
from attendance.models import (
|
||||
Attendance,
|
||||
AttendanceActivity,
|
||||
AttendanceGeneralSetting,
|
||||
AttendanceLateComeEarlyOut,
|
||||
GraceTime,
|
||||
)
|
||||
@@ -33,7 +35,7 @@ from base.context_processors import (
|
||||
enable_late_come_early_out_tracking,
|
||||
timerunner_enabled,
|
||||
)
|
||||
from base.models import AttendanceAllowedIP, EmployeeShiftDay
|
||||
from base.models import AttendanceAllowedIP, Company, EmployeeShiftDay
|
||||
from horilla.decorators import hx_request_required, login_required
|
||||
from horilla.horilla_middlewares import _thread_locals
|
||||
|
||||
@@ -196,134 +198,144 @@ def clock_in(request):
|
||||
"""
|
||||
This method is used to mark the attendance once per a day and multiple attendance activities.
|
||||
"""
|
||||
allowed_attendance_ips = AttendanceAllowedIP.objects.first()
|
||||
# check wether check in/check out feature is enabled
|
||||
selected_company = request.session.get("selected_company")
|
||||
company = Company.objects.filter(id=selected_company).first()
|
||||
attendance_general_settings = AttendanceGeneralSetting.objects.filter(
|
||||
company_id=company
|
||||
).first()
|
||||
if attendance_general_settings and attendance_general_settings.enable_check_in:
|
||||
allowed_attendance_ips = AttendanceAllowedIP.objects.first()
|
||||
|
||||
# 'not request.__dict__.get("datetime")' used to check if the request is from a biometric device
|
||||
if (
|
||||
not request.__dict__.get("datetime")
|
||||
and allowed_attendance_ips
|
||||
and allowed_attendance_ips.is_enabled
|
||||
):
|
||||
# 'not request.__dict__.get("datetime")' used to check if the request is from a biometric device
|
||||
if (
|
||||
not request.__dict__.get("datetime")
|
||||
and allowed_attendance_ips
|
||||
and allowed_attendance_ips.is_enabled
|
||||
):
|
||||
|
||||
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
||||
ip = request.META.get("REMOTE_ADDR")
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(",")[0]
|
||||
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
||||
ip = request.META.get("REMOTE_ADDR")
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(",")[0]
|
||||
|
||||
allowed_ips = allowed_attendance_ips.additional_data.get("allowed_ips", [])
|
||||
ip_allowed = False
|
||||
for allowed_ip in allowed_ips:
|
||||
try:
|
||||
if ipaddress.ip_address(ip) in ipaddress.ip_network(
|
||||
allowed_ip, strict=False
|
||||
):
|
||||
ip_allowed = True
|
||||
break
|
||||
except ValueError:
|
||||
continue
|
||||
allowed_ips = allowed_attendance_ips.additional_data.get("allowed_ips", [])
|
||||
ip_allowed = False
|
||||
for allowed_ip in allowed_ips:
|
||||
try:
|
||||
if ipaddress.ip_address(ip) in ipaddress.ip_network(
|
||||
allowed_ip, strict=False
|
||||
):
|
||||
ip_allowed = True
|
||||
break
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if not ip_allowed:
|
||||
return HttpResponse(_("You cannot mark attendance from this network"))
|
||||
if not ip_allowed:
|
||||
return HttpResponse(_("You cannot mark attendance from this network"))
|
||||
|
||||
employee, work_info = employee_exists(request)
|
||||
datetime_now = datetime.now()
|
||||
if request.__dict__.get("datetime"):
|
||||
datetime_now = request.datetime
|
||||
if employee and work_info is not None:
|
||||
shift = work_info.shift_id
|
||||
date_today = date.today()
|
||||
if request.__dict__.get("date"):
|
||||
date_today = request.date
|
||||
attendance_date = date_today
|
||||
day = date_today.strftime("%A").lower()
|
||||
day = EmployeeShiftDay.objects.get(day=day)
|
||||
now = datetime.now().strftime("%H:%M")
|
||||
if request.__dict__.get("time"):
|
||||
now = request.time.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 Horilla consider a 24 hours from noon to next day noon,
|
||||
# the shift day taken today if the attendance clocked in after 12 O clock.
|
||||
employee, work_info = employee_exists(request)
|
||||
datetime_now = datetime.now()
|
||||
if request.__dict__.get("datetime"):
|
||||
datetime_now = request.datetime
|
||||
if employee and work_info is not None:
|
||||
shift = work_info.shift_id
|
||||
date_today = date.today()
|
||||
if request.__dict__.get("date"):
|
||||
date_today = request.date
|
||||
attendance_date = date_today
|
||||
day = date_today.strftime("%A").lower()
|
||||
day = EmployeeShiftDay.objects.get(day=day)
|
||||
now = datetime.now().strftime("%H:%M")
|
||||
if request.__dict__.get("time"):
|
||||
now = request.time.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 Horilla 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
|
||||
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
|
||||
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
|
||||
attendance = 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,
|
||||
in_datetime=datetime_now,
|
||||
)
|
||||
script = ""
|
||||
hidden_label = ""
|
||||
time_runner_enabled = timerunner_enabled(request)["enabled_timerunner"]
|
||||
mouse_in = ""
|
||||
mouse_out = ""
|
||||
if time_runner_enabled:
|
||||
script = """
|
||||
<script>
|
||||
$(".time-runner").removeClass("stop-runner");
|
||||
run = 1;
|
||||
at_work_seconds = {at_work_seconds_forecasted};
|
||||
</script>
|
||||
""".format(
|
||||
at_work_seconds_forecasted=employee.get_forecasted_at_work()[
|
||||
"forecasted_at_work_seconds"
|
||||
]
|
||||
)
|
||||
attendance_date = date_yesterday
|
||||
day = day_yesterday
|
||||
attendance = 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,
|
||||
in_datetime=datetime_now,
|
||||
)
|
||||
script = ""
|
||||
hidden_label = ""
|
||||
time_runner_enabled = timerunner_enabled(request)["enabled_timerunner"]
|
||||
mouse_in = ""
|
||||
mouse_out = ""
|
||||
if time_runner_enabled:
|
||||
script = """
|
||||
<script>
|
||||
$(".time-runner").removeClass("stop-runner");
|
||||
run = 1;
|
||||
at_work_seconds = {at_work_seconds_forecasted};
|
||||
</script>
|
||||
""".format(
|
||||
at_work_seconds_forecasted=employee.get_forecasted_at_work()[
|
||||
"forecasted_at_work_seconds"
|
||||
]
|
||||
)
|
||||
hidden_label = """
|
||||
style="display:none"
|
||||
"""
|
||||
mouse_in = """ onmouseenter = "$(this).find('span').show();$(this).find('.time-runner').hide();" """
|
||||
mouse_out = """ onmouseleave = "$(this).find('span').hide();$(this).find('.time-runner').show();" """
|
||||
hidden_label = """
|
||||
style="display:none"
|
||||
"""
|
||||
mouse_in = """ onmouseenter = "$(this).find('span').show();$(this).find('.time-runner').hide();" """
|
||||
mouse_out = """ onmouseleave = "$(this).find('span').hide();$(this).find('.time-runner').show();" """
|
||||
|
||||
return HttpResponse(
|
||||
"""
|
||||
<button class="oh-btn oh-btn--warning-outline check-in mr-2"
|
||||
{mouse_in}
|
||||
{mouse_out}
|
||||
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>
|
||||
<span {hidden_label} class="hr-check-in-out-text">{check_out}</span>
|
||||
<div class="time-runner"></div>
|
||||
</button>
|
||||
{script}
|
||||
""".format(
|
||||
check_out=_("Check-Out"),
|
||||
script=script,
|
||||
hidden_label=hidden_label,
|
||||
mouse_in=mouse_in,
|
||||
mouse_out=mouse_out,
|
||||
)
|
||||
)
|
||||
return HttpResponse(
|
||||
"""
|
||||
<button class="oh-btn oh-btn--warning-outline check-in mr-2"
|
||||
{mouse_in}
|
||||
{mouse_out}
|
||||
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>
|
||||
<span {hidden_label} class="hr-check-in-out-text">{check_out}</span>
|
||||
<div class="time-runner"></div>
|
||||
</button>
|
||||
{script}
|
||||
""".format(
|
||||
check_out=_("Check-Out"),
|
||||
script=script,
|
||||
hidden_label=hidden_label,
|
||||
mouse_in=mouse_in,
|
||||
mouse_out=mouse_out,
|
||||
_(
|
||||
"You Don't have work information filled or your employee detail neither entered "
|
||||
)
|
||||
)
|
||||
return HttpResponse(
|
||||
_(
|
||||
"You Don't have work information filled or your employee detail neither entered "
|
||||
)
|
||||
)
|
||||
else:
|
||||
messages.error(request, _("Check in/Check out feature is not enabled."))
|
||||
return HttpResponse("<script>location.reload();</script>")
|
||||
|
||||
|
||||
def clock_out_attendance_and_activity(employee, date_today, now, out_datetime=None):
|
||||
@@ -458,103 +470,113 @@ def clock_out(request):
|
||||
"""
|
||||
This method is used to set the out date and time for attendance and attendance activity
|
||||
"""
|
||||
datetime_now = datetime.now()
|
||||
if request.__dict__.get("datetime"):
|
||||
datetime_now = request.datetime
|
||||
employee, work_info = employee_exists(request)
|
||||
shift = work_info.shift_id
|
||||
date_today = date.today()
|
||||
if request.__dict__.get("date"):
|
||||
date_today = request.date
|
||||
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")
|
||||
if request.__dict__.get("time"):
|
||||
now = request.time.strftime("%H:%M")
|
||||
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
|
||||
day=day, shift=shift
|
||||
)
|
||||
attendance = clock_out_attendance_and_activity(
|
||||
employee=employee, date_today=date_today, now=now, out_datetime=datetime_now
|
||||
)
|
||||
if attendance:
|
||||
early_out_instance = attendance.late_come_early_out.filter(type="early_out")
|
||||
is_night_shift = attendance.is_night_shift()
|
||||
next_date = attendance.attendance_date + timedelta(days=1)
|
||||
if not early_out_instance.exists():
|
||||
if is_night_shift:
|
||||
now_sec = strtime_seconds(now)
|
||||
mid_sec = strtime_seconds("12:00")
|
||||
# check wether check in/check out feature is enabled
|
||||
selected_company = request.session.get("selected_company")
|
||||
company = Company.objects.filter(id=selected_company).first()
|
||||
attendance_general_settings = AttendanceGeneralSetting.objects.filter(
|
||||
company_id=company
|
||||
).first()
|
||||
if attendance_general_settings and attendance_general_settings.enable_check_in:
|
||||
datetime_now = datetime.now()
|
||||
if request.__dict__.get("datetime"):
|
||||
datetime_now = request.datetime
|
||||
employee, work_info = employee_exists(request)
|
||||
shift = work_info.shift_id
|
||||
date_today = date.today()
|
||||
if request.__dict__.get("date"):
|
||||
date_today = request.date
|
||||
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")
|
||||
if request.__dict__.get("time"):
|
||||
now = request.time.strftime("%H:%M")
|
||||
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
|
||||
day=day, shift=shift
|
||||
)
|
||||
attendance = clock_out_attendance_and_activity(
|
||||
employee=employee, date_today=date_today, now=now, out_datetime=datetime_now
|
||||
)
|
||||
if attendance:
|
||||
early_out_instance = attendance.late_come_early_out.filter(type="early_out")
|
||||
is_night_shift = attendance.is_night_shift()
|
||||
next_date = attendance.attendance_date + timedelta(days=1)
|
||||
if not early_out_instance.exists():
|
||||
if is_night_shift:
|
||||
now_sec = strtime_seconds(now)
|
||||
mid_sec = strtime_seconds("12:00")
|
||||
|
||||
if (attendance.attendance_date == date_today) or (
|
||||
# check is next day mid
|
||||
mid_sec >= now_sec
|
||||
and date_today == next_date
|
||||
):
|
||||
if (attendance.attendance_date == date_today) or (
|
||||
# check is next day mid
|
||||
mid_sec >= now_sec
|
||||
and date_today == next_date
|
||||
):
|
||||
early_out(
|
||||
attendance=attendance,
|
||||
start_time=start_time_sec,
|
||||
end_time=end_time_sec,
|
||||
shift=shift,
|
||||
)
|
||||
elif attendance.attendance_date == date_today:
|
||||
early_out(
|
||||
attendance=attendance,
|
||||
start_time=start_time_sec,
|
||||
end_time=end_time_sec,
|
||||
shift=shift,
|
||||
)
|
||||
elif attendance.attendance_date == date_today:
|
||||
early_out(
|
||||
attendance=attendance,
|
||||
start_time=start_time_sec,
|
||||
end_time=end_time_sec,
|
||||
shift=shift,
|
||||
)
|
||||
|
||||
script = ""
|
||||
hidden_label = ""
|
||||
time_runner_enabled = timerunner_enabled(request)["enabled_timerunner"]
|
||||
mouse_in = ""
|
||||
mouse_out = ""
|
||||
if time_runner_enabled:
|
||||
script = """
|
||||
<script>
|
||||
$(document).ready(function () {{
|
||||
$('.at-work-seconds').html(secondsToDuration({at_work_seconds_forecasted}))
|
||||
}});
|
||||
run = 0;
|
||||
at_work_seconds = {at_work_seconds_forecasted};
|
||||
</script>
|
||||
""".format(
|
||||
at_work_seconds_forecasted=employee.get_forecasted_at_work()[
|
||||
"forecasted_at_work_seconds"
|
||||
],
|
||||
)
|
||||
hidden_label = """
|
||||
style="display:none"
|
||||
"""
|
||||
mouse_in = """ onmouseenter="$(this).find('div.at-work-seconds').hide();$(this).find('span').show();" """
|
||||
mouse_out = """onmouseleave="$(this).find('div.at-work-seconds').show();$(this).find('span').hide();" """
|
||||
return HttpResponse(
|
||||
"""
|
||||
<button class="oh-btn oh-btn--success-outline mr-2"
|
||||
{mouse_in}
|
||||
{mouse_out}
|
||||
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>
|
||||
<span class="hr-check-in-out-text" {hidden_label} >{check_in}</span>
|
||||
<div class="at-work-seconds"></div>
|
||||
</button>
|
||||
{script}
|
||||
script = ""
|
||||
hidden_label = ""
|
||||
time_runner_enabled = timerunner_enabled(request)["enabled_timerunner"]
|
||||
mouse_in = ""
|
||||
mouse_out = ""
|
||||
if time_runner_enabled:
|
||||
script = """
|
||||
<script>
|
||||
$(document).ready(function () {{
|
||||
$('.at-work-seconds').html(secondsToDuration({at_work_seconds_forecasted}))
|
||||
}});
|
||||
run = 0;
|
||||
at_work_seconds = {at_work_seconds_forecasted};
|
||||
</script>
|
||||
""".format(
|
||||
check_in=_("Check-In"),
|
||||
script=script,
|
||||
hidden_label=hidden_label,
|
||||
mouse_in=mouse_in,
|
||||
mouse_out=mouse_out,
|
||||
at_work_seconds_forecasted=employee.get_forecasted_at_work()[
|
||||
"forecasted_at_work_seconds"
|
||||
],
|
||||
)
|
||||
hidden_label = """
|
||||
style="display:none"
|
||||
"""
|
||||
mouse_in = """ onmouseenter="$(this).find('div.at-work-seconds').hide();$(this).find('span').show();" """
|
||||
mouse_out = """onmouseleave="$(this).find('div.at-work-seconds').show();$(this).find('span').hide();" """
|
||||
return HttpResponse(
|
||||
"""
|
||||
<button class="oh-btn oh-btn--success-outline mr-2"
|
||||
{mouse_in}
|
||||
{mouse_out}
|
||||
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>
|
||||
<span class="hr-check-in-out-text" {hidden_label} >{check_in}</span>
|
||||
<div class="at-work-seconds"></div>
|
||||
</button>
|
||||
{script}
|
||||
""".format(
|
||||
check_in=_("Check-In"),
|
||||
script=script,
|
||||
hidden_label=hidden_label,
|
||||
mouse_in=mouse_in,
|
||||
mouse_out=mouse_out,
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
messages.error(request, _("Check in/Check out feature is not enabled."))
|
||||
return HttpResponse("<script>location.reload();</script>")
|
||||
|
||||
@@ -2494,6 +2494,42 @@ def enable_disable_tracking_late_come_early_out(request):
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
|
||||
|
||||
@login_required
|
||||
def check_in_check_out_setting(request):
|
||||
"""
|
||||
Check in check out setting
|
||||
"""
|
||||
attendance_settings = AttendanceGeneralSetting.objects.all()
|
||||
return render(
|
||||
request,
|
||||
"attendance/settings/check_in_check_out_enable_form.html",
|
||||
{"attendance_settings": attendance_settings},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def enable_disable_check_in(request):
|
||||
"""
|
||||
Enables or disables check in check out.
|
||||
"""
|
||||
if request.method == "POST":
|
||||
if request.POST.get("isChecked") and request.POST.get("isChecked") == "false":
|
||||
enable = False
|
||||
else:
|
||||
enable = True
|
||||
setting_id = request.POST.get("setting_Id")
|
||||
attendance_gen_setting = AttendanceGeneralSetting.objects.filter(
|
||||
id=setting_id
|
||||
).first()
|
||||
attendance_gen_setting.enable_check_in = enable
|
||||
attendance_gen_setting.save()
|
||||
message = _("enabled") if enable else _("disabled")
|
||||
messages.success(
|
||||
request, _("Check in/Check out {} successfully").format(message)
|
||||
)
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("attendance.view_attendancevalidationcondition")
|
||||
def grace_time_view(request):
|
||||
|
||||
Reference in New Issue
Block a user