From 25829dad7764c816bd917a85261b0f6ccf1fb96c Mon Sep 17 00:00:00 2001 From: Horilla Date: Thu, 25 Jan 2024 15:59:15 +0530 Subject: [PATCH] [ADD] OFFBOARDING: Resignation request --- offboarding/admin.py | 9 +- offboarding/filters.py | 32 +++ offboarding/forms.py | 89 +++++++- offboarding/models.py | 102 ++++++++- .../offboarding/resignation/filter.html | 55 +++++ .../offboarding/resignation/form.html | 7 + .../offboarding/resignation/nav.html | 35 +++ .../resignation/request_cards.html | 188 +++++++++++++++ .../resignation/requests_view.html | 18 ++ .../offboarding/settings/settings.html | 13 ++ offboarding/urls.py | 32 ++- offboarding/views.py | 216 ++++++++++++++++-- 12 files changed, 760 insertions(+), 36 deletions(-) create mode 100644 offboarding/filters.py create mode 100644 offboarding/templates/offboarding/resignation/filter.html create mode 100644 offboarding/templates/offboarding/resignation/form.html create mode 100644 offboarding/templates/offboarding/resignation/nav.html create mode 100644 offboarding/templates/offboarding/resignation/request_cards.html create mode 100644 offboarding/templates/offboarding/resignation/requests_view.html create mode 100644 offboarding/templates/offboarding/settings/settings.html diff --git a/offboarding/admin.py b/offboarding/admin.py index ff57014eb..8a10c2734 100644 --- a/offboarding/admin.py +++ b/offboarding/admin.py @@ -4,10 +4,17 @@ from offboarding.models import ( OffboardingNote, OffboardingTask, EmployeeTask, + ResignationLetter, ) # Register your models here. admin.site.register( - [OffboardingStageMultipleFile, OffboardingNote, OffboardingTask, EmployeeTask] + [ + OffboardingStageMultipleFile, + ResignationLetter, + OffboardingNote, + OffboardingTask, + EmployeeTask, + ] ) diff --git a/offboarding/filters.py b/offboarding/filters.py new file mode 100644 index 000000000..90e370ac4 --- /dev/null +++ b/offboarding/filters.py @@ -0,0 +1,32 @@ +""" +offboarding/filters.py + +This module is used to register django_filters +""" +import django_filters +from django import forms +from base.filters import FilterSet +from offboarding.models import ResignationLetter + + +class LetterFilter(FilterSet): + """ + LetterFilter class + """ + + search = django_filters.CharFilter(field_name="title", lookup_expr="icontains") + planned_to_leave_on = django_filters.DateFilter( + field_name="planned_to_leave_on", + widget=forms.DateInput(attrs={"type": "date"}), + ) + + class Meta: + model = ResignationLetter + fields = [ + "status", + "employee_id", + "planned_to_leave_on", + "employee_id__employee_work_info__department_id", + "employee_id__employee_work_info__job_position_id", + "employee_id__employee_work_info__reporting_manager_id", + ] diff --git a/offboarding/forms.py b/offboarding/forms.py index 0e662fd6b..a129eb48f 100644 --- a/offboarding/forms.py +++ b/offboarding/forms.py @@ -4,11 +4,14 @@ offboarding/forms.py This module is used to register forms for offboarding app """ +import contextlib from typing import Any from django import forms from django.template.loader import render_to_string from base.forms import ModelForm +from base import thread_local_middleware from employee.forms import MultipleFileField +from notifications.signals import notify from offboarding.models import ( EmployeeTask, Offboarding, @@ -17,6 +20,7 @@ from offboarding.models import ( OffboardingStage, OffboardingStageMultipleFile, OffboardingTask, + ResignationLetter, ) @@ -89,8 +93,15 @@ class OffboardingEmployeeForm(ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.instance.pk: - self.initial["notice_period_starts"] = self.instance.notice_period_starts.strftime("%Y-%m-%d") - self.initial["notice_period_ends"] = self.instance.notice_period_ends.strftime("%Y-%m-%d") + if self.instance.notice_period_starts: + self.initial[ + "notice_period_starts" + ] = self.instance.notice_period_starts.strftime("%Y-%m-%d") + if self.instance.notice_period_ends: + self.initial[ + "notice_period_ends" + ] = self.instance.notice_period_ends.strftime("%Y-%m-%d") + class StageSelectForm(ModelForm): """ @@ -180,7 +191,13 @@ class TaskForm(ModelForm): super().__init__(*args, **kwargs) self.fields["stage_id"].empty_label = "All Stages in Offboarding" self.fields["managers"].empty_label = None - queryset = OffboardingEmployee.objects.filter(stage_id__offboarding_id=OffboardingStage.objects.filter(id=self.initial.get("stage_id")).first().offboarding_id) + queryset = OffboardingEmployee.objects.filter( + stage_id__offboarding_id=OffboardingStage.objects.filter( + id=self.initial.get("stage_id") + ) + .first() + .offboarding_id + ) self.fields["tasks_to"].queryset = queryset def as_p(self): @@ -200,3 +217,69 @@ class TaskForm(ModelForm): employee_id=employee, task_id=self.instance, ) + + +class ResignationLetterForm(ModelForm): + """ + Resignation Letter + """ + + description = forms.CharField( + widget=forms.Textarea(attrs={"data-summernote": "", "style": "display:none;"}), + label="Description", + ) + verbose_name = "Resignation Letter" + + class Meta: + model = ResignationLetter + fields = "__all__" + + def as_p(self): + """ + Render the form fields as HTML table rows with Bootstrap styling. + """ + context = {"form": self} + table_html = render_to_string("common_form.html", context) + return table_html + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["planned_to_leave_on"].widget = forms.DateInput( + attrs={"type": "date", "class": "oh-input w-100"} + ) + exclude = [] + if self.instance.pk: + exclude.append("employee_id") + self.verbose_name = ( + self.instance.employee_id.get_full_name() + " Resignation Letter" + ) + + request = getattr(thread_local_middleware._thread_locals, "request", None) + + if request and not request.user.has_perm("offboarding.add_offboardingemployee"): + exclude = exclude + [ + "employee_id", + "status", + "is_active", + ] + self.instance.employee_id = request.user.employee_get + for field in exclude: + del self.fields[field] + + def save(self, commit: bool = ...) -> Any: + instance = super().save(commit) + request = getattr(thread_local_middleware._thread_locals, "request", None) + if request and not request.user.has_perm("offboarding.add_offboardingemployee"): + with contextlib.suppress(Exception): + notify.send( + request.user.employee_get, + recipient=self.instance.employee_id.get_reporting_manager().employee_user_id, + verb=f"{self.instance.employee_id.get_full_name()} requested for resignation.", + verb_ar=f"", + verb_de=f"", + verb_es=f"", + verb_fr=f"", + redirect="#", + icon="information", + ) + return instance diff --git a/offboarding/models.py b/offboarding/models.py index ccd9245a3..04ca6933f 100644 --- a/offboarding/models.py +++ b/offboarding/models.py @@ -1,9 +1,9 @@ -from collections.abc import Iterable -from typing import Any +from datetime import date from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver from base import thread_local_middleware +from base.models import Company from employee.models import Employee from horilla_audit.models import HorillaAuditInfo, HorillaAuditLog from notifications.signals import notify @@ -25,7 +25,10 @@ class Offboarding(models.Model): created_at = models.DateTimeField(auto_now_add=True) status = models.CharField(max_length=10, default="ongoing", choices=statuses) is_active = models.BooleanField(default=True) - + company_id = models.ForeignKey( + Company, on_delete=models.CASCADE, null=True, editable=False + ) + def __str__(self): return self.title @@ -91,18 +94,91 @@ class OffboardingEmployee(models.Model): Employee, on_delete=models.CASCADE, verbose_name="Employee" ) stage_id = models.ForeignKey( - OffboardingStage, on_delete=models.PROTECT, verbose_name="Stage" + OffboardingStage, on_delete=models.PROTECT, verbose_name="Stage", null=True ) - notice_period = models.IntegerField() - unit = models.CharField(max_length=10, choices=units) - notice_period_starts = models.DateField() - notice_period_ends = models.DateField() + notice_period = models.IntegerField(null=True) + unit = models.CharField(max_length=10, choices=units, null=True) + notice_period_starts = models.DateField(null=True) + notice_period_ends = models.DateField(null=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self) -> str: return self.employee_id.get_full_name() +class ResignationLetter(models.Model): + """ + Resignation Request Employee model + """ + + statuses = [ + ("requested", "Requested"), + ("approved", "Approved"), + ("rejected", "Rejected"), + ] + employee_id = models.ForeignKey( + Employee, on_delete=models.CASCADE, verbose_name="Employee" + ) + title = models.CharField(max_length=30, null=True) + description = models.TextField( + null=True, + ) + planned_to_leave_on = models.DateField() + status = models.CharField(max_length=10, choices=statuses, default="requested") + offboarding_employee_id = models.ForeignKey( + OffboardingEmployee, on_delete=models.CASCADE, editable=False, null=True + ) + created_at = models.DateTimeField(auto_now_add=True) + is_active = models.BooleanField(default=True) + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + if self.status == "approved": + pass + + return + + def to_offboarding_employee( + self, offboarding, notice_period_starts, notice_period_ends + ): + """ + This method is used to convert/add employee to offboarding + """ + offboarding_employee = OffboardingEmployee.objects.filter( + employee_id=self.employee_id + ).first() + offboarding_employee = ( + offboarding_employee if offboarding_employee else OffboardingEmployee() + ) + offboarding_employee.employee_id = self.employee_id + offboarding_employee.stage_id = ( + OffboardingStage.objects.order_by("created_at") + .filter(offboarding_id=offboarding) + .first() + ) + offboarding_employee.notice_period_starts = notice_period_starts + offboarding_employee.notice_period_ends = notice_period_ends + if ( + notice_period_starts + and notice_period_ends + and not isinstance(notice_period_starts, str) + and not isinstance(notice_period_ends, str) + ): + diffs = date( + day=notice_period_ends.day, + month=notice_period_ends.month, + year=notice_period_ends.year, + ) - date( + day=notice_period_starts.day, + month=notice_period_starts.month, + year=notice_period_starts.year, + ) + diffs = diffs.days + offboarding_employee.notice_period = diffs if diffs > 0 else None + offboarding_employee.unit = "day" if diffs > 0 else None + offboarding_employee.save() + + class OffboardingTask(models.Model): """ OffboardingTask model @@ -146,6 +222,7 @@ class EmployeeTask(models.Model): ) status = models.CharField(max_length=10, choices=statuses, default="todo") task_id = models.ForeignKey(OffboardingTask, on_delete=models.CASCADE) + description = models.TextField(null=True, editable=False) history = HorillaAuditLog( related_name="history_set", bases=[ @@ -156,7 +233,7 @@ class EmployeeTask(models.Model): class Meta: unique_together = ["employee_id", "task_id"] - + def save(self, *args, **kwargs): super().save(*args, **kwargs) request = getattr(_thread_locals, "request", None) @@ -218,3 +295,10 @@ class OffboardingNote(models.Model): if self.employee_id: self.stage_id = self.employee_id.stage_id return super().save(*args, **kwargs) + + +class OffboardingGeneralSetting(models.Model): + """ + OffboardingGeneralSettings + """ + resignation_request = models.BooleanField(default=True) \ No newline at end of file diff --git a/offboarding/templates/offboarding/resignation/filter.html b/offboarding/templates/offboarding/resignation/filter.html new file mode 100644 index 000000000..2fc15f0ea --- /dev/null +++ b/offboarding/templates/offboarding/resignation/filter.html @@ -0,0 +1,55 @@ +{% load i18n %} +
+
+ +
+
+
+
{% trans "Reimbursement" %}
+
+
+
+
+ + {{f.form.employee_id}} +
+
+ + {{f.form.status}} +
+
+ + {{f.form.employee_id__employee_work_info__reporting_manager_id}} +
+
+
+
+ + {{f.form.employee_id__employee_work_info__department_id}} +
+
+ + {{f.form.planned_to_leave_on}} +
+
+ + {{f.form.employee_id__employee_work_info__job_position_id}} +
+
+
+
+
+
+ +
+
+ +
\ No newline at end of file diff --git a/offboarding/templates/offboarding/resignation/form.html b/offboarding/templates/offboarding/resignation/form.html new file mode 100644 index 000000000..d05124f46 --- /dev/null +++ b/offboarding/templates/offboarding/resignation/form.html @@ -0,0 +1,7 @@ +
+{{form.as_p}} +
+ \ No newline at end of file diff --git a/offboarding/templates/offboarding/resignation/nav.html b/offboarding/templates/offboarding/resignation/nav.html new file mode 100644 index 000000000..c3602bdb3 --- /dev/null +++ b/offboarding/templates/offboarding/resignation/nav.html @@ -0,0 +1,35 @@ +{% load i18n %} +
+
+

