From 3d857c8e1cf4603e0ad026d4f1fd777f3bb667a3 Mon Sep 17 00:00:00 2001 From: Horilla Date: Thu, 22 May 2025 15:48:58 +0530 Subject: [PATCH] [UPDT] ATTENDANCE: Geofencing and Facedetection settings page based on selected company --- facedetection/models.py | 30 +++++++++++++++- facedetection/views.py | 10 +++--- geofencing/forms.py | 7 ++-- geofencing/models.py | 44 +++++++++++++++-------- geofencing/views.py | 6 +++- horilla_api/api_views/attendance/views.py | 1 + 6 files changed, 73 insertions(+), 25 deletions(-) diff --git a/facedetection/models.py b/facedetection/models.py index aa63e586d..25272e471 100644 --- a/facedetection/models.py +++ b/facedetection/models.py @@ -1,5 +1,6 @@ import os +from django.core.exceptions import ValidationError from django.db import models from django.db.models.signals import post_delete from django.dispatch import receiver @@ -9,10 +10,37 @@ from django.dispatch import receiver class FaceDetection(models.Model): company_id = models.OneToOneField( - "base.Company", related_name="face_detection", on_delete=models.CASCADE + "base.Company", + related_name="face_detection", + on_delete=models.CASCADE, + null=True, + blank=True, ) start = models.BooleanField(default=False) + def clean(self): + if self.company_id is None: + qs = FaceDetection.objects.filter(company_id__isnull=True) + if self.pk: + qs = qs.exclude(pk=self.pk) + if qs.exists(): + raise ValidationError( + "Only one FaceDetection can have a null company_id." + ) + + def save(self, *args, **kwargs): + self.full_clean() # Ensures `clean()` runs + super().save(*args, **kwargs) + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["company_id"], + name="unique_company_id_when_not_null_facedetection", + condition=~models.Q(company_id=None), + ) + ] + class EmployeeFaceDetection(models.Model): employee_id = models.OneToOneField( diff --git a/facedetection/views.py b/facedetection/views.py index 3133f9419..d4666e7fe 100644 --- a/facedetection/views.py +++ b/facedetection/views.py @@ -10,6 +10,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView +from base.models import Company from facedetection.forms import FaceDetectionSetupForm from horilla.decorators import hx_request_required @@ -34,10 +35,6 @@ class FaceDetectionConfigAPIView(APIView): except Exception as e: raise serializers.ValidationError(e) - @method_decorator( - permission_required("facedetection.view_facedetection", raise_exception=True), - name="dispatch", - ) def get(self, request): serializer = FaceDetectionSerializer(self.get_facedetection(request)) return Response(serializer.data, status=status.HTTP_200_OK) @@ -122,7 +119,10 @@ class EmployeeFaceDetectionGetPostAPIView(APIView): def get_company(request): try: - company = request.user.employee_get.get_company() + selected_company = request.session.get("selected_company") + if selected_company == "all": + return None + company = Company.objects.get(id=selected_company) return company except Exception as e: raise serializers.ValidationError(e) diff --git a/geofencing/forms.py b/geofencing/forms.py index f926680a5..dcfedc726 100644 --- a/geofencing/forms.py +++ b/geofencing/forms.py @@ -1,11 +1,13 @@ +from django.template.loader import render_to_string from base.forms import ModelForm + from .models import GeoFencing -from django.template.loader import render_to_string + class GeoFencingSetupForm(ModelForm): verbose_name = "Geofence Configuration" - + class Meta: model = GeoFencing exclude = ["company_id"] @@ -17,4 +19,3 @@ class GeoFencingSetupForm(ModelForm): context = {"form": self} table_html = render_to_string("common_form.html", context) return table_html - \ No newline at end of file diff --git a/geofencing/models.py b/geofencing/models.py index 038551672..6a12bd5a0 100644 --- a/geofencing/models.py +++ b/geofencing/models.py @@ -1,13 +1,12 @@ from django.core.exceptions import ValidationError from django.db import models +from django.db.models import Q from geopy.geocoders import Nominatim -from base.models import Company - class GeoFencing(models.Model): - latitude = models.FloatField(max_length=100) - longitude = models.FloatField(max_length=100) + latitude = models.FloatField() + longitude = models.FloatField() radius_in_meters = models.IntegerField() company_id = models.OneToOneField( "base.Company", @@ -19,21 +18,36 @@ class GeoFencing(models.Model): start = models.BooleanField(default=False) def clean(self): - geolocator = Nominatim(user_agent="geo_checker") # Use a unique user-agent + if self.company_id is None: + qs = GeoFencing.objects.filter(company_id__isnull=True) + if self.pk: + qs = qs.exclude(pk=self.pk) + if qs.exists(): + raise ValidationError("Only one GeoFencing can have a null company_id.") + + geolocator = Nominatim( + user_agent="geo_checker_unique" + ) # Unique user-agent is important try: location = geolocator.reverse( (self.latitude, self.longitude), exactly_one=True ) - if location: - pass - else: - raise ValidationError("Invalid Location") + if not location: + raise ValidationError("Invalid location coordinates.") except Exception as e: - raise ValidationError(e) + raise ValidationError(f"Geolocation error: {e}") + return super().clean() - def save_base( - self, raw=..., force_insert=..., force_update=..., using=..., update_fields=... - ): - self.clean() - return super().save_base(raw, force_insert, force_update, using, update_fields) + def save(self, *args, **kwargs): + self.full_clean() # Run clean before save + super().save(*args, **kwargs) + + class Meta: + constraints = [ + models.UniqueConstraint( + fields=["company_id"], + name="unique_company_id_when_not_null_geofencing", + condition=~Q(company_id=None), + ) + ] diff --git a/geofencing/views.py b/geofencing/views.py index dc3dd962c..eed72364f 100644 --- a/geofencing/views.py +++ b/geofencing/views.py @@ -11,6 +11,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView +from base.models import Company from geofencing.forms import GeoFencingSetupForm from .models import GeoFencing @@ -152,7 +153,10 @@ class GeoFencingSetUpPermissionCheck(APIView): def get_company(request): try: - company = request.user.employee_get.get_company() + selected_company = request.session.get("selected_company") + if selected_company == "all": + return None + company = Company.objects.get(id=selected_company) return company except Exception as e: raise serializers.ValidationError(e) diff --git a/horilla_api/api_views/attendance/views.py b/horilla_api/api_views/attendance/views.py index 7005243b7..e25a46381 100644 --- a/horilla_api/api_views/attendance/views.py +++ b/horilla_api/api_views/attendance/views.py @@ -65,6 +65,7 @@ class ClockInAPIView(APIView): permission_classes = [IsAuthenticated] def post(self, request): + print("========", request.user.employee_get.check_online()) if not request.user.employee_get.check_online(): try: if request.user.employee_get.get_company().geo_fencing.start: