[UPDT] ATTENDANCE: Added condition checking for biometric app presence and its settings

This commit is contained in:
Horilla
2024-04-17 21:56:01 +05:30
parent 0a5dfae2ee
commit e1bc4f91b5
14 changed files with 381 additions and 21 deletions

View File

@@ -164,3 +164,10 @@ def get_initial_prefix(request):
instance_id = settings.id
prefix = settings.badge_id_prefix
return {"get_initial_prefix": prefix, "prefix_instance_id": instance_id}
def biometric_app_exists(request):
from django.conf import settings
biometric_app_exists = "biometric" in settings.INSTALLED_APPS
return {"biometric_app_exists": biometric_app_exists}

View File

@@ -981,32 +981,27 @@ class DynamicEmailConfiguration(HorillaModel):
default=False, verbose_name=_("Primary Mail Server")
)
host = models.CharField(
null=True, max_length=256, verbose_name=_("Email Host")
)
host = models.CharField(null=True, max_length=256, verbose_name=_("Email Host"))
port = models.SmallIntegerField( null=True, verbose_name=_("Email Port"))
port = models.SmallIntegerField(null=True, verbose_name=_("Email Port"))
from_email = models.EmailField(
null=True, max_length=256, verbose_name=_("Default From Email")
null=True, max_length=256, verbose_name=_("Default From Email")
)
username = models.CharField(
null=True,
max_length=256,
verbose_name=_("Email Host Username"),
)
display_name = models.CharField(
null=True,
max_length=256,
verbose_name=_("Display Name"),
)
password = models.CharField(
null=True,
max_length=256,
verbose_name=_("Email Authentication Password"),
@@ -1019,7 +1014,7 @@ class DynamicEmailConfiguration(HorillaModel):
fail_silently = models.BooleanField(default=False, verbose_name=_("Fail Silently"))
timeout = models.SmallIntegerField(
null=True, verbose_name=_("Email Send Timeout (seconds)")
null=True, verbose_name=_("Email Send Timeout (seconds)")
)
company_id = models.OneToOneField(
Company, on_delete=models.CASCADE, null=True, blank=True
@@ -1034,7 +1029,7 @@ class DynamicEmailConfiguration(HorillaModel):
)
)
if not self.company_id and not self.is_primary:
raise ValidationError({"company_id": _("This field is required")})
raise ValidationError({"company_id": _("This field is required")})
def __str__(self):
return self.username
@@ -1359,10 +1354,19 @@ class DriverViewed(models.Model):
class DashboardEmployeeCharts(HorillaModel):
from employee.models import Employee
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
charts = models.JSONField(default=list, blank=True, null=True)
def __str__(self):
return f"{self.employee} - charts"
class BiometricAttendance(models.Model):
is_installed = models.BooleanField(default=False)
company_id = models.ForeignKey(
Company, null=True, editable=False, on_delete=models.PROTECT,related_name="biometric_enabled_company"
)
def __str__(self):
return f"{self.is_installed}"

View File

@@ -0,0 +1,33 @@
{% extends 'settings.html' %} {% load i18n %} {% block settings %}
<div class="oh-inner-sidebar-content mb-4">
<div class="oh-inner-sidebar-content__header d-flex justify-content-between align-items-center">
<h2 class="oh-inner-sidebar-content__title">{% trans "Biometric Attendance" %}</h2>
</div>
<div class="oh-switch ms-3">{% trans "Activate Biometric Attendance" %}&nbsp;&nbsp;&nbsp;&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;
<input type="checkbox" name="is_installed" data-widget="style-widget" class="style-widget oh-switch__checkbox"
{% if biometric.is_installed %} checked title="{% trans 'Activated' %}" {% else %} title="{% trans 'Activate' %}" {% endif %}
id="is_installed">
</div>
</div>
<script>
$(document).ready(function(){
$('#is_installed').on('change',function(){
var boolean = $(this).is(":checked")
$.ajax({
type: "GET",
url: "/settings/activate-biometric-attendance",
data: {
is_installed: boolean,
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload();
} else {
}
},
});
});
});
</script>
{% endblock settings %}

View File

