[FIX]attendance bug fix
This commit is contained in:
@@ -20,9 +20,10 @@ class YourForm(forms.Form):
|
||||
# Custom validation logic goes here
|
||||
pass
|
||||
"""
|
||||
import uuid
|
||||
import uuid, datetime
|
||||
from calendar import month_name
|
||||
from django import forms
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.forms import DateTimeInput
|
||||
@@ -132,6 +133,14 @@ class AttendanceUpdateForm(ModelForm):
|
||||
kwargs["initial"] = initial
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
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 AttendanceForm(ModelForm):
|
||||
"""
|
||||
@@ -166,6 +175,14 @@ class AttendanceForm(ModelForm):
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
initial = {
|
||||
"attendance_clock_out_date": datetime.datetime.today()
|
||||
.date()
|
||||
.strftime("%Y-%m-%d"),
|
||||
"attendance_clock_out": datetime.datetime.today()
|
||||
.time()
|
||||
.strftime("%H:%M"),
|
||||
}
|
||||
if instance := kwargs.get("instance"):
|
||||
# django forms not showing value inside the date, time html element.
|
||||
# so here overriding default forms instance method to set initial value
|
||||
@@ -183,7 +200,7 @@ class AttendanceForm(ModelForm):
|
||||
initial[
|
||||
"attendance_clock_out_date"
|
||||
] = instance.attendance_clock_out_date.strftime("%Y-%m-%d")
|
||||
kwargs["initial"] = initial
|
||||
kwargs["initial"] = initial
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["employee_id"].widget.attrs.update({"id": str(uuid.uuid4())})
|
||||
self.fields["shift_id"].widget.attrs.update({"id": str(uuid.uuid4())})
|
||||
@@ -201,6 +218,14 @@ class AttendanceForm(ModelForm):
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
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
|
||||
|
||||
def clean_employee_id(self):
|
||||
"""
|
||||
Used to validate employee_id field
|
||||
|
||||
@@ -69,6 +69,7 @@ class AttendanceActivity(models.Model):
|
||||
"""
|
||||
AttendanceActivity model
|
||||
"""
|
||||
|
||||
employee_id = models.ForeignKey(
|
||||
Employee,
|
||||
on_delete=models.CASCADE,
|
||||
@@ -88,6 +89,7 @@ class AttendanceActivity(models.Model):
|
||||
"""
|
||||
Meta class to add some additional options
|
||||
"""
|
||||
|
||||
ordering = ["-attendance_date", "employee_id__employee_first_name", "clock_in"]
|
||||
|
||||
|
||||
@@ -95,6 +97,7 @@ class Attendance(models.Model):
|
||||
"""
|
||||
Attendance model_
|
||||
"""
|
||||
|
||||
employee_id = models.ForeignKey(
|
||||
Employee,
|
||||
on_delete=models.CASCADE,
|
||||
@@ -143,6 +146,7 @@ class Attendance(models.Model):
|
||||
"""
|
||||
Meta class to add some additional options
|
||||
"""
|
||||
|
||||
unique_together = ("employee_id", "attendance_date")
|
||||
permissions = [
|
||||
("change_validateattendance", "Validate Attendance"),
|
||||
@@ -253,11 +257,40 @@ class Attendance(models.Model):
|
||||
employee_ot.save()
|
||||
return employee_ot
|
||||
|
||||
def clean(self, *args, **kwargs):
|
||||
super().clean(*args, **kwargs)
|
||||
now = datetime.now().time()
|
||||
today = datetime.today().date()
|
||||
out_time = self.attendance_clock_out
|
||||
if self.attendance_clock_in_date < self.attendance_date:
|
||||
raise ValidationError(
|
||||
{
|
||||
"attendance_clock_in_date": \
|
||||
"Attendance check-in date never smaller than attendance date"
|
||||
}
|
||||
)
|
||||
if self.attendance_clock_out_date < self.attendance_clock_in_date:
|
||||
raise ValidationError(
|
||||
{
|
||||
"attendance_clock_out_date": \
|
||||
"Attendance check-out date never smaller than attendance check-in date"
|
||||
}
|
||||
)
|
||||
if self.attendance_clock_out_date >= today:
|
||||
if out_time > now:
|
||||
raise ValidationError(
|
||||
{"attendance_clock_out": "Check out time not allow in the future"}
|
||||
)
|
||||
print("----------------------")
|
||||
print(now)
|
||||
print("----------------------")
|
||||
|
||||
|
||||
class AttendanceOverTime(models.Model):
|
||||
"""
|
||||
AttendanceOverTime model
|
||||
"""
|
||||
|
||||
employee_id = models.ForeignKey(
|
||||
Employee,
|
||||
on_delete=models.CASCADE,
|
||||
@@ -288,6 +321,7 @@ class AttendanceOverTime(models.Model):
|
||||
"""
|
||||
Meta class to add some additional options
|
||||
"""
|
||||
|
||||
unique_together = [("employee_id"), ("month"), ("year")]
|
||||
ordering = ["-year", "-month_sequence"]
|
||||
|
||||
@@ -317,6 +351,7 @@ class AttendanceLateComeEarlyOut(models.Model):
|
||||
"""
|
||||
AttendanceLateComeEarlyOut model
|
||||
"""
|
||||
|
||||
choices = [
|
||||
("late_come", _("Late Come")),
|
||||
("early_out", _("Early Out")),
|
||||
@@ -338,6 +373,7 @@ class AttendanceLateComeEarlyOut(models.Model):
|
||||
"""
|
||||
Meta class to add some additional options
|
||||
"""
|
||||
|
||||
unique_together = [("attendance_id"), ("type")]
|
||||
|
||||
def __str__(self) -> str:
|
||||
@@ -349,6 +385,7 @@ class AttendanceValidationCondition(models.Model):
|
||||
"""
|
||||
AttendanceValidationCondition model
|
||||
"""
|
||||
|
||||
validation_at_work = models.CharField(
|
||||
default="09:00", max_length=10, validators=[validate_time_format]
|
||||
)
|
||||
|
||||
@@ -1,86 +1,8 @@
|
||||
{% load i18n %}
|
||||
<form hx-post="{% url 'attendance-create' %}" hx-target="#addAttendanceModalBody" id="addForm">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label class="oh-label" for="firstname">{% trans "Employee" %}</label>
|
||||
{{form.employee_id}}
|
||||
{{form.employee_id.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Shift" %}</label>
|
||||
{{form.shift_id}}
|
||||
{{form.shift_id.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Work Type" %}</label>
|
||||
{{form.work_type_id}}
|
||||
{{form.work_type_id.errors}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Attendance Date" %}</label>
|
||||
{{form.attendance_date}}
|
||||
{{form.attendance_date.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Minimum Hour" %}</label>
|
||||
{{form.minimum_hour}}
|
||||
{{form.minimum_hour.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Check-In Date" %}</label>
|
||||
{{form.attendance_clock_in_date}}
|
||||
{{form.attendance_clock_in_date.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "In Time" %}</label>
|
||||
{{form.attendance_clock_in}}
|
||||
{{form.attendance_clock_in.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Check-Out Date" %}</label>
|
||||
{{form.attendance_clock_out_date}}
|
||||
{{form.attendance_clock_out_date.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Out Time" %}</label>
|
||||
{{form.attendance_clock_out}}
|
||||
{{form.attendance_clock_out.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "At Work" %}</label>
|
||||
{{form.attendance_worked_hour}}
|
||||
{{form.attendance_worked_hour.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Overtime" %}</label>
|
||||
{{form.attendance_overtime}}
|
||||
{{form.attendance_overtime.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Validated" %}</label><br>
|
||||
{{form.attendance_validated}}
|
||||
{{form.attendance_validated.errors}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oh-modal__dialog-footer">
|
||||
<input type="submit" value='{% trans "Add Attendance" %}' class="oh-btn oh-btn--secondary oh-btn--shadow">
|
||||
</div>
|
||||
</form>
|
||||
<form
|
||||
hx-post="{% url 'attendance-create' %}"
|
||||
hx-target="#addAttendanceModalBody"
|
||||
id="addForm"
|
||||
>
|
||||
{{form.as_p}}
|
||||
</form>
|
||||
|
||||
@@ -478,7 +478,7 @@ aria-hidden="true"
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div id="updateAttendanceModalBody">
|
||||
<div class="oh-modal__dialog-body" id="updateAttendanceModalBody">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,92 +1,11 @@
|
||||
{% load i18n %}
|
||||
<form hx-post="{% url 'attendance-update' form.instance.id %}" hx-swap="#updateAttendanceModalBody" method="post" id="updateForm">
|
||||
<div class="oh-modal__dialog-body">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label class="oh-label" for="firstname">{% trans "Employee" %}</label>
|
||||
{{form.employee_id}}
|
||||
{{form.employee_id.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Shift" %}</label>
|
||||
{{form.shift_id}}
|
||||
{{form.shift_id.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Work Type" %}</label>
|
||||
{{form.work_type_id}}
|
||||
{{form.work_type_id.errors}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Attendance Date" %}</label>
|
||||
{{form.attendance_date}}
|
||||
{{form.attendance_date.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Minimum Hour" %}</label>
|
||||
{{form.minimum_hour}}
|
||||
{{form.minimum_hour.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Check-In Date" %}</label>
|
||||
{{form.attendance_clock_in_date}}
|
||||
{{form.attendance_clock_in_date.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "In Time" %}</label>
|
||||
{{form.attendance_clock_in}}
|
||||
{{form.attendance_clock_in.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Check-Out Date" %}</label>
|
||||
{{form.attendance_clock_out_date}}
|
||||
{{form.attendance_clock_out_date.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Out Time" %}</label>
|
||||
{{form.attendance_clock_out}}
|
||||
{{form.attendance_clock_out.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "At Work" %}</label>
|
||||
{{form.attendance_worked_hour}}
|
||||
{{form.attendance_worked_hour.errors}}
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Overtime" %}</label>
|
||||
{{form.attendance_overtime}}
|
||||
{{form.attendance_overtime.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6">
|
||||
<label class="oh-label" for="lastname">{% trans "Validated" %}</label><br>
|
||||
{{form.attendance_validated}}
|
||||
{{form.attendance_validated.errors}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-modal__dialog-footer">
|
||||
<input type="submit" value='Save' class="pl-5 pr-5 oh-btn oh-btn--secondary oh-btn--shadow">
|
||||
<form
|
||||
hx-post="{% url 'attendance-update' form.instance.id %}"
|
||||
hx-swap="#updateAttendanceModalBody"
|
||||
method="post"
|
||||
id="updateForm"
|
||||
>
|
||||
{{form.as_p}}
|
||||
|
||||
<script></script>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
@@ -7,8 +7,8 @@
|
||||
<div class="oh-sticky-table__th"hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=employee_id__employee_first_name">{% trans "Employee" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=attendance_date">{% trans "Attendnace Date" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=clock_in_date">{% trans "In Date" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=">{% trans "Clock In" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=">{% trans "Clock Out" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=">{% trans "Check In" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=">{% trans "Check Out" %}</div>
|
||||
<div class='oh-sticky-table__th'hx-target='#activity-table' hx-get="{% url 'attendance-activity-search' %}?{{pd}}&orderby=clock_out_date">{% trans "Out Date" %}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
50
attendance/templates/attendance_form.html
Normal file
50
attendance/templates/attendance_form.html
Normal file
@@ -0,0 +1,50 @@
|
||||
{% load widget_tweaks %} {% load attendancefilters %}
|
||||
|
||||
<div class="oh-general__tab-target oh-profile-section" id="personal">
|
||||
<div class="oh-profile-section__card">
|
||||
<div class="row">
|
||||
<div class="col-12">{{form.non_field_errors}}</div>
|
||||
|
||||
{% for field in form.visible_fields %}
|
||||
{% if field.field.widget|is_select_multiple %}
|
||||
<label
|
||||
class="oh-label"
|
||||
for="id_{{ field.name }}"
|
||||
title="{{ field.help_text|safe }}"
|
||||
>{{ field.label }}</label
|
||||
>
|
||||
{{ field|add_class:"form-control" }}
|
||||
{{field.errors}}
|
||||
|
||||
{% else %}
|
||||
<div class="col-12 col-md-6">
|
||||
<label
|
||||
class="oh-label"
|
||||
for="id_{{ field.name }}"
|
||||
title="{{ field.help_text|safe }}"
|
||||
>{{ field.label }}</label
|
||||
>
|
||||
{% if field.field.widget.input_type == "checkbox" %}
|
||||
<div class="oh-switch" style="width: 30px">
|
||||
{{ field|add_class:"oh-switch__checkbox" }}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ field|add_class:"form-control" }}
|
||||
{% endif %}
|
||||
{{field.errors}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-row-reverse">
|
||||
<button
|
||||
type="submit"
|
||||
class="oh-btn oh-btn--secondary mt-2 mr-0 pl-4 pr-5 oh-btn--w-100-resp"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -6,6 +6,7 @@ This module is used to write custom template filters.
|
||||
"""
|
||||
from itertools import groupby
|
||||
from django import template
|
||||
from django.forms.widgets import SelectMultiple
|
||||
from django.template import TemplateSyntaxError
|
||||
from django.template.defaultfilters import register
|
||||
from attendance.views import strtime_seconds
|
||||
@@ -172,3 +173,18 @@ def any_permission(user, app_label):
|
||||
bool: True if any permission on the module
|
||||
"""
|
||||
return user.has_module_perms(app_label)
|
||||
|
||||
|
||||
@register.filter
|
||||
def is_select_multiple(widget):
|
||||
"""
|
||||
Custom template filter to check if a widget is an instance of SelectMultiple.
|
||||
|
||||
Usage:
|
||||
{% load custom_filters %}
|
||||
|
||||
{% if field.field.widget|is_select_multiple %}
|
||||
<!-- Your code here -->
|
||||
{% endif %}
|
||||
"""
|
||||
return isinstance(widget, SelectMultiple)
|
||||
|
||||
Reference in New Issue
Block a user