+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/attendance/urls.py b/attendance/urls.py
index 4307c8fd4..6d392df82 100644
--- a/attendance/urls.py
+++ b/attendance/urls.py
@@ -465,6 +465,16 @@ urlpatterns = [
views.enable_disable_tracking_late_come_early_out,
name="enable-disable-tracking-late-come-early-out",
),
+ path(
+ "check-in-check-out-setting/",
+ views.check_in_check_out_setting,
+ name="check-in-check-out-setting",
+ ),
+ path(
+ "enable-disable-check-in",
+ views.enable_disable_check_in,
+ name="enable-disable-check-in",
+ ),
path(
"grace-settings-view/",
views.grace_time_view,
diff --git a/attendance/views/clock_in_out.py b/attendance/views/clock_in_out.py
index 6a21ab9a5..2a9f4be71 100644
--- a/attendance/views/clock_in_out.py
+++ b/attendance/views/clock_in_out.py
@@ -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 = """
+
+ """.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 = """
-
- """.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(
+ """
+
+ {check_out}
+
+
+ {script}
+ """.format(
+ check_out=_("Check-Out"),
+ script=script,
+ hidden_label=hidden_label,
+ mouse_in=mouse_in,
+ mouse_out=mouse_out,
+ )
+ )
return HttpResponse(
- """
-
- {check_out}
-
-
- {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("")
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 = """
-
- """.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(
- """
-
-
- {check_in}
-
-
- {script}
+ script = ""
+ hidden_label = ""
+ time_runner_enabled = timerunner_enabled(request)["enabled_timerunner"]
+ mouse_in = ""
+ mouse_out = ""
+ if time_runner_enabled:
+ 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(
+ """
+
+
+ {check_in}
+
+
+ {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("")
diff --git a/attendance/views/views.py b/attendance/views/views.py
index 942246e62..713a4f743 100644
--- a/attendance/views/views.py
+++ b/attendance/views/views.py
@@ -2494,6 +2494,42 @@ def enable_disable_tracking_late_come_early_out(request):
return HttpResponse("")
+@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("")
+
+
@login_required
@permission_required("attendance.view_attendancevalidationcondition")
def grace_time_view(request):
diff --git a/base/templates/announcement/announcements_list.html b/base/templates/announcement/announcements_list.html
index 167256a6e..b60488811 100644
--- a/base/templates/announcement/announcements_list.html
+++ b/base/templates/announcement/announcements_list.html
@@ -41,4 +41,4 @@
{% endif %}
-
\ No newline at end of file
+
diff --git a/base/templatetags/horillafilters.py b/base/templatetags/horillafilters.py
index fb5ae188d..bbff108cd 100644
--- a/base/templatetags/horillafilters.py
+++ b/base/templatetags/horillafilters.py
@@ -16,7 +16,7 @@ from django.template import TemplateSyntaxError
from django.template.defaultfilters import register
from django.utils.translation import gettext as _
-from base.models import EmployeeShiftSchedule
+from base.models import Company, EmployeeShiftSchedule
from employee.methods.duration_methods import strtime_seconds
from horilla.horilla_middlewares import _thread_locals
from horilla.methods import get_horilla_model_class
@@ -307,3 +307,32 @@ def currency_symbol_position(amount):
currency_symbol = f"{currency} {amount}"
return currency_symbol
+
+
+@register.filter(name="is_check_in_enabled")
+def is_check_in_enabled(request):
+ """
+ This method checks whether the check-in/check-out feature is enabled.
+ """
+ from attendance.models import AttendanceGeneralSetting
+
+ # from base.models import Company # Assuming Company is the correct model for `selected_company`
+ selected_company = request.session.get("selected_company")
+ if not selected_company:
+ return False # Safeguard if session key is missing
+
+ # Fetch the settings based on the selected company
+ if selected_company == "all":
+ attendance_settings, created = AttendanceGeneralSetting.objects.get_or_create(
+ company_id=None
+ )
+ else:
+ company = Company.objects.filter(id=selected_company).first()
+ if not company:
+ return False # Return False if the company doesn't exist
+ attendance_settings, created = AttendanceGeneralSetting.objects.get_or_create(
+ company_id=company
+ )
+
+ # Check if check-in is enabled
+ return bool(attendance_settings and attendance_settings.enable_check_in)
diff --git a/templates/settings.html b/templates/settings.html
index 55e427f48..ed15325b4 100644
--- a/templates/settings.html
+++ b/templates/settings.html
@@ -367,6 +367,16 @@
>
{% endif %}
+