diff --git a/attendance/filters.py b/attendance/filters.py
index 8ff3304ed..a61f83f50 100644
--- a/attendance/filters.py
+++ b/attendance/filters.py
@@ -348,7 +348,7 @@ class AttendanceFilters(FilterSet):
"""
id = django_filters.NumberFilter(field_name="id")
- search = django_filters.CharFilter(method=filter_by_name)
+ search = django_filters.CharFilter(method="filter_by_name")
employee = django_filters.CharFilter(field_name="employee_id__id")
date_attendance = django_filters.DateFilter(field_name="attendance_date")
employee_id = django_filters.ModelMultipleChoiceFilter(
diff --git a/attendance/forms.py b/attendance/forms.py
index 055fd00b2..6b2f1265a 100644
--- a/attendance/forms.py
+++ b/attendance/forms.py
@@ -864,14 +864,6 @@ class GraceTimeForm(ModelForm):
exclude = ["objects", "allowed_time_in_secs", "is_active"]
- def as_p(self, *args, **kwargs):
- """
- Render the form fields as HTML table rows with Bootstrap styling.
- """
- context = {"form": self}
- table_html = render_to_string("attendance_form.html", context)
- return table_html
-
class AttendanceRequestCommentForm(ModelForm):
"""
diff --git a/attendance/models.py b/attendance/models.py
index 0e4e39bc5..cb4596aef 100644
--- a/attendance/models.py
+++ b/attendance/models.py
@@ -970,12 +970,19 @@ class GraceTime(HorillaModel):
verbose_name=_("Allowed time"),
)
allowed_time_in_secs = models.IntegerField()
+ allowed_clock_in = models.BooleanField(
+ default=True, help_text=_("Allcocate this grace time for Check-In Attendance")
+ )
+ allowed_clock_out = models.BooleanField(
+ default=False, help_text=_("Allcocate this grace time for Check-Out Attendance")
+ )
is_default = models.BooleanField(default=False)
+
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
objects = HorillaCompanyManager()
def __str__(self) -> str:
- return str(f"{self.allowed_time} - Minutes")
+ return str(f"{self.allowed_time} - Hours")
def clean(self):
"""
@@ -999,7 +1006,11 @@ class GraceTime(HorillaModel):
.exists()
):
raise ValidationError(
- _("There is already a grace time with this allowed time that exists.")
+ {
+ "allowed_time": _(
+ "There is already an existing grace time with this allowed time."
+ )
+ }
)
def save(self, *args, **kwargs):
diff --git a/attendance/templates/attendance/break_point/condition.html b/attendance/templates/attendance/break_point/condition.html
index 4ece5f555..18e9598eb 100644
--- a/attendance/templates/attendance/break_point/condition.html
+++ b/attendance/templates/attendance/break_point/condition.html
@@ -67,20 +67,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{% endblock %}
diff --git a/attendance/templates/attendance/grace_time/grace_time_form.html b/attendance/templates/attendance/grace_time/grace_time_form.html
index 7fcf88bd6..bf0f27207 100644
--- a/attendance/templates/attendance/grace_time/grace_time_form.html
+++ b/attendance/templates/attendance/grace_time/grace_time_form.html
@@ -1,50 +1,92 @@
{% load i18n %}
-
+{% load widget_tweaks %}
{% if form.errors %}
-
-
-
- {% for error in form.non_field_errors %}
-
- {{ error }}
-
- {% endfor %}
-
+
+
+
+ {% for error in form.non_field_errors %}
+
{{ error }}
+ {% endfor %}
+
{% endif %}
-
diff --git a/attendance/templates/attendance/grace_time/grace_time_table.html b/attendance/templates/attendance/grace_time/grace_time_table.html
new file mode 100644
index 000000000..3e5ad533a
--- /dev/null
+++ b/attendance/templates/attendance/grace_time/grace_time_table.html
@@ -0,0 +1,193 @@
+{% load static %}{% load i18n %}
+{% if messages %}
+
+ {% for message in messages %}
+
+ {% endfor %}
+
+{% endif %}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/attendance/urls.py b/attendance/urls.py
index b2a6fb289..0fb68ad03 100644
--- a/attendance/urls.py
+++ b/attendance/urls.py
@@ -354,7 +354,7 @@ urlpatterns = [
name="delete-grace-time",
),
path(
- "update-isactive-gracetime",
+ "update-isactive-gracetime/
",
views.update_isactive_gracetime,
name="update-isactive-gracetime",
),
diff --git a/attendance/views/clock_in_out.py b/attendance/views/clock_in_out.py
index fbc7c5546..0ebf5a678 100644
--- a/attendance/views/clock_in_out.py
+++ b/attendance/views/clock_in_out.py
@@ -70,7 +70,10 @@ def late_come(attendance, start_time, end_time, shift):
# Checking gracetime allowance before creating late come
if shift.grace_time_id:
# checking grace time in shift, it has the higher priority
- if shift.grace_time_id.is_active == True:
+ if (
+ shift.grace_time_id.is_active == True
+ and shift.grace_time_id.allowed_clock_in == True
+ ):
# Setting allowance for the check in time
now_sec -= shift.grace_time_id.allowed_time_in_secs
# checking default grace time
@@ -79,8 +82,9 @@ def late_come(attendance, start_time, end_time, shift):
is_default=True,
is_active=True,
).first()
- # Setting allowance for the check in time
- now_sec -= grace_time.allowed_time_in_secs
+ # Setting allowance for the check in time if grace allocate for clock in event
+ if grace_time.allowed_clock_in:
+ now_sec -= grace_time.allowed_time_in_secs
else:
pass
if start_time > end_time and start_time != end_time:
@@ -377,7 +381,7 @@ def early_out_create(attendance):
return late_come_obj
-def early_out(attendance, start_time, end_time):
+def early_out(attendance, start_time, end_time, shift):
"""
This method is used to mark the early check-out attendance before the shift ends
args:
@@ -385,9 +389,25 @@ def early_out(attendance, start_time, end_time):
start_time : attendance day shift start time
start_end : attendance day shift end time
"""
-
now_sec = strtime_seconds(attendance.attendance_clock_out.strftime("%H:%M"))
mid_day_sec = strtime_seconds("12:00")
+ # Checking gracetime allowance before creating early out
+ if shift and shift.grace_time_id:
+ if (
+ shift.grace_time_id.is_active == True
+ and shift.grace_time_id.allowed_clock_out == True
+ ):
+ now_sec += shift.grace_time_id.allowed_time_in_secs
+ elif GraceTime.objects.filter(is_default=True, is_active=True).exists():
+ grace_time = GraceTime.objects.filter(
+ is_default=True,
+ is_active=True,
+ ).first()
+ # Setting allowance for the check out time if grace allocate for clock out event
+ if grace_time.allowed_clock_out:
+ now_sec += grace_time.allowed_time_in_secs
+ else:
+ pass
if start_time > end_time:
# Early out condition for night shift
if now_sec < mid_day_sec:
@@ -443,7 +463,10 @@ def clock_out(request):
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
+ attendance=attendance,
+ start_time=start_time_sec,
+ end_time=end_time_sec,
+ shift=shift,
)
script = ""
diff --git a/attendance/views/views.py b/attendance/views/views.py
index edac86b56..2ed3a2d76 100644
--- a/attendance/views/views.py
+++ b/attendance/views/views.py
@@ -1759,39 +1759,41 @@ def delete_grace_time(request, grace_id):
messages.error(request, _("Grace Time Does not exists.."))
except ProtectedError:
messages.error(request, _("Related datas exists."))
- if request.GET.get("view") == "shift":
- return redirect("/settings/grace-settings-view")
- else:
- return redirect("/settings/grace-settings-view")
+ context = {
+ "condition": AttendanceValidationCondition.objects.first(),
+ "default_grace_time": GraceTime.objects.filter(is_default=True).first(),
+ "grace_times": GraceTime.objects.all().exclude(is_default=True),
+ }
+
+ return render(request, "attendance/grace_time/grace_time_table.html", context)
@login_required
@permission_required("attendance.update_gracetime")
-def update_isactive_gracetime(request):
+def update_isactive_gracetime(request, obj_id):
"""
ajax function to update is active field in grace time.
Args:
- - isChecked: Boolean value representing the state of grace time,
- - graceId: Id of grace time object
+ - is_active: Boolean value representing the state of grace time,
+ - obj_id: Id of grace time object
"""
- isChecked = request.POST.get("isChecked")
- graceId = request.POST.get("graceId")
- grace_time = GraceTime.objects.get(id=graceId)
- if isChecked == "true":
+ is_active = request.POST.get("is_active")
+ grace_time = GraceTime.objects.get(id=obj_id)
+ if is_active == "on":
grace_time.is_active = True
-
- response = {
- "type": "success",
- "message": _("Default grace time activated successfully."),
- }
+ messages.success(request, _("Grace time activated successfully."))
else:
grace_time.is_active = False
- response = {
- "type": "success",
- "message": _("Default grace time deactivated successfully."),
- }
+ messages.success(request, _("Grace time deactivated successfully."))
grace_time.save()
- return JsonResponse(response)
+
+ context = {
+ "condition": AttendanceValidationCondition.objects.first(),
+ "default_grace_time": GraceTime.objects.filter(is_default=True).first(),
+ "grace_times": GraceTime.objects.all().exclude(is_default=True),
+ }
+
+ return render(request, "attendance/grace_time/grace_time_table.html", context)
@login_required
diff --git a/base/methods.py b/base/methods.py
index 6491b58d7..3b5d1e453 100644
--- a/base/methods.py
+++ b/base/methods.py
@@ -22,6 +22,7 @@ from base.models import Company, DynamicPagination
from employee.models import Employee, EmployeeWorkInformation
from horilla.decorators import login_required
from leave.models import LeaveRequest, LeaveRequestConditionApproval
+from recruitment.models import Candidate
def filtersubordinates(request, queryset, perm=None, field=None):
@@ -589,6 +590,8 @@ def reload_queryset(fields):
if isinstance(v, ModelChoiceField):
if v.queryset.model == Employee:
v.queryset = v.queryset.model.objects.filter(is_active=True)
+ elif v.queryset.model == Candidate:
+ v.queryset = v.queryset.model.objects.filter(is_active=True)
else:
v.queryset = v.queryset.model.objects.all()
return
diff --git a/horilla/horilla_settings.py b/horilla/horilla_settings.py
index 655cf6dbf..44a4f83d7 100644
--- a/horilla/horilla_settings.py
+++ b/horilla/horilla_settings.py
@@ -3,7 +3,7 @@ from horilla import settings
"""
DB_INIT_PASSWORD: str
-The password used for database setup and initialization. This password is a
-48-character alphanumeric string generated using a UUID to ensure high entropy and security.
+The password used for database setup and initialization. This password is a
+48-character alphanumeric string generated using a UUID to ensure high entropy and security.
"""
DB_INIT_PASSWORD = ""