[UPDT] BASE: Added additional fields in shift scheduler form to trigger automatic clock out

This commit is contained in:
Horilla
2024-08-16 10:20:58 +05:30
parent 770ad67d3c
commit 432e17ca9b
6 changed files with 234 additions and 58 deletions

View File

@@ -1054,25 +1054,70 @@ class EmployeeShiftScheduleUpdateForm(ModelForm):
"""
fields = "__all__"
exclude = ["is_active"]
exclude = ["is_active", "is_night_shift"]
widgets = {
"start_time": DateInput(attrs={"type": "time"}),
"end_time": DateInput(attrs={"type": "time"}),
"auto_punch_out_time": DateInput(attrs={"type": "time"}),
}
model = EmployeeShiftSchedule
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 = {
"start_time": instance.start_time.strftime("%H:%M"),
"end_time": instance.end_time.strftime("%H:%M"),
"start_time": (
instance.start_time.strftime("%H:%M")
if instance.start_time
else None
),
"end_time": (
instance.end_time.strftime("%H:%M") if instance.end_time else None
),
"auto_punch_out_time": (
instance.auto_punch_out_time.strftime("%H:%M")
if instance.auto_punch_out_time
else None
),
}
kwargs["initial"] = initial
super().__init__(*args, **kwargs)
self.fields["is_auto_punch_out_enabled"].widget.attrs.update(
{"onchange": "toggleDivVisibility(this)"}
)
def as_p(self):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("horilla_form.html", context)
return table_html
def clean(self):
cleaned_data = super().clean()
auto_punch_out_enabled = self.cleaned_data["is_auto_punch_out_enabled"]
auto_punch_out_time = self.cleaned_data["auto_punch_out_time"]
end_time = self.cleaned_data["end_time"]
if auto_punch_out_enabled:
if not auto_punch_out_time:
raise ValidationError(
{
"auto_punch_out_time": _(
"Automatic punch out time is required when automatic punch out is enabled."
)
}
)
if auto_punch_out_enabled and auto_punch_out_time and end_time:
if auto_punch_out_time < end_time:
raise ValidationError(
{
"auto_punch_out_time": _(
"Automatic punch out time cannot be earlier than the end time."
)
}
)
return cleaned_data
class EmployeeShiftScheduleForm(ModelForm):
@@ -1095,6 +1140,7 @@ class EmployeeShiftScheduleForm(ModelForm):
widgets = {
"start_time": DateInput(attrs={"type": "time"}),
"end_time": DateInput(attrs={"type": "time"}),
"auto_punch_out_time": DateInput(attrs={"type": "time"}),
}
def __init__(self, *args, **kwargs):
@@ -1104,13 +1150,61 @@ class EmployeeShiftScheduleForm(ModelForm):
# so here overriding default forms instance method to set initial value
# """
initial = {
"start_time": instance.start_time.strftime("%H:%M"),
"end_time": instance.end_time.strftime("%H:%M"),
"start_time": (
instance.start_time.strftime("%H:%M")
if instance.start_time
else None
),
"end_time": (
instance.end_time.strftime("%H:%M") if instance.end_time else None
),
"auto_punch_out_time": (
instance.auto_punch_out_time.strftime("%H:%M")
if instance.auto_punch_out_time
else None
),
}
kwargs["initial"] = initial
super().__init__(*args, **kwargs)
self.fields["day"].widget.attrs.update({"id": str(uuid.uuid4())})
self.fields["shift_id"].widget.attrs.update({"id": str(uuid.uuid4())})
self.fields["is_auto_punch_out_enabled"].widget.attrs.update(
{"onchange": "toggleDivVisibility(this)"}
)
def as_p(self):
"""
Render the form fields as HTML table rows with Bootstrap styling.
"""
context = {"form": self}
table_html = render_to_string("horilla_form.html", context)
return table_html
def clean(self):
cleaned_data = super().clean()
auto_punch_out_enabled = self.cleaned_data["is_auto_punch_out_enabled"]
auto_punch_out_time = self.cleaned_data["auto_punch_out_time"]
end_time = self.cleaned_data["end_time"]
if auto_punch_out_enabled:
if not auto_punch_out_time:
raise ValidationError(
{
"auto_punch_out_time": _(
"Automatic punch out time is required when automatic punch out is enabled."
)
}
)
if auto_punch_out_enabled and auto_punch_out_time and end_time:
if auto_punch_out_time < end_time:
raise ValidationError(
{
"auto_punch_out_time": _(
"Automatic punch out time cannot be earlier than the end time."
)
}
)
return cleaned_data
def save(self, commit=True):
instance = super().save(commit=False)

View File

@@ -570,17 +570,36 @@ class EmployeeShiftSchedule(HorillaModel):
"""
day = models.ForeignKey(
EmployeeShiftDay, on_delete=models.PROTECT, related_name="day_schedule"
EmployeeShiftDay,
on_delete=models.PROTECT,
related_name="day_schedule",
verbose_name=_("Shift Day"),
)
shift_id = models.ForeignKey(
EmployeeShift, on_delete=models.PROTECT, verbose_name=_("Shift")
)
minimum_working_hour = models.CharField(
default="08:15", max_length=5, validators=[validate_time_format]
default="08:15",
max_length=5,
validators=[validate_time_format],
verbose_name=_("Minimum Working Hours"),
)
start_time = models.TimeField(null=True, verbose_name=_("Start Time"))
end_time = models.TimeField(null=True, verbose_name=_("End Time"))
is_night_shift = models.BooleanField(default=False, verbose_name=_("Night Shift"))
is_auto_punch_out_enabled = models.BooleanField(
default=False,
verbose_name=_("Enable Automatic Check Out"),
help_text=_("Enable this to trigger automatic check out."),
)
auto_punch_out_time = models.TimeField(
null=True,
blank=True,
verbose_name=_("Automatic Check Out Time"),
help_text=_(
"Time at which the horilla will automatically check out the employee attendance if they forget."
),
)
start_time = models.TimeField(null=True)
end_time = models.TimeField(null=True)
is_night_shift = models.BooleanField(default=False)
company_id = models.ManyToManyField(Company, blank=True, verbose_name=_("Company"))
objects = HorillaCompanyManager("shift_id__employee_shift__company_id")

View File

@@ -3,21 +3,21 @@
{% block settings %}{% load static %}
<div class="oh-inner-sidebar-content">
{% if perms.base.view_employeeshiftschedule %}
<div class="oh-inner-sidebar-content__header d-flex justify-content-between align-items-center">
<h2 class="oh-inner-sidebar-content__title">{% trans "Shift Schedule" %}</h2>
{% if perms.base.add_employeeshiftschedule %}
<button
class="oh-btn oh-btn--secondary oh-btn--shadow"
data-toggle="oh-modal-toggle"
data-target="#objectCreateModal"
hx-get="{% url 'employee-shift-schedule-create' %}"
hx-target="#objectCreateModalTarget"
>
<ion-icon name="add-outline" class="me-1"></ion-icon>
{% trans "Create" %}
</button>
{% endif %}
</div>
<div class="oh-inner-sidebar-content__header d-flex justify-content-between align-items-center">
<h2 class="oh-inner-sidebar-content__title">{% trans "Shift Schedule" %}</h2>
{% if perms.base.add_employeeshiftschedule %}
<button
class="oh-btn oh-btn--secondary oh-btn--shadow"
data-toggle="oh-modal-toggle"
data-target="#objectCreateModal"
hx-get="{% url 'employee-shift-schedule-create' %}"
hx-target="#objectCreateModalTarget"
>
<ion-icon name="add-outline" class="me-1"></ion-icon>
{% trans "Create" %}
</button>
{% endif %}
</div>
{% if shift_schedule %}
{% include 'base/shift/schedule_view.html' %}
{% else %}
@@ -27,6 +27,15 @@
</div>
{% endif %}
{% endif %}
</div>
<script>
function toggleDivVisibility(element) {
var isChecked = $(element).prop('checked');
if (isChecked) {
$(element).closest('form').find('#id_auto_punch_out_time_parent_div', '#id_auto_punch_out_time').show();
} else {
$(element).closest('form').find('#id_auto_punch_out_time_parent_div', '#id_auto_punch_out_time').hide();
}
}
</script>
{% endblock settings %}

View File

@@ -1,33 +1,26 @@
{% load i18n %}
<div class="oh-modal__dialog-header pb-0">
<h2 class="oh-modal__dialog-title" id="editModal1ModalLabel">
{% if shift_schedule.id %}
{% trans "Update Employee Shift Schedule" %}
{% else %}
{% trans "Create Employee Shift Schedule" %}
{% endif %}
</h2>
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>
<h2 class="oh-modal__dialog-title" id="editModal1ModalLabel">
{% if shift_schedule.id %}
{% trans "Update Employee Shift Schedule" %}
{% else %}
{% trans "Create Employee Shift Schedule" %}
{% endif %}
</h2>
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div class="oh-modal__dialog-body">
<form
{% if shift_schedule.id %}
hx-post="{% url 'employee-shift-schedule-update' shift_schedule.id %}"
hx-target="#objectUpdateModalTarget"
{% else %}
hx-post="{% url 'employee-shift-schedule-create' %}"
hx-target="#objectCreateModalTarget"
{% endif %}
class="oh-profile-section"
>
{% csrf_token %} {{ form.non_field_errors}}
{{form.as_p}}
<div class="oh-modal__dialog-footer p-0 mt-3">
<button type="submit" class="oh-btn oh-btn--secondary oh-btn--shadow">
{% trans "Save" %}
</button>
</div>
</form>
<form {% if shift_schedule.id %} hx-post="{% url 'employee-shift-schedule-update' shift_schedule.id %}"
hx-target="#objectUpdateModalTarget" {% else %} hx-post="{% url 'employee-shift-schedule-create' %}"
hx-target="#objectCreateModalTarget" {% endif %}>
{% csrf_token %} {{ form.non_field_errors}}
{{form.as_p}}
</form>
</div>
<script>
$(document).ready(function(e){
$("[name=is_auto_punch_out_enabled]").change();
});
</script>