2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
forms.py
|
|
|
|
|
|
|
|
|
|
This module contains the form classes used in the application.
|
|
|
|
|
|
|
|
|
|
Each form represents a specific functionality or data input in the
|
|
|
|
|
application. They are responsible for validating
|
|
|
|
|
and processing user input data.
|
|
|
|
|
|
|
|
|
|
Classes:
|
|
|
|
|
- YourForm: Represents a form for handling specific data input.
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
from django import forms
|
|
|
|
|
|
|
|
|
|
class YourForm(forms.Form):
|
|
|
|
|
field_name = forms.CharField()
|
|
|
|
|
|
|
|
|
|
def clean_field_name(self):
|
|
|
|
|
# Custom validation logic goes here
|
|
|
|
|
pass
|
|
|
|
|
"""
|
2023-07-05 11:46:47 +05:30
|
|
|
import uuid, datetime
|
2023-05-30 15:21:53 +05:30
|
|
|
from calendar import month_name
|
2023-05-10 15:06:57 +05:30
|
|
|
from django import forms
|
2023-07-05 11:46:47 +05:30
|
|
|
from django.template.loader import render_to_string
|
2023-05-10 15:06:57 +05:30
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
from django.core.exceptions import ValidationError
|
|
|
|
|
from django.forms import DateTimeInput
|
|
|
|
|
from employee.models import Employee
|
2023-05-30 15:21:53 +05:30
|
|
|
from attendance.models import (
|
|
|
|
|
Attendance,
|
|
|
|
|
AttendanceOverTime,
|
|
|
|
|
AttendanceActivity,
|
|
|
|
|
AttendanceLateComeEarlyOut,
|
|
|
|
|
AttendanceValidationCondition,
|
|
|
|
|
)
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
class ModelForm(forms.ModelForm):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Overriding django default model form to apply some styles
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
for field_name, field in self.fields.items():
|
|
|
|
|
widget = field.widget
|
2023-05-30 15:21:53 +05:30
|
|
|
if isinstance(
|
|
|
|
|
widget, (forms.NumberInput, forms.EmailInput, forms.TextInput)
|
|
|
|
|
):
|
|
|
|
|
label = _(field.label.title())
|
|
|
|
|
field.widget.attrs.update(
|
|
|
|
|
{"class": "oh-input w-100", "placeholder": label}
|
|
|
|
|
)
|
|
|
|
|
elif isinstance(widget, (forms.Select,)):
|
|
|
|
|
label = ""
|
2023-05-10 15:06:57 +05:30
|
|
|
if field.label is not None:
|
2023-05-18 15:05:28 +05:30
|
|
|
label = _(field.label)
|
|
|
|
|
field.empty_label = _("---Choose {label}---").format(label=label)
|
2023-05-30 15:21:53 +05:30
|
|
|
self.fields[field_name].widget.attrs.update(
|
|
|
|
|
{
|
|
|
|
|
"class": "oh-select oh-select-2 w-100",
|
|
|
|
|
"id": uuid.uuid4(),
|
|
|
|
|
"style": "height:50px;border-radius:0;",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
elif isinstance(widget, (forms.Textarea)):
|
2023-05-18 15:05:28 +05:30
|
|
|
label = _(field.label.title())
|
2023-05-30 15:21:53 +05:30
|
|
|
field.widget.attrs.update(
|
|
|
|
|
{
|
|
|
|
|
"class": "oh-input w-100",
|
|
|
|
|
"placeholder": field.label,
|
|
|
|
|
"rows": 2,
|
|
|
|
|
"cols": 40,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
elif isinstance(
|
|
|
|
|
widget,
|
|
|
|
|
(
|
|
|
|
|
forms.CheckboxInput,
|
|
|
|
|
forms.CheckboxSelectMultiple,
|
|
|
|
|
),
|
|
|
|
|
):
|
|
|
|
|
field.widget.attrs.update({"class": "oh-switch__checkbox"})
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttendanceUpdateForm(ModelForm):
|
|
|
|
|
"""
|
|
|
|
|
This model form is used to direct save the validated query dict to attendance model
|
|
|
|
|
from AttendanceForm. This form can be used to update existing attendance.
|
|
|
|
|
"""
|
2023-05-30 15:21:53 +05:30
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
class Meta:
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Meta class to add the additional info
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
fields = "__all__"
|
|
|
|
|
exclude = [
|
|
|
|
|
"overtime_second",
|
|
|
|
|
"at_work_second",
|
|
|
|
|
"attendance_day",
|
|
|
|
|
"approved_overtime_second",
|
|
|
|
|
]
|
2023-05-10 15:06:57 +05:30
|
|
|
model = Attendance
|
|
|
|
|
widgets = {
|
2023-05-30 15:21:53 +05:30
|
|
|
"attendance_clock_in": DateTimeInput(attrs={"type": "time"}),
|
|
|
|
|
"attendance_clock_out": DateTimeInput(attrs={"type": "time"}),
|
|
|
|
|
"attendance_clock_out_date": DateTimeInput(attrs={"type": "date"}),
|
|
|
|
|
"attendance_date": DateTimeInput(attrs={"type": "date"}),
|
|
|
|
|
"attendance_clock_in_date": DateTimeInput(attrs={"type": "date"}),
|
|
|
|
|
}
|
2023-05-10 15:06:57 +05:30
|
|
|
|
2023-05-30 15:21:53 +05:30
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
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
|
|
|
|
|
initial = {
|
|
|
|
|
"attendance_date": instance.attendance_date.strftime("%Y-%m-%d"),
|
|
|
|
|
"attendance_clock_in": instance.attendance_clock_in.strftime("%H:%M"),
|
|
|
|
|
"attendance_clock_in_date": instance.attendance_clock_in_date.strftime(
|
|
|
|
|
"%Y-%m-%d"
|
|
|
|
|
),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
|
|
|
|
if instance.attendance_clock_out_date is not None:
|
2023-05-30 15:21:53 +05:30
|
|
|
initial[
|
|
|
|
|
"attendance_clock_out"
|
|
|
|
|
] = instance.attendance_clock_out.strftime("%H:%M")
|
|
|
|
|
initial[
|
|
|
|
|
"attendance_clock_out_date"
|
|
|
|
|
] = instance.attendance_clock_out_date.strftime("%Y-%m-%d")
|
|
|
|
|
kwargs["initial"] = initial
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
2023-07-05 11:46:47 +05:30
|
|
|
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
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
class AttendanceForm(ModelForm):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Model form for Attendance model
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
employee_id = forms.ModelMultipleChoiceField(
|
|
|
|
|
queryset=Employee.objects.filter(employee_work_info__isnull=False),
|
|
|
|
|
)
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
class Meta:
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Meta class to add the additional info
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
model = Attendance
|
|
|
|
|
fields = "__all__"
|
|
|
|
|
exclude = (
|
|
|
|
|
"attendance_overtime_approve",
|
|
|
|
|
"attendance_overtime_calculation",
|
|
|
|
|
"at_work_second",
|
|
|
|
|
"overtime_second",
|
|
|
|
|
"attendance_day",
|
|
|
|
|
"approved_overtime_second",
|
|
|
|
|
)
|
2023-05-10 15:06:57 +05:30
|
|
|
widgets = {
|
2023-05-30 15:21:53 +05:30
|
|
|
"attendance_clock_in": DateTimeInput(attrs={"type": "time"}),
|
|
|
|
|
"attendance_clock_out": DateTimeInput(attrs={"type": "time"}),
|
|
|
|
|
"attendance_clock_out_date": DateTimeInput(attrs={"type": "date"}),
|
|
|
|
|
"attendance_date": DateTimeInput(attrs={"type": "date"}),
|
|
|
|
|
"attendance_clock_in_date": DateTimeInput(attrs={"type": "date"}),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
|
|
|
|
|
2023-05-30 15:21:53 +05:30
|
|
|
def __init__(self, *args, **kwargs):
|
2023-07-05 11:46:47 +05:30
|
|
|
initial = {
|
|
|
|
|
"attendance_clock_out_date": datetime.datetime.today()
|
|
|
|
|
.date()
|
|
|
|
|
.strftime("%Y-%m-%d"),
|
|
|
|
|
"attendance_clock_out": datetime.datetime.today()
|
|
|
|
|
.time()
|
|
|
|
|
.strftime("%H:%M"),
|
|
|
|
|
}
|
2023-05-30 15:21:53 +05:30
|
|
|
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
|
|
|
|
|
initial = {
|
|
|
|
|
"attendance_date": instance.attendance_date.strftime("%Y-%m-%d"),
|
|
|
|
|
"attendance_clock_in": instance.attendance_clock_in.strftime("%H:%M"),
|
|
|
|
|
"attendance_clock_in_date": instance.attendance_clock_in_date.strftime(
|
|
|
|
|
"%Y-%m-%d"
|
|
|
|
|
),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
|
|
|
|
if instance.attendance_clock_out_date is not None:
|
2023-05-30 15:21:53 +05:30
|
|
|
initial[
|
|
|
|
|
"attendance_clock_out"
|
|
|
|
|
] = instance.attendance_clock_out.strftime("%H:%M")
|
|
|
|
|
initial[
|
|
|
|
|
"attendance_clock_out_date"
|
|
|
|
|
] = instance.attendance_clock_out_date.strftime("%Y-%m-%d")
|
2023-07-05 11:46:47 +05:30
|
|
|
kwargs["initial"] = initial
|
2023-05-30 15:21:53 +05:30
|
|
|
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())})
|
|
|
|
|
self.fields["work_type_id"].widget.attrs.update({"id": str(uuid.uuid4())})
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
def save(self, commit=True):
|
|
|
|
|
instance = super().save(commit=False)
|
2023-05-30 15:21:53 +05:30
|
|
|
for emp_id in self.data.getlist("employee_id"):
|
2023-05-10 15:06:57 +05:30
|
|
|
if int(emp_id) != int(instance.employee_id.id):
|
|
|
|
|
data_copy = self.data.copy()
|
2023-05-30 15:21:53 +05:30
|
|
|
data_copy.update({"employee_id": str(emp_id)})
|
2023-05-10 15:06:57 +05:30
|
|
|
attendance = AttendanceUpdateForm(data_copy).save(commit=False)
|
|
|
|
|
attendance.save()
|
|
|
|
|
if commit:
|
|
|
|
|
instance.save()
|
|
|
|
|
return instance
|
|
|
|
|
|
2023-07-05 11:46:47 +05:30
|
|
|
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
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
def clean_employee_id(self):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Used to validate employee_id field
|
|
|
|
|
"""
|
|
|
|
|
employee = self.cleaned_data["employee_id"]
|
2023-05-10 15:06:57 +05:30
|
|
|
for emp in employee:
|
2023-05-30 15:21:53 +05:30
|
|
|
attendance = Attendance.objects.filter(
|
|
|
|
|
employee_id=emp, attendance_date=self.data["attendance_date"]
|
|
|
|
|
).first()
|
2023-05-10 15:06:57 +05:30
|
|
|
if attendance is not None:
|
2023-05-30 15:21:53 +05:30
|
|
|
raise ValidationError(
|
|
|
|
|
_(
|
|
|
|
|
"Attendance for the date is already exist for %(emp)s"
|
|
|
|
|
% {"emp": emp}
|
|
|
|
|
)
|
|
|
|
|
)
|
2023-05-10 15:06:57 +05:30
|
|
|
if employee.first() is None:
|
2023-05-30 15:21:53 +05:30
|
|
|
raise ValidationError(_("Employee not chosen"))
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
return employee.first()
|
2023-05-30 15:21:53 +05:30
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
class AttendanceActivityForm(ModelForm):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Model form for AttendanceActivity model
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
class Meta:
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Meta class to add the additional info
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
model = AttendanceActivity
|
|
|
|
|
fields = "__all__"
|
2023-05-10 15:06:57 +05:30
|
|
|
widgets = {
|
2023-05-30 15:21:53 +05:30
|
|
|
"clock_in": DateTimeInput(attrs={"type": "time"}),
|
|
|
|
|
"clock_out": DateTimeInput(attrs={"type": "time"}),
|
|
|
|
|
"clock_in_date": DateTimeInput(attrs={"type": "date"}),
|
|
|
|
|
"clock_out_date": DateTimeInput(attrs={"type": "date"}),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
2023-05-30 15:21:53 +05:30
|
|
|
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
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
initial = {
|
2023-05-30 15:21:53 +05:30
|
|
|
"attendance_date": instance.attendance_date.strftime("%Y-%m-%d"),
|
|
|
|
|
"clock_in_date": instance.clock_in_date.strftime("%Y-%m-%d"),
|
|
|
|
|
"clock_in": instance.clock_in.strftime("%H:%M"),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
|
|
|
|
if instance.clock_out is not None:
|
2023-05-30 15:21:53 +05:30
|
|
|
initial["clock_out"] = instance.clock_out.strftime("%H:%M")
|
|
|
|
|
initial["clock_out_date"] = instance.clock_out_date.strftime("%Y-%m-%d")
|
|
|
|
|
kwargs["initial"] = initial
|
|
|
|
|
super().__init__(*args, **kwargs)
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class MonthSelectField(forms.ChoiceField):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Generate month choices
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
def __init__(self, *args, **kwargs):
|
2023-05-30 15:21:53 +05:30
|
|
|
choices = [
|
|
|
|
|
(month_name[i].lower(), _(month_name[i].capitalize())) for i in range(1, 13)
|
|
|
|
|
]
|
|
|
|
|
super().__init__(choices=choices, *args, **kwargs)
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttendanceOverTimeForm(ModelForm):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Model form for AttendanceOverTime model
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
month = MonthSelectField(label=_("Month"))
|
|
|
|
|
|
|
|
|
|
class Meta:
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Meta class to add the additional info
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
model = AttendanceOverTime
|
2023-05-30 15:21:53 +05:30
|
|
|
fields = "__all__"
|
|
|
|
|
exclude = ["hour_account_second", "overtime_second", "month_sequence"]
|
2023-05-10 15:06:57 +05:30
|
|
|
labels = {
|
2023-05-30 15:21:53 +05:30
|
|
|
"employee_id": _("Employee"),
|
|
|
|
|
"year": _("Year"),
|
|
|
|
|
"hour_account": _("Hour Account"),
|
|
|
|
|
"overtime": _("Overtime"),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
2023-05-30 15:21:53 +05:30
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
self.fields["employee_id"].widget.attrs.update({"id": str(uuid.uuid4())})
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttendanceLateComeEarlyOutForm(ModelForm):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Model form for attendance AttendanceLateComeEarlyOut
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
class Meta:
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Meta class to add the additional info
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
model = AttendanceLateComeEarlyOut
|
2023-05-30 15:21:53 +05:30
|
|
|
fields = "__all__"
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttendanceValidationConditionForm(ModelForm):
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Model form for AttendanceValidationCondition
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
class Meta:
|
2023-05-30 15:21:53 +05:30
|
|
|
"""
|
|
|
|
|
Meta class to add the additional info
|
|
|
|
|
"""
|
|
|
|
|
|
2023-05-10 15:06:57 +05:30
|
|
|
model = AttendanceValidationCondition
|
2023-05-30 15:21:53 +05:30
|
|
|
validation_at_work = forms.DurationField()
|
|
|
|
|
approve_overtime_after = forms.DurationField()
|
|
|
|
|
overtime_cutoff = forms.DurationField()
|
2023-05-10 15:06:57 +05:30
|
|
|
|
|
|
|
|
labels = {
|
2023-05-30 15:21:53 +05:30
|
|
|
"validation_at_work": _(
|
|
|
|
|
"Do not Auto Validate Attendance if an Employee \
|
|
|
|
|
Works More Than this Amount of Duration"
|
|
|
|
|
),
|
|
|
|
|
"minimum_overtime_to_approve": _("Minimum Hour to Approve Overtime"),
|
|
|
|
|
"overtime_cutoff": _("Maximum Allowed Overtime Per Day"),
|
2023-05-10 15:06:57 +05:30
|
|
|
}
|
2023-05-30 15:21:53 +05:30
|
|
|
fields = "__all__"
|