{% trans 'Resignations' %}

+
+
+
+
+
+ + +
+ {% include 'offboarding/resignation/filter.html' %} + +
+ +
+
+ + diff --git a/offboarding/templates/offboarding/resignation/request_cards.html b/offboarding/templates/offboarding/resignation/request_cards.html new file mode 100644 index 000000000..0e2b22125 --- /dev/null +++ b/offboarding/templates/offboarding/resignation/request_cards.html @@ -0,0 +1,188 @@ +{% load i18n %} +{% include 'filter_tags.html' %} +{% if perms.offboarding.view_resignationletter %} +
+ + + {% trans 'Rejected' %} + + + + {% trans 'Requested' %} + + + + {% trans 'Approved' %} + +
+{% endif %} + +
+ {% for record in letters %} +
+
+
+
{{ record.status|capfirst }}
+
+
+ {% if perms.offboarding.change_resignationletter %} +
+ + + +
+ {% endif %} + +
+
+
+
+
+ +
+
+ {{ record.employee_id.get_full_name }} + + {{ record.employee_id.get_department }} / {{ record.employee_id.get_job_position }} +
+
+
+

{{ record.title }}

+
{{ record.description|safe }}
+
+ {% if perms.offboarding.change_resignationletter %} +
+ + {% if record.status != "approved" %} + + {% else %} + + {% endif %} + + + + + + +
+ {% endif %} + +
+
+ {% endfor %} +
+ +
+
+ {% trans 'Page' %} + {{ letters.number }} {% trans 'of' %} {{ letters.paginator.num_pages }}. + + +
+
+ + \ No newline at end of file diff --git a/offboarding/templates/offboarding/resignation/requests_view.html b/offboarding/templates/offboarding/resignation/requests_view.html new file mode 100644 index 000000000..577f002f3 --- /dev/null +++ b/offboarding/templates/offboarding/resignation/requests_view.html @@ -0,0 +1,18 @@ +{% extends "index.html" %} +{% block content %} + +{% include "offboarding/resignation/nav.html" %} +
+ {% include "offboarding/resignation/request_cards.html" %} +
+{% endblock content %} \ No newline at end of file diff --git a/offboarding/templates/offboarding/settings/settings.html b/offboarding/templates/offboarding/settings/settings.html new file mode 100644 index 000000000..b85f53b10 --- /dev/null +++ b/offboarding/templates/offboarding/settings/settings.html @@ -0,0 +1,13 @@ +{% load i18n %} +{% csrf_token %} +
+