@@ -896,4 +896,14 @@ urlpatterns = [
path("driver-viewed", views.driver_viewed_status, name="driver-viewed"),
path("employee-charts", views.employee_charts, name="employee-charts"),
path("employee-chart-show", views.employee_chart_show, name="employee-chart-show"),
path(
"settings/enable-biometric-attendance/",
views.enable_biometric_attendance_view,
name="enable-biometric-attendance",
),
path(
"settings/activate-biometric-attendance",
views.activate_biometric_attendance,
name="activate-biometric-attendance",
),
]

View File

@@ -25,6 +25,7 @@ from attendance.forms import AttendanceValidationConditionForm
from attendance.methods.group_by import group_by_queryset
from attendance.models import AttendanceValidationCondition, GraceTime
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from horilla_audit.forms import HistoryTrackingFieldsForm
from horilla_audit.models import AccountBlockUnblock, AuditTag, HistoryTrackingFields
from notifications.models import Notification
@@ -112,6 +113,7 @@ from base.models import (
WorkTypeRequest,
Tags,
WorkTypeRequestComment,
BiometricAttendance,
)
from base.filters import (
RotatingShiftRequestReGroup,
@@ -5499,3 +5501,35 @@ def employee_chart_show(request):
return HttpResponse("<script>window.location.reload();</script>")
context = {"dashboard_charts": charts, "employee_chart": employee_charts.charts}
return render(request, "dashboard_chart_form.html", context)
def enable_biometric_attendance_view(request):
biometric = BiometricAttendance.objects.first()
return render(
request,
"base/install_biometric_attendance.html",
{"biometric": biometric},
)
def activate_biometric_attendance(request):
if request.method == "GET":
is_installed = request.GET.get("is_installed")
instance = BiometricAttendance.objects.first()
if not instance:
instance = BiometricAttendance.objects.create()
if is_installed == "true":
instance.is_installed = True
messages.success(
request,
_("The biometric attendance feature has been activated successfully."),
)
else:
instance.is_installed = False
messages.info(
request,
_(
"The biometric attendance feature has been deactivated successfully."
),
)
instance.save()
return JsonResponse({"message": "Success"})

View File

@@ -1,16 +1,16 @@
import logging, os
from urllib.parse import urlencode
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext as _
from base.models import MultipleApprovalManagers
from employee.models import Employee, EmployeeWorkInformation
from django.contrib import messages
from django.shortcuts import render
from horilla.settings import TEMPLATES, BASE_DIR
from horilla import settings
from leave.models import LeaveRequestConditionApproval
from base.models import BiometricAttendance
logger = logging.getLogger(__name__)
@@ -101,14 +101,14 @@ def duplicate_permission(function):
is_manager = EmployeeWorkInformation.objects.filter(
reporting_manager_id=employee
).exists()
app_label = kwargs["model"]._meta.app_label
model_name = kwargs["model"]._meta.model_name
obj_id = kwargs["obj_id"]
object_instance = kwargs["model"].objects.filter(pk=obj_id).first()
object_instance = kwargs["model"].objects.filter(pk=obj_id).first()
try:
if object_instance.employee_id == employee:
return function(request, *args, **kwargs)
return function(request, *args, **kwargs)
except:
pass
permission = f"{app_label}.add_{model_name}"
@@ -239,3 +239,20 @@ def owner_can_enter(function, perm: str, model: object, manager_access=False):
return render(request, "no_perm.html")
return _function
def install_required(function):
def _function(request, *args, **kwargs):
object = BiometricAttendance.objects.all().first()
if object.is_installed:
return function(request, *args, **kwargs)
else:
messages.info(
request,
_(
"Please activate the biometric attendance feature in the settings menu."
),
)
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
return _function

View File

@@ -3,7 +3,6 @@ horilla_apps
This module is used to register horilla addons
"""
from horilla.settings import INSTALLED_APPS
from horilla import settings
@@ -15,4 +14,4 @@ INSTALLED_APPS.append("haystack")
INSTALLED_APPS.append("helpdesk")
INSTALLED_APPS.append("offboarding")
setattr(settings, "EMAIL_BACKEND", "base.backends.ConfiguredEmailBackend")
setattr(settings,"EMAIL_BACKEND","base.backends.ConfiguredEmailBackend")

View File

@@ -0,0 +1,33 @@
"""
horilla_context_process.py
This module is used to register context processors without effecting the horilla/settings.py module
"""
from horilla.settings import TEMPLATES
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.get_companies",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.resignation_request_enabled",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.timerunner_enabled",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.intial_notice_period",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.check_candidate_self_tracking",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.check_candidate_self_tracking_rating",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.get_initial_prefix",
)
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
"base.context_processors.biometric_app_exists",
)

View File

@@ -103,6 +103,7 @@ sidebar_urls = [
"resignation-requests-view",
"action-type",
"general-settings",
"view-biometric-devices",
]
remove_urls = [
"objective-detailed-view",

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

202
templates/animation.html Normal file
View File

@@ -0,0 +1,202 @@
{% load i18n %} {% load static %}
<style>
@keyframes biometricPulse {
from {
transform: translateX(-10%);
}
to {
transform: translateX(100%);
}
}
#mask-biometric-animation {
animation: biometricPulse 2s linear 0.1s infinite;
}
.hr-biometric {
width: 200px;
height: auto;
object-fit: contain;
}
.hr-biometric-container {
position: absolute; /* or position: relative; */
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.hr-biometric-message{
color: #303030;
display: block;
margin-top: 1.25rem;
}
</style>
<div class="hr-biometric-container">
<!-- SVG CODE -->
<svg
class="hr-biometric"
width="1102"
height="339"
viewBox="0 0 1102 339"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect
x="671.5"
y="5.5"
width="425"
height="328"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="694.5"
y="28.5"
width="185"
height="72"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="693.5"
y="128.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="694.5"
y="195.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="694.5"
y="262.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="765.5"
y="128.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="766.5"
y="195.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="766.5"
y="262.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="839.5"
y="128.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="840.5"
y="195.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="840.5"
y="262.5"
width="39"
height="39"
fill="white"
stroke="#999999"
stroke-width="11" />
<rect
x="908.5"
y="131.5"
width="155"
height="170"
fill="white"
stroke="#999999"
stroke-width="11" />
<line
x1="936"
y1="100.5"
x2="1036"
y2="100.5"
stroke="#999999"
stroke-width="7" />
<line
x1="936"
y1="32.5"
x2="1036"
y2="32.5"
stroke="#999999"
stroke-width="7" />
<line
x1="920"
y1="83.5"
x2="1053"
y2="83.5"
stroke="#999999"
stroke-width="7" />
<line
x1="919"
y1="49.5"
x2="1052"
y2="49.5"
stroke="#999999"
stroke-width="7" />
<line
x1="912.023"
y1="66.5001"
x2="1061.02"
y2="67.5001"
stroke="#999999"
stroke-width="7" />
<mask
id="mask0_703_126"
style="mask-type: alpha"
maskUnits="userSpaceOnUse"
x="0"
y="42"
width="606"
height="262">
<path
d="M0.5 221.5H225.5L322 135.5V301.5L407.5 60.5L434.5 221.5H606"
stroke="white"
stroke-width="9" />
</mask>
<g mask="url(#mask0_703_126)">
<rect
x="-561"
y="-262"
width="669"
height="686"
id="mask-biometric-animation"
fill="#E54F38" />
</g>
</svg>
<!-- END OF SVG CODE -->
<span class="hr-biometric-message">{% trans "Trying to connect..." %}</span>
</div>

View File

@@ -113,7 +113,16 @@
>
{% endif %}
</div>
{% if biometric_app_exists %}
<div class="oh-input-group">
<a
id="condition"
href="{% url 'enable-biometric-attendance' %}"
class="oh-inner-sidebar__link oh-dropdown__link"
>{% trans "Biometric Attendance" %}
</a>
</div>
{% endif %}
</div>
</div>
</div>

View File

@@ -428,6 +428,17 @@
>
</li>
{% endif %}
{% if biometric_app_exists and is_installed %}
{% if perms.attendance.view_attendance or request.user|is_reportingmanager %}
<li class="oh-sidebar__submenu-item">
<a
class="oh-sidebar__submenu-link"
href="{% url 'view-biometric-devices' %}"
>{% trans "Biometric Devices" %}</a
>
</li>
{% endif %}
{% endif %}
<li class="oh-sidebar__submenu-item">
<a
class="oh-sidebar__submenu-link"