[ADD] HORILLA API: Add Horilla API into master code base

This commit is contained in:
Horilla
2024-10-10 15:41:46 +05:30
parent f42ac1a391
commit 053964edd9
42 changed files with 7330 additions and 0 deletions

View File

@@ -0,0 +1,301 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from asset.models import *
from ...api_serializers.asset.serializers import *
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from ...api_filters.asset.filters import AssetCategoryFilter
from asset.filters import AssetFilter
from django.http import QueryDict
from datetime import date
class AssetAPIView(APIView):
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend]
filterset_class = AssetFilter
def get_asset(self, pk):
try:
return Asset.objects.get(pk=pk)
except Asset.DoesNotExist as e:
raise serializers.ValidationError(e)
def get(self, request, pk=None):
if pk:
asset = self.get_asset(pk)
serializer = AssetSerializer(asset)
return Response(serializer.data)
paginator = PageNumberPagination()
queryset = Asset.objects.all()
filterset = self.filterset_class(request.GET, queryset=queryset)
page = paginator.paginate_queryset(filterset.qs, request)
serializer = AssetGetAllSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = AssetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
asset = self.get_asset(pk)
serializer = AssetSerializer(asset, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
asset = self.get_asset(pk)
asset.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AssetCategoryAPIView(APIView):
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend]
filterset_class = AssetCategoryFilter
def get_asset_category(self, pk):
try:
return AssetCategory.objects.get(pk=pk)
except AssetCategory.DoesNotExist as e:
raise serializers.ValidationError(e)
def get(self, request, pk=None):
if pk:
asset_category = self.get_asset_category(pk)
serializer = AssetCategorySerializer(asset_category)
return Response(serializer.data)
paginator = PageNumberPagination()
queryset = AssetCategory.objects.all()
filterset = self.filterset_class(request.GET, queryset=queryset)
page = paginator.paginate_queryset(filterset.qs, request)
serializer = AssetCategorySerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = AssetCategorySerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
asset_category = self.get_asset_category(pk)
serializer = AssetCategorySerializer(asset_category, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
asset_category = self.get_asset_category(pk)
asset_category.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AssetLotAPIView(APIView):
permission_classes = [IsAuthenticated]
def get_asset_lot(self, pk):
try:
return AssetLot.objects.get(pk=pk)
except AssetLot.DoesNotExist as e:
raise serializers.ValidationError(e)
def get(self, request, pk=None):
if pk:
asset_lot = self.get_asset_lot(pk)
serializer = AssetLotSerializer(asset_lot)
return Response(serializer.data)
paginator = PageNumberPagination()
assets = AssetLot.objects.all()
page = paginator.paginate_queryset(assets, request)
serializer = AssetLotSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = AssetLotSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
asset_lot = self.get_asset_lot(pk)
serializer = AssetLotSerializer(asset_lot, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
asset_lot = self.get_asset_lot(pk)
asset_lot.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AssetAllocationAPIView(APIView):
permission_classes = [IsAuthenticated]
def get_asset_assignment(self, pk):
try:
return AssetAssignment.objects.get(pk=pk)
except AssetAssignment.DoesNotExist as e:
raise serializers.ValidationError(e)
def get(self, request, pk=None):
if pk:
asset_assignment = self.get_asset_assignment(pk)
serializer = AssetAssignmentGetSerializer(asset_assignment)
return Response(serializer.data)
paginator = PageNumberPagination()
assets = AssetAssignment.objects.all()
page = paginator.paginate_queryset(assets, request)
serializer = AssetAssignmentGetSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = AssetAssignmentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
asset_assignment = self.get_asset_assignment(pk)
serializer = AssetAssignmentSerializer(
asset_assignment, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
asset_assignment = self.get_asset_assignment(pk)
asset_assignment.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AssetRequestAPIView(APIView):
permission_classes = [IsAuthenticated]
def get_asset_request(self, pk):
try:
return AssetRequest.objects.get(pk=pk)
except AssetRequest.DoesNotExist as e:
raise serializers.ValidationError(e)
def get(self, request, pk=None):
if pk:
asset_request = self.get_asset_request(pk)
serializer = AssetRequestGetSerializer(asset_request)
return Response(serializer.data)
paginator = PageNumberPagination()
assets = AssetRequest.objects.all().order_by('-id')
page = paginator.paginate_queryset(assets, request)
serializer = AssetRequestGetSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = AssetRequestSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
asset_request = self.get_asset_request(pk)
serializer = AssetRequestSerializer(asset_request, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
asset_request = self.get_asset_request(pk)
asset_request.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AssetRejectAPIView(APIView):
permission_classes = [IsAuthenticated]
def get_asset_request(self, pk):
try:
return AssetRequest.objects.get(pk=pk)
except AssetRequest.DoesNotExist as e:
raise serializers.ValidationError(e)
def put(self, request, pk):
asset_request = self.get_asset_request(pk)
if asset_request.asset_request_status == "Requested":
asset_request.asset_request_status = 'Rejected'
asset_request.save()
return Response(status=204)
raise serializers.ValidationError({"error":"Access Denied.."})
class AssetApproveAPIView(APIView):
permission_classes = [IsAuthenticated]
def get_asset_request(self, pk):
try:
return AssetRequest.objects.get(pk=pk)
except AssetRequest.DoesNotExist as e:
raise serializers.ValidationError(e)
def put(self, request, pk):
asset_request = self.get_asset_request(pk)
if asset_request.asset_request_status == "Requested":
data = request.data
if isinstance(data, QueryDict):
data = data.dict()
data['assigned_to_employee_id'] = asset_request.requested_employee_id.id
data['assigned_by_employee_id'] = request.user.employee_get.id
serializer = AssetApproveSerializer(data=data, context={'asset_request': asset_request})
if serializer.is_valid():
serializer.save()
asset_id = Asset.objects.get(id=data['asset_id'])
asset_id.asset_status = "In use"
asset_id.save()
asset_request.asset_request_status = 'Approved'
asset_request.save()
return Response(status=200)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
raise serializers.ValidationError({"error":"Access Denied.."})
class AssetReturnAPIView(APIView):
permission_classes = [IsAuthenticated]
def get_asset_assignment(self, pk):
try:
return AssetAssignment.objects.get(pk=pk)
except AssetAssignment.DoesNotExist as e:
raise serializers.ValidationError(e)
def put(self, request, pk):
asset_assignment = self.get_asset_assignment(pk)
if request.user.has_perm('app_name.change_mymodel'):
serializer = AssetReturnSerializer(instance=asset_assignment, data=request.data)
if serializer.is_valid():
images = [ReturnImages.objects.create(image=image) for image in request.data.getlist('image')]
asset_return = serializer.save()
asset_return.return_images.set(images)
if asset_return.return_status == 'Healthy':
Asset.objects.filter(id=pk).update(asset_status='Available')
else:
Asset.objects.filter(id=pk).update(asset_status='Not-Available')
AssetAssignment.objects.filter(id=asset_return.id).update(return_date=date.today())
return Response(status=200)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
AssetAssignment.objects.filter(id=pk).update(return_request=True)
return Response(status=200)

View File

@@ -0,0 +1,23 @@
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from ...api_decorators.base.decorators import manager_permission_required
class AttendancePermissionCheck(APIView):
permission_classes = [IsAuthenticated]
@manager_permission_required("attendance.view_attendance")
def get(self,request):
return Response(status=200)
class AttendancePermissionCheck(APIView):
permission_classes = [IsAuthenticated]
@manager_permission_required("attendance.view_attendance")
def get(self,request):
return Response(status=200)

View File

@@ -0,0 +1,917 @@
from django.db.models import Case, Value, When, F, CharField
from django.http import QueryDict
from attendance.models import AttendanceActivity
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from datetime import date, datetime, timedelta, timezone
from attendance.models import EmployeeShiftDay
from attendance.views.dashboard import (
find_expected_attendances,
find_late_come,
find_on_time,
)
from attendance.views.views import *
from attendance.views.clock_in_out import *
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from attendance.models import Attendance
from base.methods import is_reportingmanager
from ...api_decorators.base.decorators import manager_permission_required
from ...api_methods.base.methods import groupby_queryset, permission_based_queryset
from employee.filters import EmployeeFilter
from horilla_api.api_serializers.attendance.serializers import (
AttendanceActivitySerializer,
AttendanceLateComeEarlyOutSerializer,
AttendanceOverTimeSerializer,
AttendanceRequestSerializer,
AttendanceSerializer,
MailTemplateSerializer,
)
from rest_framework.pagination import PageNumberPagination
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import permission_required
from django.conf import settings
from django.core.mail import EmailMessage
from recruitment.models import RecruitmentMailTemplate
from base.backends import ConfiguredEmailBackend
from django import template
from base.methods import generate_pdf
# Create your views here.
def query_dict(data):
query_dict = QueryDict("", mutable=True)
for key, value in data.items():
if isinstance(value, list):
for item in value:
query_dict.appendlist(key, item)
else:
query_dict.update({key: value})
return query_dict
class ClockInAPIView(APIView):
"""
Allows authenticated employees to clock in, determining the correct shift and attendance date, including handling night shifts.
Methods:
post(request): Processes and records the clock-in time.
"""
permission_classes = [IsAuthenticated]
def post(self, request):
employee, work_info = employee_exists(request)
datetime_now = datetime.now()
if request.__dict__.get("datetime"):
datetime_now = request.datetime
if employee and work_info is not None:
shift = work_info.shift_id
date_today = date.today()
if request.__dict__.get("date"):
date_today = request.date
attendance_date = date_today
day = date_today.strftime("%A").lower()
day = EmployeeShiftDay.objects.get(day=day)
now = datetime.now().strftime("%H:%M")
if request.__dict__.get("time"):
now = request.time.strftime("%H:%M")
now_sec = strtime_seconds(now)
mid_day_sec = strtime_seconds("12:00")
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
day=day, shift=shift
)
if start_time_sec > end_time_sec:
# night shift
# ------------------
# Night shift in Horilla consider a 24 hours from noon to next day noon,
# the shift day taken today if the attendance clocked in after 12 O clock.
if mid_day_sec > now_sec:
# Here you need to create attendance for yesterday
date_yesterday = date_today - timedelta(days=1)
day_yesterday = date_yesterday.strftime("%A").lower()
day_yesterday = EmployeeShiftDay.objects.get(day=day_yesterday)
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
day=day_yesterday, shift=shift
)
attendance_date = date_yesterday
day = day_yesterday
clock_in_attendance_and_activity(
employee=employee,
date_today=date_today,
attendance_date=attendance_date,
day=day,
now=now,
shift=shift,
minimum_hour=minimum_hour,
start_time=start_time_sec,
end_time=end_time_sec,
in_datetime=datetime_now,
)
return Response({"message": "Clocked-In"}, status=200)
return Response(
{
"error": "You Don't have work information filled or your employee detail neither entered "
}
)
class ClockOutAPIView(APIView):
"""
Allows authenticated employees to clock out, updating the latest attendance record and handling early outs.
Methods:
post(request): Records the clock-out time.
"""
permission_classes = [IsAuthenticated]
def post(self, request):
datetime_now = datetime.now()
if request.__dict__.get("datetime"):
datetime_now = request.datetime
employee, work_info = employee_exists(request)
shift = work_info.shift_id
date_today = date.today()
if request.__dict__.get("date"):
date_today = request.date
day = date_today.strftime("%A").lower()
day = EmployeeShiftDay.objects.get(day=day)
attendance = (
Attendance.objects.filter(employee_id=employee)
.order_by("id", "attendance_date")
.last()
)
if attendance is not None:
day = attendance.attendance_day
now = datetime.now().strftime("%H:%M")
if request.__dict__.get("time"):
now = request.time.strftime("%H:%M")
minimum_hour, start_time_sec, end_time_sec = shift_schedule_today(
day=day, shift=shift
)
early_out_instance = attendance.late_come_early_out.filter(type="early_out")
if not early_out_instance.exists():
early_out(
attendance=attendance, start_time=start_time_sec, end_time=end_time_sec
)
clock_out_attendance_and_activity(
employee=employee, date_today=date_today, now=now, out_datetime=datetime_now
)
return Response({"message": "Clocked-Out"}, status=200)
class AttendanceView(APIView):
"""
Handles CRUD operations for attendance records.
Methods:
get_queryset(request, type): Returns filtered attendance records.
get(request, pk=None, type=None): Retrieves a specific record or a list of records.
post(request): Creates a new attendance record.
put(request, pk): Updates an existing attendance record.
delete(request, pk): Deletes an attendance record and adjusts related overtime if needed.
"""
permission_classes = [IsAuthenticated]
filterset_class = AttendanceFilters
def get_queryset(self, request, type):
if type == "ot":
condition = AttendanceValidationCondition.objects.first()
minot = strtime_seconds("00:30")
if condition is not None:
minot = strtime_seconds(condition.minimum_overtime_to_approve)
queryset = Attendance.objects.filter(
overtime_second__gte=minot,
attendance_validated=True,
)
elif type == "validated":
queryset = Attendance.objects.filter(attendance_validated=True)
elif type == "non-validated":
queryset = Attendance.objects.filter(attendance_validated=False)
else:
queryset = Attendance.objects.all()
user = request.user
# checking user level permissions
perm = "attendance.view_attendance"
queryset = permission_based_queryset(user, perm, queryset, user_obj=True)
return queryset
def get(self, request, pk=None, type=None):
# individual object workflow
if pk:
attendance = get_object_or_404(Attendance, pk=pk)
serializer = AttendanceSerializer(instance=attendance)
return Response(serializer.data, status=200)
# permission based querysete
attendances = self.get_queryset(request, type)
# filtering queryset
attendances_filter_queryset = self.filterset_class(
request.GET, queryset=attendances
).qs
field_name = request.GET.get("groupby_field", None)
if field_name:
url = request.build_absolute_uri()
return groupby_queryset(
request, url, field_name, attendances_filter_queryset
)
# pagination workflow
paginater = PageNumberPagination()
page = paginater.paginate_queryset(attendances_filter_queryset, request)
serializer = AttendanceSerializer(page, many=True)
return paginater.get_paginated_response(serializer.data)
@manager_permission_required("attendance.add_attendance")
def post(self, request):
serializer = AttendanceSerializer(data=request.data)
if serializer.is_valid():
validated_data = serializer.validated_data
instance = Attendance(**validated_data)
instance.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(
permission_required("attendance.change_attendance", raise_exception=True)
)
def put(self, request, pk):
try:
attendance = Attendance.objects.get(id=pk)
except Attendance.DoesNotExist:
return Response({"detail": "Attendance record not found."}, status=404)
serializer = AttendanceSerializer(instance=attendance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
# Customize error message for unique constraint
serializer_errors = serializer.errors
if "non_field_errors" in serializer.errors:
unique_error_msg = (
"The fields employee_id, attendance_date must make a unique set."
)
if unique_error_msg in serializer.errors["non_field_errors"]:
serializer_errors = {
"non_field_errors": [
"The employee already has attendance on this date."
]
}
return Response(serializer_errors, status=400)
@method_decorator(
permission_required("attendance.delete_attendance", raise_exception=True)
)
def delete(self, request, pk):
attendance = Attendance.objects.get(id=pk)
month = attendance.attendance_date
month = month.strftime("%B").lower()
overtime = attendance.employee_id.employee_overtime.filter(month=month).last()
if overtime is not None:
if attendance.attendance_overtime_approve:
# Subtract overtime of this attendance
total_overtime = strtime_seconds(overtime.overtime)
attendance_overtime_seconds = strtime_seconds(
attendance.attendance_overtime
)
if total_overtime > attendance_overtime_seconds:
total_overtime = total_overtime - attendance_overtime_seconds
else:
total_overtime = attendance_overtime_seconds - total_overtime
overtime.overtime = format_time(total_overtime)
overtime.save()
try:
attendance.delete()
return Response({"status", "deleted"}, status=200)
except Exception as error:
return Response({"error:", f"{error}"}, status=400)
else:
try:
attendance.delete()
return Response({"status", "deleted"}, status=200)
except Exception as error:
return Response({"error:", f"{error}"}, status=400)
class ValidateAttendanceView(APIView):
"""
Validates an attendance record and sends a notification to the employee.
Method:
put(request, pk): Marks the attendance as validated and notifies the employee.
"""
def put(self, request, pk):
attendance = Attendance.objects.filter(id=pk).update(attendance_validated=True)
attendance = Attendance.objects.filter(id=pk).first()
try:
notify.send(
request.user.employee_get,
recipient=attendance.employee_id.employee_user_id,
verb=f"Your attendance for the date {attendance.attendance_date} is validated",
verb_ar=f"تم تحقيق حضورك في تاريخ {attendance.attendance_date}",
verb_de=f"Deine Anwesenheit für das Datum {attendance.attendance_date} ist bestätigt.",
verb_es=f"Se valida tu asistencia para la fecha {attendance.attendance_date}.",
verb_fr=f"Votre présence pour la date {attendance.attendance_date} est validée.",
redirect="/attendance/view-my-attendance",
icon="checkmark",
api_redirect=f"/api/attendance/attendance?employee_id{attendance.employee_id}",
)
except:
pass
return Response(status=200)
class OvertimeApproveView(APIView):
"""
Approves overtime for an attendance record and sends a notification to the employee.
Method:
put(request, pk): Marks the overtime as approved and notifies the employee.
"""
def put(self, request, pk):
try:
attendance = Attendance.objects.filter(id=pk).update(
attendance_overtime_approve=True
)
except Exception as E:
return Response({"error": str(E)}, status=400)
attendance = Attendance.objects.filter(id=pk).first()
try:
notify.send(
request.user.employee_get,
recipient=attendance.employee_id.employee_user_id,
verb=f"Your {attendance.attendance_date}'s attendance overtime approved.",
verb_ar=f"تمت الموافقة على إضافة ساعات العمل الإضافية لتاريخ {attendance.attendance_date}.",
verb_de=f"Die Überstunden für den {attendance.attendance_date} wurden genehmigt.",
verb_es=f"Se ha aprobado el tiempo extra de asistencia para el {attendance.attendance_date}.",
verb_fr=f"Les heures supplémentaires pour la date {attendance.attendance_date} ont été approuvées.",
redirect="/attendance/attendance-overtime-view",
icon="checkmark",
api_redirect="/api/attendance/attendance-hour-account/",
)
except:
pass
return Response(status=200)
class AttendanceRequestView(APIView):
"""
Handles requests for creating, updating, and viewing attendance records.
Methods:
get(request, pk=None): Retrieves a specific attendance request by `pk` or a filtered list of requests.
post(request): Creates a new attendance request.
put(request, pk): Updates an existing attendance request.
"""
serializer_class = AttendanceRequestSerializer
permission_classes = [IsAuthenticated]
def get(self, request, pk=None):
if pk:
attendance = Attendance.objects.get(id=pk)
serializer = AttendanceRequestSerializer(instance=attendance)
return Response(serializer.data, status=200)
requests = Attendance.objects.filter(
is_validate_request=True,
)
requests = filtersubordinates(
request=request,
perm="attendance.view_attendance",
queryset=requests,
)
requests = requests | Attendance.objects.filter(
employee_id__employee_user_id=request.user,
is_validate_request=True,
)
request_filtered_queryset = AttendanceFilters(request.GET, requests).qs
field_name = request.GET.get("groupby_field", None)
if field_name:
# groupby workflow
url = request.build_absolute_uri()
return groupby_queryset(request, url, field_name, request_filtered_queryset)
pagenation = PageNumberPagination()
page = pagenation.paginate_queryset(request_filtered_queryset, request)
serializer = self.serializer_class(page, many=True)
return pagenation.get_paginated_response(serializer.data)
def post(self, request):
serializer = AttendanceRequestSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=404)
@manager_permission_required("attendance.update_attendance")
def put(self, request, pk):
attendance = Attendance.objects.get(id=pk)
serializer = AttendanceRequestSerializer(instance=attendance, data=request.data)
if serializer.is_valid():
instance = serializer.save()
instance.employee_id = attendance.employee_id
instance.id = attendance.id
if attendance.request_type != "create_request":
attendance.requested_data = json.dumps(instance.serialize())
attendance.request_description = instance.request_description
# set the user level validation here
attendance.is_validate_request = True
attendance.save()
else:
instance.is_validate_request_approved = False
instance.is_validate_request = True
instance.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=404)
class AttendanceRequestApproveView(APIView):
"""
Approves and updates an attendance request.
Method:
put(request, pk): Approves the attendance request, updates attendance records, and handles related activities.
"""
@manager_permission_required("attendance.change_attendance")
def put(self, request, pk):
try:
attendance = Attendance.objects.get(id=pk)
prev_attendance_date = attendance.attendance_date
prev_attendance_clock_in_date = attendance.attendance_clock_in_date
prev_attendance_clock_in = attendance.attendance_clock_in
attendance.attendance_validated = True
attendance.is_validate_request_approved = True
attendance.is_validate_request = False
attendance.request_description = None
attendance.save()
if attendance.requested_data is not None:
requested_data = json.loads(attendance.requested_data)
requested_data["attendance_clock_out"] = (
None
if requested_data["attendance_clock_out"] == "None"
else requested_data["attendance_clock_out"]
)
requested_data["attendance_clock_out_date"] = (
None
if requested_data["attendance_clock_out_date"] == "None"
else requested_data["attendance_clock_out_date"]
)
Attendance.objects.filter(id=pk).update(**requested_data)
# DUE TO AFFECT THE OVERTIME CALCULATION ON SAVE METHOD, SAVE THE INSTANCE ONCE MORE
attendance = Attendance.objects.get(id=pk)
attendance.save()
if (
attendance.attendance_clock_out is None
or attendance.attendance_clock_out_date is None
):
attendance.attendance_validated = True
activity = AttendanceActivity.objects.filter(
employee_id=attendance.employee_id,
attendance_date=prev_attendance_date,
clock_in_date=prev_attendance_clock_in_date,
clock_in=prev_attendance_clock_in,
)
if activity:
activity.update(
employee_id=attendance.employee_id,
attendance_date=attendance.attendance_date,
clock_in_date=attendance.attendance_clock_in_date,
clock_in=attendance.attendance_clock_in,
)
else:
AttendanceActivity.objects.create(
employee_id=attendance.employee_id,
attendance_date=attendance.attendance_date,
clock_in_date=attendance.attendance_clock_in_date,
clock_in=attendance.attendance_clock_in,
)
except Exception as E:
return Response({"error": str(E)}, status=400)
return Response({"status": "approved"}, status=200)
class AttendanceRequestCancelView(APIView):
"""
Cancels an attendance request.
Method:
put(request, pk): Cancels the attendance request, resetting its status and data, and deletes the request if it was a create request.
"""
def put(self, request, pk):
try:
attendance = Attendance.objects.get(id=pk)
if (
attendance.employee_id.employee_user_id == request.user
or is_reportingmanager(request)
or request.user.has_perm("attendance.change_attendance")
):
attendance.is_validate_request_approved = False
attendance.is_validate_request = False
attendance.request_description = None
attendance.requested_data = None
attendance.request_type = None
attendance.save()
if attendance.request_type == "create_request":
attendance.delete()
except Exception as E:
return Response({"error": str(E)}, status=400)
return Response({"status": "success"}, status=200)
class AttendanceOverTimeView(APIView):
"""
Manages CRUD operations for attendance overtime records.
Methods:
get(request, pk=None): Retrieves a specific overtime record by `pk` or a list of records with filtering and pagination.
post(request): Creates a new overtime record.
put(request, pk): Updates an existing overtime record.
delete(request, pk): Deletes an overtime record.
"""
permission_classes = [IsAuthenticated]
def get(self, request, pk=None):
if pk:
attendance_ot = get_object_or_404(AttendanceOverTime, pk=pk)
serializer = AttendanceOverTimeSerializer(attendance_ot)
return Response(serializer.data, status=200)
filterset_class = AttendanceOverTimeFilter(request.GET)
queryset = filterset_class.qs
self_account = queryset.filter(employee_id__employee_user_id=request.user)
permission_based_queryset = filtersubordinates(
request, queryset, "attendance.view_attendanceovertime"
)
queryset = permission_based_queryset | self_account
field_name = request.GET.get("groupby_field", None)
if field_name:
# groupby workflow
url = request.build_absolute_uri()
return groupby_queryset(request, url, field_name, queryset)
pagenation = PageNumberPagination()
page = pagenation.paginate_queryset(queryset, request)
serializer = AttendanceOverTimeSerializer(page, many=True)
return pagenation.get_paginated_response(serializer.data)
@manager_permission_required("attendance.add_attendanceovertime")
def post(self, request):
serializer = AttendanceOverTimeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@manager_permission_required("attendance.change_attendanceovertime")
def put(self, request, pk):
attendance_ot = get_object_or_404(AttendanceOverTime, pk=pk)
serializer = AttendanceOverTimeSerializer(
instance=attendance_ot, data=request.data
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(
permission_required(
"attendance.delete_attendanceovertime", raise_exception=True
)
)
def delete(self, request, pk):
attendance = get_object_or_404(AttendanceOverTime, pk=pk)
attendance.delete()
return Response({"message": "Overtime deleted successfully"}, status=204)
class LateComeEarlyOutView(APIView):
"""
Handles retrieval and deletion of late come and early out records.
Methods:
get(request, pk=None): Retrieves a list of late come and early out records with filtering.
delete(request, pk=None): Deletes a specific late come or early out record by `pk`.
"""
permission_classes = [IsAuthenticated]
def get(self, request, pk=None):
data = LateComeEarlyOutFilter(request.GET)
serializer = AttendanceLateComeEarlyOutSerializer(data.qs, many=True)
return Response(serializer.data, status=200)
def delete(self, request, pk=None):
attendance = get_object_or_404(AttendanceLateComeEarlyOut, pk=pk)
attendance.delete()
return Response({"message": "Attendance deleted successfully"}, status=204)
class AttendanceActivityView(APIView):
"""
Retrieves attendance activity records.
Method:
get(request, pk=None): Retrieves a list of all attendance activity records.
"""
def get(self, request, pk=None):
data = AttendanceActivity.objects.all()
serializer = AttendanceActivitySerializer(data, many=True)
return Response(serializer.data, status=200)
class TodayAttendance(APIView):
"""
Provides the ratio of marked attendances to expected attendances for the current day.
Method:
get(request): Calculates and returns the attendance ratio for today.
"""
def get(self, request):
today = datetime.today()
week_day = today.strftime("%A").lower()
on_time = find_on_time(request, today=today, week_day=week_day)
late_come = find_late_come(start_date=today)
late_come_obj = len(late_come)
marked_attendances = late_come_obj + on_time
expected_attendances = find_expected_attendances(week_day=week_day)
marked_attendances_ratio = 0
if expected_attendances != 0:
marked_attendances_ratio = (
f"{(marked_attendances / expected_attendances) * 100:.2f}"
)
return Response(
{"marked_attendances_ratio": marked_attendances_ratio}, status=200
)
class OfflineEmployeesCountView(APIView):
"""
Retrieves the count of active employees who have not clocked in today.
Method:
get(request): Returns the number of active employees who are not yet clocked in.
"""
def get(self, request):
count = (
EmployeeFilter({"not_in_yet": date.today()})
.qs.exclude(employee_work_info__isnull=True)
.filter(is_active=True)
.count()
)
return Response({"count": count}, status=200)
class OfflineEmployeesListView(APIView):
"""
Lists active employees who have not clocked in today, including their leave status.
Method:
get(request): Retrieves and paginates a list of employees not clocked in today with their leave status.
"""
def get(self, request):
queryset = (
EmployeeFilter({"not_in_yet": date.today()})
.qs.exclude(employee_work_info__isnull=True)
.filter(is_active=True)
)
leave_status = self.get_leave_status(queryset)
pagenation = PageNumberPagination()
page = pagenation.paginate_queryset(leave_status, request)
return pagenation.get_paginated_response(page)
def get_leave_status(self, queryset):
today = date.today()
queryset = queryset.distinct()
# Annotate each employee with their leave status
employees_with_leave_status = queryset.annotate(
leave_status=Case(
# Define different cases based on leave requests and attendance
When(
leaverequest__start_date__lte=today,
leaverequest__end_date__gte=today,
leaverequest__status="approved",
then=Value("On Leave"),
),
When(
leaverequest__start_date__lte=today,
leaverequest__end_date__gte=today,
leaverequest__status="requested",
then=Value("Waiting Approval"),
),
When(
leaverequest__start_date__lte=today,
leaverequest__end_date__gte=today,
then=Value("Canceled / Rejected"),
),
When(
employee_attendances__attendance_date=today, then=Value("Working")
),
default=Value("Expected working"), # Default status
output_field=CharField(),
),
job_position_id=F("employee_work_info__job_position_id"),
).values(
"employee_first_name",
"employee_last_name",
"leave_status",
"employee_profile",
"id",
"job_position_id",
)
for employee in employees_with_leave_status:
if employee["employee_profile"]:
employee["employee_profile"] = (
settings.MEDIA_URL + employee["employee_profile"]
)
return employees_with_leave_status
class CheckingStatus(APIView):
"""
Checks and provides the current attendance status for the authenticated user.
Method:
get(request): Returns the attendance status, duration at work, and clock-in time if available.
"""
permission_classes = [IsAuthenticated]
@classmethod
def _format_seconds(cls, seconds):
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
return f"{hours:02}:{minutes:02}:{seconds:02}"
def get(self, request):
attendance_activity = (
AttendanceActivity.objects.filter(employee_id=request.user.employee_get)
.order_by("-id")
.first()
)
duration = None
work_seconds = request.user.employee_get.get_forecasted_at_work()[
"forecasted_at_work_seconds"
]
duration = CheckingStatus._format_seconds(int(work_seconds))
status = False
clock_in_time = None
today = datetime.now()
attendance_activity_first = (
AttendanceActivity.objects.filter(
employee_id=request.user.employee_get, clock_in_date=today
)
.order_by("in_datetime")
.first()
)
if attendance_activity:
clock_in_time = attendance_activity_first.clock_in.strftime("%I:%M %p")
if attendance_activity.clock_out_date:
status = False
else:
status = True
return Response(
{"status": status, "duration": duration, "clock_in": clock_in_time},
status=200,
)
return Response(
{"status": status, "duration": duration, "clock_in_time": clock_in_time},
status=200,
)
class MailTemplateView(APIView):
"""
Retrieves a list of recruitment mail templates.
Method:
get(request): Returns all recruitment mail templates.
"""
permission_classes = [IsAuthenticated]
def get(self, request):
instances = RecruitmentMailTemplate.objects.all()
serializer = MailTemplateSerializer(instances, many=True)
return Response(serializer.data, status=200)
class ConvertedMailTemplateConvert(APIView):
"""
Renders a recruitment mail template with data from a specified employee.
Method:
put(request): Renders the mail template body with employee and user data and returns the result.
"""
permission_classes = [IsAuthenticated]
def put(self, request):
template_id = request.data.get("template_id", None)
employee_id = request.data.get("employee_id", None)
employee = Employee.objects.filter(id=employee_id).first()
bdy = RecruitmentMailTemplate.objects.filter(id=template_id).first()
template_bdy = template.Template(bdy.body)
context = template.Context(
{"instance": employee, "self": request.user.employee_get}
)
render_bdy = template_bdy.render(context)
return Response(render_bdy)
class OfflineEmployeeMailsend(APIView):
"""
Sends an email with attachments and rendered templates to a specified employee.
Method:
post(request): Renders email templates with employee and user data, attaches files, and sends the email.
"""
permission_classes = [IsAuthenticated]
def post(self, request):
employee_id = request.POST.get("employee_id")
subject = request.POST.get("subject", "")
bdy = request.POST.get("body", "")
other_attachments = request.FILES.getlist("other_attachments")
attachments = [
(file.name, file.read(), file.content_type) for file in other_attachments
]
email_backend = ConfiguredEmailBackend()
host = email_backend.dynamic_username
employee = Employee.objects.get(id=employee_id)
template_attachment_ids = request.POST.getlist("template_attachments")
bodys = list(
RecruitmentMailTemplate.objects.filter(
id__in=template_attachment_ids
).values_list("body", flat=True)
)
for html in bodys:
# due to not having solid template we first need to pass the context
template_bdy = template.Template(html)
context = template.Context(
{"instance": employee, "self": request.user.employee_get}
)
render_bdy = template_bdy.render(context)
attachments.append(
(
"Document",
generate_pdf(render_bdy, {}, path=False, title="Document").content,
"application/pdf",
)
)
template_bdy = template.Template(bdy)
context = template.Context(
{"instance": employee, "self": request.user.employee_get}
)
render_bdy = template_bdy.render(context)
email = EmailMessage(
subject,
render_bdy,
host,
[employee.employee_work_info.email],
)
email.content_subtype = "html"
email.attachments = attachments
try:
email.send()
if employee.employee_work_info.email:
return Response(f"Mail sent to {employee.get_full_name()}")
else:
return Response(f"Email not set for {employee.get_full_name()}")
except Exception as e:
return Response("Something went wrong")

View File

@@ -0,0 +1,27 @@
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.views import APIView
from rest_framework.response import Response
from django.contrib.auth import authenticate
from ...api_serializers.auth.serializers import GetEmployeeSerializer
class LoginAPIView(APIView):
def post(self, request):
if 'username' and 'password' in request.data.keys():
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(username=username, password=password)
if user:
refresh = RefreshToken.for_user(user)
employee = user.employee_get
result = {
'employee' : GetEmployeeSerializer(employee).data,
'access': str(refresh.access_token),
}
return Response(result, status=200)
else:
return Response({'error': 'Invalid credentials'}, status=401)
else:
return Response({'error':'Please provide Username and Password'})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,749 @@
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.pagination import PageNumberPagination
from django.http import Http404
from ...api_decorators.base.decorators import manager_or_owner_permission_required, manager_permission_required
from employee.filters import DisciplinaryActionFilter, DocumentRequestFilter, EmployeeFilter
from employee.models import DisciplinaryAction, Employee, EmployeeBankDetails, EmployeeWorkInformation, Policy,EmployeeType
from employee.views import work_info_export, work_info_import
from ...api_methods.base.methods import groupby_queryset, permission_based_queryset
from ...api_decorators.employee.decorators import or_condition
from horilla.decorators import owner_can_enter
from horilla_documents.models import Document, DocumentRequest
from ... api_serializers.employee.serializers import (DisciplinaryActionSerializer, DocumentRequestSerializer, DocumentSerializer,
EmployeeBankDetailsSerializer, EmployeeListSerializer, EmployeeSelectorSerializer, EmployeeSerializer, EmployeeTypeSerializer, EmployeeWorkInformationSerializer, PolicySerializer)
from django_filters.rest_framework import DjangoFilterBackend
from django.contrib.auth.decorators import permission_required
from django.utils.decorators import method_decorator
from rest_framework.permissions import IsAuthenticated
from django.db.models import ProtectedError
from notifications.signals import notify
from django.db.models import Q
class EmployeeTypeAPIView(APIView):
"""
Retrieves employee types.
Methods:
get(request, pk=None): Returns a single employee type if pk is provided, otherwise returns all employee types.
"""
def get(self,request,pk=None):
if pk:
employee_type = EmployeeType.objects.get(id=pk)
serializer = EmployeeTypeSerializer(employee_type)
return Response(serializer.data,status=200)
employee_type = EmployeeType.objects.all()
serializer = EmployeeTypeSerializer(employee_type,many=True)
return Response(serializer.data,status=200)
class EmployeeAPIView(APIView):
"""
Handles CRUD operations for employees.
Methods:
get(request, pk=None):
- Retrieves a single employee by pk if provided.
- Retrieves and filters all employees if pk is not provided.
post(request):
- Creates a new employee if the user has the 'employee.change_employee' permission.
put(request, pk):
- Updates an existing employee if the user is the employee, a manager, or has 'employee.change_employee' permission.
delete(request, pk):
- Deletes an employee if the user has the 'employee.delete_employee' permission.
"""
filter_backends = [DjangoFilterBackend]
filterset_class = EmployeeFilter
permission_classes = [IsAuthenticated]
def get(self, request, pk=None):
if pk:
try:
employee = Employee.objects.get(pk=pk)
except Employee.DoesNotExist:
return Response({"error": "Employee does not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = EmployeeSerializer(employee)
return Response(serializer.data)
paginator = PageNumberPagination()
employees_queryset = Employee.objects.all()
employees_filter_queryset = self.filterset_class(
request.GET, queryset=employees_queryset).qs
field_name = request.GET.get("groupby_field", None)
if field_name:
url = request.build_absolute_uri()
return groupby_queryset(request, url, field_name, employees_filter_queryset)
page = paginator.paginate_queryset(employees_filter_queryset, request)
serializer = EmployeeSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
@manager_permission_required("employee.change_employee")
def post(self, request):
serializer = EmployeeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
user = request.user
employee = Employee.objects.get(pk=pk)
is_manager = EmployeeWorkInformation.objects.filter(
reporting_manager_id=user.employee_get).first()
if employee == user.employee_get or is_manager or user.has_perm("employee.change_employee"):
serializer = EmployeeSerializer(
employee, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response({"error": "You don't have permission"}, status=400)
@method_decorator(permission_required('employee.delete_employee'))
def delete(self, request, pk):
try:
employee = Employee.objects.get(pk=pk)
employee.delete()
except Employee.DoesNotExist:
return Response({"error": "Employee does not exist"}, status=status.HTTP_404_NOT_FOUND)
except ProtectedError as e:
return Response({"error": str(e)}, status=status.HTTP_204_NO_CONTENT)
return Response(status=status.HTTP_204_NO_CONTENT)
class EmployeeListAPIView(APIView):
"""
Retrieves a paginated list of employees with optional search functionality.
Methods:
get(request):
- Returns a paginated list of employees.
- Optionally filters employees based on a search query in the first or last name.
"""
permission_classes = [IsAuthenticated]
def get(self, request):
paginator = PageNumberPagination()
paginator.page_size = 13
search = request.query_params.get('search',None)
if search:
employees_queryset = Employee.objects.filter(Q(employee_first_name__icontains = search)|Q(employee_last_name__icontains = search))
else:
employees_queryset = Employee.objects.all()
page = paginator.paginate_queryset(employees_queryset, request)
serializer = EmployeeListSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
class EmployeeBankDetailsAPIView(APIView):
"""
Manage employee bank details with CRUD operations.
Methods:
get(request, pk=None):
- Retrieves bank details for a specific employee if `pk` is provided.
- Returns a paginated list of all employee bank details if `pk` is not provided.
post(request):
- Creates a new bank detail entry for an employee.
put(request, pk):
- Updates existing bank details for an employee identified by `pk`.
delete(request, pk):
- Deletes bank details for an employee identified by `pk`.
"""
permission_classes = [IsAuthenticated]
def get_queryset(self):
queryset = EmployeeBankDetails.objects.all()
user = self.request.user
# checking user level permissions
perm = "base.view_employeebankdetails"
queryset = permission_based_queryset(user, perm, queryset)
return queryset
def get(self, request, pk=None):
if pk:
try:
bank_detail = EmployeeBankDetails.objects.get(pk=pk)
except EmployeeBankDetails.DoesNotExist:
return Response({"error": "Bank details do not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = EmployeeBankDetailsSerializer(bank_detail)
return Response(serializer.data)
paginator = PageNumberPagination()
employee_bank_details = self.get_queryset(request)
page = paginator.paginate_queryset(employee_bank_details, request)
serializer = EmployeeBankDetailsSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
@manager_or_owner_permission_required(EmployeeBankDetails, "employee.add_employeebankdetails")
def post(self, request):
serializer = EmployeeBankDetailsSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@manager_or_owner_permission_required(EmployeeBankDetails, "employee.add_employeebankdetails")
def put(self, request, pk):
try:
bank_detail = EmployeeBankDetails.objects.get(pk=pk)
except EmployeeBankDetails.DoesNotExist:
return Response({"error": "Bank details do not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = EmployeeBankDetailsSerializer(
bank_detail, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@manager_permission_required("employee.change_employeebankdetails")
def delete(self, request, pk):
try:
bank_detail = EmployeeBankDetails.objects.get(pk=pk)
bank_detail.delete()
except EmployeeBankDetails.DoesNotExist:
return Response({"error": "Bank details do not exist"}, status=status.HTTP_404_NOT_FOUND)
except Exception as E:
return Response({"error": str(E)}, status=400)
return Response(status=status.HTTP_204_NO_CONTENT)
class EmployeeWorkInformationAPIView(APIView):
"""
Manage employee work information with CRUD operations.
Methods:
get(request, pk):
- Retrieves work information for a specific employee identified by `pk`.
post(request):
- Creates a new work information entry for an employee.
put(request, pk):
- Updates existing work information for an employee identified by `pk`.
delete(request, pk):
- Deletes work information for an employee identified by `pk`.
"""
permission_classes = [IsAuthenticated]
def get(self, request, pk):
work_info = EmployeeWorkInformation.objects.get(pk=pk)
serializer = EmployeeWorkInformationSerializer(work_info)
return Response(serializer.data)
@manager_permission_required("employee.add_employeeworkinformation")
def post(self, request):
serializer = EmployeeWorkInformationSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@manager_permission_required("employee.change_employeeworkinformation")
def put(self, request, pk):
try:
work_info = EmployeeWorkInformation.objects.get(pk=pk)
except EmployeeWorkInformation.DoesNotExist:
raise Http404
serializer = EmployeeWorkInformationSerializer(
work_info, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@method_decorator(permission_required("employee.delete_employeeworkinformation"), name='dispatch')
def delete(self, request, pk):
try:
work_info = EmployeeWorkInformation.objects.get(pk=pk)
except EmployeeWorkInformation.DoesNotExist:
raise Http404
work_info.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class EmployeeWorkInfoExportView(APIView):
"""
Endpoint for exporting employee work information.
Methods:
get(request):
- Exports work information data based on user permissions.
"""
permission_classes = [IsAuthenticated]
@manager_permission_required("employee.add_employeeworkinformation")
def get(self, request):
return work_info_export(request)
class EmployeeWorkInfoImportView(APIView):
"""
Endpoint for importing employee work information.
Methods:
get(request):
- Handles the importing of work information data based on user permissions.
"""
permission_classes = [IsAuthenticated]
@manager_permission_required("employee.add_employeeworkinformation")
def get(self, request):
return work_info_import(request)
class EmployeeBulkUpdateView(APIView):
"""
Endpoint for bulk updating employee and work information.
Permissions:
- Requires authentication and "change_employee" permission.
0
Methods:
put(request):
- Updates multiple employees and their work information.
"""
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("employee.change_employee"), name='dispatch')
def put(self, request):
employee_ids = request.data.get('ids', [])
employees = Employee.objects.filter(id__in=employee_ids)
employee_work_info = EmployeeWorkInformation.objects.filter(
employee_id__in=employees)
employee_data = request.data.get('employee_data', {})
work_info_data = request.data.get("employee_work_info", {})
fields_to_remove = [
"badge_id",
"employee_first_name",
"employee_last_name",
"is_active",
"email",
"phone",
"employee_bank_details__account_number",
]
for field in fields_to_remove:
employee_data.pop(field, None)
work_info_data.pop(field, None)
try:
employees.update(**employee_data)
employee_work_info.update(**work_info_data)
except Exception as e:
return Response({"error": str(e)}, status=400)
return Response({"status": "success"}, status=200)
class DisciplinaryActionAPIView(APIView):
"""
Endpoint for managing disciplinary actions.
Permissions:
- Requires authentication.
Methods:
get(request, pk=None):
- Retrieves a specific disciplinary action by `pk` or lists all disciplinary actions with optional filtering.
post(request):
- Creates a new disciplinary action.
put(request, pk):
- Updates an existing disciplinary action by `pk`.
delete(request, pk):
- Deletes a specific disciplinary action by `pk`.
"""
filterset_class = DisciplinaryActionFilter
permission_classes = [IsAuthenticated]
def get_object(self, pk):
try:
return DisciplinaryAction.objects.get(pk=pk)
except DisciplinaryAction.DoesNotExist:
raise Http404
def get(self, request, pk=None):
if pk:
disciplinary_action = self.get_object(pk)
serializer = DisciplinaryActionSerializer(disciplinary_action)
return Response(serializer.data, status=200)
else:
paginator = PageNumberPagination()
disciplinary_actions = DisciplinaryAction.objects.all()
disciplinary_action_filter_queryset = self.filterset_class(
request.GET, queryset=disciplinary_actions).qs
page = paginator.paginate_queryset(
disciplinary_action_filter_queryset, request)
serializer = DisciplinaryActionSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = DisciplinaryActionSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
disciplinary_action = self.get_object(pk)
serializer = DisciplinaryActionSerializer(
disciplinary_action, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
disciplinary_action = self.get_object(pk)
disciplinary_action.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class PolicyAPIView(APIView):
"""
Endpoint for managing policies.
Permissions:
- Requires authentication.
Methods:
get(request, pk=None):
- Retrieves a specific policy by `pk` or lists all policies with optional search functionality.
post(request):
- Creates a new policy.
put(request, pk):
- Updates an existing policy by `pk`.
delete(request, pk):
- Deletes a specific policy by `pk`.
"""
permission_classes = [IsAuthenticated]
def get_object(self, pk):
try:
return Policy.objects.get(pk=pk)
except Policy.DoesNotExist:
raise Http404
def get(self, request, pk=None):
if pk:
policy = self.get_object(pk)
serializer = PolicySerializer(policy)
return Response(serializer.data)
else:
search = request.GET.get("search", None)
if search:
policies = Policy.objects.filter(title__icontains=search)
else:
policies = Policy.objects.all()
serializer = PolicySerializer(policies, many=True)
paginator = PageNumberPagination()
page = paginator.paginate_queryset(
policies, request)
serializer = PolicySerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
def post(self, request):
serializer = PolicySerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
def put(self, request, pk):
policy = self.get_object(pk)
serializer = PolicySerializer(policy, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=400)
def delete(self, request, pk):
policy = self.get_object(pk)
policy.delete()
return Response(status=204)
class DocumentRequestAPIView(APIView):
"""
Endpoint for managing document requests.
Permissions:
- Requires authentication.
- Specific actions require manager-level permissions.
Methods:
get(request, pk=None):
- Retrieves a specific document request by `pk` or lists all document requests with pagination.
post(request):
- Creates a new document request and notifies relevant employees.
put(request, pk):
- Updates an existing document request by `pk`.
delete(request, pk):
- Deletes a specific document request by `pk`.
"""
permission_classes = [IsAuthenticated]
def get_object(self, pk):
try:
return DocumentRequest.objects.get(pk=pk)
except DocumentRequest.DoesNotExist:
raise Http404
def get(self, request, pk=None):
if pk:
document_request = self.get_object(pk)
serializer = DocumentRequestSerializer(document_request)
return Response(serializer.data)
else:
document_requests = DocumentRequest.objects.all()
pagination = PageNumberPagination()
page = pagination.paginate_queryset(
document_requests, request)
serializer = DocumentRequestSerializer(
page, many=True)
return pagination.get_paginated_response(serializer.data)
@manager_permission_required("horilla_documents.add_documentrequests")
def post(self, request):
serializer = DocumentRequestSerializer(data=request.data)
if serializer.is_valid():
obj = serializer.save()
try:
employees = [
user.employee_user_id for user in obj.employee_id.all()]
notify.send(
request.user.employee_get,
recipient=employees,
verb=f"{request.user.employee_get} requested a document.",
verb_ar=f"طلب {request.user.employee_get} مستنداً.",
verb_de=f"{request.user.employee_get} hat ein Dokument angefordert.",
verb_es=f"{request.user.employee_get} solicitó un documento.",
verb_fr=f"{request.user.employee_get} a demandé un document.",
redirect="/employee/employee-profile",
icon="chatbox-ellipses",
api_redirect=f"/api/employee/document-request/{obj.id}"
)
except:
pass
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@manager_permission_required("horilla_documents.change_documentrequests")
def put(self, request, pk):
document_request = self.get_object(pk)
serializer = DocumentRequestSerializer(
document_request, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@method_decorator(permission_required("employee.delete_employee", raise_exception=True))
def delete(self, request, pk):
document_request = self.get_object(pk)
document_request.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class DocumentAPIView(APIView):
filterset_class = DocumentRequestFilter
permission_classes = [IsAuthenticated]
def get_object(self, pk):
try:
return Document.objects.get(pk=pk)
except Document.DoesNotExist:
raise Http404
def get(self, request, pk=None):
if pk:
document = self.get_object(pk)
serializer = DocumentSerializer(document)
return Response(serializer.data)
else:
documents = Document.objects.all()
document_requests_filtered = self.filterset_class(
request.GET, queryset=documents).qs
paginator = PageNumberPagination()
page = paginator.paginate_queryset(
document_requests_filtered, request)
serializer = DocumentSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
@manager_or_owner_permission_required(DocumentRequest, "horilla_documents.add_document")
def post(self, request):
serializer = DocumentSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
try:
notify.send(
request.user.employee_get,
recipient=request.user.employee_get.get_reporting_manager().employee_user_id,
verb=f"{request.user.employee_get} uploaded a document",
verb_ar=f"قام {request.user.employee_get} بتحميل مستند",
verb_de=f"{request.user.employee_get} hat ein Dokument hochgeladen",
verb_es=f"{request.user.employee_get} subió un documento",
verb_fr=f"{request.user.employee_get} a téléchargé un document",
redirect=f"/employee/employee-view/{request.user.employee_get.id}/",
icon="chatbox-ellipses",
api_redirect=f"/api/employee/documents/"
)
except:
pass
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@method_decorator(owner_can_enter("horilla_documents.change_document", Employee))
def put(self, request, pk):
document = self.get_object(pk)
serializer = DocumentSerializer(document, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@method_decorator(owner_can_enter("horilla_documents.delete_document", Employee))
def delete(self, request, pk):
document = self.get_object(pk)
document.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class DocumentRequestApproveRejectView(APIView):
permission_classes = [IsAuthenticated]
@manager_permission_required("horilla_documents.add_document")
def post(self, request, id, status):
document = Document.objects.filter(id=id).first()
document.status = status
document.save()
return Response({"status": "success"}, status=200)
class DocumentBulkApproveRejectAPIView(APIView):
permission_classes = [IsAuthenticated]
@manager_permission_required("horilla_documents.add_document")
def put(self, request):
ids = request.data.get("ids", None)
status = request.data.get("status", None)
status_code = 200
if ids:
documents = Document.objects.filter(id__in=ids)
response = []
for document in documents:
if not document.document:
status_code = 400
response.append(
{"id": document.id, "error": "No documents"})
continue
response.append({"id": document.id, "status": "success"})
document.status = status
document.save()
return Response(response, status=status_code)
class EmployeeBulkArchiveView(APIView):
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("employee.delete_employee", raise_exception=True))
def post(self, request, is_active):
ids = request.data.get("ids")
error = []
for employee_id in ids:
employee = Employee.objects.get(id=employee_id)
employee.is_active = is_active
employee.employee_user_id.is_active = is_active
if employee.get_archive_condition() is False:
employee.save()
error.append({"employee": str(employee),
"error": "Related model found for this employee. "})
return Response(error, status=200)
class EmployeeArchiveView(APIView):
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("employee.delete_employee", raise_exception=True))
def post(self, request, id, is_active):
employee = Employee.objects.get(id=id)
employee.is_active = is_active
employee.employee_user_id.is_active = is_active
response = None
if employee.get_archive_condition() is False:
employee.save()
else:
response = {"employee": str(
employee), "error": employee.get_archive_condition()}
return Response(response, status=200)
class EmployeeSelectorView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
employee = request.user.employee_get
employees = Employee.objects.filter(employee_user_id=request.user)
is_manager = EmployeeWorkInformation.objects.filter(
reporting_manager_id=employee
).exists()
if is_manager:
employees = Employee.objects.filter(
Q(pk=employee.pk) | Q(
employee_work_info__reporting_manager_id=employee)
)
if request.user.has_perm("employee.view_employee"):
employees = Employee.objects.all()
paginator = PageNumberPagination()
page = paginator.paginate_queryset(
employees, request)
serializer = EmployeeSelectorSerializer(page, many=True)
return paginator.get_paginated_response(serializer.data)
class ReportingManagerCheck(APIView):
permission_classes = [IsAuthenticated]
def get(self,request):
if Employee.objects.filter(employee_work_info__reporting_manager_id =request.user.employee_get):
return Response(status=200)
return Response(status=404)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from ...api_serializers.notifications.serializers import NotificationSerializer
from rest_framework.pagination import PageNumberPagination
# Create your views here.
class NotificationView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, type):
if type == 'all':
queryset = request.user.notifications.all()
elif type == 'unread':
queryset = request.user.notifications.unread()
pagination = PageNumberPagination()
page = pagination.paginate_queryset(queryset, request)
serializer = NotificationSerializer(page, many=True)
return pagination.get_paginated_response(serializer.data)
class NotificationReadDelView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, id):
obj = request.user.notifications.filter(id=id).first()
obj.mark_as_read()
serializer = NotificationSerializer(obj)
return Response(serializer.data, status=200)
def delete(self, request, id):
obj = request.user.notifications.filter(id=id).first()
obj.deleted = True
obj.save()
return Response({"status": "deleted"}, status=200)
class NotificationBulkReadDelView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
obj = request.user.notifications.all()
obj.mark_all_as_read()
return Response({"status": "marked as read"}, status=200)
def delete(self, request):
obj = request.user.notifications.all()
obj.mark_all_as_deleted()
return Response({"status": "deleted"}, status=200)
class NotificationBulkDelUnreadMessageView(APIView):
permission_classes = [IsAuthenticated]
def delete(self, request):
obj = request.user.notifications.unread()
obj.mark_all_as_deleted()
return Response({"status": "deleted"}, status=200)

View File

@@ -0,0 +1,348 @@
from collections import defaultdict
import gettext
from django.shortcuts import render
from rest_framework.views import APIView
from base.backends import ConfiguredEmailBackend
from payroll.models.tax_models import TaxBracket
from payroll.threadings.mail import MailSendThread
from payroll.views.views import payslip_pdf
from ... api_serializers.payroll.serializers import AllowanceSerializer, ContractSerializer, DeductionSerializer, LoanAccountSerializer, PayslipSerializer, ReimbursementSerializer, TaxBracketSerializer
from ...api_methods.base.methods import groupby_queryset
from payroll.filters import AllowanceFilter, ContractFilter, DeductionFilter, PayslipFilter
from payroll.models.models import Allowance, Contract, Deduction, LoanAccount, Payslip, Reimbursement
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.contrib.auth.decorators import permission_required
from django.utils.decorators import method_decorator
class PayslipView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request,id=None):
if id:
payslip = Payslip.objects.filter(id=id).first()
if request.user.has_perm("payroll.view_payslip") or payslip.employee_id == request.user.employee_get:
serializer = PayslipSerializer(payslip)
return Response(serializer.data,status=200)
if request.user.has_perm("payroll.view_payslip"):
payslips = Payslip.objects.all()
else:
payslips = Payslip.objects.filter(
employee_id__employee_user_id=request.user
)
payslip_filter_queryset = PayslipFilter(request.GET, payslips).qs
# groupby workflow
field_name = request.GET.get("groupby_field", None)
if field_name:
url = request.build_absolute_uri()
return groupby_queryset(request, url, field_name, payslip_filter_queryset)
pagination = PageNumberPagination()
page = pagination.paginate_queryset(payslip_filter_queryset, request)
serializer = PayslipSerializer(page, many=True)
return pagination.get_paginated_response(serializer.data)
class PayslipDownloadView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, id):
if request.user.has_perm("payroll.view_payslip"):
return payslip_pdf(request, id)
if Payslip.objects.filter(id=id, employee_id=request.user.employee_get):
return payslip_pdf(request, id)
else:
raise Response({"error":"You don't have permission"})
class PayslipSendMailView(APIView):
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("payroll.add_payslip", raise_exception=True))
def post(self, request):
email_backend = ConfiguredEmailBackend()
if not getattr(
email_backend, "dynamic_username_with_display_name", None
) or not len(email_backend.dynamic_username_with_display_name):
return Response({"error": "Email server is not configured"}, status=400)
payslip_ids = request.data.get("id", [])
payslips = Payslip.objects.filter(id__in=payslip_ids)
result_dict = defaultdict(
lambda: {"employee_id": None, "instances": [], "count": 0}
)
for payslip in payslips:
employee_id = payslip.employee_id
result_dict[employee_id]["employee_id"] = employee_id
result_dict[employee_id]["instances"].append(payslip)
result_dict[employee_id]["count"] += 1
mail_thread = MailSendThread(
request, result_dict=result_dict, ids=payslip_ids)
mail_thread.start()
return Response({"status": "success"}, status=200)
class ContractView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request,id=None):
if id :
contract = Contract.objects.filter(id=id).first()
serializer = ContractSerializer(contract)
return Response(serializer.data,status=200)
if request.user.has_perm("payroll.view_contract"):
contracts = Contract.objects.all()
else:
contracts = Contract.objects.filter(
employee_id=request.user.employee_get)
filter_queryset = ContractFilter(request.GET, contracts).qs
# groupby workflow
field_name = request.GET.get("groupby_field", None)
if field_name:
url = request.build_absolute_uri()
return groupby_queryset(request, url, field_name, filter_queryset)
pagination = PageNumberPagination()
page = pagination.paginate_queryset(filter_queryset, request)
serializer = ContractSerializer(page, many=True)
return pagination.get_paginated_response(serializer.data)
@method_decorator(permission_required("payroll.add_contract", raise_exception=True))
def post(self, request):
serializer = ContractSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.change_contract", raise_exception=True))
def put(self, request, pk):
contract = Contract.objects.get(id=pk)
serializer = ContractSerializer(instance=contract, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.delete_contract", raise_exception=True))
def delete(self, request, pk):
contract = Contract.objects.get(id=pk)
contract.delete()
return Response({"status": "deleted"}, status=200)
class AllowanceView(APIView):
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("payroll.view_allowance", raise_exception=True))
def get(self, request,pk=None):
if pk:
allowance = Allowance.objects.get(id=pk)
serializer = AllowanceSerializer(instance=allowance)
return Response(serializer.data,status=200)
allowance = Allowance.objects.all()
filter_queryset = AllowanceFilter(request.GET, allowance).qs
pagination = PageNumberPagination()
page = pagination.paginate_queryset(filter_queryset, request)
serializer = AllowanceSerializer(page, many=True)
return pagination.get_paginated_response(serializer.data)
@method_decorator(permission_required("payroll.add_allowance", raise_exception=True))
def post(self, request):
serializer = AllowanceSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.change_allowance", raise_exception=True))
def put(self, request, pk):
contract = Allowance.objects.get(id=pk)
serializer = AllowanceSerializer(instance=contract, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.delete_allowance", raise_exception=True))
def delete(self, request, pk):
contract = Allowance.objects.get(id=pk)
contract.delete()
return Response({"status": "deleted"}, status=200)
class DeductionView(APIView):
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("payroll.view_deduction", raise_exception=True))
def get(self, request,pk=None):
if pk:
deduction = Deduction.objects.get(id=pk)
serializer = DeductionSerializer(instance=deduction)
return Response(serializer.data,status=200)
deduction = Deduction.objects.all()
filter_queryset = DeductionFilter(request.GET, deduction).qs
pagination = PageNumberPagination()
page = pagination.paginate_queryset(filter_queryset, request)
serializer = DeductionSerializer(page, many=True)
return pagination.get_paginated_response(serializer.data)
@method_decorator(permission_required("payroll.add_deduction", raise_exception=True))
def post(self, request):
serializer = DeductionSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.change_deduction", raise_exception=True))
def put(self, request, pk):
contract = Deduction.objects.get(id=pk)
serializer = DeductionSerializer(instance=contract, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.delete_deduction", raise_exception=True))
def delete(self, request, pk):
contract = Deduction.objects.get(id=pk)
contract.delete()
return Response({"status": "deleted"}, status=200)
class LoanAccountView(APIView):
permission_classes = [IsAuthenticated]
@method_decorator(permission_required("payroll.add_loanaccount", raise_exception=True))
def post(self, request):
serializer = LoanAccountSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.view_loanaccount", raise_exception=True))
def get(self, request, pk=None):
if pk:
loan_account = LoanAccount.objects.get(id=pk)
serializer = LoanAccountSerializer(instance=loan_account)
return Response(serializer.data, status=200)
loan_accounts = LoanAccount.objects.all()
pagination = PageNumberPagination()
page = pagination.paginate_queryset(loan_accounts, request)
serializer = LoanAccountSerializer(page, many=True)
return pagination.get_paginated_response(serializer.data)
@method_decorator(permission_required("payroll.change_loanaccount", raise_exception=True))
def put(self, request, pk):
loan_account = LoanAccount.objects.get(id=pk)
serializer = LoanAccountSerializer(loan_account, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.delete_loanaccount", raise_exception=True))
def delete(self, request, pk):
loan_account = LoanAccount.objects.get(id=pk)
loan_account.delete()
return Response(status=200)
class ReimbursementView(APIView):
serializer_class = ReimbursementSerializer
permission_classes = [IsAuthenticated]
def get(self, request, pk=None):
if pk:
reimbursement = Reimbursement.objects.get(id=pk)
serializer = self.serializer_class(reimbursement)
return Response(serializer.data, status=200)
reimbursements = Reimbursement.objects.all()
if request.user.has_perm("payroll.view_reimbursement"):
reimbursements = Reimbursement.objects.all()
else:
reimbursements = Reimbursement.objects.filter(
employee_id=request.user.employee_get)
pagination = PageNumberPagination()
page = pagination.paginate_queryset(reimbursements, request)
serializer = self.serializer_class(page, many=True)
return pagination.get_paginated_response(serializer.data)
def post(self, request):
serializer = self.serializer_class(
data=request.data, context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.change_reimbursement", raise_exception=True))
def put(self, request, pk):
reimbursement = Reimbursement.objects.get(id=pk)
serializer = self.serializer_class(
instance=reimbursement, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
@method_decorator(permission_required("payroll.delete_reimbursement", raise_exception=True))
def delete(self, request, pk):
reimbursement = Reimbursement.objects.get(id=pk)
reimbursement.delete()
return Response(status=200)
class ReimbusementApproveRejectView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, pk):
status = request.data.get('status', None)
amount = request.data.get('amount', None)
amount = eval(request.data.get('amount')
) if request.data.get('amount') else 0
amount = max(0, amount)
reimbursement = Reimbursement.objects.filter(id=pk)
if amount:
reimbursement.update(amount=amount)
reimbursement.update(status=status)
return Response({"status": reimbursement.first().status}, status=200)
class TaxBracketView(APIView):
def get(self, request, pk=None):
if pk:
tax_bracket = TaxBracket.objects.get(id=pk)
serializer = TaxBracketSerializer(tax_bracket)
return Response(serializer.data, status=200)
tax_brackets = TaxBracket.objects.all()
serializer = TaxBracketSerializer(instance=tax_brackets, many=True)
return Response(serializer.data, status=200)
def post(self, request):
serializer = TaxBracketSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
def put(self, request, pk):
tax_bracket = TaxBracket.objects.get(id=pk)
serializer = TaxBracketSerializer(
instance=tax_bracket, data=request.data, partial=True)
if serializer.save():
serializer.save()
return Response(serializer.data, status=200)
return Response(serializer.errors, status=400)
def delete(self, request, pk):
tax_bracket = TaxBracket.objects.get(id=pk)
tax_bracket.delete()
return Response(status=200)