{% trans 'Resignation Request' %}

+
+{% trans 'By enabling this normal users can request for their resignation' %} +
+
+ +
+ +
+ diff --git a/offboarding/urls.py b/offboarding/urls.py index 0ff95a75e..a410aadf3 100644 --- a/offboarding/urls.py +++ b/offboarding/urls.py @@ -28,7 +28,33 @@ urlpatterns = [ path("offboarding-add-task", views.add_task, name="offboarding-add-task"), path("update-task-status", views.update_task_status, name="update-task-status"), path("offboarding-assign-task", views.task_assign, name="offboarding-assign-task"), - path("delete-offboarding-employee",views.delete_employee,name="delete-offboarding-employee"), - path("delete-offboarding-task",views.delete_task,name="delete-offboarding-task"), - path("offboarding-individual-view//",views.offboarding_individual_view,name="offboarding-individual-view"), + path( + "delete-offboarding-employee", + views.delete_employee, + name="delete-offboarding-employee", + ), + path("delete-offboarding-task", views.delete_task, name="delete-offboarding-task"), + path( + "offboarding-individual-view//", + views.offboarding_individual_view, + name="offboarding-individual-view", + ), + path("requests-view", views.request_view, name="resignation-request-view"), + path( + "create-resignation-request", + views.create_resignation_request, + name="create-resignation-request", + ), + path( + "search-resignation-request", + views.search_resignation_request, + name="search-resignation-request", + ), + path( + "delete-resignation-request", + views.delete_resignation_request, + name="delete-resignation-request", + ), + path("update-letter-status", views.update_status, name="update-letter-status"), + path("enable-resignation-request", views.enable_resignation_request, name="enable-resignation-request"), ] diff --git a/offboarding/views.py b/offboarding/views.py index c3de79d20..8c07c42fe 100644 --- a/offboarding/views.py +++ b/offboarding/views.py @@ -1,19 +1,24 @@ +import datetime +from urllib.parse import parse_qs from django.http import HttpResponse, JsonResponse from django.shortcuts import redirect, render from django.contrib import messages from django.contrib.auth.models import User from employee.models import Employee from horilla.decorators import login_required, permission_required +from base.views import paginator_qry from offboarding.decorators import ( any_manager_can_enter, offboarding_manager_can_enter, offboarding_or_stage_manager_can_enter, ) +from offboarding.filters import LetterFilter from offboarding.forms import ( NoteForm, OffboardingEmployeeForm, OffboardingForm, OffboardingStageForm, + ResignationLetterForm, StageSelectForm, TaskForm, ) @@ -21,10 +26,12 @@ from offboarding.models import ( EmployeeTask, Offboarding, OffboardingEmployee, + OffboardingGeneralSetting, OffboardingNote, OffboardingStage, OffboardingStageMultipleFile, OffboardingTask, + ResignationLetter, ) from notifications.signals import notify from django.utils.translation import gettext_lazy as _ @@ -161,12 +168,14 @@ def delete_employee(request): This method is used to delete the offboarding employee """ employee_ids = request.GET.getlist("employee_ids") - instances = OffboardingEmployee.objects.filter(id__in=employee_ids) + instances = OffboardingEmployee.objects.filter(id__in=employee_ids) OffboardingEmployee.objects.filter(id__in=employee_ids).delete() messages.success(request, _("Offboarding employee deleted")) notify.send( request.user.employee_get, - recipient=User.objects.filter(id__in=instances.values_list("employee_id__employee_user_id",flat=True)), + recipient=User.objects.filter( + id__in=instances.values_list("employee_id__employee_user_id", flat=True) + ), verb=f"You have been removed from the offboarding", verb_ar=f"", verb_de=f"", @@ -215,7 +224,9 @@ def change_stage(request): ) notify.send( request.user.employee_get, - recipient=User.objects.filter(id__in=employees.values_list("employee_id__employee_user_id",flat=True)), + recipient=User.objects.filter( + id__in=employees.values_list("employee_id__employee_user_id", flat=True) + ), verb=f"Offboarding stage has been changed", verb_ar=f"", verb_de=f"", @@ -227,12 +238,18 @@ def change_stage(request): return render( request, "offboarding/stage/offboarding_body.html", - {"offboarding": stage.offboarding_id, "stage_forms": stage_forms,"response_message":_("stage changed successfully.")}, + { + "offboarding": stage.offboarding_id, + "stage_forms": stage_forms, + "response_message": _("stage changed successfully."), + }, ) @login_required -@any_manager_can_enter("offboarding.view_offboardingnote",offboarding_employee_can_enter=True) +@any_manager_can_enter( + "offboarding.view_offboardingnote", offboarding_employee_can_enter=True +) def view_notes(request): """ This method is used to render all the notes of the employee @@ -329,21 +346,31 @@ def add_task(request): instance=instance, ) if request.method == "POST": - form = TaskForm(request.POST, instance=instance,initial={ - "stage_id": stage_id, - }) + form = TaskForm( + request.POST, + instance=instance, + initial={ + "stage_id": stage_id, + }, + ) if form.is_valid(): form.save() messages.success(request, "Task Added") return HttpResponse("") - return render(request, "offboarding/task/form.html", {"form": form,}) + return render( + request, + "offboarding/task/form.html", + { + "form": form, + }, + ) @login_required @any_manager_can_enter( "offboarding.change_employeetask", offboarding_employee_can_enter=True ) -def update_task_status(request,*args, **kwargs): +def update_task_status(request, *args, **kwargs): """ This method is used to update the assigned tasks status """ @@ -357,7 +384,11 @@ def update_task_status(request,*args, **kwargs): employee_task.update(status=status) notify.send( request.user.employee_get, - recipient=User.objects.filter(id__in=employee_task.values_list("task_id__managers__employee_user_id",flat=True)), + recipient=User.objects.filter( + id__in=employee_task.values_list( + "task_id__managers__employee_user_id", flat=True + ) + ), verb=f"Offboarding Task status has been updated", verb_ar=f"", verb_de=f"", @@ -374,7 +405,11 @@ def update_task_status(request,*args, **kwargs): return render( request, "offboarding/stage/offboarding_body.html", - {"offboarding": stage.offboarding_id, "stage_forms": stage_forms,"response_message": _("Task status changed successfully.")}, + { + "offboarding": stage.offboarding_id, + "stage_forms": stage_forms, + "response_message": _("Task status changed successfully."), + }, ) @@ -414,8 +449,9 @@ def delete_task(request): messages.success(request, "Task deleted") return redirect(pipeline) + @login_required -def offboarding_individual_view(request,emp_id): +def offboarding_individual_view(request, emp_id): """ This method is used to get the individual view of the offboarding employees parameters: @@ -424,13 +460,153 @@ def offboarding_individual_view(request,emp_id): employee = OffboardingEmployee.objects.get(id=emp_id) tasks = EmployeeTask.objects.filter(employee_id=emp_id) stage_forms = {} - offboarding_stages = OffboardingStage.objects.filter(offboarding_id = employee.stage_id.offboarding_id) - stage_forms[str(employee.stage_id.offboarding_id.id)] = StageSelectForm(offboarding=employee.stage_id.offboarding_id) + offboarding_stages = OffboardingStage.objects.filter( + offboarding_id=employee.stage_id.offboarding_id + ) + stage_forms[str(employee.stage_id.offboarding_id.id)] = StageSelectForm( + offboarding=employee.stage_id.offboarding_id + ) context = { - 'employee':employee, - "tasks":tasks, + "employee": employee, + "tasks": tasks, "choices": EmployeeTask.statuses, - "offboarding_stages":offboarding_stages, - "stage_forms":stage_forms + "offboarding_stages": offboarding_stages, + "stage_forms": stage_forms, } - return render(request, 'offboarding/pipeline/individual_view.html', context) \ No newline at end of file + return render(request, "offboarding/pipeline/individual_view.html", context) + + +@login_required +@permission_required("offboarding.view_resignationletter") +def request_view(request): + """ + This method is used to view the resignation request + """ + defatul_filter = {"status": "requested"} + filter_instance = LetterFilter(defatul_filter) + offboardings = Offboarding.objects.all() + + return render( + request, + "offboarding/resignation/requests_view.html", + { + "letters": paginator_qry(filter_instance.qs, request.GET.get("page")), + "f": filter_instance, + "filter_dict": {"status": ["Requested"]}, + "offboardings": offboardings, + }, + ) + + +@login_required +def search_resignation_request(request): + """ + This method is used to search/filter the letter + """ + if request.user.has_perm("offboarding.view_resignationletter"): + letters = LetterFilter(request.GET).qs + else: + letters = ResignationLetter.objects.filter( + employee_id__employee_user_id=request.user + ) + data_dict = parse_qs(request.GET.urlencode()) + return render( + request, + "offboarding/resignation/request_cards.html", + { + "letters": paginator_qry(letters, request.GET.get("page")), + "filter_dict": data_dict, + "pd": request.GET.urlencode(), + }, + ) + + +@login_required +@permission_required("offboarding.delete_resignationletter") +def delete_resignation_request(request): + """ + This method is used to delete resignation letter instance + """ + ids = request.GET.getlist("letter_ids") + ResignationLetter.objects.filter(id__in=ids).delete() + messages.success(request, "Resignation letter deleted") + return redirect(request_view) + + +def create_resignation_request(request): + """ + This method is used to render form to create resignation requests + """ + instance_id = eval(str(request.GET.get("instance_id"))) + instance = None + if instance_id: + instance = ResignationLetter.objects.get(id=instance_id) + form = ResignationLetterForm(instance=instance) + if request.method == "POST": + form = ResignationLetterForm(request.POST, instance=instance) + if form.is_valid(): + form.save() + messages.success(request, "Resingation letter saved") + return HttpResponse("") + return render(request, "offboarding/resignation/form.html", {"form": form}) + + +@login_required +@permission_required("offboarding.change_resignationletter") +def update_status(request): + """ + This method is used to update the status of resignation letter + """ + ids = request.GET.getlist("letter_ids") + status = request.GET["status"] + offboarding_id = request.GET.get("offboarding_id") + if offboarding_id: + offboarding = Offboarding.objects.get(id=offboarding_id) + notice_period_starts = request.GET.get("notice_period_starts") + notice_period_ends = request.GET.get("notice_period_ends") + if (notice_period_starts and notice_period_ends) is not None: + notice_period_starts = datetime.datetime.strptime( + notice_period_starts, "%Y-%m-%d" + ).date() + notice_period_ends = datetime.datetime.strptime( + notice_period_ends, "%Y-%m-%d" + ).date() + + letters = ResignationLetter.objects.filter(id__in=ids) + # if use update method instead of save then save method will not trigger + if status in ["approved", "rejected"]: + for letter in letters: + letter.status = status + letter.save() + if status == "approved": + letter.to_offboarding_employee( + offboarding, notice_period_starts, notice_period_ends + ) + messages.success( + request, f"Resingation request has been {letter.get_status_display()}" + ) + notify.send( + request.user.employee_get, + recipient=letter.employee_id.employee_user_id, + verb=f"Resingation request has been {letter.get_status_display()}", + verb_ar=f"", + verb_de=f"", + verb_es=f"", + verb_fr=f"", + redirect="#", + icon="information", + ) + return redirect(request_view) + + +@login_required +@permission_required("offboarding.offboardinggeneralsetting") +def enable_resignation_request(request): + """ + Enable disable resignation letter feature + """ + resignation_request_feature = OffboardingGeneralSetting.objects.first() + resignation_request_feature = resignation_request_feature if resignation_request_feature else OffboardingGeneralSetting() + resignation_request_feature.resignation_request = "resignation_request" in request.GET.keys() + resignation_request_feature.save() + return HttpResponse("Success")