Skip to content

Commit

Permalink
Merge pull request #22 from MahirMahbub/feature/attendance_by_card
Browse files Browse the repository at this point in the history
Feature/attendance by card
  • Loading branch information
MahirMahbub authored Jun 4, 2023
2 parents d10b1a6 + fe38bb1 commit 8aa961c
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 66 deletions.
30 changes: 21 additions & 9 deletions apps/card_portal/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from datetime import datetime

from django.contrib import admin
from django.contrib.auth.forms import AdminPasswordChangeForm, PasswordChangeForm, \
ReadOnlyPasswordHashField
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.forms import ModelForm
from django.utils import timezone
from django.utils.datetime_safe import date
from django.utils.translation import gettext_lazy as _
from rangefilter.filters import DateRangeFilterBuilder

from apps.card_portal.models import Employee, EmployeesDesignation, EmployeesImage, EmployeesDailyAttendance, Machine, \
MachinePermittedEmployee, EmployeeAccessCardUsageLog
Expand Down Expand Up @@ -88,12 +92,19 @@ class EmployeesImageAdmin(admin.ModelAdmin):

@admin.register(EmployeesDailyAttendance)
class EmployeesDailyAttendanceAdmin(admin.ModelAdmin):
list_display = ('employee', 'date', 'in_time', 'out_time', 'is_present')
list_display = ('employee', 'date', 'in_time', 'out_time', 'is_present', 'total_time')
list_filter = (
'employee__first_name', 'employee__last_name', 'employee__email', 'date', 'in_time', 'out_time', 'is_present'
'employee__first_name', 'employee__last_name', 'employee__email', ('date', DateRangeFilterBuilder()), 'in_time', 'out_time', 'is_present'
)
search_fields = ('employee__first_name', 'employee__last_name', 'employee__email', 'date', 'in_time', 'out_time')
readonly_fields = ('created_at', 'updated_at', 'date', 'in_time', 'out_time', 'employee', 'is_present')
readonly_fields = ('created_at', 'updated_at', 'employee', 'is_present')

@staticmethod
def total_time(obj: EmployeesDailyAttendance)->datetime:
return datetime.combine(date.today(), obj.out_time) - datetime.combine(date.today(), obj.in_time) \
if obj.out_time else \
timezone.now().astimezone(tz=timezone.get_current_timezone()).replace(tzinfo=None) - datetime.combine(
date.today(), obj.in_time)

def has_add_permission(self, request):
return False
Expand Down Expand Up @@ -158,13 +169,12 @@ class MachineAdmin(admin.ModelAdmin):
# readonly_fields = ('last_login',)
inlines = [EmployeesMachineAdminInline]


# change_password_form = PasswordChangeForm


@admin.register(MachinePermittedEmployee)
class MachinePermittedEmployeeAdmin(admin.ModelAdmin):
list_display = ('employee', 'machine', 'start_date', 'expiry_date')
list_display = ('employee', 'machine', 'start_date', 'expiry_date', 'start_date')
list_filter = (
'employee__first_name', 'employee__last_name', 'employee__email', 'machine__model', 'start_date', 'expiry_date')
search_fields = (
Expand All @@ -175,10 +185,10 @@ class MachinePermittedEmployeeAdmin(admin.ModelAdmin):
class EmployeeAccessCardUsageLogAdmin(admin.ModelAdmin):
list_display = ('employee', 'machine', 'date', 'access_type', 'time')
list_filter = (
'employee__first_name', 'employee__last_name', 'employee__email', 'machine', 'access_type'
'employee__first_name', 'employee__last_name', 'employee__email', 'machine', 'access_type', ('date', DateRangeFilterBuilder())
)
search_fields = (
'employee__first_name', 'employee__last_name', 'employee__email', 'machine', 'access_type'
'employee__first_name', 'employee__last_name', 'employee__email'
)

def has_add_permission(self, request):
Expand All @@ -189,3 +199,5 @@ def has_change_permission(self, request, obj=None):

def has_delete_permission(self, request, obj=None):
return False

# @admin.register(EmployeeWorkLog)
4 changes: 4 additions & 0 deletions apps/card_portal/models/machines.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ class MachinePermittedEmployee(BaseModelMixin):
machine = models.ForeignKey(Machine, on_delete=models.CASCADE, null=True, blank=True)
start_date = models.DateField(auto_now_add=True)
expiry_date = models.DateField(null=True, blank=True)

def __str__(self):
return "ID: " + str(self.id) + ", EMPLOYEE_ID: " + str(
self.employee.id) + ", MACHINE_ID: " + str(self.machine.id)
18 changes: 12 additions & 6 deletions apps/card_portal/serializers.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from datetime import date
import traceback
from datetime import date

from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import update_last_login
from django.db import transaction, DatabaseError
from django.utils import timezone
from rest_framework import serializers, status
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
import logging

from apps.card_portal.models import EmployeesDailyAttendance, Employee, EmployeeAccessCardUsageLog, Machine
from django.utils import timezone


logger = logging.getLogger(__name__)
class EmployeesDailyAttendanceCreationSerializer(serializers.Serializer): # noqa
rdf = serializers.CharField(required=True, help_text="RDF number of the employee")
# date = serializers.DateField(required=True, help_text="Date of the attendance")
Expand Down Expand Up @@ -37,8 +39,12 @@ def create(self, validated_data):
employee = Employee.objects.filter(rdf_number=validated_data['rdf']).first()
if employee is None:
raise serializers.ValidationError({"message": "Employee not found"})
if machine.machinepermittedemployee_set.filter(employee=employee).first() is None:
raise serializers.ValidationError({"message": "Access Denied. Employee is not permitted to use this machine"})
machine_permitted_employee = machine.machinepermittedemployee_set.filter(employee=employee).first()
if machine_permitted_employee is None:
raise serializers.ValidationError(
{"message": "Access Denied. Employee is not permitted to use this machine"})
if machine_permitted_employee.expiry_date is not None and machine_permitted_employee.expiry_date < _date:
raise serializers.ValidationError({"message": "Access Denied. Employee is not expired to use this machine"})

if last_attendance is not None:
check_in, check_out, rdf = self._extract_attendance_data_from_validated_data(validated_data)
Expand Down Expand Up @@ -83,7 +89,7 @@ def create(self, validated_data):
)
return EmployeesDailyAttendance.objects.create(employee=employee, **validated_data)
except DatabaseError as db_exec:
print(traceback.format_exc())
logger.error(traceback.format_exc())
raise serializers.ValidationError({"message": "Check-in failed"})
if check_in is not None:
if last_attendance.in_time is not None and last_attendance.out_time is None:
Expand Down
58 changes: 57 additions & 1 deletion config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from pathlib import Path

import environ
from typing import List

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
Expand Down Expand Up @@ -95,6 +94,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
# "django.contrib.sites",
'rangefilter',
"django.contrib.postgres",
"rest_framework_simplejwt",
"corsheaders",
Expand All @@ -103,6 +103,7 @@
"apps.card_portal",
"apps.face_portal",


]

MIDDLEWARE = [
Expand Down Expand Up @@ -207,3 +208,58 @@
}

AUTH_USER_MODEL = "card_portal.GenericUser"

LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
"filters": {
"require_debug_true": {
"()": "django.utils.log.RequireDebugTrue",
},
},
"handlers": {
"console": {
"level": "INFO",
"filters": ["require_debug_true"],
"class": "logging.StreamHandler",
"formatter": "simple",
},
"file_error": {
"level": "ERROR",
"class": "logging.FileHandler",
"filename": BASE_DIR / "logs" / "debug.log",
"formatter": "simple",
},
"file_debug": {
"level": "DEBUG",
"class": "logging.FileHandler",
"filename": BASE_DIR / "logs" / "debug.log",
"formatter": "simple",
},
"mail_admins": {
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler",
},
},
"loggers": {
"django": {
"handlers": ["console", "file_error", "file_debug"],
"propagate": True,
},
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
},
}
Empty file added logs/__init__.py
Empty file.
51 changes: 1 addition & 50 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,56 +1,7 @@
asgiref==3.6.0
attrs==22.2.0
Django==4.1.5
django-cors-headers==3.13.0
django-environ==0.10.0
djangorestframework==3.14.0
drf-spectacular==0.25.1
ecdsa==0.18.0
inflection==0.5.1
jose==1.0.0
jsonschema==4.17.3
Pillow==9.4.0
psycopg2-binary==2.9.5
pyasn1==0.5.0
pyrsistent==0.19.3
python-dotenv==1.0.0
python-jose==3.3.0
pytz==2022.7.1
PyYAML==6.0
rsa==4.9
six==1.16.0
sqlparse==0.4.3
tzdata==2022.7
uritemplate==4.1.1
asgiref==3.6.0
attrs==22.2.0
Django==4.1.5
django-cors-headers==3.13.0
django-environ==0.10.0
djangorestframework==3.14.0
djangorestframework-simplejwt==5.2.2
drf-spectacular==0.25.1
ecdsa==0.18.0
inflection==0.5.1
jose==1.0.0
jsonschema==4.17.3
Pillow==9.4.0
psycopg2-binary==2.9.5
pyasn1==0.5.0
PyJWT==2.7.0
pyrsistent==0.19.3
python-dotenv==1.0.0
python-jose==3.3.0
pytz==2022.7.1
PyYAML==6.0
rsa==4.9
six==1.16.0
sqlparse==0.4.3
tzdata==2022.7
uritemplate==4.1.1
asgiref==3.6.0
attrs==22.2.0
Django==4.1.5
django-admin-rangefilter==0.10.0
django-cors-headers==3.13.0
django-environ==0.10.0
django-model-utils==4.3.1
Expand Down

0 comments on commit 8aa961c

Please sign in to comment.