[UPDT] BASE: Added additional fields in shift scheduler form to trigger automatic clock out
This commit is contained in:
112
base/forms.py
112
base/forms.py
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user